Begin new plugin system refactor, removing hooks

This commit is contained in:
Krzosa Karol
2026-01-15 22:23:04 +01:00
parent db06c783a9
commit 3864060699
21 changed files with 3033 additions and 172 deletions

View File

@@ -1551,13 +1551,8 @@ void ReopenBuffer(Buffer *buffer) {
void SaveBuffer(Buffer *buffer) {
ProfileFunction();
For (GlobalHooks) {
if (it.kind == HookKind_BeforeSavingBuffer) {
ProfileScopeEx(it.name);
HookParam param = {};
param.buffer = buffer;
it.function(param);
}
if (TrimTrailingWhitespace) {
TrimWhitespace(buffer, false);
}
Scratch scratch;

View File

@@ -291,12 +291,6 @@ void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
view->update_scroll = false;
}
void HOOK_TrimTrailingWhitespace(HookParam param) {
if (TrimTrailingWhitespace) {
TrimWhitespace(param.buffer, false);
}
} RegisterHook(HOOK_TrimTrailingWhitespace, HookKind_BeforeSavingBuffer, "", "Cleans trailing whitespace before saving to file");
void ConvertLineEndingsToLF(Buffer *buffer, bool trim_lines_with_caret = false) {
Scratch scratch;
@@ -477,17 +471,6 @@ BSet Exec(String cmd, String working_dir, bool set_active = true) {
return main;
}
BSet ExecBuild(String cmd) {
BSet build = GetBSet(BuildWindowID);
BSet main = GetBSet(PrimaryWindowID);
SelectRange(build.view, Range{});
ResetBuffer(build.buffer);
Exec(build.view->id, true, cmd, WorkDir);
main.window->active_goto_list = build.view->id;
main.window->goto_list_pos = 0;
return build;
}
void CMD_SaveAll(HookParam param) {
For(Buffers) {
// NOTE: file_mod_time is only set when buffer got read or written to disk already so should be saved
@@ -497,17 +480,6 @@ void CMD_SaveAll(HookParam param) {
}
} RegisterCommand(CMD_SaveAll, "ctrl-shift-s");
void CMD_Build(HookParam param) {
CMD_SaveAll({});
#if OS_WINDOWS
ExecBuild("build.bat");
#else
ExecBuild("sh build.sh");
#endif
BSet main = GetBSet(BuildWindowID);
main.window->visible = true;
} RegisterCommand(CMD_Build, "f1", "Run build.sh or build.bat in working directory, output is printed in a popup console and a special build buffer");
void CMD_GotoNextInList(HookParam param) {
BSet main = GetBSet(PrimaryWindowID);
GotoNextInList(main.window, 1);
@@ -1109,16 +1081,17 @@ String Coro_CloseAllEx(mco_coro *co) {
return "Yes";
}
void CMD_QuitWithoutSaving(HookParam param) {
#ifdef PLUGIN_REMEDYBG
QuitDebugger();
#endif
AppIsRunning = false;
} RegisterCommand(CMD_QuitWithoutSaving, "", "Self explanatory");
void Coro_Quit(mco_coro *co) {
String res = Coro_CloseAllEx(co);
if (res != "Cancel") {
For (GlobalHooks) {
if (it.kind == HookKind_AppQuit) {
ProfileScopeEx(it.name);
it.function({});
}
}
AppIsRunning = false;
CMD_QuitWithoutSaving({});
}
}
@@ -1128,16 +1101,6 @@ void CMD_Quit(HookParam param) {
CoResume(data);
} RegisterCommand(CMD_Quit, "", "Ask user which files he would like to save and exit");
void CMD_QuitWithoutSaving(HookParam param) {
For (GlobalHooks) {
if (it.kind == HookKind_AppQuit) {
ProfileScopeEx(it.name);
it.function({});
}
}
AppIsRunning = false;
} RegisterCommand(CMD_QuitWithoutSaving, "", "Self explanatory");
void Coro_CloseAll(mco_coro *co) {
Coro_CloseAllEx(co);
}
@@ -1587,8 +1550,44 @@ void CMD_ReplaceAll(HookParam param) {
CoResume(data);
} RegisterCommand(CMD_ReplaceAll, "ctrl-shift-r", "Search and replace over the entire project, you need to select a text with format like this 'FindAnd@>ReplaceWith' and executing the command will change all occurences of FindAnd to ReplaceWith");
struct SearchProjectParams {
String16 needle;
BufferID buffer;
};
void UpdateSearchProjectView(HookParam param) {
void Coro_SearchProject(mco_coro *co) {
SearchProjectParams *param = (SearchProjectParams *)CoCurr->user_ctx;
Array<BufferID> buffers = {CoCurr->arena};
For (Buffers) {
Add(&buffers, it->id);
}
ForItem (id, buffers) {
Buffer *it = GetBuffer(id, NULL);
if (it == NULL || it->special || it->is_dir || it->temp || it->dont_try_to_save_in_bulk_ops) {
continue;
}
{
Scratch scratch;
Array<Caret> occurences = FindAll(scratch, it, param->needle);
Buffer *out_buffer = GetBuffer(param->buffer);
ForItem (caret, occurences) {
Int pos = caret.range.min;
Int line = PosToLine(it, pos);
Range range = GetLineRangeWithoutNL(it, line);
Int column = pos - range.min;
String16 line_string = GetString(it, range);
String line_string8 = ToString(scratch, line_string);
RawAppendf(out_buffer, "%S ||> %S:%lld:%lld\n", line_string8, it->name, (long long)line + 1, (long long)column + 1);
}
}
CoYield(co);
}
}
void UpdateSearchProjectView() {
Scratch scratch;
BSet active = GetBSet(ActiveWindowID);
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
@@ -1636,7 +1635,7 @@ void CMD_SearchProject(HookParam param) {
main.window->goto_list_pos = active.view->carets[0].range.min;
Open(string);
});
AddHook(&view->hooks, HookKind_AppUpdate, "UpdateSearchProjectView", "", UpdateSearchProjectView);
view->update_hook = UpdateSearchProjectView;
SelectRange(view, GetLineRangeWithoutNL(search_project_buffer, 0));
if (string.len) {
Replace(view, string);

View File

@@ -0,0 +1,135 @@
String16 FetchFuzzyViewLoadLine(View *view) {
Buffer *buffer = GetBuffer(view->active_buffer);
Range range = view->carets[0].range;
String16 string = GetString(buffer, range);
if (GetSize(range) == 0) {
Int line = PosToLine(buffer, range.min);
if (line == 0) {
line = ClampTop(1ll, buffer->line_starts.len - 1ll);
}
string = GetLineStringWithoutNL(buffer, line);
Int idx = 0;
String16 delim = u"||>";
if (Seek(string, delim, &idx, SeekFlag_None)) {
string = Skip(string, idx + delim.len);
}
}
return string;
}
void OpenCommand(BSet active) {
String16 string = FetchFuzzyViewLoadLine(active.view);
Open(string);
}
float NewFuzzyRate(String16 s, String16 p) {
float score = 0;
// try to do this: https://github.com/junegunn/fzf/blob/master/src/algo/algo.go
return score;
}
float FuzzyRate(String16 s, String16 p) {
float score = 0;
for (Int outer_pi = 0; outer_pi < p.len; outer_pi += 1) {
String16 pit = Skip(p, outer_pi);
if (IsWhitespace(At(pit, 0))) {
continue;
}
float matching = 0;
for (Int outer_si = 0; outer_si < s.len; outer_si += 1) {
String16 sit = Skip(s, outer_si);
if (IsWhitespace(At(sit, 0))) {
continue;
}
Int si = 0;
Int pi = 0;
for (;si < sit.len && pi < pit.len;) {
while (si < sit.len && IsWhitespace(sit[si])) si += 1;
while (pi < pit.len && IsWhitespace(pit[pi])) pi += 1;
if (pi >= pit.len) break;
if (si >= sit.len) break;
if (ToLowerCase(sit[si]) == ToLowerCase(pit[pi])) {
matching += 1.0f;
} else {
break;
}
si += 1;
pi += 1;
}
}
score += matching;
}
score = score / (float)s.len;
return score;
}
inline bool MergeSortCompare(FuzzyPair *a, FuzzyPair *b) {
bool result = a->rating > b->rating;
return result;
}
Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle) {
ProfileFunction();
if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
if (line_max < 0 || line_min > buffer->line_starts.len) return {};
Array<FuzzyPair> ratings = {allocator};
Reserve(&ratings, line_max - line_min + 4);
for (Int i = line_min; i < line_max; i += 1) {
String16 s = GetLineStringWithoutNL(buffer, i);
Int idx = 0;
if (Seek(s, u"||>", &idx, SeekFlag_None)) {
s = GetPrefix(s, idx);
} else if (Seek(s, u"<||", &idx, SeekFlag_None)) {
s = GetPrefix(s, idx);
}
s = Trim(s);
float rating = FuzzyRate(s, needle);
Add(&ratings, {(int32_t)i, rating});
}
Array<FuzzyPair> temp = Copy(allocator, ratings);
MergeSort(ratings.len, ratings.data, temp.data);
return ratings;
}
void UpdateFuzzySearchView() {
Scratch scratch;
BSet active = GetBSet(ActiveWindowID);
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
uint64_t hash = HashBytes(line_string.data, line_string.len * sizeof(char16_t));
if (active.view->prev_search_line_hash != hash) {
active.view->prev_search_line_hash = hash;
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 1, active.buffer->line_starts.len, line_string);
Buffer *scratch_buff = CreateScratchBuffer(scratch, active.buffer->cap);
RawAppend(scratch_buff, line_string);
For(IterateInReverse(&ratings)) {
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
if (s.len == 0) continue;
RawAppend(scratch_buff, u"\n");
RawAppend(scratch_buff, s);
}
Caret caret = active.view->carets[0];
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
SelectEntireBuffer(active.view);
Replace(active.view, GetString(scratch_buff));
active.view->carets[0] = caret;
}
}
void SetFuzzy(View *view) {
AddCommand(&view->hooks, "Open", "ctrl-q | enter | f12", [](HookParam){
BSet active = GetBSet(ActiveWindowID);
BSet main = GetBSet(PrimaryWindowID);
NextActiveWindowID = main.window->id;
String16 string = FetchFuzzyViewLoadLine(active.view);
Open(string);
});
view->update_hook = UpdateFuzzySearchView;
}

View File

@@ -33,18 +33,32 @@ BufferID NullBufferID;
ViewID NullViewID;
WindowID NullWindowID;
// hidden floating window
WindowID DebugWindowID;
ViewID DebugViewID;
BufferID DebugBufferID;
WindowID CommandWindowID;
WindowID StatusBarWindowID;
WindowID SearchWindowID;
ViewID SearchViewID;
BufferID SearchBufferID;
WindowID BuildWindowID;
ViewID BuildViewID;
BufferID BuildBufferID;
#ifdef PLUGIN_DEBUG_WINDOW
WindowID DebugWindowID;
ViewID DebugViewID;
BufferID DebugBufferID;
#endif
#ifdef PLUGIN_COMMAND_WINDOW
WindowID CommandWindowID;
#endif
#ifdef PLUGIN_SEARCH_WINDOW
WindowID SearchWindowID;
ViewID SearchViewID;
BufferID SearchBufferID;
#endif
#ifdef PLUGIN_STATUS_WINDOW
WindowID StatusWindowID;
#endif
#ifdef PLUGIN_BUILD_WINDOW
WindowID BuildWindowID;
ViewID BuildViewID;
BufferID BuildBufferID;
#endif
BufferID SearchProjectBufferID;
BufferID GlobalConfigBufferID;
@@ -175,3 +189,8 @@ RegisterVariable(String, InternetBrowser, "firefox");
RegisterVariable(String, OpenCodePatterns, ".c .h .cpp .hpp .cc .cxx .rs .go .zig .py .lua .js .ts .jsx .tsx .java .kt .swift .cs .rb .php .html .css .scss .bat .sh .bash .zsh .sql .asm .s .cmake .make .json .yaml .toml .ini .txt .md .rst .Makefile .Dockerfile .gitignore .bashrc .zshrc");
RegisterVariable(String, OpenCodeExcludePatterns, "");
RegisterVariable(Int, TrimTrailingWhitespace, 1);
// BEGIN PLUGIN_REMEDYBG
RegisterVariable(String, BinaryUnderDebug, "build/te.exe");
RegisterVariable(String, RemedyBGPath, "remedybg.exe");
// END PLUGIN_REMEDYBG

View File

@@ -0,0 +1,60 @@
void InitBuildWindow() {
Window *window = CreateWind();
BuildWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "build"));
buffer->special = true;
buffer->no_history = true;
BuildBufferID = buffer->id;
View *view = CreateView(buffer->id);
view->special = true;
BuildViewID = view->id;
window->active_view = view->id;
window->secondary_window_style = true;
window->draw_line_highlight = true;
window->primary = false;
window->visible = false;
window->lose_visibility_on_escape = true;
window->jump_history = false;
}
void LayoutBuildWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(BuildWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = window->font->line_spacing * 10;
window->document_rect = window->total_rect = CutBottom(rect, barsize);
}
BSet ExecBuild(String cmd) {
BSet build = GetBSet(BuildWindowID);
BSet main = GetBSet(PrimaryWindowID);
SelectRange(build.view, Range{});
ResetBuffer(build.buffer);
Exec(build.view->id, true, cmd, WorkDir);
main.window->active_goto_list = build.view->id;
main.window->goto_list_pos = 0;
return build;
}
void CMD_Build(HookParam param) {
CMD_SaveAll({});
#if OS_WINDOWS
ExecBuild("build.bat");
#else
ExecBuild("sh build.sh");
#endif
BSet main = GetBSet(BuildWindowID);
main.window->visible = true;
} RegisterCommand(CMD_Build, "f1", "Run build.sh or build.bat in working directory, output is printed in a popup console and a special build buffer");
void CMD_ShowBuildWindow(HookParam param) {
BSet main = GetBSet(BuildWindowID);
if (ActiveWindowID != BuildWindowID) {
main.window->visible = true;
NextActiveWindowID = BuildWindowID;
} else {
main.window->visible = false;
}
} RegisterCommand(CMD_ShowBuildWindow, "ctrl-grave");

View File

@@ -0,0 +1,3 @@
#define PLUGIN_BUILD_WINDOW
void InitBuildWindow();
void LayoutBuildWindow(Rect2I *rect, int16_t wx, int16_t wy);

View File

@@ -0,0 +1,98 @@
void CMD_ShowCommands(HookParam param) {
// @todo: maybe redo this, similar behavior but use View stored information
// if (ActiveWindowID == CommandWindowID && LastExecutedManualCommand == CMD_ShowCommands) {
// NextActiveWindowID = PrimaryWindowID;
// return;
// }
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (GlobalHooks) {
if (it.name == "OpenCommand") {
continue;
}
// RawAppendf(command_bar.buffer, "\n:%-30S <|| :Set %-30S '%-30S'", it.name, it.name, it.binding);
RawAppendf(command_bar.buffer, "\n:%-30S <|| ", it.name);
if (it.docs.len) {
RawAppendf(command_bar.buffer, "%S", it.docs);
}
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowCommands, "ctrl-shift-p", "List available commands and their documentation inside the command window");
void CMD_ShowDebugBufferList(HookParam param) {
// @todo: maybe redo this, similar behavior but use View stored information
// if (ActiveWindowID == CommandWindowID && LastExecutedManualCommand == CMD_ShowDebugBufferList) {
// NextActiveWindowID = PrimaryWindowID;
// return;
// }
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (Buffers) {
bool is_special = it->special || it->temp || it->is_dir || it->dont_try_to_save_in_bulk_ops;
if (!is_special) {
continue;
}
RawAppendf(command_bar.buffer, "\n%S", it->name);
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowDebugBufferList, "ctrl-shift-alt-p", "Show full list of buffers, including the special ones that normally just clutter list");
void CMD_ShowBufferList(HookParam param) {
// @todo: maybe redo this, similar behavior but use View stored information
// if (ActiveWindowID == CommandWindowID && LastExecutedManualCommand == CMD_ShowBufferList) {
// NextActiveWindowID = PrimaryWindowID;
// return;
// }
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (Buffers) {
bool is_special = it->special || it->temp || it->is_dir || it->dont_try_to_save_in_bulk_ops;
if (is_special) {
continue;
}
RawAppendf(command_bar.buffer, "\n%S", it->name);
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowBufferList, "ctrl-p", "List open buffers inside the command window that you can fuzzy search over");
void LayoutCommandWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(CommandWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = Clamp((Int)window->font->line_spacing*10, (Int)0, (Int)wx - 100);
window->document_rect = window->total_rect = CutBottom(rect, barsize);
}
void InitCommandWindow() {
Window *window = CreateWind();
CommandWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "command_bar"));
buffer->special = true;
buffer->no_history = true;
View *view = CreateView(buffer->id);
view->special = true;
SetFuzzy(view);
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->secondary_window_style = true;
window->draw_line_highlight = true;
window->primary = false;
window->visible = false;
window->sync_visibility_with_focus = true;
window->lose_focus_on_escape = true;
window->jump_history = false;
}

View File

@@ -0,0 +1,3 @@
#define PLUGIN_COMMAND_WINDOW
void InitCommandWindow();
void LayoutCommandWindow(Rect2I *rect, int16_t wx, int16_t wy);

View File

@@ -0,0 +1,85 @@
void InitDebugWindow() {
Window *window = CreateWind();
DebugWindowID = window->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->visible = false;
window->z = 2;
window->primary = false;
window->jump_history = false;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
DebugBufferID = buffer->id;
buffer->no_history = true;
buffer->special = true;
View *view = CreateView(buffer->id);
view->special = true;
DebugViewID = view->id;
window->active_view = view->id;
window->visible = false;
}
void LayoutDebugWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(DebugWindowID);
Rect2 screen_rect = Rect0Size((float)wx, (float)wy);
Vec2 size = GetSize(screen_rect);
Rect2 a = CutRight(&screen_rect, 0.3f * size.x);
Rect2 b = CutTop(&a, 0.4f * size.y);
Rect2 c = Shrink(b, 20);
window->document_rect = window->total_rect = ToRect2I(c);
}
void UpdateDebugWindow() {
ProfileFunction();
BSet set = GetBSet(DebugWindowID);
if (!set.window->visible) {
return;
}
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->id.id == set.buffer->id.id) {
return;
}
BSet main = GetBSet(PrimaryWindowID);
Scratch scratch;
String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID);
String16 string = ToString16(scratch, s);
RawReplaceText(set.buffer, GetRange(set.buffer), string);
float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse);
RawAppendf(set.buffer, "mouse: [%f, %f]\n", roundf(DPIScale * xmouse), roundf(DPIScale * ymouse));
RawAppendf(set.buffer, "BufferID id = %d\n", main.buffer->id.id);
RawAppendf(set.buffer, "String name = %S\n", main.buffer->name);
RawAppendf(set.buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id);
RawAppendf(set.buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id);
RawAppendf(set.buffer, "Int file_mod_time = %lld\n", (long long)main.buffer->file_mod_time);
RawAppendf(set.buffer, "\n");
RawAppendf(set.buffer, "U16 *data = %zu\n", main.buffer->data);
RawAppendf(set.buffer, "Int len = %lld\n", (long long)main.buffer->len);
RawAppendf(set.buffer, "Int cap = %lld\n", (long long)main.buffer->cap);
RawAppendf(set.buffer, "Array<Int> line_starts = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->line_starts.len, (long long)main.buffer->line_starts.cap, main.buffer->line_starts.data);
RawAppendf(set.buffer, "\n");
RawAppendf(set.buffer, "Array<HistoryEntry> undo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->undo_stack.len, (long long)main.buffer->undo_stack.cap, main.buffer->undo_stack.data);
RawAppendf(set.buffer, "Array<HistoryEntry> redo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->redo_stack.len, (long long)main.buffer->redo_stack.cap, main.buffer->redo_stack.data);
RawAppendf(set.buffer, "int edit_phase = %d", main.buffer->edit_phase);
RawAppendf(set.buffer, "\n");
RawAppendf(set.buffer, "int no_history = %d\n", main.buffer->no_history);
RawAppendf(set.buffer, "int no_line_starts = %d\n", main.buffer->no_line_starts);
RawAppendf(set.buffer, "int dirty = %d\n", main.buffer->dirty);
RawAppendf(set.buffer, "int changed_on_disk = %d\n", main.buffer->changed_on_disk);
RawAppendf(set.buffer, "int temp = %d\n", main.buffer->temp);
}
void CMD_ToggleDebug(HookParam param) {
Window *window = GetWindow(DebugWindowID);
window->visible = !window->visible;
} RegisterCommand(CMD_ToggleDebug, "ctrl-0", "Open a floating window that might become useful for debugging");

View File

@@ -0,0 +1,4 @@
#define PLUGIN_DEBUG_WINDOW
void InitDebugWindow();
void LayoutDebugWindow(Rect2I *rect, int16_t wx, int16_t wy);
void UpdateDebugWindow();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
#define PLUGIN_REMEDYBG
void QuitDebugger();

View File

@@ -0,0 +1,103 @@
void CMD_Search(HookParam param) {
BSet main = GetBSet(ActiveWindowID);
String16 string = {};
if (main.view->carets.len == 1 && GetSize(main.view->carets[0]) > 0) {
string = GetString(main.buffer, main.view->carets[0].range);
}
BSet set = GetBSet(SearchWindowID);
set.window->visible = true;
NextActiveWindowID = SearchWindowID;
SelectEntireBuffer(set.view);
if (string.len > 0) {
Replace(set.view, string);
SelectEntireBuffer(set.view);
}
} RegisterCommand(CMD_Search, "ctrl-f", "Open up a search window");
void SearchWindowFindNext(bool forward = true) {
BSet main = GetBSet(PrimaryWindowID);
BSet set = GetBSet(SearchWindowID);
String16 seek = GetString(set.buffer, GetRange(set.buffer));
Find(main.view, seek, forward);
main.window->search_bar_anchor = main.view->carets[0];
CenterView(PrimaryWindowID);
}
void CMD_SearchNextInSearch(HookParam param) {
SearchWindowFindNext(true);
}
void CMD_SearchPrevInSearch(HookParam param) {
SearchWindowFindNext(false);
}
void CMD_SearchNext(HookParam param) {
SearchWindowFindNext(true);
} RegisterCommand(CMD_SearchNext, "f3", "Go to the next occurence of the search window needle");
void CMD_SearchPrev(HookParam param) {
SearchWindowFindNext(false);
} RegisterCommand(CMD_SearchPrev, "shift-f3", "Go to the previous occurence of the search window needle");
void CMD_SearchAll(HookParam param) {
BSet main = GetBSet(PrimaryWindowID);
BSet set = GetBSet(SearchWindowID);
String16 needle = GetString(set.buffer, GetRange(set.buffer));
SelectAllOccurences(main.view, needle);
set.window->visible = false;
} RegisterCommand(CMD_SearchAll, "alt-f3", "Use the search window needle and seek all the possible occurences in current buffer");
void CMD_ToggleCaseSensitiveSearch(HookParam param) {
SearchCaseSensitive = !SearchCaseSensitive;
} RegisterCommand(CMD_ToggleCaseSensitiveSearch, "alt-c", "Text editor wide search toggle, should apply to most search things");
void CMD_ToggleSearchWordBoundary(HookParam param) {
SearchWordBoundary = !SearchWordBoundary;
} RegisterCommand(CMD_ToggleSearchWordBoundary, "alt-w", "Text editor wide search toggle, should apply to most search things");
void InitSearchWindow() {
Window *window = CreateWind();
SearchWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "search"));
buffer->special = true;
SearchBufferID = buffer->id;
View *view = CreateView(buffer->id);
view->special = true;
SearchViewID = view->id;
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->secondary_window_style = true;
window->draw_line_highlight = false;
window->primary = false;
window->visible = false;
window->lose_visibility_on_escape = true;
window->jump_history = false;
AddCommand(&view->hooks, "SearchAll", "alt-enter", CMD_SearchAll);
AddCommand(&view->hooks, "SearchPrevInSearch", "shift-enter", CMD_SearchPrevInSearch);
AddCommand(&view->hooks, "SearchNextInSearch", "enter", CMD_SearchNextInSearch);
}
void LayoutSearchWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(SearchWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = GetExpandingBarSize(window);
window->document_rect = window->total_rect = CutBottom(rect, barsize);
window->line_numbers_rect = CutLeft(&window->document_rect, window->font->char_spacing * 6);
}
void UpdateSearchWindow() {
if (ActiveWindowID == SearchWindowID) {
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->begin_frame_change_id != active.buffer->change_id) {
BSet main = GetBSet(PrimaryWindowID);
main.view->carets[0] = main.window->search_bar_anchor;
String16 seek = GetString(active.buffer, GetRange(active.buffer));
Find(main.view, seek, true);
CenterView(main.window->id);
}
}
}

