diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp new file mode 100644 index 0000000..d4e941b --- /dev/null +++ b/src/text_editor/management.cpp @@ -0,0 +1,184 @@ +inline Window *GetWindow(WindowID id) { + For(Windows) if (it.id.id == id.id) return ⁢ + return &Windows[0]; +} + +inline Buffer *GetBuffer(BufferID id) { + For(Buffers) if (it.id.id == id.id) return ⁢ + return &Buffers[0]; +} + +inline Buffer *GetBuffer(String name) { + For(Buffers) if (it.name == name) return ⁢ + return &Buffers[0]; +} + +inline View *GetView(ViewID id) { + For(Views) if (it.id.id == id.id) return ⁢ + return &Views[0]; +} + +inline bool IsNull(Buffer *buffer) { return buffer->id.id == NullBufferID.id; } + +void SetActiveWindow(WindowID window); +inline bool IsActive(Window *window) { return window->id.id == ActiveWindow.id; } +inline bool IsActive(Window *window, View *view) { return window->active_view.id == view->id.id; } +inline Window *GetActiveWindow() { return GetWindow(ActiveWindow); } +inline View *GetActiveView(Window *window) { + if (window->active_view.id == 0) return GetView(window->views[0]); + else return GetView(window->active_view); +} + +Window *CreateWindow() { + Window *w = Alloc(&Windows); + w->visible = true; + w->draw_scrollbar = true; + w->draw_line_numbers = true; + w->id = AllocWindowID(); + return w; +} + +void AddView(Window *w, ViewID view) { + if (w->active_view.id == 0) w->active_view = view; + For(w->views) if (it.id == view.id) return; + Add(&w->views, view); +} + +View *CreateView(BufferID buffer_id) { + View *w = Alloc(&Views); + w->id = AllocViewID(); + w->buffer_id = buffer_id; + Add(&w->carets, {0, 0}); + return w; +} + +void SetActiveWindow(WindowID window) { + if (LastFrameIDWhenSwitchedActiveWindow != FrameID) { + if (ActiveWindow.id != CommandWindowID.id) { + LastActiveWindow = ActiveWindow; + } + ActiveWindow = window; + LastFrameIDWhenSwitchedActiveWindow = FrameID; + } +} + +Window *FindParentWindow(ViewID view_id) { + ForItem(window, Windows) { + if (window.active_view.id == view_id.id) { + return &window; + } else { + ForItem(child_view, window.views) { + if (child_view.id == view_id.id) { + return &window; + } + } + } + } + return NULL; +} + +View *FindViewWithBufferName(String name) { + For(Views) { + Buffer *buffer = GetBuffer(it.buffer_id); + if (buffer->name == name) { + return ⁢ + } + } + return NULL; +} + +Buffer *BufferOpenFile(String path) { + Scratch scratch; + String abs_path = GetAbsolutePath(scratch, path); + + Buffer *possible_buffer = GetBuffer(abs_path); + if (!IsNull(possible_buffer)) return possible_buffer; + + Allocator sys_allocator = GetSystemAllocator(); + if (!FileExists(path)) { + String dir = ChopLastSlash(abs_path); + if (!IsDir(dir)) { + return GetBuffer(NullBufferID); + } else { + path = Copy(sys_allocator, abs_path); + Buffer *buffer = CreateBuffer(sys_allocator, path); + return buffer; + } + } else { + path = Copy(sys_allocator, abs_path); + String string = ReadFile(scratch, path); + Buffer *buffer = CreateBuffer(sys_allocator, path, string.len * 4); + + for (Int i = 0; i < string.len;) { + if (string.data[i] == '\r') { + i += 1; + continue; + } + if (string.data[i] == '\t') { + // @WARNING: DONT INCREASE THE SIZE CARELESSLY, WE NEED TO ADJUST BUFFER SIZE + for (Int i = 0; i < 4; i += 1) buffer->data[buffer->len++] = L' '; + i += 1; + continue; + } + + uint32_t u32 = '?'; + UTF32Result decode = UTF8ToUTF32(string.data + i, (int64_t)(string.len - i)); + if (!decode.error) { + i += decode.advance; + u32 = decode.out_str; + } else { + i += 1; + } + + UTF16Result encode = UTF32ToUTF16(decode.out_str); + if (!encode.error) { + for (int64_t encode_i = 0; encode_i < encode.len; encode_i += 1) { + buffer->data[buffer->len++] = encode.out_str[encode_i]; + Assert(buffer->len < buffer->cap); + } + } else { + buffer->data[buffer->len++] = L'?'; + } + } + UpdateLines(buffer, {}, String16{(wchar_t *)buffer->data, buffer->len}); + return buffer; + } +} + +View *ViewOpenFile(String name) { + // if there is no view for this file, create one + View *view = FindViewWithBufferName(name); + if (!view) { + Buffer *buffer = BufferOpenFile(name); + if (IsNull(buffer)) Assert(0); // @todo + view = CreateView(buffer->id); + return view; + } + + // If there is a buffer and view for this file then figure out + // if we need another view or can we reuse + Window *window = FindParentWindow(view->id); + if (!window) { + Buffer *buffer = BufferOpenFile(name); + if (IsNull(buffer)) Assert(0); // @todo + view = CreateView(buffer->id); + return view; + } + + // Create new view, 2 view into same buffer at the same time + if (window->active_view.id == view->id.id) { + Buffer *buffer = BufferOpenFile(name); + if (IsNull(buffer)) Assert(0); // @todo + view = CreateView(buffer->id); + return view; + } + + // Unlink and reuse + For(window->views) { + if (it.id == view->id.id) { + UnorderedRemove(&window->views, it); + break; + } + } + return view; +}