jump history

This commit is contained in:
Krzosa Karol
2025-12-08 08:37:52 +01:00
parent ef6a7be285
commit 20207e6040
8 changed files with 203 additions and 46 deletions

View File

@@ -996,7 +996,7 @@ API void UndoEdit(Buffer *buffer, Array<Caret> *carets) {
if (buffer->undo_stack.len > 0) { if (buffer->undo_stack.len > 0) {
HistoryEntry *next = GetLast(buffer->undo_stack); HistoryEntry *next = GetLast(buffer->undo_stack);
if (entry.time - next->time <= 0.3) { if (entry.time - next->time <= StyleUndoMergeTimeout) {
UndoEdit(buffer, carets); UndoEdit(buffer, carets);
} }
} }
@@ -1017,6 +1017,16 @@ API void ResetHistory(Buffer *buffer) {
DeallocHistoryEntries(&buffer->undo_stack); DeallocHistoryEntries(&buffer->undo_stack);
} }
API void ResetBuffer(Buffer *buffer) {
ResetHistory(buffer);
buffer->change_id += 1;
buffer->line_starts.len = 0;
buffer->len = 0;
if (!buffer->no_line_starts) {
Add(&buffer->line_starts, (Int)0);
}
}
void ClearRedoStack(Buffer *buffer) { void ClearRedoStack(Buffer *buffer) {
DeallocHistoryEntries(&buffer->redo_stack); DeallocHistoryEntries(&buffer->redo_stack);
} }

View File