View File

@@ -0,0 +1,4 @@
#define PLUGIN_SEARCH_WINDOW
void InitSearchWindow();
void LayoutSearchWindow(Rect2I *rect, int16_t wx, int16_t wy);
void UpdateSearchWindow();

View File

@@ -0,0 +1,97 @@
void InitStatusWindow() {
Window *window = CreateWind();
StatusWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "status_bar"));
buffer->special = true;
View *view = CreateView(buffer->id);
view->special = true;
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->draw_line_highlight = true;
window->secondary_window_style = true;
window->primary = false;
window->jump_history = false;
window->lose_focus_on_escape = true;
}
void LayoutStatusWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(StatusWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = GetExpandingBarSize(window);
window->document_rect = window->total_rect = CutBottom(rect, barsize);
}
void UpdateStatusWindow() {
ProfileFunction();
Window *status_bar_window = GetWindow(StatusWindowID, NULL);
Scratch scratch;
BSet main = GetBSet(PrimaryWindowID);
BSet title = GetBSet(status_bar_window);
title.view->scroll.y = 0;
String16 buffer_string = GetString(title.buffer);
Range replace_range = {0, title.buffer->len};
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
// Parse the title and line
if (title.window->id == ActiveWindowID) {
if (title.buffer->change_id == title.buffer->begin_frame_change_id) {
return;
}
String16 buffer_name = GetString(title.buffer, replace_range);
buffer_name = Trim(buffer_name);
Int column = ChopNumber(&buffer_name);
if (column == -1) return;
Chop(&buffer_name, u":");
Int line = ChopNumber(&buffer_name);
if (line == -1) {
line = column;
column = 0;
}
Chop(&buffer_name, u":");
Int buffer_pos = XYToPos(main.buffer, {column, line});
Caret &caret = main.view->carets[0];
if (GetFront(caret) != buffer_pos) {
caret = MakeCaret(buffer_pos);
}
return;
}
Caret caret = main.view->carets[0];
XY xy = PosToXY(main.buffer, GetFront(caret));
// add separator at the end of buffer
if (!found_separator) {
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
ReplaceEx(scratch, title.view, u" | :Prev :Next :Close");
}
// replace data up to separator with filename and stuff
const char *reopen = main.buffer->changed_on_disk ? " :Reopen" : "";
const char *case_sens = SearchCaseSensitive ? " C" : "";
const char *word_bound = SearchWordBoundary ? " W" : "";
const char *dirty = main.buffer->dirty ? " !" : "";
String s = Format(scratch, "%S:%lld:%lld%s%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, dirty, case_sens, word_bound, reopen);
For (ActiveProcesses) {
if (it.view_id == main.view->id.id) {
s = Format(scratch, "%S %lld :KillProcess", s, (long long)it.id);
}
}
String16 string = ToString16(scratch, s);
String16 string_to_replace = GetString(title.buffer, replace_range);
if (string_to_replace != string) {
SelectRange(title.view, replace_range);
ReplaceEx(scratch, title.view, string);
}
SelectRange(title.view, MakeRange(0));
ResetHistory(title.buffer);
}

View File

@@ -0,0 +1,4 @@
#define PLUGIN_STATUS_WINDOW
void InitStatusWindow();
void LayoutStatusWindow(Rect2I *rect, int16_t wx, int16_t wy);
void UpdateStatusWindow();

View File

@@ -4,7 +4,7 @@
// the appropriate handles. This happens in this case when git grep calls
// 'less' program which errors out and doesn't print anything
// @todo: maybe I should ask someone smarter about this!
void UpdateProcesses(HookParam param) {
void UpdateProcesses() {
IterRemove(ActiveProcesses) {
IterRemovePrepare(ActiveProcesses);
Scratch scratch;
@@ -19,14 +19,16 @@ void UpdateProcesses(HookParam param) {
remove_item = true;
}
}
} RegisterHook(UpdateProcesses, HookKind_AppUpdate, "", "Polls all the processes and outputs the results to corresponding views");
}
void Exec(ViewID view, bool scroll_to_end, String cmd, String working_dir) {
Process process = SpawnProcess(cmd, working_dir, {}, ProcessEnviroment);
ReportDebugf("process %lld start. is_valid = %d cmd = %S working_dir = %S", process.id, process.is_valid, cmd, working_dir);
process.view_id = view.id;
process.scroll_to_end = scroll_to_end;
if (process.is_valid) Add(&ActiveProcesses, process);
if (process.is_valid) {
Add(&ActiveProcesses, process);
}
}
void Exec(ViewID view, bool scroll_to_end, String16 cmd16, String working_dir) {

View File

@@ -15,16 +15,20 @@
#include "render/font.cpp"
#include "render/opengl.cpp"
#include "text_editor.h"
#include "plugin_command_window.h"
#include "plugin_search_window.h"
#include "plugin_debug_window.h"
#include "plugin_status_window.h"
#include "plugin_build_window.h"
#if OS_WINDOWS
#include "plugin_remedybg.h"
#endif
#include "globals.cpp"
#include "coroutines.cpp"
#include "buffer.cpp"
#include "view.cpp"
#include "window.cpp"
#include "window_status.cpp"
#include "window_command.cpp"
#include "window_debug.cpp"
#include "window_search.cpp"
#include "window_build.cpp"
#include "fuzzy_search_view.cpp"
#include "process.cpp"
#include "event.cpp"
#include "config.cpp"
@@ -34,7 +38,14 @@
#include "draw.cpp"
#include "test/tests.cpp"
#include "remedybg_plugin.cpp"
#include "plugin_command_window.cpp"
#include "plugin_search_window.cpp"
#include "plugin_status_window.cpp"
#include "plugin_build_window.cpp"
#include "plugin_debug_window.cpp"
#if OS_WINDOWS
#include "plugin_remedybg.cpp"
#endif
#if OS_WASM
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
@@ -581,25 +592,30 @@ void Update(Event event) {
OnCommand(event);
#ifdef PLUGIN_DEBUG_WINDOW
UpdateDebugWindow();
#endif
#ifdef PLUGIN_STATUS_WINDOW
UpdateStatusWindow();
#endif
#ifdef PLUGIN_SEARCH_WINDOW
UpdateSearchWindow();
#endif
// ActiveViewHook
{
BSet set = GetBSet(ActiveWindowID);
For (set.view->hooks) {
if (it.kind == HookKind_AppUpdate) {
ProfileScopeEx(it.name);
it.function(HookParam{});
}
}
For (GlobalHooks) {
if (it.kind == HookKind_AppUpdate) {
ProfileScopeEx(it.name);
it.function(HookParam{});
}
if (set.view->update_hook) {
set.view->update_hook();
}
}
UpdateProcesses();
CoUpdate(&event);
For(IterateInReverse(&order)) {
if (!it->visible) continue;
View *view = GetView(it->active_view);
@@ -664,8 +680,19 @@ void Update(Event event) {
// Behavior where these windows cannot be visible at the same time
{
WindowID id[] = {BuildWindowID, CommandWindowID, SearchWindowID};
for (int i = 0; i < Lengthof(id); i += 1) {
WindowID id[] = {
{-1}, // This is just so that we have a valid array if all windows are disabled
#ifdef PLUGIN_BUILD_WINDOW
BuildWindowID,
#endif
#ifdef PLUGIN_COMMAND_WINDOW
CommandWindowID,
#endif
#ifdef PLUGIN_SEARCH_WINDOW
SearchWindowID,
#endif
};
for (int i = 1; i < Lengthof(id); i += 1) {
if (ActiveWindowID == id[i]) {
for (int j = 0; j < Lengthof(id); j += 1) {
if (i == j) continue;
@@ -921,14 +948,25 @@ int main(int argc, char **argv)
CoResume(co_data);
#endif
{
For (GlobalHooks) {
if (it.kind == HookKind_AppInit) {
ProfileScopeEx(it.name);
it.function({});
}
}
}
#ifdef PLUGIN_STATUS_WINDOW
InitStatusWindow();
#endif
#ifdef PLUGIN_COMMAND_WINDOW
InitCommandWindow();
#endif
#ifdef PLUGIN_DEBUG_WINDOW
InitDebugWindow();
#endif
#ifdef PLUGIN_BUILD_WINDOW
InitBuildWindow();
#endif
#ifdef PLUGIN_SEARCH_WINDOW
InitSearchWindow();
#endif
#if OS_WASM
emscripten_set_main_loop(MainLoop, 0, 1);

View File

@@ -27,38 +27,7 @@ struct HistoryEntry {
enum HookKind {
HookKind_Invalid,
HookKind_AppInit,
HookKind_AppUpdate,
HookKind_AppQuit,
// Should we have commands like PostCommand, PreCommand? what would be the purpose?
HookKind_Command,
// Currently we are only basically allowing control over non-layouted windows.
// How can this be expanded?
// - Changing the layout algorithm: this seems like a decent one
// - What beside that?
HookKind_HandleWindowLayout,
// Move the special window rendering to hooks?
// HookKind_RenderWindow,
// HookKind_CreateWindow,
// How to handle formatters for multiple languages and other saving rules???
HookKind_BeforeSavingBuffer,
HookKind_CreateBuffer,
// HookKind_BufferSave,
// HookKind_AfterBufferSave,
// HookKind_ResolveOpen,
// HookKind_BeforeBufferOpen,
// HookKind_BufferOpen,
// HookKind_AfterBufferOpen,
HookKind_CreateView,
};
// Global hooks, per (window, view, buffer) hooks
@@ -106,15 +75,15 @@ struct Buffer {
int edit_phase;
Array<Hook> hooks;
struct {
unsigned no_history : 1;
unsigned no_line_starts : 1;
unsigned dirty : 1;
unsigned changed_on_disk : 1;
unsigned temp : 1;
unsigned dont_try_to_save_in_bulk_ops : 1;
unsigned close : 1;
unsigned special : 1;
unsigned is_dir : 1;
uint32_t no_history : 1;
uint32_t no_line_starts : 1;
uint32_t dirty : 1;
uint32_t changed_on_disk : 1;
uint32_t temp : 1;
uint32_t dont_try_to_save_in_bulk_ops : 1;
uint32_t close : 1;
uint32_t special : 1;
uint32_t is_dir : 1;
};
};
@@ -130,10 +99,11 @@ struct View {
String hook_cmd;
Array<Hook> hooks;
Function *update_hook;
uint64_t prev_search_line_hash;
struct {
unsigned close : 1;
unsigned special : 1;
uint32_t close : 1;
uint32_t special : 1;
};
};

View File

@@ -115,26 +115,6 @@ String16 FetchLoadWord(View *view) {
return string;
}
String16 FetchFuzzyViewLoadLine(View *view) {
Buffer *buffer = GetBuffer(view->active_buffer);
Range range = view->carets[0].range;
String16 string = GetString(buffer, range);
if (GetSize(range) == 0) {
Int line = PosToLine(buffer, range.min);
if (line == 0) {
line = ClampTop(1ll, buffer->line_starts.len - 1ll);
}
string = GetLineStringWithoutNL(buffer, line);
Int idx = 0;
String16 delim = u"||>";
if (Seek(string, delim, &idx, SeekFlag_None)) {
string = Skip(string, idx + delim.len);
}
}
return string;
}
char16_t GetIndentChar() {
char16_t c = u' ';
if (IndentKindWhichIsTabsOrSpaces == "spaces") {

View File

@@ -138,19 +138,25 @@ void LayoutWindows(int16_t wx, int16_t wy) {
ProfileFunction();
Rect2I screen_rect = RectI0Size(wx, wy);
ForItem (n, Windows) {
ForItem (hook, n->hooks) {
if (hook.kind == HookKind_HandleWindowLayout) {
ProfileScopeEx(it.name);
HookParam param = {};
param.layout.window = n;
param.layout.rect = &screen_rect;
param.layout.wx = wx;
param.layout.wy = wy;
hook.function(param);
}
}
}
#ifdef PLUGIN_STATUS_WINDOW
LayoutStatusWindow(&screen_rect, wx, wy);
#endif
#ifdef PLUGIN_SEARCH_WINDOW
LayoutSearchWindow(&screen_rect, wx, wy);
#endif
#ifdef PLUGIN_COMMAND_WINDOW
LayoutCommandWindow(&screen_rect, wx, wy);
#endif
#ifdef PLUGIN_DEBUG_WINDOW
LayoutDebugWindow(&screen_rect, wx, wy);
#endif
#ifdef PLUGIN_BUILD_WINDOW
LayoutBuildWindow(&screen_rect, wx, wy);
#endif
// Column layout
Int c = 0;