summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-05-22 00:00:29 +0200
committerAlbert Cervin <albert@acervin.com>2024-09-12 20:17:56 +0200
commit405da5f84b072ea97b69359454899f45d92d24b6 (patch)
tree20525b4bc44a5d8cbab4d62abe8413e174731db6 /src/main
parent4ab7e453e26afc6e9f4938c65f89463fbba9e267 (diff)
downloaddged-405da5f84b072ea97b69359454899f45d92d24b6.tar.gz
dged-405da5f84b072ea97b69359454899f45d92d24b6.tar.xz
dged-405da5f84b072ea97b69359454899f45d92d24b6.zip
WIP LSP client
This contains the start of an LSP client. Nothing (except starting the LSP server) works at the moment and the feature is disabled by default.
Diffstat (limited to 'src/main')
-rw-r--r--src/main/bindings.c8
-rw-r--r--src/main/bindings.h4
-rw-r--r--src/main/cmds.c182
-rw-r--r--src/main/cmds.h2
-rw-r--r--src/main/completion.c52
-rw-r--r--src/main/completion.h18
-rw-r--r--src/main/lsp.c108
-rw-r--r--src/main/lsp.h11
-rw-r--r--src/main/main.c55
-rw-r--r--src/main/search-replace.c209
-rw-r--r--src/main/search-replace.h2
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.