@@ -1,4 +1,64 @@
void CheckpointBeforeGoto(Window *window, View *view) {
if (window->jump_history == false) return;
Add(&window->goto_history, {view->id, view->carets[0], GetTimeSeconds()});
window->goto_redo.len = 0;
}
void CheckpointBeforeGoto(Window *window) {
CheckpointBeforeGoto(window, GetView(window->active_view));
}
GotoCrumb GetCrumb(Array<GotoCrumb> *cr) {
for (; cr->len;) {
GotoCrumb c = Pop(cr);
View *view = FindView(c.view_id);
if (view) return c;
}
return {};
}
void GotoBackward(Window *window) {
if (window->jump_history == false) return;
if (window->goto_history.len <= 0) return;
BSet set = GetBSet(window);
Add(&window->goto_redo, {set.view->id, set.view->carets[0], GetTimeSeconds()});
GotoCrumb c = GetCrumb(&window->goto_history);
window->active_view = c.view_id;
View *view = GetView(c.view_id);
view->carets[0] = c.caret;
UpdateScroll(window, true);
if (window->goto_history.len) {
GotoCrumb *next = GetLast(window->goto_history);
if (c.time - next->time <= StyleUndoMergeTimeout) {
GotoBackward(window);
}
}
}
void GotoForward(Window *window) {
if (window->goto_redo.len <= 0) return;
if (window->jump_history == false) return;
BSet set = GetBSet(window);
Add(&window->goto_history, {set.view->id, set.view->carets[0], GetTimeSeconds()});
GotoCrumb c = GetCrumb(&window->goto_redo);
window->active_view = c.view_id;
View *view = GetView(c.view_id);
view->carets[0] = c.caret;
UpdateScroll(window, true);
if (window->goto_redo.len) {
GotoCrumb *next = GetLast(window->goto_redo);
if (c.time - next->time <= StyleUndoMergeTimeout) {
GotoForward(window);
}
}
}
void JumpGarbageBuffer(BSet *set, String buffer_name = "") { void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
CheckpointBeforeGoto(set->window);
if (buffer_name.len == 0) { if (buffer_name.len == 0) {
String current_dir = ChopLastSlash(set->buffer->name); String current_dir = ChopLastSlash(set->buffer->name);
buffer_name = GetUniqueBufferName(current_dir, "temp"); buffer_name = GetUniqueBufferName(current_dir, "temp");
@@ -9,6 +69,7 @@ void JumpGarbageBuffer(BSet *set, String buffer_name = "") {
} }
void Command_BeginJump(BSet *set, BufferID buffer_id = NullBufferID) { void Command_BeginJump(BSet *set, BufferID buffer_id = NullBufferID) {
CheckpointBeforeGoto(set->window);
set->buffer = GetBuffer(buffer_id); set->buffer = GetBuffer(buffer_id);
set->view = WindowOpenBufferView(set->window, set->buffer->name); set->view = WindowOpenBufferView(set->window, set->buffer->name);
} }
@@ -855,6 +916,43 @@ void Command_Find(View *seek_view, String16 needle, bool forward = true) {
IF_DEBUG(AssertRanges(seek_view->carets)); IF_DEBUG(AssertRanges(seek_view->carets));
} }
void Command_GotoNextInList(Window *window, Int line_offset = 1) {
Assert(line_offset == 1 || line_offset == -1);
View *active_view = GetView(window->active_view);
View *view_goto = GetView(window->active_goto_list);
window->active_view = view_goto->id;
Buffer *buffer_goto = GetBuffer(view_goto->active_buffer);
int64_t pos = window->goto_list_pos;
Int line = PosToLine(buffer_goto, pos);
bool opened = false;
for (Int i = line + line_offset; i >= 0 && i < buffer_goto->line_starts.len; i += line_offset) {
Range line_range = GetLineRangeWithoutNL(buffer_goto, i);
String16 line = GetString(buffer_goto, line_range);
view_goto->carets[0] = MakeCaret(line_range.min);
window->goto_list_pos = line_range.min;
line = Trim(line);
MergeCarets(buffer_goto, &view_goto->carets);
IF_DEBUG(AssertRanges(view_goto->carets));
if (line.len == 0) {
continue;
}
BSet set = Command_Open(line, "goto_build");
if (set.window == NULL) {
continue;
}
opened = true;
break;
}
if (!opened) window->active_view = active_view->id;
}
void Command_FuzzySort(View *view, String16 needle) { void Command_FuzzySort(View *view, String16 needle) {
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
@@ -1051,7 +1149,8 @@ BSet Command_Open(Window *window, String path, String meta, bool set_active = tr
Command_Appendf(set.view, "%S\n", it.filename); Command_Appendf(set.view, "%S\n", it.filename);
} }
} else { } else {
View *view = WindowOpenBufferView(set.window, ores.file_path); CheckpointBeforeGoto(set.window);
View *view = WindowOpenBufferView(set.window, ores.file_path);
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
if (ores.line != -1) { if (ores.line != -1) {
if (ores.col == -1) ores.col = 1; if (ores.col == -1) ores.col = 1;
@@ -1122,6 +1221,8 @@ int Lua_Cmd(lua_State *L) {
BSet main = GetLastActiveLayoutSet(); BSet main = GetLastActiveLayoutSet();
if (kind == "console") { if (kind == "console") {
BSet set = GetConsoleSet(); BSet set = GetConsoleSet();
main.window->active_goto_list = set.view->id;
main.window->goto_list_pos = set.buffer->len;
Command_SelectRangeOneCursor(set.view, MakeRange(set.buffer->len)); Command_SelectRangeOneCursor(set.view, MakeRange(set.buffer->len));
Command_BeginJump(&set); Command_BeginJump(&set);
Exec(set.view->id, true, cmd, working_dir); Exec(set.view->id, true, cmd, working_dir);
@@ -1133,6 +1234,8 @@ int Lua_Cmd(lua_State *L) {
ActiveWindow = main.window->id; ActiveWindow = main.window->id;
} else { } else {
JumpGarbageBuffer(&main); JumpGarbageBuffer(&main);
main.window->active_goto_list = main.view->id;
main.window->goto_list_pos = 0;
Exec(main.view->id, true, cmd, working_dir); Exec(main.view->id, true, cmd, working_dir);
ActiveWindow = main.window->id; ActiveWindow = main.window->id;
} }
@@ -1140,10 +1243,11 @@ int Lua_Cmd(lua_State *L) {
return 0; return 0;
} }
void Command_ListBuffers() { void Command_ShowBufferList() {
BSet main = GetActiveSet(); BSet main = GetBSet(CommandBarWindowID);
main.window->visible = true;
ActiveWindow = main.window->id; ActiveWindow = main.window->id;
JumpGarbageBuffer(&main); ResetBuffer(main.buffer);
For(Buffers) { For(Buffers) {
RawAppendf(main.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name); RawAppendf(main.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
} }
@@ -1152,11 +1256,6 @@ void Command_ListBuffers() {
Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer)); Command_SelectRangeOneCursor(main.view, GetBufferEndAsRange(main.buffer));
} }
int Lua_ListBuffers(lua_State *L) {
Command_ListBuffers();
return 0;
}
void Command_ListViews() { void Command_ListViews() {
BSet main = GetLastActiveLayoutSet(); BSet main = GetLastActiveLayoutSet();
ActiveWindow = main.window->id; ActiveWindow = main.window->id;

View File

@@ -126,6 +126,7 @@ void OnCommand(Event event) {
Assert(ScrollbarSelected.id == -1); Assert(ScrollbarSelected.id == -1);
BSet selected = GetBSet(DocumentSelected); BSet selected = GetBSet(DocumentSelected);
Vec2I mouse = MouseVec2I(); Vec2I mouse = MouseVec2I();
// Special case for full-screen where we can have document // Special case for full-screen where we can have document
// aligned with monitor screen in which case mouse cursor cannot // aligned with monitor screen in which case mouse cursor cannot
@@ -184,6 +185,13 @@ void OnCommand(Event event) {
} }
} }
if (Mouse(X2)) {
GotoForward(GetLastActiveLayoutSet().window);
}
if (Mouse(X1)) {
GotoBackward(GetLastActiveLayoutSet().window);
}
if (Ctrl() && Shift() && Mouse(RIGHT)) { if (Ctrl() && Shift() && Mouse(RIGHT)) {
} else if (Alt() && Ctrl() && Mouse(RIGHT)) { } else if (Alt() && Ctrl() && Mouse(RIGHT)) {
@@ -232,6 +240,8 @@ void OnCommand(Event event) {
bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect); bool mouse_in_line_numbers = AreOverlapping(mouse, active.window->line_numbers_rect);
if (mouse_in_document || mouse_in_line_numbers) { if (mouse_in_document || mouse_in_line_numbers) {
DocumentSelected = active.window->id; DocumentSelected = active.window->id;
CheckpointBeforeGoto(active.window);
Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse); Int p = ScreenSpaceToBufferPos(active.window, active.view, active.buffer, mouse);
if (Alt()) Insert(&active.view->carets, MakeCaret(p, p), 0); if (Alt()) Insert(&active.view->carets, MakeCaret(p, p), 0);
@@ -293,12 +303,7 @@ void OnCommand(Event event) {
if (CtrlAltPress(SDLK_P)) { if (CtrlAltPress(SDLK_P)) {
} else if (CtrlPress(SDLK_P)) { } else if (CtrlPress(SDLK_P)) {
// Command_ListCode(); Command_ShowBufferList();
Window *window = GetWindow(CommandBarWindowID);
window->visible = !window->visible;
ActiveWindow = window->id;
BSet set = GetBSet(window);
Command_ListBuffers();
} }
if (CtrlPress(SDLK_0)) { if (CtrlPress(SDLK_0)) {
@@ -350,6 +355,10 @@ void OnCommand(Event event) {
WindowOpenBufferView(active.window, event.text); WindowOpenBufferView(active.window, event.text);
} }
if (Press(SDLK_DOWN) || Press(SDLK_RIGHT) || Press(SDLK_LEFT) || Press(SDLK_UP)) {
CheckpointBeforeGoto(active.window);
}
if (CtrlAltPress(SDLK_DOWN)) { if (CtrlAltPress(SDLK_DOWN)) {
Command_DuplicateLine(active.view, DIR_DOWN); Command_DuplicateLine(active.view, DIR_DOWN);
} else if (AltShiftPress(SDLK_DOWN)) { } else if (AltShiftPress(SDLK_DOWN)) {
@@ -428,30 +437,40 @@ void OnCommand(Event event) {
} }
if (ShiftPress(SDLK_PAGEUP)) { if (ShiftPress(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsByPageSize(active.window, DIR_UP, SHIFT_PRESS); Command_MoveCursorsByPageSize(active.window, DIR_UP, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEUP)) { } else if (CtrlPress(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
Command_SelectRangeOneCursor(active.view, MakeRange(0)); Command_SelectRangeOneCursor(active.view, MakeRange(0));
} else if (Press(SDLK_PAGEUP)) { } else if (Press(SDLK_PAGEUP)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsByPageSize(active.window, DIR_UP); Command_MoveCursorsByPageSize(active.window, DIR_UP);
} }
if (ShiftPress(SDLK_PAGEDOWN)) { if (ShiftPress(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsByPageSize(active.window, DIR_DOWN, SHIFT_PRESS); Command_MoveCursorsByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
} else if (CtrlPress(SDLK_PAGEDOWN)) { } else if (CtrlPress(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
Command_SelectRangeOneCursor(active.view, MakeRange(active.buffer->len)); Command_SelectRangeOneCursor(active.view, MakeRange(active.buffer->len));
} else if (Press(SDLK_PAGEDOWN)) { } else if (Press(SDLK_PAGEDOWN)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsByPageSize(active.window, DIR_DOWN); Command_MoveCursorsByPageSize(active.window, DIR_DOWN);
} }
if (ShiftPress(SDLK_HOME)) { if (ShiftPress(SDLK_HOME)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsToSide(active.view, DIR_LEFT, SHIFT_PRESS); Command_MoveCursorsToSide(active.view, DIR_LEFT, SHIFT_PRESS);
} else if (Press(SDLK_HOME)) { } else if (Press(SDLK_HOME)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsToSide(active.view, DIR_LEFT); Command_MoveCursorsToSide(active.view, DIR_LEFT);
} }
if (ShiftPress(SDLK_END)) { if (ShiftPress(SDLK_END)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsToSide(active.view, DIR_RIGHT, SHIFT_PRESS); Command_MoveCursorsToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
} else if (Press(SDLK_END)) { } else if (Press(SDLK_END)) {
CheckpointBeforeGoto(active.window);
Command_MoveCursorsToSide(active.view, DIR_RIGHT); Command_MoveCursorsToSide(active.view, DIR_RIGHT);
} }
@@ -494,6 +513,7 @@ void OnCommand(Event event) {
} }
if (CtrlPress(SDLK_D)) { if (CtrlPress(SDLK_D)) {
CheckpointBeforeGoto(active.window);
String16 string = GetString(active.buffer, active.view->carets[0].range); String16 string = GetString(active.buffer, active.view->carets[0].range);
Caret caret = FindNext(active.buffer, string, active.view->carets[0]); Caret caret = FindNext(active.buffer, string, active.view->carets[0]);
Insert(&active.view->carets, caret, 0); Insert(&active.view->carets, caret, 0);
@@ -558,10 +578,6 @@ void OnCommand(Event event) {
window->visible = !window->visible; window->visible = !window->visible;
} }
// if (CtrlPress(SDLK_N)) {
// Command_New();
// }
if (CtrlPress(SDLK_S)) { if (CtrlPress(SDLK_S)) {
SaveBuffer(active.buffer); SaveBuffer(active.buffer);
} }
@@ -585,6 +601,10 @@ void OnCommand(Event event) {
} }
if (AltPress(SDLK_Q)) {
GotoBackward(main.window);
}
if (CtrlPress(SDLK_Q)) { if (CtrlPress(SDLK_Q)) {
if (active.view->fuzzy_search) { if (active.view->fuzzy_search) {
@@ -596,7 +616,15 @@ void OnCommand(Event event) {
if (Press(SDLK_ESCAPE)) { if (Press(SDLK_ESCAPE)) {
active.view->carets.len = 1; active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0])); active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
if (active.window->lose_focus_on_escape && active.window->id == ActiveWindow) {
if (active.window->layout) {
//
} else {
ActiveWindow = LastActiveLayoutWindowID;
}
}
} }
// :OnCommandEnding // :OnCommandEnding

View File

@@ -210,21 +210,21 @@ String GetFieldString(lua_State *L, String name) {
return result; return result;
} }
Int GetFieldInt(lua_State *L, const char *name) { Int GetFieldAInt(lua_State *L, const char *name) {
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
lua_Integer num = lua_tointeger(L, -1); lua_Integer num = lua_tointeger(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
return (Int)num; return (Int)num;
} }
double GetFieldFloat(lua_State *L, const char *name) { double GetFieldAFloat(lua_State *L, const char *name) {
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
double num = lua_tonumber(L, -1); double num = lua_tonumber(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
return num; return num;
} }
const char *GetFieldString(lua_State *L, const char *name) { const char *GetFieldAString(lua_State *L, const char *name) {
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
const char *result = lua_tostring(L, -1); const char *result = lua_tostring(L, -1);
@@ -256,7 +256,7 @@ int Lua_Play(lua_State *L) {
defer { lua_pop(L, 1); }; defer { lua_pop(L, 1); };
Event event = {}; Event event = {};
#define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetField##KIND(L, #NAME); #define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetFieldA##KIND(L, #NAME);
EVENT_FIELDS EVENT_FIELDS
#undef X #undef X
Add(&EventPlayback, event); Add(&EventPlayback, event);

View File

@@ -29,7 +29,6 @@ luaL_Reg LuaFunctions[] = {
{"C", Lua_C}, {"C", Lua_C},
{"Open", Lua_Open}, {"Open", Lua_Open},
{"Cmd", Lua_Cmd}, {"Cmd", Lua_Cmd},
{"ListBuffers", Lua_ListBuffers},
{"ListViews", Lua_ListViews}, {"ListViews", Lua_ListViews},
{"Eval", Lua_Eval}, {"Eval", Lua_Eval},
{"SetProjectFile", Lua_SetProjectFile}, {"SetProjectFile", Lua_SetProjectFile},

View File

@@ -149,16 +149,17 @@ Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
} }
Window *CreateWind() { Window *CreateWind() {
Allocator allocator = GetSystemAllocator(); Allocator allocator = GetSystemAllocator();
Window *w = AllocType(allocator, Window); Window *w = AllocType(allocator, Window);
w->font = &PrimaryFont; w->font = &PrimaryFont;
w->visible = true; w->visible = true;
w->layout = true; w->layout = true;
w->draw_scrollbar = StyleDrawScrollbar; w->draw_scrollbar = StyleDrawScrollbar;
w->draw_line_numbers = StyleDrawLineNumbers; w->draw_line_numbers = StyleDrawLineNumbers;
w->draw_line_highlight = true; w->draw_line_highlight = true;
w->id = AllocWindowID(w); w->jump_history = true;
w->weight = 1.0; w->id = AllocWindowID(w);
w->weight = 1.0;
Add(&Windows, w); Add(&Windows, w);
return w; return w;
} }
@@ -380,11 +381,23 @@ View *WindowOpenBufferView(Window *new_parent_window, String name) {
return result; return result;
} }
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;
}
bool ViewIsReferenced(ViewID view) { bool ViewIsReferenced(ViewID view) {
if (view == NullViewID) { if (view == NullViewID) {
return true; return true;
} }
if (ViewIsCrumb(view)) {
return true;
}
For(Windows) { For(Windows) {
if (it->active_view == view) { if (it->active_view == view) {
return true; return true;
@@ -455,6 +468,8 @@ void GarbageCollect() {
IterRemove(Windows) { IterRemove(Windows) {
IterRemovePrepare(Windows); IterRemovePrepare(Windows);
if (it->kill) { if (it->kill) {
Dealloc(&it->goto_history);
Dealloc(&it->goto_redo);
Dealloc(sys_allocator, it); Dealloc(sys_allocator, it);
remove_item = true; remove_item = true;
} }

View File

@@ -16,6 +16,12 @@ struct View {
String16 prev_search_line; String16 prev_search_line;
}; };
struct GotoCrumb {
ViewID view_id;
Caret caret;
double time;
};
struct Window { struct Window {
WindowID id; WindowID id;
ViewID active_view; ViewID active_view;
@@ -32,6 +38,12 @@ struct Window {
double weight; double weight;
Int status_bar_last_buffer_change_id; Int status_bar_last_buffer_change_id;
Array<GotoCrumb> goto_history;
Array<GotoCrumb> goto_redo;
ViewID active_goto_list;
Int goto_list_pos;
struct { struct {
bool draw_scrollbar : 1; bool draw_scrollbar : 1;
bool draw_line_numbers : 1; bool draw_line_numbers : 1;
@@ -41,6 +53,8 @@ struct Window {
bool layout : 1; bool layout : 1;
bool kill : 1; bool kill : 1;
bool sync_visibility_with_focus : 1; bool sync_visibility_with_focus : 1;
bool lose_focus_on_escape : 1;
bool jump_history : 1;
}; };
}; };

View File

@@ -16,17 +16,7 @@ Int GetExpandingBarSize(Window *window) {
void InitWindows() { void InitWindows() {
Scratch scratch; Scratch scratch;
{ CreateWind();
Window *window = CreateWind();
window->active_view = CreateView(ScratchBuffer->id)->id;
window->weight = 1.0;
{
Window *window = CreateWind();
window->active_view = TraceView->id;
CreateWind();
CreateWind();
}
}
// COMMAND BAR // COMMAND BAR
{ {
@@ -42,7 +32,8 @@ void InitWindows() {
window->layout = false; window->layout = false;
window->visible = false; window->visible = false;
window->sync_visibility_with_focus = true; window->sync_visibility_with_focus = true;
buffer->no_history = true; window->lose_focus_on_escape = true;
window->jump_history = false;
} }
// SEARCH BAR // SEARCH BAR
@@ -60,6 +51,7 @@ void InitWindows() {
window->draw_line_highlight = false; window->draw_line_highlight = false;
window->layout = false; window->layout = false;
window->visible = false; window->visible = false;
window->lose_focus_on_escape = true;
} }
// STATUS BAR at the bottom // STATUS BAR at the bottom