diff options
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/bindings.c | 8 | ||||
| -rw-r--r-- | src/main/bindings.h | 4 | ||||
| -rw-r--r-- | src/main/cmds.c | 182 | ||||
| -rw-r--r-- | src/main/cmds.h | 2 | ||||
| -rw-r--r-- | src/main/completion.c | 52 | ||||
| -rw-r--r-- | src/main/completion.h | 18 | ||||
| -rw-r--r-- | src/main/lsp.c | 108 | ||||
| -rw-r--r-- | src/main/lsp.h | 11 | ||||
| -rw-r--r-- | src/main/main.c | 55 | ||||
| -rw-r--r-- | src/main/search-replace.c | 209 | ||||
| -rw-r--r-- | src/main/search-replace.h | 2 |
11 files changed, 450 insertions, 201 deletions
diff --git a/src/main/bindings.c b/src/main/bindings.c index 7b25c7b..889c32b 100644 --- a/src/main/bindings.c +++ b/src/main/bindings.c @@ -72,6 +72,10 @@ void set_default_buffer_bindings(struct keymap *keymap) { } int32_t execute(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + // TODO: this should be more lib-like return minibuffer_execute(); } @@ -82,7 +86,7 @@ static struct command execute_minibuffer_command = { .userdata = NULL, }; -void init_bindings() { +void init_bindings(void) { g_global_keymap = keymap_create("global", 32); g_ctrlx_map = keymap_create("c-x", 32); g_windows_keymap = keymap_create("c-x w", 32); @@ -203,7 +207,7 @@ uint32_t buffer_keymaps(struct buffer *buffer, struct keymap *keymaps[], return nkeymaps; } -void destroy_bindings() { +void destroy_bindings(void) { keymap_destroy(&g_windows_keymap); keymap_destroy(&g_global_keymap); keymap_destroy(&g_ctrlx_map); diff --git a/src/main/bindings.h b/src/main/bindings.h index 4fd760a..96f20fd 100644 --- a/src/main/bindings.h +++ b/src/main/bindings.h @@ -4,7 +4,7 @@ struct keymap; struct buffer; struct binding; -void init_bindings(); +void init_bindings(void); typedef uint64_t buffer_keymap_id; buffer_keymap_id buffer_add_keymap(struct buffer *buffer, struct keymap keymap); @@ -12,4 +12,4 @@ void buffer_remove_keymap(buffer_keymap_id id); uint32_t buffer_keymaps(struct buffer *buffer, struct keymap *keymaps[], uint32_t max_nkeymaps); -void destroy_bindings(); +void destroy_bindings(void); diff --git a/src/main/cmds.c b/src/main/cmds.c index 18f333d..40983a2 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -20,7 +20,12 @@ #include "completion.h" #include "search-replace.h" -int32_t _abort(struct command_ctx ctx, int argc, const char *argv[]) { +static void (*g_terminate_cb)(void) = NULL; + +static int32_t _abort(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + abort_replace(); abort_search(); abort_completion(); @@ -33,16 +38,27 @@ int32_t _abort(struct command_ctx ctx, int argc, const char *argv[]) { int32_t unimplemented_command(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; minibuffer_echo("TODO: %s is not implemented", (const char *)ctx.userdata); return 0; } -int32_t exit_editor(struct command_ctx ctx, int argc, const char *argv[]) { - ((void (*)())ctx.userdata)(); +static int32_t exit_editor(struct command_ctx ctx, int argc, + const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + + if (g_terminate_cb != NULL) { + g_terminate_cb(); + } + return 0; } -int32_t write_file(struct command_ctx ctx, int argc, const char *argv[]) { +static int32_t write_file(struct command_ctx ctx, int argc, + const char *argv[]) { const char *pth = NULL; if (argc == 0) { return minibuffer_prompt(ctx, "write to file: "); @@ -55,7 +71,7 @@ int32_t write_file(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -static void run_interactive_comp_inserted() { minibuffer_execute(); } +static void run_interactive_comp_inserted(void) { minibuffer_execute(); } int32_t run_interactive(struct command_ctx ctx, int argc, const char *argv[]) { if (argc == 0) { @@ -63,7 +79,7 @@ int32_t run_interactive(struct command_ctx ctx, int argc, const char *argv[]) { enable_completion(minibuffer_buffer(), ((struct completion_trigger){ .kind = CompletionTrigger_Input, - .input = + .data.input = (struct completion_trigger_input){ .nchars = 0, .trigger_initially = false}}), providers, 1, run_interactive_comp_inserted); @@ -106,9 +122,9 @@ int32_t do_switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { } } -COMMAND_FN("do-switch-buffer", do_switch_buffer, do_switch_buffer, NULL); +COMMAND_FN("do-switch-buffer", do_switch_buffer, do_switch_buffer, NULL) -static void switch_buffer_comp_inserted() { minibuffer_execute(); } +static void switch_buffer_comp_inserted(void) { minibuffer_execute(); } int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { if (argc == 0) { @@ -117,7 +133,7 @@ int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { enable_completion(minibuffer_buffer(), ((struct completion_trigger){ .kind = CompletionTrigger_Input, - .input = + .data.input = (struct completion_trigger_input){ .nchars = 0, .trigger_initially = false}}), providers, 1, switch_buffer_comp_inserted); @@ -156,9 +172,9 @@ int32_t do_kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) { } } -COMMAND_FN("do-kill-buffer", do_kill_buffer, do_kill_buffer, NULL); +COMMAND_FN("do-kill-buffer", do_kill_buffer, do_kill_buffer, NULL) -static void kill_buffer_comp_inserted() { minibuffer_execute(); } +static void kill_buffer_comp_inserted(void) { minibuffer_execute(); } int32_t kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) { if (argc == 0) { @@ -167,7 +183,7 @@ int32_t kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) { enable_completion(minibuffer_buffer(), ((struct completion_trigger){ .kind = CompletionTrigger_Input, - .input = + .data.input = (struct completion_trigger_input){ .nchars = 0, .trigger_initially = false}}), providers, 1, kill_buffer_comp_inserted); @@ -188,7 +204,6 @@ void timer_to_list_line(const struct timer *timer, void *userdata) { static char buf[128]; const char *name = timer_name(timer); - size_t namelen = strlen(name); size_t len = snprintf(buf, 128, "%s - %.2f ms (min: %.2f, max: %.2f)", name, (timer_average(timer) / 1e6), timer_min(timer) / (float)1e6, @@ -197,6 +212,8 @@ void timer_to_list_line(const struct timer *timer, void *userdata) { } void timers_refresh(struct buffer *buffer, void *userdata) { + (void)userdata; + buffer_set_readonly(buffer, false); buffer_clear(buffer); timers_for_each(timer_to_list_line, buffer); @@ -208,6 +225,9 @@ void timers_refresh(struct buffer *buffer, void *userdata) { } int32_t timers(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct buffer *b = buffers_find(ctx.buffers, "*timers*"); if (b == NULL) { b = buffers_add(ctx.buffers, buffer_create("*timers*")); @@ -236,7 +256,7 @@ void buffer_to_list_line(struct buffer *buffer, void *userdata) { listbuf, begin, (struct location){.line = begin.line, .col = begin.col + nchars}, (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ + .data.colors = (struct text_property_colors){ .set_bg = false, .set_fg = true, .fg = Color_Green, @@ -249,7 +269,7 @@ void buffer_to_list_line(struct buffer *buffer, void *userdata) { (struct location){.line = begin.line, .col = begin.col + 24 + nchars_path}, (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ + .data.colors = (struct text_property_colors){ .set_bg = false, .set_fg = true, .fg = Color_Blue, @@ -259,12 +279,16 @@ void buffer_to_list_line(struct buffer *buffer, void *userdata) { listbuf, (struct location){.line = begin.line, .col = 0}, (struct location){.line = begin.line, .col = buffer_line_length(listbuf, begin.line)}, - (struct text_property){.type = TextProperty_Data, .userdata = buffer}); + (struct text_property){.type = TextProperty_Data, + .data.userdata = buffer}); } } int32_t buflist_visit_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct window *w = ctx.active_window; struct buffer_view *bv = window_buffer_view(w); @@ -275,7 +299,7 @@ int32_t buflist_visit_cmd(struct command_ctx ctx, int argc, for (uint32_t propi = 0; propi < nprops; ++propi) { struct text_property *p = props[propi]; if (p->type == TextProperty_Data) { - window_set_buffer(w, p->userdata); + window_set_buffer(w, p->data.userdata); return 0; } } @@ -300,6 +324,8 @@ void buflist_refresh(struct buffer *buffer, void *userdata) { int32_t buflist_refresh_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; buflist_refresh(window_buffer(ctx.active_window), ctx.buffers); return 0; } @@ -310,6 +336,9 @@ static struct command buflist_refresh_command = { }; int32_t buflist_kill_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct window *w = ctx.active_window; struct buffer_view *bv = window_buffer_view(w); @@ -333,6 +362,9 @@ int32_t buflist_kill_cmd(struct command_ctx ctx, int argc, const char *argv[]) { } int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct buffer *b = buffers_find(ctx.buffers, "*buffers*"); if (b == NULL) { b = buffers_add(ctx.buffers, buffer_create("*buffers*")); @@ -373,7 +405,7 @@ int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -static void find_file_comp_inserted() { minibuffer_execute(); } +static void find_file_comp_inserted(void) { minibuffer_execute(); } static int32_t open_file(struct buffers *buffers, struct window *active_window, const char *pth) { @@ -412,14 +444,13 @@ static int32_t open_file(struct buffers *buffers, struct window *active_window, } int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { - const char *pth = NULL; if (argc == 0) { minibuffer_clear(); struct completion_provider providers[] = {path_provider()}; enable_completion(minibuffer_buffer(), ((struct completion_trigger){ .kind = CompletionTrigger_Input, - .input = + .data.input = (struct completion_trigger_input){ .nchars = 0, .trigger_initially = true}}), providers, 1, find_file_comp_inserted); @@ -432,7 +463,7 @@ int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -COMMAND_FN("find-file-internal", find_file, find_file, NULL); +COMMAND_FN("find-file-internal", find_file, find_file, NULL) int32_t find_file_relative(struct command_ctx ctx, int argc, const char *argv[]) { struct buffer *b = window_buffer(ctx.active_window); @@ -450,7 +481,7 @@ int32_t find_file_relative(struct command_ctx ctx, int argc, enable_completion(minibuffer_buffer(), ((struct completion_trigger){ .kind = CompletionTrigger_Input, - .input = + .data.input = (struct completion_trigger_input){ .nchars = 0, .trigger_initially = true}}), providers, 1, find_file_comp_inserted); @@ -481,7 +512,8 @@ int32_t find_file_relative(struct command_ctx ctx, int argc, } void register_global_commands(struct commands *commands, - void (*terminate_cb)()) { + void (*terminate_cb)(void)) { + g_terminate_cb = terminate_cb; struct command global_commands[] = { {.name = "find-file", .fn = find_file}, {.name = "find-file-relative", .fn = find_file_relative}, @@ -492,7 +524,7 @@ void register_global_commands(struct commands *commands, {.name = "abort", .fn = _abort}, {.name = "timers", .fn = timers}, {.name = "buffer-list", .fn = buffer_list}, - {.name = "exit", .fn = exit_editor, .userdata = terminate_cb}}; + {.name = "exit", .fn = exit_editor}}; register_commands(commands, global_commands, sizeof(global_commands) / sizeof(global_commands[0])); @@ -505,6 +537,8 @@ void teardown_global_commands(void) { cleanup_search_replace(); } #define BUFFER_VIEW_WRAPCMD(fn) \ static int32_t fn##_cmd(struct command_ctx ctx, int argc, \ const char *argv[]) { \ + (void)argc; \ + (void)argv; \ buffer_view_##fn(window_buffer_view(ctx.active_window)); \ return 0; \ } @@ -512,51 +546,59 @@ void teardown_global_commands(void) { cleanup_search_replace(); } #define BUFFER_WRAPCMD(fn) \ static int32_t fn##_cmd(struct command_ctx ctx, int argc, \ const char *argv[]) { \ + (void)argc; \ + (void)argv; \ buffer_##fn(window_buffer(ctx.active_window)); \ return 0; \ } -BUFFER_WRAPCMD(to_file); -BUFFER_WRAPCMD(reload); -BUFFER_VIEW_WRAPCMD(kill_line); -BUFFER_VIEW_WRAPCMD(forward_delete_char); -BUFFER_VIEW_WRAPCMD(backward_delete_char); -BUFFER_VIEW_WRAPCMD(delete_word); -BUFFER_VIEW_WRAPCMD(backward_char); -BUFFER_VIEW_WRAPCMD(backward_word); -BUFFER_VIEW_WRAPCMD(forward_char); -BUFFER_VIEW_WRAPCMD(forward_word); -BUFFER_VIEW_WRAPCMD(backward_line); -BUFFER_VIEW_WRAPCMD(forward_line); -BUFFER_VIEW_WRAPCMD(goto_end_of_line); -BUFFER_VIEW_WRAPCMD(goto_beginning_of_line); -BUFFER_VIEW_WRAPCMD(newline); -BUFFER_VIEW_WRAPCMD(indent); -BUFFER_VIEW_WRAPCMD(indent_alt); -BUFFER_VIEW_WRAPCMD(set_mark); -BUFFER_VIEW_WRAPCMD(clear_mark); -BUFFER_VIEW_WRAPCMD(copy); -BUFFER_VIEW_WRAPCMD(cut); -BUFFER_VIEW_WRAPCMD(paste); -BUFFER_VIEW_WRAPCMD(paste_older); -BUFFER_VIEW_WRAPCMD(goto_beginning); -BUFFER_VIEW_WRAPCMD(goto_end); -BUFFER_VIEW_WRAPCMD(undo); -BUFFER_VIEW_WRAPCMD(sort_lines); +BUFFER_WRAPCMD(to_file) +BUFFER_WRAPCMD(reload) +BUFFER_VIEW_WRAPCMD(kill_line) +BUFFER_VIEW_WRAPCMD(forward_delete_char) +BUFFER_VIEW_WRAPCMD(backward_delete_char) +BUFFER_VIEW_WRAPCMD(delete_word) +BUFFER_VIEW_WRAPCMD(backward_char) +BUFFER_VIEW_WRAPCMD(backward_word) +BUFFER_VIEW_WRAPCMD(forward_char) +BUFFER_VIEW_WRAPCMD(forward_word) +BUFFER_VIEW_WRAPCMD(backward_line) +BUFFER_VIEW_WRAPCMD(forward_line) +BUFFER_VIEW_WRAPCMD(goto_end_of_line) +BUFFER_VIEW_WRAPCMD(goto_beginning_of_line) +BUFFER_VIEW_WRAPCMD(newline) +BUFFER_VIEW_WRAPCMD(indent) +BUFFER_VIEW_WRAPCMD(indent_alt) +BUFFER_VIEW_WRAPCMD(set_mark) +BUFFER_VIEW_WRAPCMD(clear_mark) +BUFFER_VIEW_WRAPCMD(copy) +BUFFER_VIEW_WRAPCMD(cut) +BUFFER_VIEW_WRAPCMD(paste) +BUFFER_VIEW_WRAPCMD(paste_older) +BUFFER_VIEW_WRAPCMD(goto_beginning) +BUFFER_VIEW_WRAPCMD(goto_end) +BUFFER_VIEW_WRAPCMD(undo) +BUFFER_VIEW_WRAPCMD(sort_lines) static int32_t scroll_up_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + buffer_view_backward_nlines(window_buffer_view(ctx.active_window), window_height(ctx.active_window) - 1); return 0; -}; +} static int32_t scroll_down_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + buffer_view_forward_nlines(window_buffer_view(ctx.active_window), window_height(ctx.active_window) - 1); return 0; -}; +} static int32_t goto_line(struct command_ctx ctx, int argc, const char *argv[]) { // don't want to goto line in minibuffer @@ -574,7 +616,7 @@ static int32_t goto_line(struct command_ctx ctx, int argc, const char *argv[]) { if (line < 0) { uint32_t nlines = buffer_num_lines(v->buffer); line = -line; - line = line >= nlines ? 0 : nlines - line; + line = (uint32_t)line >= nlines ? 0 : nlines - line; } else if (line > 0) { line = line - 1; } @@ -623,12 +665,18 @@ void register_buffer_commands(struct commands *commands) { static int32_t window_close_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + window_close(ctx.active_window); return 0; } static int32_t window_split_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct window *resa, *resb; window_split(ctx.active_window, &resa, &resb); return 0; @@ -636,6 +684,9 @@ static int32_t window_split_cmd(struct command_ctx ctx, int argc, static int32_t window_hsplit_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct window *resa, *resb; window_hsplit(ctx.active_window, &resa, &resb); return 0; @@ -643,6 +694,9 @@ static int32_t window_hsplit_cmd(struct command_ctx ctx, int argc, static int32_t window_vsplit_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + struct window *resa, *resb; window_vsplit(ctx.active_window, &resa, &resb); return 0; @@ -650,12 +704,19 @@ static int32_t window_vsplit_cmd(struct command_ctx ctx, int argc, static int32_t window_close_others_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + window_close_others(ctx.active_window); return 0; } static int32_t window_focus_next_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + windows_focus_next(); return 0; } @@ -676,6 +737,9 @@ static int32_t window_focus_cmd(struct command_ctx ctx, int argc, static int32_t window_focus_n_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argc; + (void)argv; + char *window_id = (char *)ctx.userdata; const char *argv_[] = {window_id}; return window_focus_cmd(ctx, 1, argv_); @@ -730,15 +794,15 @@ int32_t settings_set_cmd(struct command_ctx ctx, int argc, const char *argv[]) { struct setting_value new_value = {.type = setting->value.type}; switch (setting->value.type) { case Setting_Bool: - new_value.bool_value = strncmp("true", value, 4) == 0 || - strncmp("yes", value, 3) == 0 || - strncmp("on", value, 2) == 0; + new_value.data.bool_value = strncmp("true", value, 4) == 0 || + strncmp("yes", value, 3) == 0 || + strncmp("on", value, 2) == 0; break; case Setting_Number: - new_value.number_value = atol(value); + new_value.data.number_value = atol(value); break; case Setting_String: - new_value.string_value = (char *)value; + new_value.data.string_value = (char *)value; break; } diff --git a/src/main/cmds.h b/src/main/cmds.h index a258ce5..324842d 100644 --- a/src/main/cmds.h +++ b/src/main/cmds.h @@ -1,7 +1,7 @@ struct commands; void register_global_commands(struct commands *commands, - void (*terminate_cb)()); + void (*terminate_cb)(void)); void teardown_global_commands(void); void register_buffer_commands(struct commands *commands); diff --git a/src/main/completion.c b/src/main/completion.c index 4ffbc46..7a002ac 100644 --- a/src/main/completion.c +++ b/src/main/completion.c @@ -38,7 +38,7 @@ struct completion_state { static struct buffer *g_target_buffer = NULL; -static void hide_completion(); +static void hide_completion(void); static bool is_space(const struct codepoint *c) { // TODO: utf8 whitespace and other whitespace @@ -67,15 +67,15 @@ static struct completion_provider g_commands_provider = { .userdata = NULL, }; -struct completion_provider path_provider() { +struct completion_provider path_provider(void) { return g_path_provider; } -struct completion_provider buffer_provider() { +struct completion_provider buffer_provider(void) { return g_buffer_provider; } -struct completion_provider commands_provider() { +struct completion_provider commands_provider(void) { return g_commands_provider; } @@ -89,6 +89,10 @@ VEC(struct active_completion) g_active_completions; static int32_t goto_next_completion(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + if (g_state.current_completion < g_state.ncompletions - 1) { ++g_state.current_completion; } @@ -104,6 +108,10 @@ static int32_t goto_next_completion(struct command_ctx ctx, int argc, static int32_t goto_prev_completion(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + if (g_state.current_completion > 0) { --g_state.current_completion; } @@ -119,6 +127,10 @@ static int32_t goto_prev_completion(struct command_ctx ctx, int argc, static int32_t insert_completion(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + // is it in the popup? struct completion *comp = &g_state.completions[g_state.current_completion]; bool done = comp->complete; @@ -135,7 +147,7 @@ static int32_t insert_completion(struct command_ctx ctx, int argc, return 0; } -static void clear_completions() { +static void clear_completions(void) { for (uint32_t ci = 0; ci < g_state.ncompletions; ++ci) { free((void *)g_state.completions[ci].display); free((void *)g_state.completions[ci].insert); @@ -146,9 +158,9 @@ static void clear_completions() { g_state.ncompletions = 0; } -COMMAND_FN("next-completion", next_completion, goto_next_completion, NULL); -COMMAND_FN("prev-completion", prev_completion, goto_prev_completion, NULL); -COMMAND_FN("insert-completion", insert_completion, insert_completion, NULL); +COMMAND_FN("next-completion", next_completion, goto_next_completion, NULL) +COMMAND_FN("prev-completion", prev_completion, goto_prev_completion, NULL) +COMMAND_FN("insert-completion", insert_completion, insert_completion, NULL) static void update_completions(struct buffer *buffer, struct active_completion_ctx *ctx, @@ -246,7 +258,7 @@ static void on_buffer_insert(struct buffer *buffer, ctx->trigger_current_nchars += nchars; - if (ctx->trigger_current_nchars < ctx->trigger.input.nchars) { + if (ctx->trigger_current_nchars < ctx->trigger.data.input.nchars) { return; } @@ -267,6 +279,9 @@ static void on_buffer_insert(struct buffer *buffer, } static void update_completion_buffer(struct buffer *buffer, void *userdata) { + (void)buffer; + (void)userdata; + buffer_add_text_property( g_target_buffer, (struct location){.line = g_state.current_completion, .col = 0}, @@ -274,7 +289,7 @@ static void update_completion_buffer(struct buffer *buffer, void *userdata) { .col = buffer_line_length(g_target_buffer, g_state.current_completion)}, (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ + .data.colors = (struct text_property_colors){ .set_bg = false, .bg = 0, .set_fg = true, @@ -352,7 +367,7 @@ void enable_completion(struct buffer *source, struct completion_trigger trigger, // do we want to trigger initially? if (ctx->trigger.kind == CompletionTrigger_Input && - ctx->trigger.input.trigger_initially) { + ctx->trigger.data.input.trigger_initially) { struct oneshot_completion *comp = calloc(1, sizeof(struct oneshot_completion)); comp->ctx = ctx; @@ -361,7 +376,7 @@ void enable_completion(struct buffer *source, struct completion_trigger trigger, } } -static void hide_completion() { +static void hide_completion(void) { windows_close_popup(); if (g_state.active) { buffer_remove_keymap(g_state.keymap_id); @@ -369,13 +384,13 @@ static void hide_completion() { } } -void abort_completion() { +void abort_completion(void) { hide_completion(); g_state.active = false; clear_completions(); } -bool completion_active() { +bool completion_active(void) { return popup_window_visible() && window_buffer(popup_window()) == g_target_buffer && g_state.active; } @@ -391,7 +406,7 @@ static void cleanup_active_comp_ctx(void *userdata) { free(ctx); } -static void do_nothing(void *userdata) {} +static void do_nothing(void *userdata) { (void)userdata; } static void cleanup_active_completion(struct active_completion *comp) { buffer_remove_delete_hook(comp->buffer, comp->remove_hook_id, do_nothing); @@ -410,7 +425,7 @@ void disable_completion(struct buffer *buffer) { } } -void destroy_completion() { +void destroy_completion(void) { // clean up any active completions we might have VEC_FOR_EACH(&g_active_completions, struct active_completion * comp) { cleanup_active_completion(comp); @@ -429,10 +444,10 @@ static int cmp_completions(const void *comp_a, const void *comp_b) { } static uint32_t complete_path(struct completion_context ctx, void *userdata) { + (void)userdata; // obtain path from the buffer struct text_chunk txt = {0}; - uint32_t start_idx = 0; if (ctx.buffer == minibuffer_buffer()) { txt = minibuffer_content(); } else { @@ -455,7 +470,6 @@ static uint32_t complete_path(struct completion_context ctx, void *userdata) { uint32_t n = 0; char *p1 = to_abspath(path); - size_t len = strlen(p1); char *p2 = strdup(p1); size_t inlen = strlen(path); @@ -553,7 +567,6 @@ static uint32_t complete_buffers(struct completion_context ctx, } struct text_chunk txt = {0}; - uint32_t start_idx = 0; if (ctx.buffer == minibuffer_buffer()) { txt = minibuffer_content(); } else { @@ -608,7 +621,6 @@ static uint32_t complete_commands(struct completion_context ctx, return 0; } struct text_chunk txt = {0}; - uint32_t start_idx = 0; if (ctx.buffer == minibuffer_buffer()) { txt = minibuffer_content(); } else { diff --git a/src/main/completion.h b/src/main/completion.h index 28871b9..f2ce186 100644 --- a/src/main/completion.h +++ b/src/main/completion.h @@ -97,10 +97,10 @@ struct completion_trigger_input { struct completion_trigger { /** Type of trigger. */ enum completion_trigger_kind kind; - union { + union completion_trigger_data { uint32_t c; struct completion_trigger_input input; - }; + } data; }; /** @@ -114,12 +114,12 @@ void init_completion(struct buffers *buffers, struct commands *commands); /** * Tear down the completion system. */ -void destroy_completion(); +void destroy_completion(void); /** * Callback for completion inserted. */ -typedef void (*insert_cb)(); +typedef void (*insert_cb)(void); /** * Enable completions in the buffer @p source. @@ -141,7 +141,7 @@ void enable_completion(struct buffer *source, struct completion_trigger trigger, * This provider completes filesystem paths. * @returns A filesystem path @ref completion_provider. */ -struct completion_provider path_provider(); +struct completion_provider path_provider(void); /** * Create a new buffer completion provider. @@ -150,7 +150,7 @@ struct completion_provider path_provider(); * buffer list. * @returns A buffer name @ref completion_provider. */ -struct completion_provider buffer_provider(); +struct completion_provider buffer_provider(void); /** * Create a new command completion provider. @@ -158,19 +158,19 @@ struct completion_provider buffer_provider(); * This provider completes registered command names. * @returns A command name @ref completion_provider. */ -struct completion_provider commands_provider(); +struct completion_provider commands_provider(void); /** * Abort any active completion. */ -void abort_completion(); +void abort_completion(void); /** * Is a completion currently showing? * * @returns True if the completion window is showing completions. */ -bool completion_active(); +bool completion_active(void); /** * Disable completion for @ref buffer. diff --git a/src/main/lsp.c b/src/main/lsp.c new file mode 100644 index 0000000..d56ca07 --- /dev/null +++ b/src/main/lsp.c @@ -0,0 +1,108 @@ +#include "lsp.h" + +#include "dged/buffer.h" +#include "dged/buffers.h" +#include "dged/hash.h" +#include "dged/hashmap.h" +#include "dged/lsp.h" +#include "dged/minibuffer.h" +#include "dged/reactor.h" +#include "dged/settings.h" + +HASHMAP_ENTRY_TYPE(lsp_entry, struct lsp *); + +HASHMAP(struct lsp_entry) g_lsp_clients; + +static struct create_data { + struct reactor *reactor; + struct buffers *buffers; +} g_create_data; + +static void log_message(int type, struct s8 msg) { + (void)type; + message("%s", msg); +} + +static void create_lsp_client(struct buffer *buffer, void *userdata) { + (void)userdata; + + struct create_data *data = &g_create_data; + const char *id = buffer->lang.id; + HASHMAP_GET(&g_lsp_clients, struct lsp_entry, id, struct lsp * *lsp); + if (lsp == NULL) { + // we need to start a new server + struct setting *s = lang_setting(&buffer->lang, "language-server"); + if (!s) { // no language server set + return; + } + + char *const command[] = {s->value.data.string_value, NULL}; + + char bufname[1024] = {0}; + snprintf(bufname, 1024, "*%s-lsp-stderr*", command[0]); + struct buffer *stderr_buf = buffers_find(data->buffers, bufname); + if (stderr_buf == NULL) { + struct buffer buf = buffer_create(bufname); + buf.lazy_row_add = false; + stderr_buf = buffers_add(data->buffers, buf); + buffer_set_readonly(stderr_buf, true); + } + + struct lsp_client client_impl = { + .log_message = log_message, + }; + struct lsp *new_lsp = + lsp_create(command, data->reactor, stderr_buf, client_impl, NULL); + + if (new_lsp == NULL) { + minibuffer_echo("failed to create language server %s", command[0]); + buffers_remove(data->buffers, bufname); + return; + } + + HASHMAP_APPEND(&g_lsp_clients, struct lsp_entry, id, + struct lsp_entry * new); + new->value = new_lsp; + + if (lsp_start_server(new_lsp) < 0) { + minibuffer_echo("failed to start language server %s process.", + lsp_server_name(new_lsp)); + return; + } + } +} + +static void set_default_lsp(const char *lang_id, const char *server) { + struct language l = lang_from_id(lang_id); + if (!lang_is_fundamental(&l)) { + lang_setting_set_default( + &l, "language-server", + (struct setting_value){.type = Setting_String, + .data.string_value = (char *)server}); + lang_destroy(&l); + } +} + +void lang_servers_init(struct reactor *reactor, struct buffers *buffers) { + HASHMAP_INIT(&g_lsp_clients, 32, hash_name); + + set_default_lsp("c", "clangd"); + set_default_lsp("rs", "rust-analyzer"); + set_default_lsp("python", "pylsp"); + + g_create_data.reactor = reactor; + g_create_data.buffers = buffers; + buffer_add_create_hook(create_lsp_client, NULL); +} + +void lang_servers_update(void) { + HASHMAP_FOR_EACH(&g_lsp_clients, struct lsp_entry * e) { + lsp_update(e->value, NULL, 0); + } +} + +void lang_servers_teardown(void) { + HASHMAP_FOR_EACH(&g_lsp_clients, struct lsp_entry * e) { + lsp_stop_server(e->value); + } +} diff --git a/src/main/lsp.h b/src/main/lsp.h new file mode 100644 index 0000000..736282d --- /dev/null +++ b/src/main/lsp.h @@ -0,0 +1,11 @@ +#ifndef _MAIN_LSP_H +#define _MAIN_LSP_H + +struct reactor; +struct buffers; + +void lang_servers_init(struct reactor *reactor, struct buffers *buffers); +void lang_servers_update(void); +void lang_servers_teardown(void); + +#endif diff --git a/src/main/main.c b/src/main/main.c index 45f72cb..fa740e8 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -9,6 +9,8 @@ #include <time.h> #include <unistd.h> +#include "config.h" + #include "dged/allocator.h" #include "dged/binding.h" #include "dged/buffer.h" @@ -29,6 +31,10 @@ #define str(s) #s #endif +#ifdef LSP_ENABLE +#include "lsp.h" +#endif + #include "bindings.h" #include "cmds.h" #include "completion.h" @@ -48,11 +54,16 @@ void *frame_alloc(size_t sz) { static bool running = true; -void terminate() { running = false; } +void terminate(void) { running = false; } +void terminate2(int sig) { + (void)sig; + running = false; +} static struct display *display = NULL; static bool display_resized = false; -void resized() { +void resized(int sig) { + (void)sig; if (display != NULL) { display_resize(display); } @@ -61,7 +72,9 @@ void resized() { signal(SIGWINCH, resized); } -void segfault() { +void segfault(int sig) { + (void)sig; + // make an effort to restore the // terminal to its former glory if (display != NULL) { @@ -73,7 +86,7 @@ void segfault() { abort(); } -#define INVALID_WATCH -1 +#define INVALID_WATCH (uint32_t) - 1 static void clear_buffer_props(struct buffer *buffer, void *userdata) { (void)userdata; @@ -139,13 +152,13 @@ void update_file_watches(struct reactor *reactor) { } } -static void usage() { +static void usage(void) { printf("dged - a text editor for datagubbar/datagummor!\n"); printf("usage: dged [-l/--line line_number] [-e/--end] [-h/--help] " "[filename]\n"); } -static void version() { +static void version(void) { printf("dged - %s\n© Albert Cervin 2024\n", DGED_VERSION); } @@ -194,7 +207,7 @@ int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); - signal(SIGTERM, terminate); + signal(SIGTERM, terminate2); signal(SIGSEGV, segfault); struct commands commands = command_registry_create(32); @@ -212,7 +225,8 @@ int main(int argc, char *argv[]) { int32_t ret = settings_from_file(settings_file_abs, &errmsgs); if (ret > 0) { fprintf(stderr, "Error reading settings from %s:\n", settings_file_abs); - for (uint32_t erri = 0; erri < ret; ++erri) { + uint32_t nerrors = (uint32_t)ret; + for (uint32_t erri = 0; erri < nerrors; ++erri) { fprintf(stderr, " - %s", errmsgs[erri]); free(errmsgs[erri]); } @@ -266,7 +280,7 @@ int main(int argc, char *argv[]) { struct setting *path_setting = settings_get("editor.grammars-path"); char *settings_path = NULL; if (path_setting != NULL && path_setting->value.type == Setting_String) { - settings_path = path_setting->value.string_value; + settings_path = path_setting->value.data.string_value; } const char *builtin_path = join_path(xstr(DATADIR), "grammars"); @@ -309,6 +323,10 @@ int main(int argc, char *argv[]) { free((void *)builtin_path); #endif +#ifdef LSP_ENABLE + lang_servers_init(reactor, &buflist); +#endif + struct buffer initial_buffer = buffer_create("welcome"); if (filename != NULL) { buffer_destroy(&initial_buffer); @@ -394,7 +412,6 @@ int main(int argc, char *argv[]) { struct keyboard_update kbd_upd = keyboard_update(&kbd, reactor, frame_alloc); - uint32_t input_data_idx = 0; for (uint32_t ki = 0; ki < kbd_upd.nkeys; ++ki) { struct key *k = &kbd_upd.keys[ki]; @@ -416,15 +433,15 @@ int main(int argc, char *argv[]) { if (res.found) { switch (res.type) { case BindingType_Command: { - if (res.command == NULL) { + if (res.data.command == NULL) { minibuffer_echo_timeout( 4, "binding found for key %s but not command", k); } else { - int32_t ec = execute_command(res.command, &commands, active_window, - &buflist, 0, NULL); + int32_t ec = execute_command(res.data.command, &commands, + active_window, &buflist, 0, NULL); if (ec != 0 && !minibuffer_displaying()) { minibuffer_echo_timeout(4, "command %s failed with exit code %d", - res.command->name, ec); + res.data.command->name, ec); } } current_keymap = NULL; @@ -443,7 +460,7 @@ int main(int argc, char *argv[]) { minibuffer_echo("%s", keyname); } - current_keymap = res.keymap; + current_keymap = res.data.keymap; break; } } @@ -469,6 +486,10 @@ int main(int argc, char *argv[]) { update_file_watches(reactor); +#if defined(LSP_ENABLE) + lang_servers_update(); +#endif + // calculate frame time frame_time = timer_average(update_windows) + timer_average(update_keyboard) + timer_average(update_display); @@ -489,6 +510,10 @@ int main(int argc, char *argv[]) { syntax_teardown(); #endif +#ifdef LSP_ENABLE + lang_servers_teardown(); +#endif + display_clear(display); display_destroy(display); destroy_bindings(); diff --git a/src/main/search-replace.c b/src/main/search-replace.c index 50beb1e..32c514c 100644 --- a/src/main/search-replace.c +++ b/src/main/search-replace.c @@ -45,6 +45,55 @@ static struct search { buffer_keymap_id keymap_id; } g_current_search = {0}; +static void highlight_match(struct buffer *buffer, struct region match, + bool current) { + if (current) { + buffer_add_text_property( + buffer, match.begin, match.end, + (struct text_property){.type = TextProperty_Colors, + .data.colors = (struct text_property_colors){ + .set_bg = true, + .bg = 3, + .set_fg = true, + .fg = 0, + }}); + + } else { + buffer_add_text_property( + buffer, match.begin, match.end, + (struct text_property){.type = TextProperty_Colors, + .data.colors = (struct text_property_colors){ + .set_bg = true, + .bg = 6, + .set_fg = true, + .fg = 0, + }}); + } +} + +static void search_highlight_hook(struct buffer *buffer, void *userdata) { + (void)userdata; + + for (uint32_t matchi = 0; matchi < g_current_search.nmatches; ++matchi) { + highlight_match(buffer, g_current_search.matches[matchi], + matchi == g_current_search.current_match); + } +} + +static void replace_highlight_hook(struct buffer *buffer, void *userdata) { + (void)userdata; + + for (uint32_t matchi = 0; matchi < g_current_replace.nmatches; ++matchi) { + struct match *m = &g_current_replace.matches[matchi]; + if (m->state != Todo) { + continue; + } + + highlight_match(buffer, m->region, + matchi == g_current_replace.current_match); + } +} + static void clear_replace(void) { buffer_remove_keymap(g_current_replace.keymap_id); free(g_current_replace.matches); @@ -89,6 +138,36 @@ void abort_search(void) { minibuffer_abort_prompt(); } +static void start_search(struct buffer *buffer, const char *pattern) { + if (buffer != g_current_search.buffer) { + clear_search(); + } + + g_current_search.buffer = buffer; + g_current_search.active = true; + + // if we are in a new buffer, add the update hook for it. + if (g_current_search.highlight_hook == (uint32_t)-1) { + g_current_search.highlight_hook = + buffer_add_update_hook(buffer, search_highlight_hook, NULL); + } + + // replace the pattern if needed + if (g_current_search.pattern == NULL || + !s8eq(s8(g_current_search.pattern), s8(pattern))) { + char *new_pattern = strdup(pattern); + free(g_current_search.pattern); + g_current_search.pattern = new_pattern; + } + + // clear out any old search results + if (g_current_search.matches != NULL) { + free(g_current_search.matches); + g_current_search.matches = NULL; + g_current_search.nmatches = 0; + } +} + uint64_t matchdist(struct region *match, struct location loc) { struct location begin = match->begin; @@ -98,64 +177,21 @@ uint64_t matchdist(struct region *match, struct location loc) { // into the line it is, otherwise check the distance from location int64_t coldist = begin.col; if (linedist == 0) { - int64_t coldist = (int64_t)begin.col - (int64_t)loc.col; + coldist = (int64_t)begin.col - (int64_t)loc.col; } // arbitrary row scaling, best effort to avoid counting line length + // this is not technically correct if you have lines longer than + // 1e6 but otoh, that seems excessive return (linedist * linedist) * 1e6 + coldist * coldist; } -static void highlight_match(struct buffer *buffer, struct region match, - bool current) { - if (current) { - buffer_add_text_property( - buffer, match.begin, match.end, - (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ - .set_bg = true, - .bg = 3, - .set_fg = true, - .fg = 0, - }}); - - } else { - buffer_add_text_property( - buffer, match.begin, match.end, - (struct text_property){.type = TextProperty_Colors, - .colors = (struct text_property_colors){ - .set_bg = true, - .bg = 6, - .set_fg = true, - .fg = 0, - }}); - } -} - -static void search_highlight_hook(struct buffer *buffer, void *userdata) { - (void)userdata; - - for (uint32_t matchi = 0; matchi < g_current_search.nmatches; ++matchi) { - highlight_match(buffer, g_current_search.matches[matchi], - matchi == g_current_search.current_match); - } -} - -static void replace_highlight_hook(struct buffer *buffer, void *userdata) { - (void)userdata; - - for (uint32_t matchi = 0; matchi < g_current_replace.nmatches; ++matchi) { - struct match *m = &g_current_replace.matches[matchi]; - if (m->state != Todo) { - continue; - } - - highlight_match(buffer, m->region, - matchi == g_current_replace.current_match); - } -} - static int32_t replace_next(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(state->window); struct buffer *buffer = buffer_view->buffer; @@ -207,6 +243,10 @@ static int32_t replace_next(struct command_ctx ctx, int argc, } static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { + (void)ctx; + (void)argc; + (void)argv; + struct replace *state = &g_current_replace; struct buffer_view *buffer_view = window_buffer_view(state->window); @@ -230,8 +270,8 @@ static int32_t skip_next(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } -COMMAND_FN("replace-next", replace_next, replace_next, NULL); -COMMAND_FN("skip-next", skip_next, skip_next, NULL); +COMMAND_FN("replace-next", replace_next, replace_next, NULL) +COMMAND_FN("skip-next", skip_next, skip_next, NULL) static int cmp_matches(const void *m1, const void *m2) { struct region *match1 = (struct region *)m1; @@ -350,35 +390,9 @@ static struct region *find_closest(struct region *matches, uint32_t nmatches, return closest; } -static void do_search(struct buffer_view *view, const char *pattern, +static bool do_search(struct buffer_view *view, const char *pattern, bool reverse) { - if (view->buffer != g_current_search.buffer) { - clear_search(); - } - - g_current_search.buffer = view->buffer; - g_current_search.active = true; - - // if we are in a new buffer, add the update hook for it. - if (g_current_search.highlight_hook == (uint32_t)-1) { - g_current_search.highlight_hook = - buffer_add_update_hook(view->buffer, search_highlight_hook, NULL); - } - - // replace the pattern if needed - if (g_current_search.pattern == NULL || - !s8eq(s8(g_current_search.pattern), s8(pattern))) { - char *new_pattern = strdup(pattern); - free(g_current_search.pattern); - g_current_search.pattern = new_pattern; - } - - // clear out any old search results first - if (g_current_search.matches != NULL) { - free(g_current_search.matches); - g_current_search.matches = NULL; - g_current_search.nmatches = 0; - } + start_search(view->buffer, pattern); buffer_find(view->buffer, g_current_search.pattern, &g_current_search.matches, &g_current_search.nmatches); @@ -391,10 +405,10 @@ static void do_search(struct buffer_view *view, const char *pattern, view->dot, reverse, &closest_idx); buffer_view_goto(view, closest->begin); g_current_search.current_match = closest_idx; - } else { - abort_search(); - minibuffer_echo_timeout(4, "%s not found", pattern); + return true; } + + return false; } static const char *get_pattern() { @@ -424,12 +438,18 @@ int32_t search_interactive(struct command_ctx ctx, int argc, } minibuffer_set_prompt(search_prompt(*(bool *)ctx.userdata)); + buffer_view_goto_end(window_buffer_view(minibuffer_window())); if (pattern != NULL) { - do_search(window_buffer_view(minibuffer_target_window()), pattern, - *(bool *)ctx.userdata); + if (!do_search(window_buffer_view(minibuffer_target_window()), pattern, + *(bool *)ctx.userdata)) { + abort_search(); + minibuffer_echo_timeout(4, "%s not found", pattern); + } + free((char *)pattern); } + return 0; } @@ -437,11 +457,13 @@ static bool search_dir_backward = true; static bool search_dir_forward = false; COMMAND_FN("search-forward", search_forward, search_interactive, - &search_dir_forward); + &search_dir_forward) COMMAND_FN("search-backward", search_backward, search_interactive, - &search_dir_backward); + &search_dir_backward) int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { + (void)argv; + bool reverse = *(bool *)ctx.userdata; if (argc == 0) { struct binding bindings[] = { @@ -454,17 +476,21 @@ int32_t find(struct command_ctx ctx, int argc, const char *argv[]) { return minibuffer_prompt(ctx, search_prompt(reverse)); } + // allow enter to end the interactive search if (g_current_search.active) { abort_search(); return 0; } buffer_remove_keymap(g_current_search.keymap_id); - do_search(window_buffer_view(ctx.active_window), argv[0], reverse); + bool found = + do_search(window_buffer_view(ctx.active_window), argv[0], reverse); - if (g_current_search.active) { - abort_search(); + abort_search(); + if (!found) { + minibuffer_echo_timeout(4, "%s not found", argv[0]); } + return 0; } @@ -481,11 +507,10 @@ void register_search_replace_commands(struct commands *commands) { } void cleanup_search_replace(void) { + clear_replace(); clear_search(); if (g_current_search.pattern != NULL) { free(g_current_search.pattern); g_current_search.pattern = NULL; } - - clear_replace(); } diff --git a/src/main/search-replace.h b/src/main/search-replace.h index 16869fc..ef5e0dc 100644 --- a/src/main/search-replace.h +++ b/src/main/search-replace.h @@ -3,7 +3,7 @@ struct commands; /** * Abort a replace currently in progress. */ -void abort_replace(); +void abort_replace(void); /** * Abort a search currently in progress. |
