From a1646d84127a199fdacb6c5500d96e8829ebe8c1 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 3 Mar 2021 15:09:49 -0500 Subject: :shell, bugfixes --- README.md | 7 +++++-- buffer.c | 11 +++++++++++ build.c | 55 +++++++++++++++++++++++++++---------------------------- command.c | 6 ++++++ command.h | 2 ++ find.c | 4 +--- main.c | 6 ++++-- menu.c | 37 +++++++++++++++++++++++++++++++++++++ session.c | 2 ++ ted.cfg | 1 + ted.h | 3 ++- util.c | 8 ++------ 12 files changed, 100 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 4b0fabb..a2094f4 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,16 @@ a simple editor that starts up practically instantaneously, and performs well on ## Supported features (more coming soon) +All the keybindings listed below are customizable! + - Multiple tabs, each with a different file - Split screen (Ctrl+/, Ctrl+Shift+/) - Auto-indent - Customization of (pretty much) all colours and keyboard commands. - Syntax highlighting for C, C++, Rust, and Python. - Find and replace (with regular expressions!) -- Run build command (default keybinding F4), go to errors +- Run build command (F4), go to errors +- Run any shell command (Ctrl+!) - Go to definition (Ctrl+click) - Go to line (Ctrl+G) @@ -72,7 +75,7 @@ Then run `make.bat`. 0.5 Go to definition 2021 Feb 22 0.5a Several bugfixes, go to line 2021 Feb 23 0.6 Split-screen 2021 Feb 28 -0.7 Restore session, command selector, big bug fixes 2021 Mar 3 +0.7 Restore session, command selector, :shell, big bug fixes 2021 Mar 3 ## License diff --git a/buffer.c b/buffer.c index 7489d04..21922ee 100644 --- a/buffer.c +++ b/buffer.c @@ -2387,6 +2387,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { rgba_u32_to_floats(colors[COLOR_TEXT], text_state.color); buffer->first_line_on_screen = start_line; + buffer->last_line_on_screen = 0; for (u32 line_idx = start_line; line_idx < nlines; ++line_idx) { Line *line = &lines[line_idx]; if (arr_len(char_types) < line->len) { @@ -2429,6 +2430,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { text_state.y += text_font_char_height(font); column = 0; } + if (buffer->last_line_on_screen == 0) buffer->last_line_on_screen = nlines - 1; arr_free(char_types); @@ -2544,3 +2546,12 @@ void buffer_dedent_selection(TextBuffer *buffer) { buffer_dedent_lines(buffer, l1, l2); } +void buffer_indent_cursor_line(TextBuffer *buffer) { + u32 line = buffer->cursor_pos.line; + buffer_indent_lines(buffer, line, line); +} +void buffer_dedent_cursor_line(TextBuffer *buffer) { + u32 line = buffer->cursor_pos.line; + buffer_dedent_lines(buffer, line, line); +} + diff --git a/build.c b/build.c index 7554c50..4a65857 100644 --- a/build.c +++ b/build.c @@ -11,25 +11,41 @@ static void build_stop(Ted *ted) { process_kill(&ted->build_process); ted->building = false; ted->build_shown = false; + *ted->build_dir = '\0'; build_clear(ted); } - -static void build_start(Ted *ted) { +// make sure you set ted->build_dir before running this! +static void build_start_with_command(Ted *ted, char const *command) { + assert(*ted->build_dir); + change_directory(ted->build_dir); if (ted->building) { build_stop(ted); } - Settings *settings = &ted->settings; - ted_save_all(ted); - // get rid of any old build errors - build_clear(ted); - + if (process_run(&ted->build_process, command)) { + ted->building = true; + ted->build_shown = true; + TextBuffer *build_buffer = &ted->build_buffer; + // new empty build output buffer + buffer_new_file(build_buffer, NULL); + build_buffer->store_undo_events = false; // don't need undo events for build output buffer + char32_t text[] = {'$', ' '}; + buffer_insert_text_at_cursor(build_buffer, str32(text, 2)); + buffer_insert_utf8_at_cursor(build_buffer, command); + buffer_insert_char_at_cursor(build_buffer, '\n'); + build_buffer->view_only = true; + } else { + ted_seterr(ted, "Couldn't start build: %s", process_geterr(&ted->build_process)); + } +} + +static void build_start(Ted *ted) { bool cargo = false, make = false; - change_directory(ted->cwd); - strcpy(ted->build_dir, ted->cwd); + strbuf_cpy(ted->build_dir, ted->cwd); + Settings *settings = &ted->settings; char *command = settings->build_default_command; @@ -42,11 +58,9 @@ static void build_start(Ted *ted) { if (fs_file_exists("Cargo.toml")) { cargo = true; } else if (fs_file_exists(".." PATH_SEPARATOR_STR "Cargo.toml")) { - change_directory(".."); ted_full_path(ted, "..", ted->build_dir, sizeof ted->build_dir); cargo = true; } else if (fs_file_exists(".." PATH_SEPARATOR_STR ".." PATH_SEPARATOR_STR "Cargo.toml")) { - change_directory(".." PATH_SEPARATOR_STR ".."); ted_full_path(ted, "../..", ted->build_dir, sizeof ted->build_dir); cargo = true; } else @@ -54,7 +68,6 @@ static void build_start(Ted *ted) { if (fs_file_exists("Makefile")) { make = true; } else if (fs_file_exists(".." PATH_SEPARATOR_STR "Makefile")) { - change_directory(".."); ted_full_path(ted, "..", ted->build_dir, sizeof ted->build_dir); make = true; } @@ -66,22 +79,8 @@ static void build_start(Ted *ted) { } else if (make) { command = "make"; } - - if (process_run(&ted->build_process, command)) { - ted->building = true; - ted->build_shown = true; - TextBuffer *build_buffer = &ted->build_buffer; - // new empty build output buffer - buffer_new_file(build_buffer, NULL); - build_buffer->store_undo_events = false; // don't need undo events for build output buffer - char32_t text[] = {'$', ' '}; - buffer_insert_text_at_cursor(build_buffer, str32(text, 2)); - buffer_insert_utf8_at_cursor(build_buffer, command); - buffer_insert_char_at_cursor(build_buffer, '\n'); - build_buffer->view_only = true; - } else { - ted_seterr(ted, "Couldn't start build: %s", process_geterr(&ted->build_process)); - } + + build_start_with_command(ted, command); } static void build_go_to_error(Ted *ted) { diff --git a/command.c b/command.c index c7276ac..727b2c6 100644 --- a/command.c +++ b/command.c @@ -115,6 +115,8 @@ void command_execute(Ted *ted, Command c, i64 argument) { } else if (buffer) { if (buffer->selection) buffer_dedent_selection(buffer); + else + buffer_dedent_cursor_line(buffer); } break; case CMD_NEWLINE: @@ -319,6 +321,10 @@ void command_execute(Ted *ted, Command c, i64 argument) { case CMD_BUILD_PREV_ERROR: build_prev_error(ted); break; + case CMD_SHELL: + menu_open(ted, MENU_SHELL); + break; + case CMD_GOTO_DEFINITION: menu_open(ted, MENU_GOTO_DEFINITION); break; diff --git a/command.h b/command.h index d5d8062..41bab31 100644 --- a/command.h +++ b/command.h @@ -72,6 +72,7 @@ ENUM_U16 { CMD_BUILD, CMD_BUILD_PREV_ERROR, CMD_BUILD_NEXT_ERROR, + CMD_SHELL, CMD_GOTO_DEFINITION, // "go to definition of..." CMD_GOTO_LINE, // open "goto line..." menu @@ -151,6 +152,7 @@ static CommandName const command_names[] = { {"build", CMD_BUILD}, {"build-prev-error", CMD_BUILD_PREV_ERROR}, {"build-next-error", CMD_BUILD_NEXT_ERROR}, + {"shell", CMD_SHELL}, {"goto-definition", CMD_GOTO_DEFINITION}, {"goto-line", CMD_GOTO_LINE}, {"split-horizontal", CMD_SPLIT_HORIZONTAL}, diff --git a/find.c b/find.c index 58bff8c..1e0b409 100644 --- a/find.c +++ b/find.c @@ -451,9 +451,7 @@ static void find_open(Ted *ted, bool replace) { ted->find = true; buffer_select_all(ted->active_buffer); } - if (!ted->replace && replace) { - ted->replace = true; - } + ted->replace = replace; find_update(ted, true); } diff --git a/main.c b/main.c index a829736..6a9e46a 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,4 @@ // @TODO: -// - run shell command (i.e. not just `make`) // - completion // - more instructions (basic stuff + how to open config) @@ -73,8 +72,8 @@ bool tag_goto(Ted *ted, char const *tag); #include "find.c" #include "node.c" #include "tags.c" -#include "menu.c" #include "build.c" +#include "menu.c" #include "command.c" #include "config.c" #include "session.c" @@ -644,6 +643,9 @@ int main(int argc, char **argv) { } } } + if (ted->build_shown) + if (buffer_handle_click(ted, &ted->build_buffer, pos, times)) // handle build buffer clicks + add = false; } if (add) { ted->mouse_clicks[button][ted->nmouse_clicks[button]] = pos; diff --git a/menu.c b/menu.c index 868a4a4..24a9af8 100644 --- a/menu.c +++ b/menu.c @@ -32,6 +32,9 @@ static void menu_close(Ted *ted) { buffer_clear(&ted->argument_buffer); free(selector->entries); selector->entries = NULL; selector->n_entries = 0; } break; + case MENU_SHELL: + buffer_clear(&ted->line_buffer); + break; } ted->menu = MENU_NONE; ted->selector_open = NULL; @@ -79,6 +82,9 @@ static void menu_open(Ted *ted, Menu menu) { selector->enable_cursor = true; selector->cursor = 0; } break; + case MENU_SHELL: + ted_switch_to_buffer(ted, &ted->line_buffer); + break; } } @@ -288,6 +294,15 @@ static void menu_update(Ted *ted) { } free(search_term); } break; + case MENU_SHELL: + if (line_buffer->line_buffer_submitted) { + char *command = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0)); + menu_close(ted); + strbuf_cpy(ted->build_dir, ted->cwd); + build_start_with_command(ted, command); + free(command); + } + break; } } @@ -405,5 +420,27 @@ static void menu_render(Ted *ted) { text_render(font_bold); } break; + case MENU_SHELL: { + float line_buffer_height = char_height; + + bounds.size.y = line_buffer_height + 2 * padding; + rect_coords(bounds, &x1, &y1, &x2, &y2); + + gl_geometry_rect(bounds, colors[COLOR_MENU_BG]); + gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]); + gl_geometry_draw(); + + x1 += padding; + y1 += padding; + x2 -= padding; + y2 -= padding; + + char const *text = "Run"; + text_utf8(font_bold, text, x1, y1, colors[COLOR_TEXT]); + x1 += text_get_size_v2(font_bold, text).x + padding; + text_render(font_bold); + + buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y2)); + } break; } } diff --git a/session.c b/session.c index 4895f34..ac76511 100644 --- a/session.c +++ b/session.c @@ -37,6 +37,8 @@ static void session_read_node(Ted *ted, FILE *fp) { } else { node->active_tab = read_u16(fp); u16 ntabs = clamp_u16(read_u16(fp), 0, TED_MAX_TABS); + if (node->active_tab >= ntabs) + node->active_tab = 0; for (u16 i = 0; i < ntabs; ++i) { u16 buf_idx = read_u16(fp); if (buf_idx >= TED_MAX_BUFFERS) continue; diff --git a/ted.cfg b/ted.cfg index b38307e..d824b92 100644 --- a/ted.cfg +++ b/ted.cfg @@ -120,6 +120,7 @@ Ctrl+Alt+Shift+v = :view-only F4 = :build Ctrl+[ = :build-prev-error Ctrl+] = :build-next-error +Ctrl+! = :shell Ctrl+d = :goto-definition Ctrl+g = :goto-line diff --git a/ted.h b/ted.h index b9edc0b..ea1afdd 100644 --- a/ted.h +++ b/ted.h @@ -170,7 +170,8 @@ ENUM_U16 { MENU_ASK_RELOAD, // prompt about whether to reload file which has ben changed by another program MENU_GOTO_DEFINITION, MENU_GOTO_LINE, - MENU_COMMAND_SELECTOR + MENU_COMMAND_SELECTOR, + MENU_SHELL, // run a shell command } ENUM_U16_END(Menu); typedef struct { diff --git a/util.c b/util.c index f14f640..7d0064d 100644 --- a/util.c +++ b/util.c @@ -22,13 +22,9 @@ static u8 util_popcount(u64 x) { static u8 util_count_leading_zeroes32(u32 x) { if (x == 0) return 32; // GCC's __builtin_clz is undefined for x = 0 -#if __GNUC__ -#if UINT_MAX == 4294967295 +#if __GNUC__ && UINT_MAX == 4294967295 return (u8)__builtin_clz(x); -#else - #error "unsigned int isn't 32 bits. this function needs fixing to work on systems like yours." -#endif -#elif _WIN32 +#elif _WIN32 && UINT_MAX == 4294967295 return (u8)__lzcnt(x); #else u8 count = 0; -- cgit v1.2.3