From 2b48f30cfe5d5f10f727415e8aa01f5d1e4ee04e Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 12 Aug 2024 13:45:58 +0200 Subject: [PATCH] Clang format, mouse rebind --- src/basic/filesystem.h | 5 +- src/basic/win32.cpp | 22 ++++++++- src/text_editor/buffer.cpp | 4 +- src/text_editor/buffer_test_load.cpp | 2 + src/text_editor/commands.cpp | 33 ++++++++++--- src/text_editor/commands_window.cpp | 52 +++++++++++-------- src/text_editor/process.cpp | 74 +++++++++++++++++++++++----- src/text_editor/text_editor.h | 12 +++-- src/text_editor/todo.txt | 3 +- 9 files changed, 155 insertions(+), 52 deletions(-) diff --git a/src/basic/filesystem.h b/src/basic/filesystem.h index 96aa11c..6d4db0f 100644 --- a/src/basic/filesystem.h +++ b/src/basic/filesystem.h @@ -51,8 +51,9 @@ struct Process { }; Process CreateCommandLineProcess(String command_line, String working_dir); -bool WaitForExit(Process *process); bool PollExitCode(Process *process); void CloseProcess(Process *process); void KillProcess(Process *process); -StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size); \ No newline at end of file +StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size); +void WriteStdin(Process *process, String string); +void CloseStdin(Process *process); \ No newline at end of file diff --git a/src/basic/win32.cpp b/src/basic/win32.cpp index 0b931ae..c4b9f83 100644 --- a/src/basic/win32.cpp +++ b/src/basic/win32.cpp @@ -313,7 +313,6 @@ static void Win32CloseProcess(Process *process) { if (p->child_stdin_read != INVALID_HANDLE_VALUE) CloseHandle(p->child_stdin_read); if (p->child_stdin_write != INVALID_HANDLE_VALUE) CloseHandle(p->child_stdin_write); process->is_valid = false; - *p = {}; } static void Win32ProcessError(Process *process, String msg, String cmd) { @@ -459,4 +458,23 @@ StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size) { result = {bytes_read, bytes_avail - bytes_read}; return result; -} \ No newline at end of file +} + +void WriteStdin(Process *process, String string) { + if (string.len == 0) return; + Assert(process->is_valid); + + Win32Process *p = (Win32Process *)process->platform; + + DWORD written = 0; + bool write_error = WriteFile(p->child_stdin_write, string.data, (DWORD)string.len, &written, NULL) == 0; + + Assert(write_error == false); + Assert(written == string.len); +} + +void CloseStdin(Process *process) { + Win32Process *p = (Win32Process *)process->platform; + CloseHandle(p->child_stdin_write); + p->child_stdin_write = INVALID_HANDLE_VALUE; +} diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index c9dfd10..61e6569 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -115,12 +115,12 @@ void IKnowWhatImDoing_Append(Buffer *buffer, String16 string) { } void IKnowWhatImDoing_Append(Buffer *buffer, String string) { - Scratch scratch; + Scratch scratch(buffer->line_starts.allocator); IKnowWhatImDoing_Append(buffer, ToString16(scratch, string)); } void IKnowWhatImDoing_Appendf(Buffer *buffer, const char *fmt, ...) { - Scratch scratch; + Scratch scratch(buffer->line_starts.allocator); STRING_FORMAT(scratch, fmt, string); String16 string16 = ToString16(scratch, string); IKnowWhatImDoing_ReplaceText(buffer, GetEndAsRange(*buffer), string16); diff --git a/src/text_editor/buffer_test_load.cpp b/src/text_editor/buffer_test_load.cpp index 64f751d..662670b 100644 --- a/src/text_editor/buffer_test_load.cpp +++ b/src/text_editor/buffer_test_load.cpp @@ -36,6 +36,8 @@ This page contains characters from each of the Unicode character blocks. See also Unicode 3.2 test page. +C:\Work\text_editor\src\text_editor\buffer_history.cpp + Basic Latin ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ Latin-1 Supplement diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index bcf5036..bf2ab9e 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -330,14 +330,16 @@ bool GlobalCommand(Event event) { } } - if (event.ctrl && event.shift && Mouse(RIGHT)) { + if (Mouse(MIDDLE)) { MouseExecWord(event); - } else if (event.alt && event.ctrl && Mouse(RIGHT)) { + } + + if (event.ctrl && event.shift && Mouse(RIGHT)) { GotoForward(GetActiveMainWindowID()); + } else if (event.alt && event.ctrl && Mouse(RIGHT)) { } else if (event.ctrl && Mouse(RIGHT)) { - MouseLoadWord(event); - } else if (event.alt && Mouse(RIGHT)) { GotoBackward(GetActiveMainWindowID()); + } else if (event.alt && Mouse(RIGHT)) { } else if (Mouse(RIGHT)) { Vec2I mouse = MouseVec2I(); Window *window = GetActiveWindow(); @@ -374,7 +376,10 @@ bool GlobalCommand(Event event) { // for now let's leave it because we are relaying on global state // - maybe just do the check if active window is matching the DocumentSelected window // - if scrollbar selected then don't invoke window command - if (event.alt && Mouse(LEFT)) { + if (event.ctrl && event.shift && Mouse(LEFT)) { + MouseExecWord(event); + } else if (event.ctrl && Mouse(LEFT)) { + MouseLoadWord(event); } else if (Mouse(LEFT)) { // CTRL SHIFT Vec2I mouse = MouseVec2I(); { @@ -390,8 +395,8 @@ bool GlobalCommand(Event event) { DocumentSelected = window->id; Int p = ScreenSpaceToBufferPos(window, view, buffer, mouse); - if (event.ctrl) Insert(&view->carets, MakeCaret(p, p), 0); - if (!event.ctrl && !event.shift) view->carets.len = 1; + if (event.alt) Insert(&view->carets, MakeCaret(p, p), 0); + if (!event.alt && !event.shift) view->carets.len = 1; Caret &caret = view->carets[0]; if (event.shift) { @@ -484,6 +489,20 @@ bool GlobalCommand(Event event) { return run_window_command; } +void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string) { + Buffer *buffer = GetBuffer(view->active_buffer); + Array caret_copy = Copy(GetSystemAllocator(), view->carets); + defer { + Dealloc(&view->carets); + view->carets = caret_copy; + }; + + Scratch scratch; + Command_SelectRangeOneCursor(view, range); + Array edits = Command_ReplaceEx(scratch, view, string); + AdjustCarets(edits, &caret_copy); +} + void Command_Append(ViewID view_id, String16 string, bool scroll_to_end_if_cursor_on_last_line) { View *view = GetView(view_id); Buffer *buffer = GetBuffer(view->active_buffer); diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 16843bf..06984c5 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -374,6 +374,30 @@ void Command_ConvertLineEndings(View *view, bool dont_trim_lines_with_cursor) { view->update_scroll = false; } +void SaveBuffer(View *view) { + Buffer *buffer = GetBuffer(view->active_buffer); + if (StyleTrimWhitespaceOnSave) { + bool dont_trim_lines_with_cursor = true; + Command_TrimTrailingWhitespace(view, dont_trim_lines_with_cursor); + Command_ConvertLineEndings(view, dont_trim_lines_with_cursor); + Assert(view->active_buffer == buffer->id); + } + + Scratch scratch; + String16 string16 = GetString(*buffer); + String string = ToString(scratch, string16); + Buffer *temp_buffer = ExecAndWait(scratch, "clang-format", GetDir(buffer), string); + Command_ReplaceWithoutMovingCarets(view, GetRange(*buffer), {temp_buffer->str, temp_buffer->len}); + + // bool success = WriteFile(buffer->name, string); + + // if (success) { + // buffer->dirty = false; + // } else { + // ReportWarningf("Failed to save file with name: %.*s", FmtString(buffer->name)); + // } +} + void Command_KillSelectedLines(View *view) { Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); @@ -846,23 +870,7 @@ void WindowCommand(Event event, Window *window, View *view) { } if (Ctrl(SDLK_S)) { - if (StyleTrimWhitespaceOnSave) { - bool dont_trim_lines_with_cursor = true; - Command_TrimTrailingWhitespace(view, dont_trim_lines_with_cursor); - Command_ConvertLineEndings(view, dont_trim_lines_with_cursor); - } - - String16 string16 = GetString(*buffer); - Scratch scratch; - String string = ToString(scratch, string16); - bool success = false; - success = WriteFile(buffer->name, string); - - if (success) { - buffer->dirty = false; - } else { - ReportWarningf("Failed to save file with name: %.*s", FmtString(buffer->name)); - } + SaveBuffer(view); } if (Ctrl(SDLK_PERIOD)) { @@ -899,6 +907,12 @@ void WindowCommand(Event event, Window *window, View *view) { SetActiveWindow(titlebar->id); } + if (CtrlShift(SDLK_W)) { + GotoForward(GetActiveMainWindowID()); + } else if (Ctrl(SDLK_W)) { + GotoBackward(GetActiveMainWindowID()); + } + if (CtrlShift(SDLK_Q)) { Caret caret = view->carets[0]; Range range = caret.range; @@ -908,8 +922,6 @@ void WindowCommand(Event event, Window *window, View *view) { String16 string = GetString(*buffer, range); Command_EvalLua(view, string); - } else if (CtrlAlt(SDLK_Q)) { - GotoForward(GetActiveMainWindowID()); } else if (Ctrl(SDLK_Q)) { Caret caret = view->carets[0]; Range range = caret.range; @@ -918,8 +930,6 @@ void WindowCommand(Event event, Window *window, View *view) { window->active_goto_list = view->id; Open(string); - } else if (Alt(SDLK_Q)) { - GotoBackward(GetActiveMainWindowID()); } IF_DEBUG(AssertRanges(view->carets)); } diff --git a/src/text_editor/process.cpp b/src/text_editor/process.cpp index cb568d8..16cee95 100644 --- a/src/text_editor/process.cpp +++ b/src/text_editor/process.cpp @@ -22,8 +22,8 @@ void UpdateProcesses() { if (exited) { CloseProcess(&it); remove_item = true; - String s = Format(scratch, "exited with code: %d", it.exit_code); - Command_Append(view_id, s, it.scroll_to_end); + // String s = Format(scratch, "exited with code: %d", it.exit_code); + // Command_Append(view_id, s, it.scroll_to_end); } } } @@ -44,27 +44,79 @@ void Exec(ViewID view, bool scroll_to_end, String16 cmd16, String working_dir) { Exec(view, scroll_to_end, cmd, working_dir); } -Buffer *ExecAndWait(Allocator allocator, String cmd, String working_dir) { +Buffer *ExecAndWait(Allocator allocator, String cmd, String working_dir, String stdin_string = {}) { Process process = CreateCommandLineProcess(cmd, working_dir); if (process.error_message.len) ReportWarningf("%.*s", FmtString(process.error_message)); - if (!process.is_valid) return {}; - Scratch scratch; - Buffer *temp_buffer = CreateTempBuffer(allocator, 4096 * 2); - char *buffer = AllocArray(scratch, char, 4096); + Buffer *temp_buffer = CreateTempBuffer(allocator, 4096 * 4); + if (!process.is_valid) return temp_buffer; + + if (stdin_string.len) { + WriteStdin(&process, stdin_string); + CloseStdin(&process); + } + + Scratch scratch(allocator); + char *buffer = AllocArray(scratch, char, 4096); for (;;) { - bool exited = PollExitCode(&process); - StdoutPollInfo i0 = PollStdout(&process, buffer, 4096); - IKnowWhatImDoing_Append(temp_buffer, String{buffer, i0.size_read}); - if (exited && i0.size_available == 0) { + StdoutPollInfo info = PollStdout(&process, buffer, 4096); + String string = {buffer, info.size_read}; + String16 string16 = ToString16(scratch, string); + + if (string.len) { + IKnowWhatImDoing_Append(temp_buffer, string16); + } + + bool exited = PollExitCode(&process); + if (exited) { CloseProcess(&process); break; } } + if (process.error_message.len) { + ReportConsolef("%.*s", FmtString(process.error_message)); + } + return temp_buffer; } +void ExecAndWait(View *view, String cmd, String working_dir, String stdin_string = {}) { + Process process = CreateCommandLineProcess(cmd, working_dir); + if (process.error_message.len) ReportWarningf("%.*s", FmtString(process.error_message)); + if (!process.is_valid) return; + + if (stdin_string.len) { + WriteStdin(&process, stdin_string); + CloseStdin(&process); + } + + Scratch scratch; + char *buffer = AllocArray(scratch, char, 4096); + Buffer *the_buffer = GetBuffer(view->active_buffer); + Range range = GetRange(*the_buffer); + for (;;) { + StdoutPollInfo info = PollStdout(&process, buffer, 4096); + String string = {buffer, info.size_read}; + String16 string16 = ToString16(scratch, string); + + if (string.len) { + Command_ReplaceWithoutMovingCarets(view, range, string16); + range = GetEndAsRange(*the_buffer); + } + + bool exited = PollExitCode(&process); + if (exited) { + CloseProcess(&process); + break; + } + } + + if (process.error_message.len) { + ReportConsolef("%.*s", FmtString(process.error_message)); + } +} + void KillProcess(ViewID view) { IterRemove(ActiveProcesses) { IterRemovePrepare(ActiveProcesses); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 1b98b40..2a0ec47 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -122,11 +122,13 @@ void Open(String path); void Open(String16 path); void UpdateScroll(Window *window, bool update_caret_scrolling); -void Command_SelectEntireBuffer(View *view); -void Command_Replace(View *view, String16 string); -void Command_SelectRangeOneCursor(View *view, Range range); -void Command_Append(ViewID view_id, String16 string, bool scroll_to_end_if_cursor_on_last_line); -void Command_Append(ViewID view_id, String string, bool scroll_to_end_if_cursor_on_last_line); +void Command_SelectEntireBuffer(View *view); +void Command_Replace(View *view, String16 string); +void Command_SelectRangeOneCursor(View *view, Range range); +void Command_Append(ViewID view_id, String16 string, bool scroll_to_end_if_cursor_on_last_line); +void Command_Append(ViewID view_id, String string, bool scroll_to_end_if_cursor_on_last_line); +Array Command_ReplaceEx(Allocator scratch, View *view, String16 string); +void Command_ReplaceWithoutMovingCarets(View *view, Range range, String16 string); void ReportConsolef(const char *fmt, ...); void ReportErrorf(const char *fmt, ...); diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 2a9af4c..0cf1b8a 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -7,13 +7,12 @@ - test the code editor: try writing in it, try browsing in it, create test tooling - event serialization to lua object format - Execute enclosure which is going to execute on every keypress, modification -- Change mouse keybindings again (left+ctrl could be load - left+ctrl could be add new cursor), exec could be middle mouse - Store editor metadata in user accessible buffers? (read only) - Find matches using grep, change things in that buffer then apply those changes to all items +- might need to remodel the buffer api to also adjust carets in remaining views - apply clang format - apply clang format on save -- Wait for process and get string - OnWindowCommand allow config user to overwrite the WindowCommand keybinding, introduce his own - ctrl + f - should find Search and select content or add Search