Command bar, undo merge time

This commit is contained in:
Krzosa Karol
2025-12-07 13:57:51 +01:00
parent df84d1605d
commit ef6a7be285
15 changed files with 161 additions and 79 deletions

View File

@@ -68,6 +68,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat" Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
Style.TrimWhitespaceOnSave = true Style.TrimWhitespaceOnSave = true
Style.ClangFormatOnSave = false Style.ClangFormatOnSave = false
Style.StyleUndoMergeTimeout = 0.3
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe' INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
OS_WINDOWS = 0 OS_WINDOWS = 0
@@ -332,7 +333,7 @@ function MatchExec(s, meta)
end end
Eval(s) Eval(s)
return {kind = "skip"} return nil
end end
BuiltinOnOpenMatchers = { BuiltinOnOpenMatchers = {

View File

@@ -1097,3 +1097,7 @@ API void CloseStdin(Process *process) {
} }
#endif #endif
API double GetTimeSeconds() {
return GetTimeMicros() / 1000000.0;
}

View File

@@ -917,6 +917,7 @@ API void AddEdit(Array<Edit> *e, Range range, String16 string) {
void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array<HistoryEntry> *stack, Array<Caret> &carets) { void SaveHistoryBeforeMergeCursor(Buffer *buffer, Array<HistoryEntry> *stack, Array<Caret> &carets) {
if (buffer->no_history) return; if (buffer->no_history) return;
HistoryEntry entry = {}; HistoryEntry entry = {};
entry.time = GetTimeSeconds();
entry.carets = TightCopy(GetSystemAllocator(), carets); entry.carets = TightCopy(GetSystemAllocator(), carets);
Add(stack, entry); Add(stack, entry);
} }
@@ -992,8 +993,16 @@ API void UndoEdit(Buffer *buffer, Array<Caret> *carets) {
Allocator sys_allocator = GetSystemAllocator(); Allocator sys_allocator = GetSystemAllocator();
For(entry.edits) Dealloc(sys_allocator, it.string.data); For(entry.edits) Dealloc(sys_allocator, it.string.data);
Dealloc(&entry.edits); Dealloc(&entry.edits);
if (buffer->undo_stack.len > 0) {
HistoryEntry *next = GetLast(buffer->undo_stack);
if (entry.time - next->time <= 0.3) {
UndoEdit(buffer, carets);
}
}
} }
API void DeallocHistoryEntries(Array<HistoryEntry> *entries) { API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
For(*entries) { For(*entries) {
Dealloc(&it.carets); Dealloc(&it.carets);
@@ -1003,6 +1012,11 @@ API void DeallocHistoryEntries(Array<HistoryEntry> *entries) {
entries->len = 0; entries->len = 0;
} }
API void ResetHistory(Buffer *buffer) {
DeallocHistoryEntries(&buffer->redo_stack);
DeallocHistoryEntries(&buffer->undo_stack);
}
void ClearRedoStack(Buffer *buffer) { void ClearRedoStack(Buffer *buffer) {
DeallocHistoryEntries(&buffer->redo_stack); DeallocHistoryEntries(&buffer->redo_stack);
} }

View File

@@ -12,6 +12,7 @@ struct Edit {
struct HistoryEntry { struct HistoryEntry {
Array<Edit> edits; Array<Edit> edits;
Array<Caret> carets; Array<Caret> carets;
double time;
}; };
struct Buffer { struct Buffer {
@@ -156,6 +157,7 @@ API void AssertRanges(Array<Caret> carets);
API void RedoEdit(Buffer *buffer, Array<Caret> *carets); API void RedoEdit(Buffer *buffer, Array<Caret> *carets);
API void UndoEdit(Buffer *buffer, Array<Caret> *carets); API void UndoEdit(Buffer *buffer, Array<Caret> *carets);
API void ResetHistory(Buffer *buffer);
API void DeallocHistoryArray(Array<HistoryEntry> *entries); API void DeallocHistoryArray(Array<HistoryEntry> *entries);
API void DeallocHistoryEntries(Array<HistoryEntry> *entries); API void DeallocHistoryEntries(Array<HistoryEntry> *entries);

View File

@@ -1141,7 +1141,7 @@ int Lua_Cmd(lua_State *L) {
} }
void Command_ListBuffers() { void Command_ListBuffers() {
BSet main = GetLastActiveLayoutSet(); BSet main = GetActiveSet();
ActiveWindow = main.window->id; ActiveWindow = main.window->id;
JumpGarbageBuffer(&main); JumpGarbageBuffer(&main);
For(Buffers) { For(Buffers) {

View File

@@ -46,6 +46,29 @@ void UpdateScroll(Window *window, bool update_caret_scrolling) {
} }
} }
void FuzzySearchOpen(BSet active) {
bool success = false;
Range range = active.view->carets[0].range;
if (GetSize(range) == 0) {
Int line = PosToLine(active.buffer, range.min);
if ((active.buffer->line_starts.len - 1) == line) {
line = ClampBottom(0ll, line - 1ll);
}
String16 string = GetLineStringWithoutNL(active.buffer, line);
Int idx = 0;
if (Seek(string, u"||", &idx)) {
string = Skip(string, idx + 3);
Command_Open(string);
success = true;
}
}
if (!success) {
Command_Open(FetchLoadWord());
}
}
void OnCommand(Event event) { void OnCommand(Event event) {
ProfileFunction(); ProfileFunction();
// //
@@ -196,9 +219,7 @@ void OnCommand(Event event) {
} }
} }
if (Shift() && Ctrl() && Mouse(LEFT)) { if (Ctrl() && Mouse(LEFT)) {
MouseLoadWord(event, "exec");
} else if (Ctrl() && Mouse(LEFT)) {
MouseLoadWord(event); MouseLoadWord(event);
} else if (Mouse(LEFT)) { // Uses Alt and shift } else if (Mouse(LEFT)) { // Uses Alt and shift
Vec2I mouse = MouseVec2I(); Vec2I mouse = MouseVec2I();
@@ -270,23 +291,21 @@ void OnCommand(Event event) {
main.window->kill = true; main.window->kill = true;
} }
if (CtrlAltPress(SDLK_P)) { if (CtrlAltPress(SDLK_P)) {
Command_ListBuffers();
} else if (CtrlPress(SDLK_P)) { } else if (CtrlPress(SDLK_P)) {
Command_ListCode(); // Command_ListCode();
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)) {
ToggleVisibility(DebugWindowID); Window *window = GetWindow(DebugWindowID);
window->visible = !window->visible;
} }
if (CtrlPress(SDLK_GRAVE)) {
if (ActiveWindow != NullWindowID) {
ActiveWindow = NullWindowID;
} else {
}
}
if (CtrlPress(SDLK_1)) { if (CtrlPress(SDLK_1)) {
ActiveWindow = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow))->id; ActiveWindow = GetOverlappingWindow({0,0}, GetWindow(ActiveWindow))->id;
} }
@@ -309,7 +328,7 @@ void OnCommand(Event event) {
} }
BSet main = GetLastActiveLayoutSet(); BSet main = GetLastActiveLayoutSet();
BSet active = GetActiveSet(); BSet active = GetActiveSet();
Int buffer_change_id = active.buffer->change_id; Int buffer_change_id = active.buffer->change_id;
bool skip = CallOnCommand(&event); bool skip = CallOnCommand(&event);
@@ -320,8 +339,12 @@ void OnCommand(Event event) {
return; return;
} }
if (active.view->fuzzy_search) {
if (Press(SDLK_RETURN)) {
FuzzySearchOpen(active);
return;
}
}
if (event.kind == EVENT_DROP_FILE) { if (event.kind == EVENT_DROP_FILE) {
WindowOpenBufferView(active.window, event.text); WindowOpenBufferView(active.window, event.text);
@@ -465,7 +488,7 @@ void OnCommand(Event event) {
if (event.kind == EVENT_TEXT_INPUT) { if (event.kind == EVENT_TEXT_INPUT) {
Scratch scratch; Scratch scratch;
String string = event.text; String string = event.text;
String16 string16 = ToString16(scratch, string); String16 string16 = ToString16(scratch, string);
Command_Replace(active.view, string16); Command_Replace(active.view, string16);
} }
@@ -510,7 +533,7 @@ void OnCommand(Event event) {
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1); String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
if (active.view->prev_search_line != last_line_string) { if (active.view->prev_search_line != last_line_string) {
active.view->prev_search_line = last_line_string; active.view->prev_search_line = last_line_string;
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string); Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap); Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
For(IterateInReverse(&ratings)) { For(IterateInReverse(&ratings)) {
@@ -522,6 +545,7 @@ void OnCommand(Event event) {
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string); RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
Caret caret = active.view->carets[0]; Caret caret = active.view->carets[0];
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
Command_SelectEntireBuffer(active.view); Command_SelectEntireBuffer(active.view);
Command_Replace(active.view, GetString(temp_buffer)); Command_Replace(active.view, GetString(temp_buffer));
active.view->carets[0] = caret; active.view->carets[0] = caret;
@@ -562,32 +586,9 @@ void OnCommand(Event event) {
} }
if (CtrlPress(SDLK_SEMICOLON) || CtrlShiftPress(SDLK_Q)) { if (CtrlPress(SDLK_Q)) {
Command_Open(FetchLoadWord(), "exec");
}
else if (CtrlPress(SDLK_Q)) {
if (active.view->fuzzy_search) { if (active.view->fuzzy_search) {
bool success = false; FuzzySearchOpen(active);
Range range = active.view->carets[0].range;
if (GetSize(range) == 0) {
Int line = PosToLine(active.buffer, range.min);
if ((active.buffer->line_starts.len - 1) == line) {
line = ClampBottom(0ll, line - 1ll);
}
String16 string = GetLineStringWithoutNL(active.buffer, line);
Int idx = 0;
if (Seek(string, u"||", &idx)) {
string = Skip(string, idx + 3);
Command_Open(string);
success = true;
}
}
if (!success) {
Command_Open(FetchLoadWord());
}
} else { } else {
Command_Open(FetchLoadWord()); Command_Open(FetchLoadWord());
} }
@@ -602,3 +603,22 @@ void OnCommand(Event event) {
MergeCarets(active.buffer, &active.view->carets); MergeCarets(active.buffer, &active.view->carets);
IF_DEBUG(AssertRanges(active.view->carets)); IF_DEBUG(AssertRanges(active.view->carets));
} }
void PostCommandUpdate() {
For (Windows) {
if (it->sync_visibility_with_focus) {
if (it->id == ActiveWindow) {
it->visible = true;
} else {
it->visible = false;
}
}
}
if (ActiveWindow.id != LastActiveLayoutWindowID.id) {
Window *window = GetWindow(ActiveWindow);
if (window->layout) {
LastActiveLayoutWindowID = ActiveWindow;
}
}
}

View File

@@ -29,4 +29,5 @@ void ReloadStyle() {
StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter); StyleFontFilter = GetStyleInt("FontFilter", StyleFontFilter);
StyleFont = GetStyleString("Font", StyleFont); StyleFont = GetStyleString("Font", StyleFont);
StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall); StyleVCVarsall = GetStyleString("VCVarsall", StyleVCVarsall);
StyleUndoMergeTimeout = GetStyleFloat("UndoMergeTimeout", StyleUndoMergeTimeout);
} }

View File

@@ -69,6 +69,7 @@ Style.Font = GetExeDir().."/CascadiaMono.ttf"
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat" Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
Style.TrimWhitespaceOnSave = true Style.TrimWhitespaceOnSave = true
Style.ClangFormatOnSave = false Style.ClangFormatOnSave = false
Style.StyleUndoMergeTimeout = 0.3
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe' INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
OS_WINDOWS = 0 OS_WINDOWS = 0
@@ -333,7 +334,7 @@ function MatchExec(s, meta)
end end
Eval(s) Eval(s)
return {kind = "skip"} return nil
end end
BuiltinOnOpenMatchers = { BuiltinOnOpenMatchers = {

View File

@@ -64,4 +64,5 @@ Int StyleIndentSize = 4;
Int StyleFontSize = 15; Int StyleFontSize = 15;
Int StyleFontFilter = 0; Int StyleFontFilter = 0;
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf"; String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"; String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
double StyleUndoMergeTimeout = 0.3;

View File

@@ -130,6 +130,22 @@ static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
luaL_error(L, "lua execution got interrupted"); luaL_error(L, "lua execution got interrupted");
} }
double GetStyleFloat(String name, double default_float) {
double result = default_float;
lua_getglobal(LuaState, "Style");
defer { lua_pop(LuaState, 1); };
if (lua_istable(LuaState, -1)) {
lua_pushlstring(LuaState, name.data, name.len);
lua_gettable(LuaState, -2);
defer { lua_pop(LuaState, 1); };
if (lua_isnumber(LuaState, -1) || lua_isboolean(LuaState, -1) || lua_isinteger(LuaState, -1)) {
lua_Number num = lua_tonumber(LuaState, -1);
result = (double)num;
}
}
return result;
}
Int GetStyleInt(String name, Int default_int) { Int GetStyleInt(String name, Int default_int) {
Int result = default_int; Int result = default_int;
lua_getglobal(LuaState, "Style"); lua_getglobal(LuaState, "Style");
@@ -194,23 +210,24 @@ String GetFieldString(lua_State *L, String name) {
return result; return result;
} }
Int GetInt(lua_State *L, const char *name) { Int GetFieldInt(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 GetFloat(lua_State *L, const char *name) { double GetFieldFloat(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 *GetString(lua_State *L, const char *name) { const char *GetFieldString(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);
lua_pop(L, 1); lua_pop(L, 1);
return result; return result;
} }
@@ -239,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)Get##KIND(L, #NAME); #define X(TYPE, KIND, NAME) event.NAME = (TYPE)GetField##KIND(L, #NAME);
EVENT_FIELDS EVENT_FIELDS
#undef X #undef X
Add(&EventPlayback, event); Add(&EventPlayback, event);

View File

@@ -15,6 +15,7 @@ WindowID DebugWindowID;
ViewID DebugViewID; ViewID DebugViewID;
BufferID DebugBufferID; BufferID DebugBufferID;
WindowID CommandBarWindowID;
WindowID StatusBarWindowID; WindowID StatusBarWindowID;
WindowID SearchBarWindowID; WindowID SearchBarWindowID;
ViewID SearchViewID; ViewID SearchViewID;
@@ -407,13 +408,6 @@ bool BufferIsReferenced(BufferID buffer_id) {
void GarbageCollect() { void GarbageCollect() {
Allocator sys_allocator = GetSystemAllocator(); Allocator sys_allocator = GetSystemAllocator();
if (ActiveWindow.id != LastActiveLayoutWindowID.id) {
Window *window = GetWindow(ActiveWindow);
if (window->layout) {
LastActiveLayoutWindowID = ActiveWindow;
}
}
For(Buffers) { For(Buffers) {
if (it->file_mod_time) { if (it->file_mod_time) {
int64_t new_file_mod_time = GetFileModTime(it->name); int64_t new_file_mod_time = GetFileModTime(it->name);

View File

@@ -246,6 +246,7 @@ void Update(Event event) {
} }
OnCommand(event); OnCommand(event);
PostCommandUpdate();
UpdateProcesses(); UpdateProcesses();
CoUpdate(&event); CoUpdate(&event);
ReloadLuaConfigs(); ReloadLuaConfigs();

View File

@@ -40,6 +40,7 @@ struct Window {
bool visible : 1; bool visible : 1;
bool layout : 1; bool layout : 1;
bool kill : 1; bool kill : 1;
bool sync_visibility_with_focus : 1;
}; };
}; };

View File

@@ -110,4 +110,5 @@ void StatusBarUpdate() {
} }
Command_SelectRangeOneCursor(title.view, MakeRange(0)); Command_SelectRangeOneCursor(title.view, MakeRange(0));
ResetHistory(title.buffer);
} }

View File

@@ -6,19 +6,7 @@ Array<Window *> GetWindowZOrder(Allocator allocator) {
return order; return order;
} }
void SetVisibility(WindowID window_id, bool v) { Int GetExpandingBarSize(Window *window) {
Window *window = GetWindow(window_id);
window->visible = v;
}
bool ToggleVisibility(WindowID window_id) {
Window *window = GetWindow(window_id);
bool visible = !window->visible;
SetVisibility(window_id, visible);
return visible;
}
Int GetTitleBarSize(Window *window) {
View *view = GetView(window->active_view); View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
float result = (float)buffer->line_starts.len * window->font->line_spacing; float result = (float)buffer->line_starts.len * window->font->line_spacing;
@@ -40,6 +28,23 @@ void InitWindows() {
} }
} }
// COMMAND BAR
{
Window *window = CreateWind();
CommandBarWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, "command_bar");
View *view = CreateView(buffer->id);
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->draw_darker = true;
window->draw_line_highlight = false;
window->layout = false;
window->visible = false;
window->sync_visibility_with_focus = true;
buffer->no_history = true;
}
// SEARCH BAR // SEARCH BAR
{ {
Window *window = CreateWind(); Window *window = CreateWind();
@@ -64,7 +69,6 @@ void InitWindows() {
Buffer *buffer = CreateBuffer(SysAllocator, "status_bar"); Buffer *buffer = CreateBuffer(SysAllocator, "status_bar");
View *view = CreateView(buffer->id); View *view = CreateView(buffer->id);
window->active_view = view->id; window->active_view = view->id;
buffer->no_history = true;
window->font = &SecondaryFont; window->font = &SecondaryFont;
window->draw_line_numbers = false; window->draw_line_numbers = false;
window->draw_scrollbar = false; window->draw_scrollbar = false;
@@ -91,7 +95,7 @@ void InitWindows() {
DebugViewID = view->id; DebugViewID = view->id;
window->active_view = view->id; window->active_view = view->id;
SetVisibility(window->id, false); window->visible = false;
} }
} }
@@ -118,25 +122,45 @@ double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) {
void LayoutWindows(int16_t wx, int16_t wy) { void LayoutWindows(int16_t wx, int16_t wy) {
Rect2I screen_rect = RectI0Size(wx, wy); Rect2I screen_rect = RectI0Size(wx, wy);
// Command bar
{
Window *n = GetWindow(CommandBarWindowID);
Rect2I *rect = &screen_rect;
Rect2I copy_rect = screen_rect;
if (!n->visible) {
rect = &copy_rect;
}
Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
}
// bar at the bottom // bar at the bottom
{ {
Window *n = GetWindow(StatusBarWindowID); Window *n = GetWindow(StatusBarWindowID);
Int barsize = GetTitleBarSize(n); Rect2I *rect = &screen_rect;
n->document_rect = n->total_rect = CutBottom(&screen_rect, barsize); Rect2I copy_rect = screen_rect;
if (!n->visible) {
rect = &copy_rect;
}
Int barsize = GetExpandingBarSize(n);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
} }
// search bar // search bar
{ {
Window *n = GetWindow(SearchBarWindowID); Window *n = GetWindow(SearchBarWindowID);
if (n->visible) { Rect2I *rect = &screen_rect;
Int barsize = GetTitleBarSize(n); Rect2I copy_rect = screen_rect;
n->document_rect = n->total_rect = CutBottom(&screen_rect, barsize); if (!n->visible) {
rect = &copy_rect;
} }
Int barsize = GetExpandingBarSize(n);
n->document_rect = n->total_rect = CutBottom(rect, barsize);
} }
// floating debug window // floating debug window
{ {
Window *n = GetWindow(DebugWindowID); Window *n = GetWindow(DebugWindowID);
Rect2 screen_rect = Rect0Size(wx, wy); Rect2 screen_rect = Rect0Size(wx, wy);
Vec2 size = GetSize(screen_rect); Vec2 size = GetSize(screen_rect);