diff --git a/src/basic/win32.cpp b/src/basic/win32.cpp index 6e02591..66b941d 100644 --- a/src/basic/win32.cpp +++ b/src/basic/win32.cpp @@ -283,7 +283,7 @@ struct Win32Process { }; static_assert(sizeof(Win32Process) < sizeof(Process::platform)); -static String Win32GetPlatformError(String cmd) { +static String Win32GetPlatformError(String msg, String cmd) { LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -296,7 +296,7 @@ static String Win32GetPlatformError(String cmd) { } // @warning: leak! but we don't care - String r = Format(GetSystemAllocator(), "Failed to create process using cmd: %.*s! %s", FmtString(cmd), (char *)lpMsgBuf); + String r = Format(GetSystemAllocator(), "%.*s: %.*s! %s", FmtString(msg), FmtString(cmd), (char *)lpMsgBuf); LocalFree(lpMsgBuf); return r; } @@ -312,9 +312,9 @@ static void Win32CloseProcess(Process *process) { *p = {}; } -static void Win32ProcessError(Process *process, String cmd) { +static void Win32ProcessError(Process *process, String msg, String cmd) { Win32Process *p = (Win32Process *)process->platform; - process->error_message = Win32GetPlatformError(cmd); + process->error_message = Win32GetPlatformError(msg, cmd); Win32CloseProcess(process); } @@ -336,22 +336,22 @@ Process CreateCommandLineProcess(String command_line, String working_dir) { security_atrb.bInheritHandle = TRUE; if (!CreatePipe(&p->child_stdout_read, &p->child_stdout_write, &security_atrb, 0)) { - Win32ProcessError(&process, command_line); + Win32ProcessError(&process, "Failed to create process at create pipe stage", command_line); return process; } if (!SetHandleInformation(p->child_stdout_read, HANDLE_FLAG_INHERIT, 0)) { - Win32ProcessError(&process, command_line); + Win32ProcessError(&process, "Failed to create process at create pipe stage", command_line); return process; } if (!CreatePipe(&p->child_stdin_read, &p->child_stdin_write, &security_atrb, 0)) { - Win32ProcessError(&process, command_line); + Win32ProcessError(&process, "Failed to create process at create pipe stage", command_line); return process; } if (!SetHandleInformation(p->child_stdin_write, HANDLE_FLAG_INHERIT, 0)) { - Win32ProcessError(&process, command_line); + Win32ProcessError(&process, "Failed to create process at create pipe stage", command_line); return process; } @@ -369,7 +369,7 @@ Process CreateCommandLineProcess(String command_line, String working_dir) { PROCESS_INFORMATION info = {}; if (!CreateProcessW(L"c:\\windows\\system32\\cmd.exe", cmd.data, 0, 0, TRUE, 0, env, cwd.data, &startup, &info)) { - Win32ProcessError(&process, command_line); + Win32ProcessError(&process, "failed to create process", command_line); return process; } @@ -426,6 +426,7 @@ StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size) { StdoutPollInfo result = {}; bool peek_error = PeekNamedPipe(p->child_stdout_read, NULL, 0, NULL, &bytes_avail, NULL) == 0; if (peek_error) { + process->error_message = Win32GetPlatformError("Failed to peek stdout of child process", "PeekNamedPipe"); return result; } @@ -436,6 +437,7 @@ StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size) { DWORD bytes_read = 0; bool read_error = ReadFile(p->child_stdout_read, buffer, (DWORD)buffer_size, &bytes_read, 0) == 0; if (read_error) { + process->error_message = Win32GetPlatformError("Failed to read the stdout of child process", "ReadFile"); return result; } diff --git a/src/text_editor/generated.cpp b/src/text_editor/generated.cpp index ada25ec..90da418 100644 --- a/src/text_editor/generated.cpp +++ b/src/text_editor/generated.cpp @@ -205,9 +205,9 @@ function MatchAgainstIncludes(s) end function MatchGitCommit(s) - local i, j = string.find(s, "^commit ") - print(tostring(i)) + local i, j = string.find(s, "^commit ([a-zA-Z0-9]+)") if i then + s = s:sub(8) local command = "git --no-pager show "..s return {kind = "exec", cmd = command, working_dir = GetCurrentBufferDir()} end @@ -220,7 +220,6 @@ Rules = { MatchGitCommit, } - function ApplyRules(s) for i = #Rules,1,-1 do rule = Rules[i] diff --git a/src/text_editor/lua_api.cpp b/src/text_editor/lua_api.cpp index caadc69..2827657 100644 --- a/src/text_editor/lua_api.cpp +++ b/src/text_editor/lua_api.cpp @@ -87,6 +87,12 @@ void Open(String16 path) { Open(string); } +int LuaKill(lua_State *L) { + Window *window = GetCurrentWindow(); + KillProcess(window->active_view); + return 0; +} + int LuaOpen(lua_State *L) { Scratch scratch; String path = luaL_checkstring(L, 1); @@ -97,7 +103,7 @@ int LuaOpen(lua_State *L) { int LuaPrint(lua_State *L) { Scratch scratch; - String string = luaL_checkstring(L, 1); + String string = lua_tostring(L, 1); lua_pop(L, 1); Command_Append(ConsoleViewID, string, true); return 0; @@ -153,19 +159,6 @@ int LuaGetWorkingDir(lua_State *L) { return 1; } -int LuaOpenBigBuffer(lua_State *L) { - Window *window = GetWindow(GetLastActiveWindow()); - - // @todo: ViewOpenBuffer - new or old view for specified buffer - Buffer *buffer = CreateBuffer(GetSystemAllocator(), "big", 2500000 * 4); - LoadBigTextAndBigLine(buffer); - View *view = CreateView(buffer->id); - window->active_view = view->id; - - SetActiveWindow(window->id); - return 0; -} - int LuaGetCurrentBufferName(lua_State *L) { String name = GetCurrentBufferName(); lua_pushlstring(LuaState, name.data, name.len); @@ -188,6 +181,7 @@ luaL_Reg LuaFunctions[] = { { "GetCurrentBufferDir", LuaGetCurrentBufferDir}, { "print", LuaPrint}, { "Print", LuaPrint}, + { "Kill", LuaKill}, { NULL, NULL}, }; diff --git a/src/text_editor/notes_processes b/src/text_editor/notes_processes index 6a07278..ff01967 100644 --- a/src/text_editor/notes_processes +++ b/src/text_editor/notes_processes @@ -23,3 +23,6 @@ https://handmade.network/forums/t/1219-win32_asynchronous_pipes_question - would it be fast enough to just reparse the entire file of certain size every time? - coloring seems even more hairy to do correctly because there are multiline comments etc. - it honestly seems no matter what you do it's a very hairy problem, text was not meant for this + + +Ok for reference only, I would like to share my experience and how I solved the problem. IT may be possible that there's something wrong in the child process I spawn, but from what I see, if I call Read in non-blocking mode, so only after a PeekNamedPipe, there's nothing that prevent the process from being deallocated, even I keep a reference to the pipe. I've solved launching another thread that does blocking Read on the pipe descriptor, and I'm longer loosing the last bytes.. \ No newline at end of file diff --git a/src/text_editor/process.cpp b/src/text_editor/process.cpp index 51614da..b4cf3c7 100644 --- a/src/text_editor/process.cpp +++ b/src/text_editor/process.cpp @@ -1,18 +1,5 @@ Array ActiveProcesses = {}; -void Exec(ViewID view, bool scroll_to_end, String cmd, String working_dir) { - Process process = CreateCommandLineProcess(cmd, working_dir); - process.view_id = view.id; - process.scroll_to_end = scroll_to_end; - if (process.is_valid) Add(&ActiveProcesses, process); -} - -void Exec(ViewID view, bool scroll_to_end, String16 cmd16, String working_dir) { - Scratch scratch; - String cmd = ToString(scratch, cmd16); - Exec(view, scroll_to_end, cmd, working_dir); -} - void UpdateProcesses() { Scratch scratch; int64_t buffer_size = 4096; @@ -23,8 +10,44 @@ void UpdateProcesses() { String string = {buffer, info.size_read}; ViewID view_id = {it.view_id}; if (string.len) Command_Append(view_id, string, it.scroll_to_end); + if (it.error_message.len) Command_Append(view_id, it.error_message, it.scroll_to_end); bool exited = PollExitCode(&it); - if (exited) remove_item = true; + if (exited) { + remove_item = true; + String s = Format(scratch, "exited with code: %d", it.exit_code); + Command_Append(view_id, s, it.scroll_to_end); + } } } + +void Exec(ViewID view, bool scroll_to_end, String cmd, String working_dir) { + Process process = CreateCommandLineProcess(cmd, working_dir); + if (process.error_message.len) Command_Append(view, process.error_message, process.scroll_to_end); + process.view_id = view.id; + process.scroll_to_end = scroll_to_end; + if (process.is_valid) { + Assert(process.error_message.len == 0); + Add(&ActiveProcesses, process); + } +} + +void Exec(ViewID view, bool scroll_to_end, String16 cmd16, String working_dir) { + Scratch scratch; + String cmd = ToString(scratch, cmd16); + Exec(view, scroll_to_end, cmd, working_dir); +} + +void KillProcess(ViewID view) { + IterRemove(ActiveProcesses) { + IterRemovePrepare(ActiveProcesses); + + if (it.view_id == view.id) { + KillProcess(&it); + remove_item = true; + String string = "process was killed by user"; + Command_Append(view, string, it.scroll_to_end); + // dont break because that will fuck with removal ... + } + } +} \ No newline at end of file