API ViewID AllocViewID(View *view) {
    return {ViewIDs.id++, view};
}

API View *CreateView(BufferID active_buffer) {
    Allocator al           = GetSystemAllocator();
    View     *view         = AllocType(al, View);
    view->id               = AllocViewID(view);
    view->active_buffer    = active_buffer;
    view->carets.allocator = al;
    Add(&view->carets, {0, 0});
    Add(&Views, view);
    return view;
}

API View *FindView(ViewID view_id, View *default_view) {
    For(Views) {
        if (it->id == view_id) {
            return it;
        }
    }
    return default_view;
}

API View *FindView(BufferID buffer_id, View *default_view) {
    For(Views) {
        if (it->active_buffer == buffer_id) {
            return it;
        }
    }
    return default_view;
}

API View *FindView(String name, View *default_view) {
    For(Views) {
        Buffer *buffer = GetBuffer(it->active_buffer);
        if (buffer->name == name) {
            return it;
        }
    }
    return default_view;
}

API View *GetView(ViewID id) {
    return FindView(id, Views[0]);
}

API View *OpenBufferView(String name) {
    Buffer *buffer = BufferOpenFile(name);
    View   *view   = CreateView(buffer->id);
    return view;
}

API bool ViewIsCrumb(ViewID view_id) {
    ForItem(window, Windows) {
        For(window->goto_history) if (it.view_id == view_id) return true;
        For(window->goto_redo) if (it.view_id == view_id) return true;
    }
    return false;
}

API bool ViewIsReferenced(ViewID view) {
    if (view == NullViewID) {
        return true;
    }

    if (ViewIsCrumb(view)) {
        return true;
    }

    For(Windows) {
        if (it->active_view == view) {
            return true;
        }
    }
    return false;
}
