View, window and buffer ids

This commit is contained in:
Krzosa Karol
2024-07-23 08:57:09 +02:00
parent bc4fbfd28a
commit 740b0f217f
9 changed files with 267 additions and 217 deletions

View File

@@ -4,16 +4,18 @@ https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation
#define BUFFER_DEBUG 0 #define BUFFER_DEBUG 0
void InitBuffer(Allocator allocator, Buffer *buffer) { void InitBuffer(Allocator allocator, Buffer *buffer) {
buffer->id = AllocBufferID();
buffer->cap = 4096; buffer->cap = 4096;
buffer->data = AllocArray(allocator, U16, buffer->cap); buffer->data = AllocArray(allocator, U16, buffer->cap);
buffer->line_starts.allocator = allocator; buffer->line_starts.allocator = allocator;
Add(&buffer->line_starts, (Int)0); Add(&buffer->line_starts, (Int)0);
} }
Buffer *CreateBuffer(Allocator allocator) { BufferID CreateBuffer(Allocator allocator) {
Buffer *result = AllocType(allocator, Buffer); Buffer result = {};
InitBuffer(allocator, result); InitBuffer(allocator, &result);
return result; Add(&Buffers, result);
return result.id;
} }
void Grow(Buffer *buffer, Int change_size) { void Grow(Buffer *buffer, Int change_size) {

View File

@@ -1,46 +0,0 @@
union Range {
struct {
Int min;
Int max;
};
Int e[2];
};
struct Caret {
union {
Range range;
Int pos[2];
};
Int ifront;
};
struct XY {
Int col;
Int line;
};
struct Edit {
Range range;
String16 string;
};
// @idea: maybe redo tree?
struct HistoryEntry {
Array<Edit> edits;
Array<Caret> carets;
};
// @todo: gap buffer to improve speed of inserting on big files with only one cursor?
struct Buffer {
union {
U16 *data;
wchar_t *str;
};
Int len;
Int cap;
Array<Int> line_starts;
Array<HistoryEntry> undo_stack;
Array<HistoryEntry> redo_stack;
int debug_edit_phase;
};

View File

@@ -8,7 +8,7 @@
#include "../profiler/profiler.cpp" #include "../profiler/profiler.cpp"
#include "buffer.h" #include "text_editor.h"
#include "buffer_helpers.cpp" #include "buffer_helpers.cpp"
#include "buffer.cpp" #include "buffer.cpp"
#include "buffer_multi_cursor.cpp" #include "buffer_multi_cursor.cpp"
@@ -30,13 +30,17 @@ Int FontCharSpacing;
#include "commands.cpp" #include "commands.cpp"
#include "colors.cpp" #include "colors.cpp"
#include "view.h"
#include "windows.cpp" #include "windows.cpp"
#include "view_commands_clipboard.cpp" #include "view_commands_clipboard.cpp"
#include "view_commands.cpp" #include "view_commands.cpp"
#include "view_draw.cpp" #include "view_draw.cpp"
/* /*
- Window IDS and View IDS and Buffer IDS
- Null Window, Null View, Null Buffer
- Open file (utf8->utf16), process determine line endings, tabs to spaces?, Save file (utf16->utf8)
- move off raylib - move off raylib
- line endings - line endings
@@ -44,8 +48,6 @@ Int FontCharSpacing;
- word completion - word completion
- Colored strings - Colored strings
- file dock on left side - file dock on left side
- multiple Windows
- multiple views per window
- Font cache - Font cache
*/ */
@@ -79,26 +81,48 @@ int main(void) {
Font = LoadFontEx("c:\\Windows\\Fonts\\consola.ttf", (int)FontSize, NULL, 500); Font = LoadFontEx("c:\\Windows\\Fonts\\consola.ttf", (int)FontSize, NULL, 500);
FontCharSpacing = GetCharSpacing(Font, FontSize, FontSpacing); FontCharSpacing = GetCharSpacing(Font, FontSize, FontSpacing);
{
Window window = {AllocWindowID()};
{
View view = {}; View view = {};
view.id = AllocViewID();
{
Window window = {};
{
Add(&view.carets, {0, 0}); Add(&view.carets, {0, 0});
view.buffer = CreateBuffer(Perm); view.buffer_id = CreateBuffer(Perm);
LoadTextA(view.buffer); Buffer *buffer = GetBuffer(view.buffer_id);
Add(&window.views, view); LoadTextA(buffer);
Add(&Views, view);
Add(&window.views, view.id);
window.active_view = view.id;
} }
Add(&Windows, window); Add(&Windows, window);
} }
{ {
Window window = {}; Window window = {AllocWindowID()};
{ {
View view = {}; View view = {};
view.id = AllocViewID();
Add(&view.carets, {0, 0}); Add(&view.carets, {0, 0});
view.buffer = CreateBuffer(Perm); view.buffer_id = CreateBuffer(Perm);
LoadUnicode(view.buffer); Buffer *buffer = GetBuffer(view.buffer_id);
Add(&window.views, view); LoadUnicode(buffer);
Add(&Views, view);
Add(&window.views, view.id);
window.active_view = view.id;
}
Add(&Windows, window);
}
{
Window window = {AllocWindowID()};
{
View view = {};
view.id = AllocViewID();
Add(&view.carets, {0, 0});
view.buffer_id = CreateBuffer(Perm);
Buffer *buffer = GetBuffer(view.buffer_id);
LoadLine(buffer);
Add(&Views, view);
Add(&window.views, view.id);
window.active_view = view.id;
} }
Add(&Windows, window); Add(&Windows, window);
} }
@@ -109,19 +133,26 @@ int main(void) {
Rect2I screen_rect = GetScreenRect(); Rect2I screen_rect = GetScreenRect();
float line_numbers_size = MeasureTextEx(Font, "12345", (float)FontSize, (float)FontSpacing).x; float line_numbers_size = MeasureTextEx(Font, "12345", (float)FontSize, (float)FontSpacing).x;
{ {
Windows[0].total_rect = CutLeft(&screen_rect, (Int)((double)GetSize(screen_rect).x * 0.5)); Windows[0].total_rect = CutLeft(&screen_rect, (Int)((double)GetSize(screen_rect).x * 0.33));
Windows[0].document_rect = Windows[0].total_rect; Windows[0].document_rect = Windows[0].total_rect;
Windows[0].scrollbar_rect = CutRight(&Windows[0].document_rect, 10); Windows[0].scrollbar_rect = CutRight(&Windows[0].document_rect, 10);
Windows[0].infobar_rect = CutBottom(&Windows[0].document_rect, (Int)MenuFontSize); Windows[0].infobar_rect = CutBottom(&Windows[0].document_rect, (Int)MenuFontSize);
Windows[0].line_numbers_rect = CutLeft(&Windows[0].document_rect, (Int)line_numbers_size); Windows[0].line_numbers_rect = CutLeft(&Windows[0].document_rect, (Int)line_numbers_size);
} }
{ {
Windows[1].total_rect = screen_rect; Windows[1].total_rect = CutLeft(&screen_rect, (Int)((double)GetSize(screen_rect).x * 0.5));
Windows[1].document_rect = Windows[1].total_rect; Windows[1].document_rect = Windows[1].total_rect;
Windows[1].scrollbar_rect = CutRight(&Windows[1].document_rect, 10); Windows[1].scrollbar_rect = CutRight(&Windows[1].document_rect, 10);
Windows[1].infobar_rect = CutBottom(&Windows[1].document_rect, (Int)MenuFontSize); Windows[1].infobar_rect = CutBottom(&Windows[1].document_rect, (Int)MenuFontSize);
Windows[1].line_numbers_rect = CutLeft(&Windows[1].document_rect, (Int)line_numbers_size); Windows[1].line_numbers_rect = CutLeft(&Windows[1].document_rect, (Int)line_numbers_size);
} }
{
Windows[2].total_rect = CutLeft(&screen_rect, (Int)((double)GetSize(screen_rect).x * 1.0));
Windows[2].document_rect = Windows[2].total_rect;
Windows[2].scrollbar_rect = CutRight(&Windows[2].document_rect, 10);
Windows[2].infobar_rect = CutBottom(&Windows[2].document_rect, (Int)MenuFontSize);
Windows[2].line_numbers_rect = CutLeft(&Windows[2].document_rect, (Int)line_numbers_size);
}
BeginDrawing(); BeginDrawing();
ClearBackground(ColorBackground); ClearBackground(ColorBackground);

View File

@@ -0,0 +1,110 @@
// clang-format off
struct BufferID { Int id; };
struct ViewID { Int id; };
struct WindowID { Int id; };
union Range { struct { Int min; Int max; }; Int e[2]; };
struct Caret { union { Range range; Int pos[2]; }; Int ifront;};
struct XY { Int col; Int line; };
// clang-format on
struct Edit {
Range range;
String16 string;
};
// @idea: maybe redo tree?
struct HistoryEntry {
Array<Edit> edits;
Array<Caret> carets;
};
// @todo: gap buffer to improve speed of inserting on big files with only one cursor?
struct Buffer {
BufferID id;
union {
U16 *data;
wchar_t *str;
};
Int len;
Int cap;
Array<Int> line_starts;
Array<HistoryEntry> undo_stack;
Array<HistoryEntry> redo_stack;
int debug_edit_phase;
};
struct View {
ViewID id;
BufferID buffer_id;
Vec2I scroll;
Array<Caret> carets;
Range selection_anchor;
};
struct Window {
WindowID id;
ViewID active_view;
Array<ViewID> views;
Rect2I total_rect;
Rect2I scrollbar_rect;
Rect2I infobar_rect;
Rect2I line_numbers_rect;
Rect2I document_rect;
int mouse_selecting_scrollbar;
bool mouse_selecting;
double mouse_scroller_offset;
};
struct Scroller {
Rect2 rect;
double begin;
double end;
Int line_count;
};
Rect2I GetVisibleCells(Window &window);
void AfterEdit(View *view, Array<Edit> edits);
Scroller ComputeScrollerRect(Window &window);
WindowID WindowIDs = {1};
BufferID BufferIDs = {1};
ViewID ViewIDs = {1};
Window NullWindow = {};
View NullView = {};
Buffer NullBuffer = {};
Array<Buffer> Buffers = {};
Array<View> Views = {};
Array<Window> Windows = {};
WindowID ActiveWindow = {};
inline Window *GetWindow(WindowID id) {
For(Windows) if (it.id.id == id.id) return &it;
return &NullWindow;
}
inline Buffer *GetBuffer(BufferID id) {
For(Buffers) if (it.id.id == id.id) return &it;
return &NullBuffer;
}
inline View *GetView(ViewID id) {
For(Views) if (it.id.id == id.id) return &it;
return &NullView;
}
inline ViewID AllocViewID() { return {ViewIDs.id++}; }
inline WindowID AllocWindowID() { return {WindowIDs.id++}; }
inline BufferID AllocBufferID() { return {BufferIDs.id++}; }
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);
}

View File

@@ -1,32 +0,0 @@
struct View {
Vec2I scroll;
Buffer *buffer;
Array<Caret> carets;
Range selection_anchor;
};
struct Window {
Int active_view;
Array<View> views;
Rect2I total_rect;
Rect2I scrollbar_rect;
Rect2I infobar_rect;
Rect2I line_numbers_rect;
Rect2I document_rect;
int mouse_selecting_scrollbar;
bool mouse_selecting;
double mouse_scroller_offset;
};
struct Scroller {
Rect2 rect;
double begin;
double end;
Int line_count;
};
Rect2I GetVisibleCells(Window &window);
void AfterEdit(View *view, Array<Edit> edits);
Scroller ComputeScrollerRect(Window &window);

View File

@@ -1,48 +1,50 @@
void Command_Replace(View *view, String16 string) { void Command_Replace(View *view, String16 string) {
Buffer *buffer = GetBuffer(view->buffer_id);
Scratch scratch; Scratch scratch;
BeforeEdit(view->buffer, view->carets); BeforeEdit(buffer, view->carets);
MergeCarets(&view->carets); MergeCarets(&view->carets);
Array<Edit> edits = {scratch}; Array<Edit> edits = {scratch};
For(view->carets) AddEdit(&edits, it.range, string); For(view->carets) AddEdit(&edits, it.range, string);
ApplyEdits(view->buffer, edits); ApplyEdits(buffer, edits);
AfterEdit(view->buffer, &edits, &view->carets); AfterEdit(buffer, &edits, &view->carets);
} }
void Command_DuplicateLine(View *view, int direction) { void Command_DuplicateLine(View *view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN); Assert(direction == DIR_UP || direction == DIR_DOWN);
BeforeEdit(view->buffer, view->carets); Buffer *buffer = GetBuffer(view->buffer_id);
BeforeEdit(buffer, view->carets);
For(view->carets) it = MakeCaret(GetFront(it)); For(view->carets) it = MakeCaret(GetFront(it));
MergeCarets(&view->carets); MergeCarets(&view->carets);
Scratch scratch; Scratch scratch;
Array<Edit> edits = {scratch}; Array<Edit> edits = {scratch};
For(view->carets) { For(view->carets) {
Int line = PosToLine(*view->buffer, it.range.min); Int line = PosToLine(*buffer, it.range.min);
Range range = GetLineRange(*view->buffer, line); Range range = GetLineRange(*buffer, line);
String16 string = Copy(scratch, GetString(*view->buffer, range)); String16 string = Copy(scratch, GetString(*buffer, range));
Int pos = direction == DIR_UP ? range.min : range.max; Int pos = direction == DIR_UP ? range.min : range.max;
AddEdit(&edits, Rng(pos), string); AddEdit(&edits, Rng(pos), string);
} }
ApplyEdits(view->buffer, edits); ApplyEdits(buffer, edits);
AfterEdit(view->buffer, &edits, &view->carets); AfterEdit(buffer, &edits, &view->carets);
For(view->carets) it = MakeCaret(MovePos(*view->buffer, it.range.min, direction, false)); For(view->carets) it = MakeCaret(MovePos(*buffer, it.range.min, direction, false));
} }
bool SHIFT_PRESSED = true; bool SHIFT_PRESSED = true;
void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) { void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_UP || direction == DIR_DOWN); Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *GetActiveView(*window); View &view = *GetActiveView(window);
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
Rect2I visible_cells_rect = GetVisibleCells(*window); Rect2I visible_cells_rect = GetVisibleCells(*window);
Int y = GetSize(visible_cells_rect).y - 2; Int y = GetSize(visible_cells_rect).y - 2;
if (direction == DIR_UP) y = -y; if (direction == DIR_UP) y = -y;
For(view.carets) { For(view.carets) {
XY xy = PosToXY(buf, GetFront(it)); XY xy = PosToXY(*buffer, GetFront(it));
xy.line += y; xy.line += y;
Int pos = XYToPos(buf, xy); Int pos = XYToPos(*buffer, xy);
if (shift) { if (shift) {
it = ChangeFront(it, pos); it = ChangeFront(it, pos);
} else { } else {
@@ -53,12 +55,12 @@ void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = f
void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false) { void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT); Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
View &view = *GetActiveView(*window); View &view = *GetActiveView(window);
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
For(view.carets) { For(view.carets) {
Int end_of_buffer = 0; Int end_of_buffer = 0;
Range line_range = GetLineRange(buf, PosToLine(buf, GetFront(it)), &end_of_buffer); Range line_range = GetLineRange(*buffer, PosToLine(*buffer, GetFront(it)), &end_of_buffer);
Int pos = line_range.min; Int pos = line_range.min;
if (direction == DIR_RIGHT) { if (direction == DIR_RIGHT) {
@@ -76,12 +78,12 @@ void Command_MoveCursorsToSide(Window *window, int direction, bool shift = false
void Command_Delete(View *_view, int direction, bool ctrl = false) { void Command_Delete(View *_view, int direction, bool ctrl = false) {
Assert(direction == DIR_LEFT || direction == DIR_RIGHT); Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
View &view = *_view; View &view = *_view;
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
// Select things to delete // Select things to delete
For(view.carets) { For(view.carets) {
if (GetSize(it.range)) continue; if (GetSize(it.range)) continue;
Int pos = MovePos(buf, it.range.min, direction, ctrl); Int pos = MovePos(*buffer, it.range.min, direction, ctrl);
it = MakeCaret(pos, it.range.min); it = MakeCaret(pos, it.range.min);
} }
@@ -91,18 +93,18 @@ void Command_Delete(View *_view, int direction, bool ctrl = false) {
void Command_CreateCursorVertical(View *_view, int direction) { void Command_CreateCursorVertical(View *_view, int direction) {
Assert(direction == DIR_UP || direction == DIR_DOWN); Assert(direction == DIR_UP || direction == DIR_DOWN);
View &view = *_view; View &view = *_view;
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
Scratch scratch; Scratch scratch;
Array<Caret> arr = {scratch}; Array<Caret> arr = {scratch};
For(view.carets) { For(view.carets) {
if (PosToLine(buf, it.range.min) == PosToLine(buf, it.range.max)) { if (PosToLine(*buffer, it.range.min) == PosToLine(*buffer, it.range.max)) {
Int f = MovePos(buf, GetFront(it), direction); Int f = MovePos(*buffer, GetFront(it), direction);
Int b = MovePos(buf, GetBack(it), direction); Int b = MovePos(*buffer, GetBack(it), direction);
Add(&arr, MakeCaret(f, b)); Add(&arr, MakeCaret(f, b));
} else { } else {
Int pos = direction == DIR_UP ? it.range.min : it.range.max; Int pos = direction == DIR_UP ? it.range.min : it.range.max;
Int min = MovePos(buf, pos, direction); Int min = MovePos(*buffer, pos, direction);
Add(&arr, MakeCaret(min)); Add(&arr, MakeCaret(min));
} }
} }
@@ -112,8 +114,8 @@ void Command_CreateCursorVertical(View *_view, int direction) {
void HandleKeybindings(Window *window) { void HandleKeybindings(Window *window) {
ProfileFunction(); ProfileFunction();
View &view = *GetActiveView(*window); View &view = *GetActiveView(window);
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
Caret main_caret_on_begin_frame = view.carets[0]; Caret main_caret_on_begin_frame = view.carets[0];
{ {
@@ -130,7 +132,7 @@ void HandleKeybindings(Window *window) {
if (!IsActive(window)) { if (!IsActive(window)) {
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
ActiveWindow = GetIndex(Windows, *window); ActiveWindow = window->id;
} }
} }
} }
@@ -141,9 +143,9 @@ void HandleKeybindings(Window *window) {
} }
if (CtrlPress(KEY_F2)) { if (CtrlPress(KEY_F2)) {
LoadBigLine(view.buffer); LoadBigLine(buffer);
} else if (Press(KEY_F2)) { } else if (Press(KEY_F2)) {
LoadBigText(view.buffer); LoadBigText(buffer);
} }
if (Press(KEY_ESCAPE)) { if (Press(KEY_ESCAPE)) {
@@ -155,15 +157,15 @@ void HandleKeybindings(Window *window) {
} else if (AltShiftPress(KEY_DOWN)) { } else if (AltShiftPress(KEY_DOWN)) {
Command_CreateCursorVertical(&view, DIR_DOWN); Command_CreateCursorVertical(&view, DIR_DOWN);
} else if (CtrlShiftPress(KEY_DOWN)) { } else if (CtrlShiftPress(KEY_DOWN)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_DOWN, true)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_DOWN, true));
} else if (CtrlPress(KEY_DOWN)) { } else if (CtrlPress(KEY_DOWN)) {
For(view.carets) it = MakeCaret(MovePos(buf, it.range.max, DIR_DOWN, true)); For(view.carets) it = MakeCaret(MovePos(*buffer, it.range.max, DIR_DOWN, true));
} else if (ShiftPress(KEY_DOWN)) { } else if (ShiftPress(KEY_DOWN)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_DOWN, false)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_DOWN, false));
} else if (Press(KEY_DOWN)) { } else if (Press(KEY_DOWN)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) == 0) { if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(buf, it.range.max, DIR_DOWN, false)); it = MakeCaret(MovePos(*buffer, it.range.max, DIR_DOWN, false));
} else { } else {
it = MakeCaret(it.range.max); it = MakeCaret(it.range.max);
} }
@@ -175,15 +177,15 @@ void HandleKeybindings(Window *window) {
} else if (AltShiftPress(KEY_UP)) { } else if (AltShiftPress(KEY_UP)) {
Command_CreateCursorVertical(&view, DIR_UP); Command_CreateCursorVertical(&view, DIR_UP);
} else if (CtrlShiftPress(KEY_UP)) { } else if (CtrlShiftPress(KEY_UP)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_UP, CTRL_PRESSED)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_UP, CTRL_PRESSED));
} else if (CtrlPress(KEY_UP)) { } else if (CtrlPress(KEY_UP)) {
For(view.carets) it = MakeCaret(MovePos(buf, it.range.min, DIR_UP, CTRL_PRESSED)); For(view.carets) it = MakeCaret(MovePos(*buffer, it.range.min, DIR_UP, CTRL_PRESSED));
} else if (ShiftPress(KEY_UP)) { } else if (ShiftPress(KEY_UP)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_UP)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_UP));
} else if (Press(KEY_UP)) { } else if (Press(KEY_UP)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) == 0) { if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(buf, it.range.min, DIR_UP)); it = MakeCaret(MovePos(*buffer, it.range.min, DIR_UP));
} else { } else {
it = MakeCaret(it.range.min); it = MakeCaret(it.range.min);
} }
@@ -191,21 +193,21 @@ void HandleKeybindings(Window *window) {
} }
if (CtrlShiftPress(KEY_LEFT)) { if (CtrlShiftPress(KEY_LEFT)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_LEFT, true)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_LEFT, true));
} else if (CtrlPress(KEY_LEFT)) { } else if (CtrlPress(KEY_LEFT)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) != 0 && GetFront(it) != it.range.min) { if (GetSize(it.range) != 0 && GetFront(it) != it.range.min) {
it = MakeCaret(it.range.min); it = MakeCaret(it.range.min);
} else { } else {
it = MakeCaret(MovePos(buf, it.range.min, DIR_LEFT, true)); it = MakeCaret(MovePos(*buffer, it.range.min, DIR_LEFT, true));
} }
} }
} else if (ShiftPress(KEY_LEFT)) { } else if (ShiftPress(KEY_LEFT)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_LEFT, false)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_LEFT, false));
} else if (Press(KEY_LEFT)) { } else if (Press(KEY_LEFT)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) == 0) { if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(buf, it.range.min, DIR_LEFT, false)); it = MakeCaret(MovePos(*buffer, it.range.min, DIR_LEFT, false));
} else { } else {
it = MakeCaret(it.range.min); it = MakeCaret(it.range.min);
} }
@@ -213,21 +215,21 @@ void HandleKeybindings(Window *window) {
} }
if (CtrlShiftPress(KEY_RIGHT)) { if (CtrlShiftPress(KEY_RIGHT)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_RIGHT, true)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_RIGHT, true));
} else if (CtrlPress(KEY_RIGHT)) { } else if (CtrlPress(KEY_RIGHT)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) != 0 && GetFront(it) != it.range.max) { if (GetSize(it.range) != 0 && GetFront(it) != it.range.max) {
it = MakeCaret(it.range.max); it = MakeCaret(it.range.max);
} else { } else {
it = MakeCaret(MovePos(buf, it.range.max, DIR_RIGHT, true)); it = MakeCaret(MovePos(*buffer, it.range.max, DIR_RIGHT, true));
} }
} }
} else if (ShiftPress(KEY_RIGHT)) { } else if (ShiftPress(KEY_RIGHT)) {
For(view.carets) it = ChangeFront(it, MovePos(buf, GetFront(it), DIR_RIGHT, false)); For(view.carets) it = ChangeFront(it, MovePos(*buffer, GetFront(it), DIR_RIGHT, false));
} else if (Press(KEY_RIGHT)) { } else if (Press(KEY_RIGHT)) {
For(view.carets) { For(view.carets) {
if (GetSize(it.range) == 0) { if (GetSize(it.range) == 0) {
it = MakeCaret(MovePos(buf, it.range.max, DIR_RIGHT, false)); it = MakeCaret(MovePos(*buffer, it.range.max, DIR_RIGHT, false));
} else { } else {
it = MakeCaret(it.range.max); it = MakeCaret(it.range.max);
} }
@@ -236,23 +238,23 @@ void HandleKeybindings(Window *window) {
if (CtrlPress(KEY_D)) { if (CtrlPress(KEY_D)) {
Range range = view.carets[0].range; Range range = view.carets[0].range;
String16 string = GetString(buf, range); String16 string = GetString(*buffer, range);
String16 buffer = GetString(buf, {range.max, INT64_MAX}); String16 string_buffer = GetString(*buffer, {range.max, INT64_MAX});
Int index = 0; Int index = 0;
if (Seek(buffer, string, &index)) { if (Seek(string_buffer, string, &index)) {
Insert(&view.carets, MakeCaret(range.max + index, range.max + index + string.len), 0); Insert(&view.carets, MakeCaret(range.max + index, range.max + index + string.len), 0);
} else { } else {
String16 buffer = GetString(buf); String16 string_buffer = GetString(*buffer);
if (Seek(buffer, string, &index)) { if (Seek(string_buffer, string, &index)) {
Insert(&view.carets, MakeCaret(index, index + string.len), 0); Insert(&view.carets, MakeCaret(index, index + string.len), 0);
} }
} }
} }
if (CtrlShiftPress(KEY_Z)) { if (CtrlShiftPress(KEY_Z)) {
RedoEdit(&buf, &view.carets); RedoEdit(buffer, &view.carets);
} else if (CtrlPress(KEY_Z)) { } else if (CtrlPress(KEY_Z)) {
UndoEdit(&buf, &view.carets); UndoEdit(buffer, &view.carets);
} }
if (CtrlPress(KEY_C)) { if (CtrlPress(KEY_C)) {
@@ -267,7 +269,7 @@ void HandleKeybindings(Window *window) {
bool dont_update_scroll = false; bool dont_update_scroll = false;
if (CtrlPress(KEY_A)) { if (CtrlPress(KEY_A)) {
view.carets.len = 1; view.carets.len = 1;
view.carets[0] = MakeCaret(0, view.buffer->len); view.carets[0] = MakeCaret(0, buffer->len);
dont_update_scroll = true; dont_update_scroll = true;
} }
@@ -346,14 +348,14 @@ void HandleKeybindings(Window *window) {
Vec2I mworld = mouse - window->document_rect.min + view.scroll; Vec2I mworld = mouse - window->document_rect.min + view.scroll;
Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing}; Vec2I pos = mworld / Vec2I{FontCharSpacing, FontLineSpacing};
XY xy = {(Int)(pos.x), (Int)(pos.y)}; XY xy = {(Int)(pos.x), (Int)(pos.y)};
Int p = XYToPosWithoutNL(buf, xy); Int p = XYToPosWithoutNL(*buffer, xy);
if (mouse_in_view && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { if (mouse_in_view && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
if (IsDoubleClick()) { if (IsDoubleClick()) {
Caret *c = GetLast(view.carets); Caret *c = GetLast(view.carets);
if (InBounds({c->range.min - 1, c->range.max + 1}, p)) { if (InBounds({c->range.min - 1, c->range.max + 1}, p)) {
c->range = EncloseWord(buf, p); c->range = EncloseWord(*buffer, p);
view.selection_anchor = c->range; view.selection_anchor = c->range;
} }
} else { } else {
@@ -414,7 +416,7 @@ void HandleKeybindings(Window *window) {
if (!AreEqual(main_caret_on_begin_frame, view.carets[0]) && !dont_update_scroll) { if (!AreEqual(main_caret_on_begin_frame, view.carets[0]) && !dont_update_scroll) {
Caret c = view.carets[0]; Caret c = view.carets[0];
Int front = GetFront(c); Int front = GetFront(c);
XY xy = PosToXY(buf, front); XY xy = PosToXY(*buffer, front);
Rect2I visible = GetVisibleCells(*window); Rect2I visible = GetVisibleCells(*window);
Vec2I visible_cells = GetSize(visible); Vec2I visible_cells = GetSize(visible);
@@ -445,7 +447,7 @@ void HandleKeybindings(Window *window) {
// Clip scroll // Clip scroll
{ {
ProfileScope(clip_scroll); ProfileScope(clip_scroll);
Int last_line = LastLine(view.buffer[0]); Int last_line = LastLine(*buffer);
view.scroll.y = Clamp(view.scroll.y, (Int)0, Max((Int)0, (last_line - 1) * FontLineSpacing)); view.scroll.y = Clamp(view.scroll.y, (Int)0, Max((Int)0, (last_line - 1) * FontLineSpacing));
// @note: // @note:

View File

@@ -3,6 +3,7 @@ Array<String16> SavedClipboardCursors;
void Command_Copy(View *view) { void Command_Copy(View *view) {
Allocator sys_allocator = GetSystemAllocator(); Allocator sys_allocator = GetSystemAllocator();
Buffer *buffer = GetBuffer(view->buffer_id);
SavedClipboardCursors.allocator = sys_allocator; SavedClipboardCursors.allocator = sys_allocator;
if (SavedClipboardCursors.data) { if (SavedClipboardCursors.data) {
@@ -18,14 +19,14 @@ void Command_Copy(View *view) {
// First, if there is no selection - select the entire line // First, if there is no selection - select the entire line
For(view->carets) { For(view->carets) {
if (GetSize(it.range) == 0) { if (GetSize(it.range) == 0) {
Int line = PosToLine(*view->buffer, it.range.min); Int line = PosToLine(*buffer, it.range.min);
Range line_range = GetLineRange(*view->buffer, line); Range line_range = GetLineRange(*buffer, line);
it.range = line_range; it.range = line_range;
} }
} }
For(view->carets) { For(view->carets) {
String16 string = GetString(*view->buffer, it.range); String16 string = GetString(*buffer, it.range);
String16 copy = Copy(sys_allocator, string); String16 copy = Copy(sys_allocator, string);
Add(&SavedClipboardCursors, copy); Add(&SavedClipboardCursors, copy);
} }
@@ -38,23 +39,24 @@ void Command_Copy(View *view) {
void Command_Paste(View *view) { void Command_Paste(View *view) {
Scratch scratch; Scratch scratch;
Buffer *buffer = GetBuffer(view->buffer_id);
const char *text = GetClipboardText(); const char *text = GetClipboardText();
String string_ = text; String string_ = text;
String16 string = ToString16(scratch, string_); String16 string = ToString16(scratch, string_);
// Regular paste // Regular paste
if (string != SavedClipboardString || SavedClipboardCursors.len != view->carets.len) { if (string != SavedClipboardString || SavedClipboardCursors.len != view->carets.len) {
BeforeEdit(view->buffer, view->carets); BeforeEdit(buffer, view->carets);
MergeCarets(&view->carets); MergeCarets(&view->carets);
Array<Edit> edits = {scratch}; Array<Edit> edits = {scratch};
For(view->carets) AddEdit(&edits, it.range, string); For(view->carets) AddEdit(&edits, it.range, string);
ApplyEdits(view->buffer, edits); ApplyEdits(buffer, edits);
AfterEdit(view->buffer, &edits, &view->carets); AfterEdit(buffer, &edits, &view->carets);
return; return;
} }
// Multicursor paste // Multicursor paste
BeforeEdit(view->buffer, view->carets); BeforeEdit(buffer, view->carets);
MergeCarets(&view->carets); MergeCarets(&view->carets);
Array<Edit> edits = {scratch}; Array<Edit> edits = {scratch};
for (int64_t i = 0; i < view->carets.len; i += 1) { for (int64_t i = 0; i < view->carets.len; i += 1) {
@@ -62,6 +64,6 @@ void Command_Paste(View *view) {
Caret &it = view->carets[i]; Caret &it = view->carets[i];
AddEdit(&edits, it.range, string); AddEdit(&edits, it.range, string);
} }
ApplyEdits(view->buffer, edits); ApplyEdits(buffer, edits);
AfterEdit(view->buffer, &edits, &view->carets); AfterEdit(buffer, &edits, &view->carets);
} }

View File

@@ -5,7 +5,7 @@ Vec2I GetCellSize() {
Rect2I GetVisibleCells(Window &window) { Rect2I GetVisibleCells(Window &window) {
ProfileFunction(); ProfileFunction();
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Vec2I size = GetSize(window.document_rect); Vec2I size = GetSize(window.document_rect);
Int _cx = size.x / FontCharSpacing; Int _cx = size.x / FontCharSpacing;
@@ -21,10 +21,11 @@ Rect2I GetVisibleCells(Window &window) {
} }
Scroller ComputeScrollerRect(Window &window) { Scroller ComputeScrollerRect(Window &window) {
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Vec2I size = GetSize(window.scrollbar_rect); Vec2I size = GetSize(window.scrollbar_rect);
Rect2I vis = GetVisibleCells(window); Rect2I vis = GetVisibleCells(window);
Int line_count = view.buffer->line_starts.len + GetSize(vis).y - 1; Int line_count = buffer->line_starts.len + GetSize(vis).y - 1;
double begin = (double)vis.min.y / (double)line_count; double begin = (double)vis.min.y / (double)line_count;
double end = (double)vis.max.y / (double)line_count; double end = (double)vis.max.y / (double)line_count;
@@ -40,12 +41,13 @@ Scroller ComputeScrollerRect(Window &window) {
void DrawVisibleText(Window &window) { void DrawVisibleText(Window &window) {
ProfileFunction(); ProfileFunction();
Color tint = ColorText; Color tint = ColorText;
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Buffer *buffer = GetBuffer(view.buffer_id);
Rect2I visible = GetVisibleCells(window); Rect2I visible = GetVisibleCells(window);
for (Int line_index = visible.min.y; line_index < visible.max.y && line_index >= 0 && line_index < view.buffer->line_starts.len; line_index += 1) { for (Int line_index = visible.min.y; line_index < visible.max.y && line_index >= 0 && line_index < buffer->line_starts.len; line_index += 1) {
Range line_range = GetLineRange(*view.buffer, line_index); Range line_range = GetLineRange(*buffer, line_index);
String16 line_string = GetString(*view.buffer, line_range); String16 line_string = GetString(*buffer, line_range);
Vec2I pos = {visible.min.x * (Int)FontCharSpacing, line_index * (Int)FontLineSpacing}; Vec2I pos = {visible.min.x * (Int)FontCharSpacing, line_index * (Int)FontLineSpacing};
pos -= view.scroll; pos -= view.scroll;
@@ -81,7 +83,7 @@ Rect2I XYToRect(const View &view, XY xy) {
} }
void DrawCaret(Window &window, XY xy, float size, Color color) { void DrawCaret(Window &window, XY xy, float size, Color color) {
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Rect2I _rect = XYToRect(view, xy); Rect2I _rect = XYToRect(view, xy);
Rect2I rect = CutLeft(&_rect, (Int)(size * (float)FontCharSpacing)); Rect2I rect = CutLeft(&_rect, (Int)(size * (float)FontCharSpacing));
rect -= view.scroll; rect -= view.scroll;
@@ -90,7 +92,7 @@ void DrawCaret(Window &window, XY xy, float size, Color color) {
} }
void DrawLineHighlight(Window &window, XY fxy, Color color) { void DrawLineHighlight(Window &window, XY fxy, Color color) {
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Vec2I w = XYToWorldPos(view, XYLine(fxy.line)); Vec2I w = XYToWorldPos(view, XYLine(fxy.line));
w -= view.scroll; w -= view.scroll;
w += window.document_rect.min; w += window.document_rect.min;
@@ -103,20 +105,20 @@ void DrawLineHighlight(Window &window, XY fxy, Color color) {
void DrawSelection(Window &window, Caret &it) { void DrawSelection(Window &window, Caret &it) {
ProfileFunction(); ProfileFunction();
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
Int front = GetFront(it); Int front = GetFront(it);
Int back = GetBack(it); Int back = GetBack(it);
if (front != back) { if (front != back) {
XY bxy = PosToXY(buf, back); XY bxy = PosToXY(*buffer, back);
XY min = PosToXY(buf, it.range.min); XY min = PosToXY(*buffer, it.range.min);
XY max = PosToXY(buf, it.range.max); XY max = PosToXY(*buffer, it.range.max);
Color color = ColorSelection; Color color = ColorSelection;
Rect2I vlines = GetVisibleCells(window); Rect2I vlines = GetVisibleCells(window);
for (Int line = vlines.min.y; line <= vlines.max.y && line >= 0 && line < view.buffer->line_starts.len; line += 1) { for (Int line = vlines.min.y; line <= vlines.max.y && line >= 0 && line < buffer->line_starts.len; line += 1) {
Range range = GetLineRange(buf, line); Range range = GetLineRange(*buffer, line);
String16 line_string = GetString(buf, range); String16 line_string = GetString(*buffer, range);
for (Int col = vlines.min.x; col < vlines.max.x && col >= 0 && col < line_string.len; col += 1) { for (Int col = vlines.min.x; col < vlines.max.x && col >= 0 && col < line_string.len; col += 1) {
bool a = line > min.line && line < max.line; bool a = line > min.line && line < max.line;
@@ -146,13 +148,13 @@ void DrawSelection(Window &window, Caret &it) {
} }
void DrawWindow(Window &window) { void DrawWindow(Window &window) {
View &view = *GetActiveView(window); View &view = *GetActiveView(&window);
Buffer &buf = *view.buffer; Buffer *buffer = GetBuffer(view.buffer_id);
BeginScissorMode((int)window.document_rect.min.x, (int)window.document_rect.min.y, (int)window.document_rect.max.x - (int)window.document_rect.min.x, (int)window.document_rect.max.y - (int)window.document_rect.min.y); BeginScissorMode((int)window.document_rect.min.x, (int)window.document_rect.min.y, (int)window.document_rect.max.x - (int)window.document_rect.min.x, (int)window.document_rect.max.y - (int)window.document_rect.min.y);
For(view.carets) { For(view.carets) {
Int front = GetFront(it); Int front = GetFront(it);
XY fxy = PosToXY(buf, front); XY fxy = PosToXY(*buffer, front);
if (GetSize(it.range)) { if (GetSize(it.range)) {
DrawSelection(window, it); DrawSelection(window, it);
} else { } else {
@@ -164,7 +166,7 @@ void DrawWindow(Window &window) {
For(view.carets) { For(view.carets) {
Int front = GetFront(it); Int front = GetFront(it);
XY fxy = PosToXY(buf, front); XY fxy = PosToXY(*buffer, front);
bool main_caret = &it == &view.carets.data[0]; bool main_caret = &it == &view.carets.data[0];
DrawCaret(window, fxy, 0.3f, main_caret ? ColorMainCaret : ColorSubCaret); DrawCaret(window, fxy, 0.3f, main_caret ? ColorMainCaret : ColorSubCaret);
} }
@@ -180,7 +182,7 @@ void DrawWindow(Window &window) {
Rect2 rect = Shrink(scroller.rect, 2); Rect2 rect = Shrink(scroller.rect, 2);
Color color = ColorScrollbarScroller; Color color = ColorScrollbarScroller;
if (!window.mouse_selecting && (window.mouse_selecting_scrollbar || mouse_in_scrollbar)) { if (!window.mouse_selecting && (window.mouse_selecting_scrollbar || mouse_in_scrollbar)) {
color = ColorScrollbarScrollerSelected; if (IsActive(&window)) color = ColorScrollbarScrollerSelected;
} }
DrawRectangleRec(ToRectangle(rect), color); DrawRectangleRec(ToRectangle(rect), color);
} }
@@ -218,7 +220,7 @@ void DrawWindow(Window &window) {
Vec2 p = ToVec2(r.min); Vec2 p = ToVec2(r.min);
Scratch scratch; Scratch scratch;
Caret caret = view.carets[0]; Caret caret = view.carets[0];
XY xy = PosToXY(*view.buffer, GetFront(caret)); XY xy = PosToXY(*buffer, GetFront(caret));
String s = Format(scratch, "-- line: %lld col: %lld", (long long)xy.line + 1ll, (long long)xy.col + 1ll); String s = Format(scratch, "-- line: %lld col: %lld", (long long)xy.line + 1ll, (long long)xy.col + 1ll);
String16 string = ToString16(scratch, s); String16 string = ToString16(scratch, s);
DrawString(MenuFont, string, p, MenuFontSize, 1, ColorText); DrawString(MenuFont, string, p, MenuFontSize, 1, ColorText);

View File

@@ -1,21 +0,0 @@
Array<Window> Windows = {};
Int ActiveWindow = 0;
Window *GetActiveWindow() {
return &Windows[ActiveWindow];
}
View *GetActiveView(Window &window) {
return &window.views[window.active_view];
}
bool IsActive(Window *window) {
Window *active_window = GetActiveWindow();
bool result = window == active_window;
return result;
}
bool IsActive(Window *window, View *view) {
bool result = view == GetActiveView(*window);
return result;
}