summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/dged/binding.c7
-rw-r--r--src/dged/binding.h14
-rw-r--r--src/dged/buffer.c56
-rw-r--r--src/dged/buffer.h14
-rw-r--r--src/dged/buffer_view.c5
-rw-r--r--src/dged/command.c2
-rw-r--r--src/dged/display.c60
-rw-r--r--src/dged/display.h2
-rw-r--r--src/dged/hash.c20
-rw-r--r--src/dged/hash.h14
-rw-r--r--src/dged/hashmap.h8
-rw-r--r--src/dged/json.c234
-rw-r--r--src/dged/json.h54
-rw-r--r--src/dged/lang.c34
-rw-r--r--src/dged/lsp.c163
-rw-r--r--src/dged/lsp.h75
-rw-r--r--src/dged/minibuffer.c24
-rw-r--r--src/dged/minibuffer.h20
-rw-r--r--src/dged/path.c68
-rw-r--r--src/dged/path.h69
-rw-r--r--src/dged/process-posix.c126
-rw-r--r--src/dged/process.h35
-rw-r--r--src/dged/reactor-epoll.c12
-rw-r--r--src/dged/reactor-kqueue.c2
-rw-r--r--src/dged/reactor.h2
-rw-r--r--src/dged/settings.c22
-rw-r--r--src/dged/settings.h6
-rw-r--r--src/dged/syntax.c27
-rw-r--r--src/dged/syntax.h2
-rw-r--r--src/dged/text.h4
-rw-r--r--src/dged/timers.c8
-rw-r--r--src/dged/timers.h8
-rw-r--r--src/dged/undo.c30
-rw-r--r--src/dged/undo.h6
-rw-r--r--src/dged/utf8.c3
-rw-r--r--src/dged/vec.h3
-rw-r--r--src/dged/window.c18
-rw-r--r--src/dged/window.h16
-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
49 files changed, 1447 insertions, 477 deletions
diff --git a/src/dged/binding.c b/src/dged/binding.c
index 5111548..636e694 100644
--- a/src/dged/binding.c
+++ b/src/dged/binding.c
@@ -50,21 +50,22 @@ struct lookup_result lookup_key(struct keymap *keymaps, uint32_t nkeymaps,
return (struct lookup_result){
.found = true,
.type = BindingType_Command,
- .command = lookup_command_by_hash(commands, binding->command),
+ .data.command =
+ lookup_command_by_hash(commands, binding->data.command),
};
}
case BindingType_Keymap: {
return (struct lookup_result){
.found = true,
.type = BindingType_Keymap,
- .keymap = binding->keymap,
+ .data.keymap = binding->data.keymap,
};
}
case BindingType_DirectCommand:
return (struct lookup_result){
.found = true,
.type = BindingType_Command,
- .command = binding->direct_command,
+ .data.command = binding->data.direct_command,
};
}
}
diff --git a/src/dged/binding.h b/src/dged/binding.h
index 79f8c47..93de02d 100644
--- a/src/dged/binding.h
+++ b/src/dged/binding.h
@@ -37,19 +37,19 @@ enum binding_type {
#define BINDING_INNER(mod_, c_, command_) \
(struct binding) { \
.key = {.mod = mod_, .key = c_}, .type = BindingType_Command, \
- .command = hash_name(command_) \
+ .data.command = hash_name(command_) \
}
#define ANONYMOUS_BINDING_INNER(mod_, c_, command_) \
(struct binding) { \
.key = {.mod = mod_, .key = c_}, .type = BindingType_DirectCommand, \
- .direct_command = command_ \
+ .data.direct_command = command_ \
}
#define PREFIX_INNER(mod_, c_, keymap_) \
(struct binding) { \
.key = {.mod = mod_, .key = c_}, .type = BindingType_Keymap, \
- .keymap = keymap_ \
+ .data.keymap = keymap_ \
}
/**
@@ -89,14 +89,14 @@ struct binding {
/** Type of this binding, see @ref binding_type */
uint8_t type;
- union {
+ union binding_data {
/** A hash of a command name */
uint32_t command;
/** A command */
struct command *direct_command;
/** A keymap */
struct keymap *keymap;
- };
+ } data;
};
/**
@@ -109,12 +109,12 @@ struct lookup_result {
/** Type of binding in the result */
uint8_t type;
- union {
+ union lookup_data {
/** A command */
struct command *command;
/** A keymap */
struct keymap *keymap;
- };
+ } data;
};
struct commands;
diff --git a/src/dged/buffer.c b/src/dged/buffer.c
index 1062a47..c537fb3 100644
--- a/src/dged/buffer.c
+++ b/src/dged/buffer.c
@@ -31,7 +31,7 @@ static struct kill_ring {
uint32_t curr_idx;
uint32_t paste_idx;
} g_kill_ring = {.curr_idx = 0,
- .buffer = {0},
+ .buffer = {{0}},
.last_paste = {0},
.paste_idx = 0,
.paste_up_to_date = false};
@@ -58,7 +58,7 @@ static struct kill_ring {
\
static void remove_##name##_hook(vec_type *hooks, uint32_t id, \
remove_hook_cb callback) { \
- uint64_t found_at = -1; \
+ uint64_t found_at = (uint64_t)-1; \
VEC_FOR_EACH_INDEXED(hooks, struct name##_hook *h, idx) { \
if (h->id == id) { \
if (callback != NULL) { \
@@ -68,11 +68,12 @@ static struct kill_ring {
break; \
} \
} \
- if (found_at != -1) { \
+ if (found_at != (uint64_t)-1) { \
if (found_at < VEC_SIZE(hooks) - 1) { \
VEC_SWAP(hooks, found_at, VEC_SIZE(hooks) - 1); \
} \
VEC_POP(hooks, struct name##_hook removed); \
+ (void)removed; \
} \
}
@@ -84,13 +85,13 @@ typedef VEC(struct reload_hook) reload_hook_vec;
typedef VEC(struct delete_hook) delete_hook_vec;
typedef VEC(struct render_hook) render_hook_vec;
-DECLARE_HOOK(create, create_hook_cb, create_hook_vec);
-DECLARE_HOOK(destroy, destroy_hook_cb, destroy_hook_vec);
-DECLARE_HOOK(insert, insert_hook_cb, insert_hook_vec);
-DECLARE_HOOK(update, update_hook_cb, update_hook_vec);
-DECLARE_HOOK(reload, reload_hook_cb, reload_hook_vec);
-DECLARE_HOOK(render, render_hook_cb, render_hook_vec);
-DECLARE_HOOK(delete, delete_hook_cb, delete_hook_vec);
+DECLARE_HOOK(create, create_hook_cb, create_hook_vec)
+DECLARE_HOOK(destroy, destroy_hook_cb, destroy_hook_vec)
+DECLARE_HOOK(insert, insert_hook_cb, insert_hook_vec)
+DECLARE_HOOK(update, update_hook_cb, update_hook_vec)
+DECLARE_HOOK(reload, reload_hook_cb, reload_hook_vec)
+DECLARE_HOOK(render, render_hook_cb, render_hook_vec)
+DECLARE_HOOK(delete, delete_hook_cb, delete_hook_vec)
static create_hook_vec g_create_hooks;
uint32_t g_create_hook_id;
@@ -136,19 +137,19 @@ void buffer_remove_destroy_hook(struct buffer *buffer, uint32_t hook_id,
remove_destroy_hook(&buffer->hooks->destroy_hooks, hook_id, callback);
}
-void buffer_static_init() {
+void buffer_static_init(void) {
VEC_INIT(&g_create_hooks, 8);
settings_set_default(
"editor.tab-width",
- (struct setting_value){.type = Setting_Number, .number_value = 4});
+ (struct setting_value){.type = Setting_Number, .data.number_value = 4});
settings_set_default(
"editor.show-whitespace",
- (struct setting_value){.type = Setting_Bool, .bool_value = true});
+ (struct setting_value){.type = Setting_Bool, .data.bool_value = true});
}
-void buffer_static_teardown() {
+void buffer_static_teardown(void) {
VEC_DESTROY(&g_create_hooks);
for (uint32_t i = 0; i < KILL_RING_SZ; ++i) {
if (g_kill_ring.buffer[i].allocated) {
@@ -165,7 +166,7 @@ static uint32_t get_tab_width(struct buffer *buffer) {
uint32_t tab_width = 4;
if (tw != NULL && tw->value.type == Setting_Number) {
- tab_width = tw->value.number_value;
+ tab_width = tw->value.data.number_value;
}
return tab_width;
}
@@ -178,7 +179,7 @@ static bool use_tabs(struct buffer *buffer) {
bool use_tabs = false;
if (ut != NULL && ut->value.type == Setting_Bool) {
- use_tabs = ut->value.bool_value;
+ use_tabs = ut->value.data.bool_value;
}
return use_tabs;
@@ -664,14 +665,14 @@ struct location buffer_previous_word(struct buffer *buffer,
struct location buffer_previous_line(struct buffer *buffer,
struct location dot) {
- if (dot.line == 0) {
+ (void)buffer;
+
+ if (dot.line <= 0) {
+ dot.line = 0;
return dot;
}
--dot.line;
- uint32_t nchars = buffer_line_length(buffer, dot.line);
- uint32_t new_col = dot.col > nchars ? nchars : dot.col;
-
return dot;
}
@@ -842,7 +843,7 @@ struct location buffer_undo(struct buffer *buffer, struct location dot) {
switch (rec->type) {
case Undo_Boundary: {
- struct undo_boundary *b = &rec->boundary;
+ struct undo_boundary *b = &rec->data.boundary;
if (b->save_point) {
buffer->modified = false;
}
@@ -850,7 +851,7 @@ struct location buffer_undo(struct buffer *buffer, struct location dot) {
}
case Undo_Add: {
- struct undo_add *add = &rec->add;
+ struct undo_add *add = &rec->data.add;
pos = buffer_delete(buffer,
(struct region){
@@ -864,7 +865,7 @@ struct location buffer_undo(struct buffer *buffer, struct location dot) {
}
case Undo_Delete: {
- struct undo_delete *del = &rec->delete;
+ struct undo_delete *del = &rec->data.delete;
pos = buffer_add(buffer,
(struct location){
.line = del->pos.row,
@@ -934,7 +935,7 @@ void buffer_find(struct buffer *buffer, const char *pattern,
struct location buffer_copy(struct buffer *buffer, struct region region) {
if (region_has_size(region)) {
- struct text_chunk *curr = copy_region(buffer, region);
+ copy_region(buffer, region);
}
return region.begin;
@@ -1024,7 +1025,6 @@ struct location buffer_paste_older(struct buffer *buffer, struct location at) {
if (g_kill_ring.paste_up_to_date) {
// remove previous paste
- struct text_chunk *curr = &g_kill_ring.buffer[g_kill_ring.curr_idx];
buffer_delete(buffer, region_new(g_kill_ring.last_paste, at));
// paste older
@@ -1124,7 +1124,7 @@ static void apply_properties(struct command_list *cmds,
switch (prop->type) {
case TextProperty_Colors: {
- struct text_property_colors *colors = &prop->colors;
+ struct text_property_colors *colors = &prop->data.colors;
if (colors->set_bg) {
command_list_set_index_color_bg(cmds, colors->bg);
}
@@ -1221,7 +1221,7 @@ void render_line(struct text_chunk *line, void *userdata) {
}
}
-void buffer_update(struct buffer *buffer, struct buffer_update_params *params) {
+void buffer_update(struct buffer *buffer) {
VEC_FOR_EACH(&buffer->hooks->update_hooks, struct update_hook * h) {
h->callback(buffer, h->userdata);
}
@@ -1244,7 +1244,7 @@ void buffer_render(struct buffer *buffer, struct buffer_render_params *params) {
.origin = params->origin,
.width = params->width,
.height = params->height,
- .show_ws = (show_ws != NULL ? show_ws->value.bool_value : true) &&
+ .show_ws = (show_ws != NULL ? show_ws->value.data.bool_value : true) &&
!buffer->force_show_ws_off,
.buffer = buffer,
};
diff --git a/src/dged/buffer.h b/src/dged/buffer.h
index c9fe2ca..0e45b98 100644
--- a/src/dged/buffer.h
+++ b/src/dged/buffer.h
@@ -65,8 +65,8 @@ struct buffer {
bool force_show_ws_off;
};
-void buffer_static_init();
-void buffer_static_teardown();
+void buffer_static_init(void);
+void buffer_static_teardown(void);
/**
* Create a new buffer.
@@ -690,11 +690,6 @@ uint32_t buffer_add_create_hook(create_hook_cb callback, void *userdata);
void buffer_remove_create_hook(uint32_t hook_id, remove_hook_cb callback);
/**
- * Parameters for updating a buffer.
- */
-struct buffer_update_params {};
-
-/**
* Parameters for rendering a buffer.
*/
struct buffer_render_params {
@@ -716,11 +711,8 @@ struct buffer_render_params {
* Update a buffer.
*
* @param [in] buffer The buffer to update.
- * @param [inout] params The parameters for the update. The @ref commands field
- * in @p params will be modified with the rendering commands needed for this
- * buffer.
*/
-void buffer_update(struct buffer *buffer, struct buffer_update_params *params);
+void buffer_update(struct buffer *buffer);
/**
* Render a buffer.
diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c
index f3dd2b9..0c587a6 100644
--- a/src/dged/buffer_view.c
+++ b/src/dged/buffer_view.c
@@ -386,8 +386,7 @@ void buffer_view_update(struct buffer_view *view,
struct timer *buffer_update_timer =
timer_start("update-windows.buffer-update");
- struct buffer_update_params update_params = {};
- buffer_update(view->buffer, &update_params);
+ buffer_update(view->buffer);
timer_stop(buffer_update_timer);
uint32_t height = params->height;
@@ -446,7 +445,7 @@ void buffer_view_update(struct buffer_view *view,
buffer_add_text_property(view->buffer, reg.begin, reg.end,
(struct text_property){
.type = TextProperty_Colors,
- .colors =
+ .data.colors =
(struct text_property_colors){
.set_bg = true,
.bg = 5,
diff --git a/src/dged/command.c b/src/dged/command.c
index 2775286..5f2551f 100644
--- a/src/dged/command.c
+++ b/src/dged/command.c
@@ -79,7 +79,7 @@ void command_ctx_push_arg(struct command_ctx *ctx, const char *argv) {
}
void command_ctx_free(struct command_ctx *ctx) {
- for (uint32_t i = 0; i < ctx->saved_argc; ++i) {
+ for (uint32_t i = 0; i < (uint32_t)ctx->saved_argc; ++i) {
free((char *)ctx->saved_argv[i]);
}
diff --git a/src/dged/display.c b/src/dged/display.c
index ea3f459..0c3c47c 100644
--- a/src/dged/display.c
+++ b/src/dged/display.c
@@ -35,13 +35,13 @@ enum render_cmd_type {
struct render_command {
enum render_cmd_type type;
- union {
+ union render_cmd_data {
struct draw_text_cmd *draw_txt;
struct push_fmt_cmd *push_fmt;
struct repeat_cmd *repeat;
struct show_ws_cmd *show_ws;
struct draw_list_cmd *draw_list;
- };
+ } data;
};
struct draw_text_cmd {
@@ -87,13 +87,13 @@ struct command_list {
struct command_list *next_list;
};
-struct winsize getsize() {
+struct winsize getsize(void) {
struct winsize ws;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
return ws;
}
-struct display *display_create() {
+struct display *display_create(void) {
struct winsize ws = getsize();
@@ -182,6 +182,8 @@ void put_ansiparm(int n) {
}
void display_move_cursor(struct display *display, uint32_t row, uint32_t col) {
+ (void)display;
+
putc(ESC, stdout);
putc('[', stdout);
put_ansiparm(row + 1);
@@ -192,7 +194,6 @@ void display_move_cursor(struct display *display, uint32_t row, uint32_t col) {
void display_clear(struct display *display) {
display_move_cursor(display, 0, 0);
- uint8_t bytes[] = {ESC, '[', 'J'};
putc(ESC, stdout);
putc('[', stdout);
putc('J', stdout);
@@ -239,21 +240,21 @@ struct render_command *add_command(struct command_list *list,
cmd->type = tp;
switch (tp) {
case RenderCommand_DrawText:
- cmd->draw_txt = l->allocator(sizeof(struct draw_text_cmd));
+ cmd->data.draw_txt = l->allocator(sizeof(struct draw_text_cmd));
break;
case RenderCommand_Repeat:
- cmd->repeat = l->allocator(sizeof(struct repeat_cmd));
+ cmd->data.repeat = l->allocator(sizeof(struct repeat_cmd));
break;
case RenderCommand_PushFormat:
- cmd->push_fmt = l->allocator(sizeof(struct push_fmt_cmd));
+ cmd->data.push_fmt = l->allocator(sizeof(struct push_fmt_cmd));
break;
case RenderCommand_SetShowWhitespace:
- cmd->show_ws = l->allocator(sizeof(struct show_ws_cmd));
+ cmd->data.show_ws = l->allocator(sizeof(struct show_ws_cmd));
break;
case RenderCommand_ClearFormat:
break;
case RenderCommand_DrawList:
- cmd->draw_list = l->allocator(sizeof(struct draw_list_cmd));
+ cmd->data.draw_list = l->allocator(sizeof(struct draw_list_cmd));
break;
default:
assert(false);
@@ -266,7 +267,7 @@ struct render_command *add_command(struct command_list *list,
void command_list_draw_text(struct command_list *list, uint32_t col,
uint32_t row, uint8_t *data, uint32_t len) {
struct draw_text_cmd *cmd =
- add_command(list, RenderCommand_DrawText)->draw_txt;
+ add_command(list, RenderCommand_DrawText)->data.draw_txt;
cmd->data = data;
cmd->col = col;
cmd->row = row;
@@ -283,7 +284,7 @@ void command_list_draw_text_copy(struct command_list *list, uint32_t col,
void command_list_draw_repeated(struct command_list *list, uint32_t col,
uint32_t row, uint32_t c, uint32_t nrepeat) {
- struct repeat_cmd *cmd = add_command(list, RenderCommand_Repeat)->repeat;
+ struct repeat_cmd *cmd = add_command(list, RenderCommand_Repeat)->data.repeat;
cmd->col = col;
cmd->row = row;
cmd->c = c;
@@ -293,14 +294,14 @@ void command_list_draw_repeated(struct command_list *list, uint32_t col,
void command_list_draw_command_list(struct command_list *list,
struct command_list *to_draw) {
struct draw_list_cmd *cmd =
- add_command(list, RenderCommand_DrawList)->draw_list;
+ add_command(list, RenderCommand_DrawList)->data.draw_list;
cmd->list = to_draw;
}
void command_list_set_index_color_fg(struct command_list *list,
uint8_t color_idx) {
struct push_fmt_cmd *cmd =
- add_command(list, RenderCommand_PushFormat)->push_fmt;
+ add_command(list, RenderCommand_PushFormat)->data.push_fmt;
if (color_idx < 8) {
cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 30 + color_idx);
@@ -314,14 +315,14 @@ void command_list_set_index_color_fg(struct command_list *list,
void command_list_set_color_fg(struct command_list *list, uint8_t red,
uint8_t green, uint8_t blue) {
struct push_fmt_cmd *cmd =
- add_command(list, RenderCommand_PushFormat)->push_fmt;
+ add_command(list, RenderCommand_PushFormat)->data.push_fmt;
cmd->len = snprintf((char *)cmd->fmt, 64, "38;2;%d;%d;%d", red, green, blue);
}
void command_list_set_index_color_bg(struct command_list *list,
uint8_t color_idx) {
struct push_fmt_cmd *cmd =
- add_command(list, RenderCommand_PushFormat)->push_fmt;
+ add_command(list, RenderCommand_PushFormat)->data.push_fmt;
if (color_idx < 8) {
cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 40 + color_idx);
} else if (color_idx < 16) {
@@ -334,13 +335,13 @@ void command_list_set_index_color_bg(struct command_list *list,
void command_list_set_color_bg(struct command_list *list, uint8_t red,
uint8_t green, uint8_t blue) {
struct push_fmt_cmd *cmd =
- add_command(list, RenderCommand_PushFormat)->push_fmt;
+ add_command(list, RenderCommand_PushFormat)->data.push_fmt;
cmd->len = snprintf((char *)cmd->fmt, 64, "48;2;%d;%d;%d", red, green, blue);
}
void command_list_set_inverted_colors(struct command_list *list) {
struct push_fmt_cmd *cmd =
- add_command(list, RenderCommand_PushFormat)->push_fmt;
+ add_command(list, RenderCommand_PushFormat)->data.push_fmt;
cmd->fmt[0] = '7';
cmd->len = 1;
}
@@ -350,7 +351,7 @@ void command_list_reset_color(struct command_list *list) {
}
void command_list_set_show_whitespace(struct command_list *list, bool show) {
- add_command(list, RenderCommand_SetShowWhitespace)->show_ws->show = show;
+ add_command(list, RenderCommand_SetShowWhitespace)->data.show_ws->show = show;
}
void display_render(struct display *display,
@@ -374,7 +375,7 @@ void display_render(struct display *display,
struct render_command *cmd = &cl->cmds[cmdi];
switch (cmd->type) {
case RenderCommand_DrawText: {
- struct draw_text_cmd *txt_cmd = cmd->draw_txt;
+ struct draw_text_cmd *txt_cmd = cmd->data.draw_txt;
display_move_cursor(display, txt_cmd->row + cl->yoffset,
txt_cmd->col + cl->xoffset);
apply_fmt(fmt_stack, fmt_stack_len);
@@ -384,7 +385,7 @@ void display_render(struct display *display,
}
case RenderCommand_Repeat: {
- struct repeat_cmd *repeat_cmd = cmd->repeat;
+ struct repeat_cmd *repeat_cmd = cmd->data.repeat;
display_move_cursor(display, repeat_cmd->row + cl->yoffset,
repeat_cmd->col + cl->xoffset);
apply_fmt(fmt_stack, fmt_stack_len);
@@ -401,7 +402,7 @@ void display_render(struct display *display,
}
case RenderCommand_PushFormat: {
- struct push_fmt_cmd *fmt_cmd = cmd->push_fmt;
+ struct push_fmt_cmd *fmt_cmd = cmd->data.push_fmt;
fmt_stack[fmt_stack_len] = ';';
++fmt_stack_len;
@@ -416,11 +417,11 @@ void display_render(struct display *display,
break;
case RenderCommand_SetShowWhitespace:
- show_whitespace_state = cmd->show_ws->show;
+ show_whitespace_state = cmd->data.show_ws->show;
break;
case RenderCommand_DrawList:
- display_render(display, cmd->draw_list->list);
+ display_render(display, cmd->data.draw_list->list);
break;
}
}
@@ -430,7 +431,7 @@ void display_render(struct display *display,
timer_stop(render_timer);
}
-void hide_cursor() {
+void hide_cursor(void) {
putc(ESC, stdout);
putc('[', stdout);
putc('?', stdout);
@@ -439,7 +440,7 @@ void hide_cursor() {
putc('l', stdout);
}
-void show_cursor() {
+void show_cursor(void) {
putc(ESC, stdout);
putc('[', stdout);
putc('?', stdout);
@@ -448,8 +449,13 @@ void show_cursor() {
putc('h', stdout);
}
-void display_begin_render(struct display *display) { hide_cursor(); }
+void display_begin_render(struct display *display) {
+ (void)display;
+ hide_cursor();
+}
void display_end_render(struct display *display) {
+ (void)display;
+
show_cursor();
fflush(stdout);
}
diff --git a/src/dged/display.h b/src/dged/display.h
index f9c7ef8..950ab3c 100644
--- a/src/dged/display.h
+++ b/src/dged/display.h
@@ -13,7 +13,7 @@ struct command_list;
* The only implementation of this is currently a termios one.
* @returns A pointer to the display.
*/
-struct display *display_create();
+struct display *display_create(void);
/**
* Resize the display
diff --git a/src/dged/hash.c b/src/dged/hash.c
new file mode 100644
index 0000000..fce61af
--- /dev/null
+++ b/src/dged/hash.c
@@ -0,0 +1,20 @@
+#include "hash.h"
+
+uint32_t hash_name(const char *s) {
+ unsigned long hash = 5381;
+ int c;
+
+ while ((c = *s++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
+
+uint32_t hash_name_s8(struct s8 s) {
+ unsigned long hash = 5381;
+
+ for (uint64_t i = 0; i < s.l; ++i)
+ hash = ((hash << 5) + hash) + s.s[i]; /* hash * 33 + c */
+
+ return hash;
+}
diff --git a/src/dged/hash.h b/src/dged/hash.h
index 0fd689b..60b6d6a 100644
--- a/src/dged/hash.h
+++ b/src/dged/hash.h
@@ -1,11 +1,11 @@
+#ifndef _HASH_H
+#define _HASH_H
+
#include <stdint.h>
-static uint32_t hash_name(const char *s) {
- unsigned long hash = 5381;
- int c;
+#include "s8.h"
- while ((c = *s++))
- hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+uint32_t hash_name(const char *s);
+uint32_t hash_name_s8(struct s8 s);
- return hash;
-}
+#endif
diff --git a/src/dged/hashmap.h b/src/dged/hashmap.h
index 405c193..b8475c7 100644
--- a/src/dged/hashmap.h
+++ b/src/dged/hashmap.h
@@ -66,16 +66,16 @@
} \
var = res != NULL ? &(res->value) : NULL;
-#define HASHMAP_CONTAINS_KEY(map, key) \
- uint32_t needle = (map)->hash_fn(key); \
+#define HASHMAP_CONTAINS_KEY(map, type, k, var) \
+ uint32_t needle = (map)->hash_fn(k); \
bool exists = false; \
- VEC_FOR_EACH((map)->entries, struct pair *pair) { \
+ VEC_FOR_EACH(&(map)->entries, type *pair) { \
if (needle == pair->key) { \
exists = true; \
break; \
} \
} \
- exists
+ var = exists;
#define HASHMAP_FOR_EACH(map, var) VEC_FOR_EACH_INDEXED(&(map)->entries, var, i)
diff --git a/src/dged/json.c b/src/dged/json.c
new file mode 100644
index 0000000..24d5c15
--- /dev/null
+++ b/src/dged/json.c
@@ -0,0 +1,234 @@
+#include "json.h"
+
+#include "hash.h"
+#include "hashmap.h"
+#include "utf8.h"
+#include "vec.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+HASHMAP_ENTRY_TYPE(json_object_member, struct json_value);
+
+struct json_object {
+ HASHMAP(struct json_object_member) members;
+};
+
+struct json_array {
+ VEC(struct json_value) values;
+};
+
+static void setarray(struct json_value *val) {
+ val->type = Json_Array;
+ val->value.array = calloc(1, sizeof(struct json_array));
+ VEC_INIT(&val->value.array->values, 10);
+}
+
+static void setobject(struct json_value *val) {
+ val->type = Json_Object;
+ val->value.object = calloc(1, sizeof(struct json_object));
+ HASHMAP_INIT(&val->value.object->members, 10, hash_name);
+}
+
+static void setstring(struct json_value *val, uint8_t *current) {
+ val->type = Json_String;
+ val->value.string.s = current;
+ val->value.string.l = 0;
+}
+
+static bool is_number(uint8_t byte) { return byte >= '0' && byte <= '9'; }
+
+enum object_parse_state {
+ ObjectParseState_Key,
+ ObjectParseState_Value,
+};
+
+struct json_result json_parse(uint8_t *buf, uint64_t size) {
+ struct json_result res = {
+ .ok = true,
+ .result.document.type = Json_Null,
+ };
+
+ struct json_value *parent = NULL;
+ struct json_value *current = &res.result.document;
+ struct json_value tmp_key = {0};
+ struct json_value tmp_val = {0};
+ uint32_t line = 1, col = 0;
+
+ enum object_parse_state obj_parse_state = ObjectParseState_Key;
+ for (uint64_t bufi = 0; bufi < size; ++bufi) {
+ uint8_t byte = buf[bufi];
+
+ // handle appends to the current scope
+ if (current->type == Json_Array) {
+ VEC_PUSH(&current->value.array->values, tmp_val);
+ parent = current;
+
+ // start looking for next value
+ tmp_val.type = Json_Null;
+ current = &tmp_val;
+ } else if (current->type == Json_Object &&
+ obj_parse_state == ObjectParseState_Key) {
+ // key is in tmp_key, start looking for value
+ obj_parse_state = ObjectParseState_Value;
+ parent = current;
+
+ tmp_val.type = Json_Null;
+ current = &tmp_val;
+ } else if (current->type == Json_Object &&
+ obj_parse_state == ObjectParseState_Value) {
+ // value is in tmp_val
+ // TODO: remove this alloc, should not be needed
+ char *k = s8tocstr(tmp_key.value.string);
+ uint32_t hash = 0;
+ HASHMAP_INSERT(&current->value.object->members, struct json_object_member,
+ k, tmp_val, hash);
+ (void)hash;
+ free(k);
+
+ // start looking for next key
+ obj_parse_state = ObjectParseState_Key;
+ parent = current;
+
+ tmp_key.type = Json_Null;
+ current = &tmp_key;
+ }
+
+ switch (byte) {
+ case '[':
+ setarray(current);
+ parent = current;
+
+ tmp_val.type = Json_Null;
+ current = &tmp_val;
+ break;
+ case ']':
+ current = parent;
+ break;
+ case '{':
+ setobject(current);
+ obj_parse_state = ObjectParseState_Key;
+ parent = current;
+
+ tmp_key.type = Json_Null;
+ current = &tmp_key;
+ break;
+ case '}':
+ current = parent;
+ break;
+ case '"':
+ if (current->type == Json_String) {
+ // finish off the string
+ current->value.string.l = (buf + bufi) - current->value.string.s;
+ current = parent;
+ } else {
+ setstring(current, buf + bufi + 1 /* skip " */);
+ }
+ break;
+ case '\n':
+ ++line;
+ col = 0;
+ break;
+ default:
+ if (current->type == Json_String) {
+ // append to string
+ } else if (current->type == Json_Number &&
+ !(is_number(byte) || byte == '-' || byte == '.')) {
+ // end of number
+ current->value.string.l = (buf + bufi) - current->value.string.s;
+ char *nmbr = s8tocstr(current->value.string);
+ current->value.number = atof(nmbr);
+ free(nmbr);
+
+ current = parent;
+
+ } else if (current->type == Json_Null &&
+ (is_number(byte) || byte == '-' || byte == '.')) {
+ // borrow string storage in the value for storing number
+ // as a string
+ setstring(current, buf + bufi);
+ current->type = Json_Number;
+ } else if (byte == 't') {
+ current->type = Json_Bool;
+ current->value.boolean = true;
+
+ current = parent;
+ } else if (byte == 'f') {
+ current->type = Json_Bool;
+ current->value.boolean = false;
+
+ current = parent;
+ } else if (byte == 'n') {
+ current->type = Json_Null;
+
+ current = parent;
+ }
+ break;
+ }
+
+ // TODO: not entirely correct
+ ++col;
+ }
+ return res;
+}
+
+void json_destroy(struct json_value *value) {
+ switch (value->type) {
+ case Json_Array:
+ struct json_array *arr = value->value.array;
+ VEC_FOR_EACH(&arr->values, struct json_value * val) { json_destroy(val); }
+ VEC_DESTROY(&arr->values);
+ break;
+ case Json_Object:
+ struct json_object *obj = value->value.object;
+ HASHMAP_FOR_EACH(&obj->members, struct json_object_member * memb) {
+ json_destroy(&memb->value);
+ }
+
+ HASHMAP_DESTROY(&obj->members);
+ case Json_Null:
+ case Json_Number:
+ case Json_String:
+ case Json_Bool:
+ break;
+ }
+}
+
+uint64_t json_array_len(struct json_array *arr) {
+ return VEC_SIZE(&arr->values);
+}
+
+struct json_value *json_array_get(struct json_array *arr, uint64_t idx) {
+ struct json_value *ret = NULL;
+
+ if (idx <= VEC_SIZE(&arr->values)) {
+ ret = &VEC_ENTRIES(&arr->values)[idx];
+ }
+
+ return ret;
+}
+
+uint64_t json_len(struct json_object *obj) {
+ return HASHMAP_SIZE(&obj->members);
+}
+
+bool json_contains(struct json_object *obj, struct s8 key) {
+ // TODO: get rid of alloc
+ char *k = s8tocstr(key);
+ HASHMAP_CONTAINS_KEY(&obj->members, struct json_object_member, k, bool res);
+
+ free(k);
+
+ return res;
+}
+
+struct json_value *json_get(struct json_object *obj, struct s8 key) {
+ // TODO: get rid of alloc
+ char *k = s8tocstr(key);
+ HASHMAP_GET(&obj->members, struct json_object_member, k,
+ struct json_value * result);
+
+ free(k);
+
+ return result;
+}
diff --git a/src/dged/json.h b/src/dged/json.h
new file mode 100644
index 0000000..c0428b9
--- /dev/null
+++ b/src/dged/json.h
@@ -0,0 +1,54 @@
+#ifndef _JSON_H
+#define _JSON_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "s8.h"
+
+enum json_type {
+ Json_Array,
+ Json_Object,
+ Json_Null,
+ Json_Number,
+ Json_String,
+ Json_Bool,
+};
+
+struct json_value {
+ enum json_type type;
+ union {
+ struct s8 string;
+ struct json_object *object;
+ struct json_array *array;
+ double number;
+ bool boolean;
+ } value;
+};
+
+struct json_result {
+ bool ok;
+ union {
+ const char *error;
+ struct json_value document;
+ } result;
+};
+
+struct json_writer;
+
+struct json_result json_parse(uint8_t *buf, uint64_t size);
+void json_destroy(struct json_value *value);
+
+uint64_t json_len(struct json_object *obj);
+bool json_contains(struct json_object *obj, struct s8 key);
+struct json_value *json_get(struct json_object *obj, struct s8 key);
+
+uint64_t json_array_len(struct json_array *arr);
+void json_array_foreach(struct json_array *arr,
+ void (*cb)(uint64_t, struct json_value));
+struct json_value *json_array_get(struct json_array *arr, uint64_t idx);
+
+struct json_writer *json_writer_create();
+struct s8 json_writer_done(struct json_writer *writer);
+
+#endif
diff --git a/src/dged/lang.c b/src/dged/lang.c
index 070b96e..92b4fbd 100644
--- a/src/dged/lang.c
+++ b/src/dged/lang.c
@@ -19,17 +19,19 @@ void define_lang(const char *name, const char *id, const char *pattern,
_lang_setting_set_default(
id, "name",
(struct setting_value){.type = Setting_String,
- .string_value = (char *)name});
+ .data.string_value = (char *)name});
_lang_setting_set_default(
id, "pattern",
(struct setting_value){.type = Setting_String,
- .string_value = (char *)pattern});
- _lang_setting_set_default(id, "tab-width",
- (struct setting_value){.type = Setting_Number,
- .number_value = tab_width});
+ .data.string_value = (char *)pattern});
+ _lang_setting_set_default(
+ id, "tab-width",
+ (struct setting_value){.type = Setting_Number,
+ .data.number_value = tab_width});
_lang_setting_set_default(
id, "use-tabs",
- (struct setting_value){.type = Setting_Bool, .bool_value = use_tabs});
+ (struct setting_value){.type = Setting_Bool,
+ .data.bool_value = use_tabs});
}
static struct language g_fundamental = {
@@ -65,7 +67,8 @@ bool lang_is_fundamental(const struct language *lang) {
static struct language lang_from_settings(const char *id) {
struct setting *name = _lang_setting(id, "name");
- const char *name_value = name != NULL ? name->value.string_value : "Unknown";
+ const char *name_value =
+ name != NULL ? name->value.data.string_value : "Unknown";
return (struct language){
.id = strdup(id),
@@ -73,21 +76,6 @@ static struct language lang_from_settings(const char *id) {
};
}
-static void next_ext(const char *curr, const char **nxt, const char **end) {
- if (curr == NULL) {
- *nxt = *end = NULL;
- return;
- }
-
- *nxt = curr;
- *end = curr + strlen(curr);
-
- const char *spc = strchr(curr, ' ');
- if (spc != NULL) {
- *end = spc;
- }
-}
-
void lang_settings(struct language *lang, struct setting **settings[],
uint32_t *nsettings) {
const char *key = setting_join_key("languages", lang->id);
@@ -159,7 +147,7 @@ struct language lang_from_filename(const char *filename) {
struct setting *setting = settings[i];
char *setting_name = strrchr(setting->path, '.');
if (setting_name != NULL && strncmp(setting_name + 1, "pattern", 5) == 0) {
- const char *val = setting->value.string_value;
+ const char *val = setting->value.data.string_value;
regex_t regex;
if (regcomp(&regex, val, REG_EXTENDED) == 0 &&
regexec(&regex, filename, 0, NULL, 0) == 0) {
diff --git a/src/dged/lsp.c b/src/dged/lsp.c
new file mode 100644
index 0000000..3c699f4
--- /dev/null
+++ b/src/dged/lsp.c
@@ -0,0 +1,163 @@
+#include "lsp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "buffer.h"
+#include "process.h"
+#include "reactor.h"
+
+struct lsp {
+ const char *name;
+ char *const *command;
+ struct process *process;
+ struct reactor *reactor;
+ struct buffer *stderr_buffer;
+ struct lsp_client client_impl;
+ uint32_t stdin_event;
+ uint32_t stdout_event;
+ uint32_t stderr_event;
+};
+
+struct lsp *lsp_create(char *const command[], struct reactor *reactor,
+ struct buffer *stderr_buffer,
+ struct lsp_client client_impl, const char *name) {
+ // check length of command
+ if (command == NULL) {
+ return NULL;
+ }
+
+ uint32_t command_len = 0;
+ while (command[command_len] != NULL) {
+ ++command_len;
+ }
+
+ if (command_len == 0) {
+ return NULL;
+ }
+
+ struct lsp *lsp = calloc(1, sizeof(struct lsp));
+
+ char **cmd = calloc(command_len + 1, sizeof(const char *));
+ memcpy(cmd, command, sizeof(const char *) * command_len);
+ cmd[command_len] = NULL;
+ lsp->command = cmd;
+
+ if (name != NULL) {
+ lsp->name = strdup(name);
+ } else {
+#ifdef __unix__
+ const char *lslash = strrchr(lsp->command[0], '/');
+#elif defined(_WIN32) || defined(WIN32)
+ const char *lslash = strrchr(lsp->command[0], '\\');
+#endif
+ if (lslash == NULL) {
+ lsp->name = strdup(lsp->command[0]);
+ } else {
+ lsp->name = strdup(lslash + 1);
+ }
+ }
+ lsp->stderr_buffer = stderr_buffer;
+ lsp->client_impl = client_impl;
+ lsp->reactor = reactor;
+ lsp->stdin_event = -1;
+ lsp->stdout_event = -1;
+ lsp->stderr_event = -1;
+
+ return lsp;
+}
+
+void lsp_destroy(struct lsp *lsp) {
+ free((void *)lsp->name);
+ if (lsp->process != NULL) {
+ free(lsp->process);
+ }
+ if (lsp->command != NULL) {
+ char *command = lsp->command[0];
+ while (command != NULL) {
+ free(command);
+ ++command;
+ }
+
+ free((void *)lsp->command);
+ }
+ free(lsp);
+}
+
+uint32_t lsp_update(struct lsp *lsp, struct lsp_response **responses,
+ uint32_t responses_capacity) {
+
+ (void)responses;
+ (void)responses_capacity;
+
+ if (!lsp_server_running(lsp)) {
+ return -1;
+ }
+
+ // read stderr
+ if (lsp->stderr_event != (uint32_t)-1) {
+ uint8_t buf[1024];
+ if (reactor_poll_event(lsp->reactor, lsp->stderr_event)) {
+ ssize_t nb = 0;
+ while ((nb = read(lsp->process->stderr, buf, 1024)) > 0) {
+ buffer_set_readonly(lsp->stderr_buffer, false);
+ buffer_add(lsp->stderr_buffer, buffer_end(lsp->stderr_buffer), buf, nb);
+ buffer_set_readonly(lsp->stderr_buffer, true);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int lsp_start_server(struct lsp *lsp) {
+ struct process p;
+ struct process_create_result res = process_create(lsp->command, &p);
+
+ if (!res.ok) {
+ // TODO: losing error message here
+ return -1;
+ }
+
+ lsp->process = calloc(1, sizeof(struct process));
+ memcpy(lsp->process, &p, sizeof(struct process));
+ lsp->stderr_event = reactor_register_interest(
+ lsp->reactor, lsp->process->stderr, ReadInterest);
+
+ return 0;
+}
+
+int lsp_restart_server(struct lsp *lsp) {
+ if (lsp_server_running(lsp)) {
+ lsp_stop_server(lsp);
+ }
+
+ return lsp_start_server(lsp);
+}
+
+void lsp_stop_server(struct lsp *lsp) {
+ process_kill(lsp->process);
+ process_destroy(lsp->process);
+ free(lsp->process);
+ lsp->process = NULL;
+}
+
+bool lsp_server_running(const struct lsp *lsp) {
+ if (lsp->process == NULL) {
+ return false;
+ }
+
+ return process_running(lsp->process);
+}
+
+uint64_t lsp_server_pid(const struct lsp *lsp) {
+ if (!lsp_server_running(lsp)) {
+ return -1;
+ }
+
+ return lsp->process->id;
+}
+
+const char *lsp_server_name(const struct lsp *lsp) { return lsp->name; }
diff --git a/src/dged/lsp.h b/src/dged/lsp.h
new file mode 100644
index 0000000..3fd6285
--- /dev/null
+++ b/src/dged/lsp.h
@@ -0,0 +1,75 @@
+#ifndef _LSP_H
+#define _LSP_H
+
+#include "location.h"
+#include "s8.h"
+
+struct buffer;
+struct lsp;
+struct reactor;
+
+typedef uint32_t request_id;
+
+struct lsp_response {
+ request_id id;
+ bool ok;
+ union payload_data {
+ void *result;
+ struct s8 error;
+ } payload;
+};
+
+struct lsp_notification {
+ int something;
+};
+
+struct lsp_client {
+ void (*log_message)(int type, struct s8 msg);
+};
+
+struct hover {
+ struct s8 contents;
+
+ bool has_range;
+ struct region *range;
+};
+
+struct text_doc_item {
+ struct s8 uri;
+ struct s8 language_id;
+ uint32_t version;
+ struct s8 text;
+};
+
+struct text_doc_position {
+ struct s8 uri;
+ struct location pos;
+};
+
+struct initialize_params {
+ struct s8 client_name;
+ struct s8 client_version;
+};
+
+// lifecycle functions
+struct lsp *lsp_create(char *const command[], struct reactor *reactor,
+ struct buffer *stderr_buffer,
+ struct lsp_client client_impl, const char *name);
+uint32_t lsp_update(struct lsp *lsp, struct lsp_response **responses,
+ uint32_t responses_capacity);
+void lsp_destroy(struct lsp *lsp);
+
+// process control functions
+int lsp_start_server(struct lsp *lsp);
+int lsp_restart_server(struct lsp *lsp);
+void lsp_stop_server(struct lsp *lsp);
+bool lsp_server_running(const struct lsp *lsp);
+uint64_t lsp_server_pid(const struct lsp *lsp);
+const char *lsp_server_name(const struct lsp *lsp);
+
+// protocol functions
+void lsp_initialize(struct lsp *lsp, struct initialize_params);
+void lsp_did_open_document(struct lsp *lsp, struct text_doc_item document);
+request_id lsp_hover(struct lsp *lsp, struct text_doc_position);
+
+#endif
diff --git a/src/dged/minibuffer.c b/src/dged/minibuffer.c
index d31850b..c16a9bf 100644
--- a/src/dged/minibuffer.c
+++ b/src/dged/minibuffer.c
@@ -39,7 +39,7 @@ uint32_t minibuffer_draw_prompt(struct command_list *commands) {
static void minibuffer_abort_prompt_internal(bool clear);
-int32_t minibuffer_execute() {
+int32_t minibuffer_execute(void) {
if (g_minibuffer.prompt_active) {
struct command_ctx *c = &g_minibuffer.prompt_command_ctx;
@@ -50,7 +50,7 @@ int32_t minibuffer_execute() {
// propagate any saved arguments
char *argv[64];
- for (uint32_t i = 0; i < c->saved_argc; ++i) {
+ for (uint32_t i = 0; i < (uint32_t)c->saved_argc; ++i) {
argv[i] = (char *)c->saved_argv[i];
}
argv[c->saved_argc] = l;
@@ -79,6 +79,8 @@ int32_t minibuffer_execute() {
}
void update(struct buffer *buffer, void *userdata) {
+ (void)buffer;
+
struct timespec current;
struct minibuffer *mb = (struct minibuffer *)userdata;
clock_gettime(CLOCK_MONOTONIC, &current);
@@ -143,15 +145,15 @@ void message(const char *fmt, ...) {
nbytes > 2048 ? 2048 : nbytes);
}
-void minibuffer_destroy() {
+void minibuffer_destroy(void) {
command_ctx_free(&g_minibuffer.prompt_command_ctx);
}
-struct text_chunk minibuffer_content() {
+struct text_chunk minibuffer_content(void) {
return buffer_line(g_minibuffer.buffer, 0);
}
-struct buffer *minibuffer_buffer() {
+struct buffer *minibuffer_buffer(void) {
return g_minibuffer.buffer;
}
@@ -245,22 +247,22 @@ static void minibuffer_abort_prompt_internal(bool clear) {
g_minibuffer.prompt_active = false;
}
-void minibuffer_abort_prompt() { minibuffer_abort_prompt_internal(true); }
+void minibuffer_abort_prompt(void) { minibuffer_abort_prompt_internal(true); }
-bool minibuffer_empty() { return !minibuffer_displaying(); }
+bool minibuffer_empty(void) { return !minibuffer_displaying(); }
-bool minibuffer_displaying() {
+bool minibuffer_displaying(void) {
return g_minibuffer.buffer != NULL && !buffer_is_empty(g_minibuffer.buffer);
}
-void minibuffer_clear() {
+void minibuffer_clear(void) {
g_minibuffer.expires.tv_sec = 0;
g_minibuffer.expires.tv_nsec = 0;
buffer_clear(g_minibuffer.buffer);
}
-bool minibuffer_focused() { return g_minibuffer.prompt_active; }
+bool minibuffer_focused(void) { return g_minibuffer.prompt_active; }
-struct window *minibuffer_target_window() {
+struct window *minibuffer_target_window(void) {
return g_minibuffer.prev_window;
}
diff --git a/src/dged/minibuffer.h b/src/dged/minibuffer.h
index 6ac69c1..0b98904 100644
--- a/src/dged/minibuffer.h
+++ b/src/dged/minibuffer.h
@@ -24,11 +24,11 @@ void minibuffer_init(struct buffer *buffer, struct buffers *buffers);
*
* Note that this does not release the buffer used.
*/
-void minibuffer_destroy();
+void minibuffer_destroy(void);
-struct text_chunk minibuffer_content();
+struct text_chunk minibuffer_content(void);
-struct buffer *minibuffer_buffer();
+struct buffer *minibuffer_buffer(void);
void message(const char *fmt, ...);
@@ -74,14 +74,14 @@ uint32_t minibuffer_draw_prompt(struct command_list *commands);
*
* @returns zero on success, non-zero to indicate failure
*/
-int32_t minibuffer_execute();
+int32_t minibuffer_execute(void);
/**
* Abort the current minibuffer prompt.
*
* This returns focus to the previously focused window.
*/
-void minibuffer_abort_prompt();
+void minibuffer_abort_prompt(void);
/**
* Minibuffer prompt args
@@ -94,22 +94,22 @@ struct minibuffer_prompt_args {
/**
* Clear the current text in the minibuffer.
*/
-void minibuffer_clear();
+void minibuffer_clear(void);
-bool minibuffer_empty();
+bool minibuffer_empty(void);
/**
* Is the minibuffer currently displaying something?
*
* @returns True if the minibuffer is displaying anything, false otherwise.
*/
-bool minibuffer_displaying();
+bool minibuffer_displaying(void);
/**
* Is the minibuffer currently focused?
*
* @returns True if the minibuffer is currently focused, receiving user input.
*/
-bool minibuffer_focused();
+bool minibuffer_focused(void);
-struct window *minibuffer_target_window();
+struct window *minibuffer_target_window(void);
diff --git a/src/dged/path.c b/src/dged/path.c
new file mode 100644
index 0000000..735ef0c
--- /dev/null
+++ b/src/dged/path.c
@@ -0,0 +1,68 @@
+#include "path.h"
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *expanduser(const char *path) {
+ // replace tilde
+ char *res = NULL;
+ char *tilde_pos = strchr(path, '~');
+ if (tilde_pos != NULL) {
+ char *home = getenv("HOME");
+ if (home != NULL) {
+ // allocate a new string based with the new len
+ size_t home_len = strlen(home);
+ size_t path_len = strlen(path);
+ size_t total_len = path_len + home_len;
+ res = malloc(total_len);
+ size_t initial_len = tilde_pos - path;
+ strncpy(res, path, initial_len);
+
+ strncpy(res + initial_len, home, home_len + 1);
+
+ size_t rest_len = path_len - initial_len - 1;
+ strncpy(res + initial_len + home_len, path + initial_len + 1, rest_len);
+ res[total_len - 1] = '\0';
+ }
+ }
+
+ return res != NULL ? res : strdup(path);
+}
+
+char *to_abspath(const char *path) {
+ char *exp = expanduser(path);
+ char *p = realpath(path, NULL);
+ if (p != NULL) {
+ free(exp);
+ return p;
+ } else {
+ return exp;
+ }
+}
+
+const char *join_path_with_delim(const char *p1, const char *p2,
+ const char delim) {
+ size_t len1 = strlen(p1);
+ size_t len2 = strlen(p2);
+
+ char *path = malloc(len1 + len2 + 2);
+ uint32_t idx = 0;
+ memcpy(&path[idx], p1, len1);
+ idx += len1;
+ path[idx++] = delim;
+ memcpy(&path[idx], p2, len2);
+ idx += len2;
+ path[idx++] = '\0';
+
+ return path;
+}
+
+const char *join_path(const char *p1, const char *p2) {
+#ifdef __unix__
+ return join_path_with_delim(p1, p2, '/');
+#elif defined(_WIN32) || defined(WIN32)
+ return join_path_with_delim(p1, p2, '\\');
+#endif
+}
diff --git a/src/dged/path.h b/src/dged/path.h
index 8ea9977..6168e42 100644
--- a/src/dged/path.h
+++ b/src/dged/path.h
@@ -1,65 +1,10 @@
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
+#ifndef _PATH_H
+#define _PATH_H
-static char *expanduser(const char *path) {
- // replace tilde
- char *res = NULL;
- char *tilde_pos = strchr(path, '~');
- if (tilde_pos != NULL) {
- char *home = getenv("HOME");
- if (home != NULL) {
- // allocate a new string based with the new len
- size_t home_len = strlen(home);
- size_t path_len = strlen(path);
- size_t total_len = path_len + home_len;
- res = malloc(total_len);
- size_t initial_len = tilde_pos - path;
- strncpy(res, path, initial_len);
+char *expanduser(const char *path);
+char *to_abspath(const char *path);
+const char *join_path_with_delim(const char *p1, const char *p2,
+ const char delim);
+const char *join_path(const char *p1, const char *p2);
- strncpy(res + initial_len, home, home_len);
-
- size_t rest_len = path_len - initial_len - 1;
- strncpy(res + initial_len + home_len, path + initial_len + 1, rest_len);
- res[total_len - 1] = '\0';
- }
- }
-
- return res != NULL ? res : strdup(path);
-}
-
-static char *to_abspath(const char *path) {
- char *exp = expanduser(path);
- char *p = realpath(path, NULL);
- if (p != NULL) {
- free(exp);
- return p;
- } else {
- return exp;
- }
-}
-
-static const char *join_path_with_delim(const char *p1, const char *p2,
- const char delim) {
- size_t len1 = strlen(p1);
- size_t len2 = strlen(p2);
-
- char *path = malloc(len1 + len2 + 2);
- uint32_t idx = 0;
- memcpy(&path[idx], p1, len1);
- idx += len1;
- path[idx++] = '/';
- memcpy(&path[idx], p2, len2);
- idx += len2;
- path[idx++] = '\0';
-
- return path;
-}
-
-static const char *join_path(const char *p1, const char *p2) {
-#ifdef __unix__
- return join_path_with_delim(p1, p2, '/');
-#elif defined(_WIN32) || defined(WIN32)
- return join_path_with_delim(p1, p2, '\\');
#endif
-}
diff --git a/src/dged/process-posix.c b/src/dged/process-posix.c
new file mode 100644
index 0000000..94ceb5f
--- /dev/null
+++ b/src/dged/process-posix.c
@@ -0,0 +1,126 @@
+#include "process.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static int create_pipe(int *read_end, int *write_end, bool read_nonblock,
+ bool write_nonblock) {
+ int pipes[2] = {0};
+ if (pipe(pipes) < 0) {
+ return -1;
+ }
+
+ if (write_nonblock) {
+ int flags = fcntl(pipes[1], F_GETFL, 0);
+ if (flags < 0) {
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ if (fcntl(pipes[1], F_SETFL, flags) < 0) {
+ return -1;
+ }
+ }
+
+ if (read_nonblock) {
+ int flags = fcntl(pipes[0], F_GETFL, 0);
+ if (flags < 0) {
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ if (fcntl(pipes[0], F_SETFL, flags) < 0) {
+ return -1;
+ }
+ }
+
+ *read_end = pipes[0];
+ *write_end = pipes[1];
+
+ return 0;
+}
+
+struct process_create_result process_create(char *const command[],
+ struct process *result) {
+
+ int stdin_read, stdin_write;
+ if (create_pipe(&stdin_read, &stdin_write, false, true) < 0) {
+ return (struct process_create_result){
+ .ok = false,
+ .error_message = strerror(errno),
+ };
+ }
+
+ int stdout_read, stdout_write;
+ if (create_pipe(&stdout_read, &stdout_write, true, false) < 0) {
+ return (struct process_create_result){
+ .ok = false,
+ .error_message = strerror(errno),
+ };
+ }
+
+ int stderr_read, stderr_write;
+ if (create_pipe(&stderr_read, &stderr_write, true, false) < 0) {
+ return (struct process_create_result){
+ .ok = false,
+ .error_message = strerror(errno),
+ };
+ }
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ return (struct process_create_result){
+ .ok = false,
+ .error_message = strerror(errno),
+ };
+ } else if (pid == 0) {
+ close(stdin_write);
+ close(stdout_read);
+ close(stderr_read);
+
+ if (dup2(stdin_read, STDIN_FILENO) < 0) {
+ exit(16);
+ }
+
+ if (dup2(stdout_write, STDOUT_FILENO) < 0) {
+ exit(16);
+ }
+
+ if (dup2(stderr_write, STDERR_FILENO) < 0) {
+ exit(16);
+ }
+
+ if (execvp(command[0], command) < 0) {
+ exit(16);
+ }
+ } else {
+ close(stdin_read);
+ close(stdout_write);
+ close(stderr_write);
+
+ result->stdin = stdin_write;
+ result->stdout = stdout_read;
+ result->stderr = stderr_read;
+ result->id = (fd_t)pid;
+ result->impl = NULL;
+ }
+
+ return (struct process_create_result){
+ .ok = true,
+ };
+}
+
+void process_destroy(struct process *p) { (void)p; }
+
+bool process_running(const struct process *p) {
+ return waitpid(p->id, NULL, WNOHANG) == 0;
+}
+
+bool process_kill(const struct process *p) { return kill(p->id, SIGTERM) == 0; }
diff --git a/src/dged/process.h b/src/dged/process.h
new file mode 100644
index 0000000..cefec8c
--- /dev/null
+++ b/src/dged/process.h
@@ -0,0 +1,35 @@
+#ifndef _PROCESS_H
+#define _PROCESS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef _WIN32
+typedef HANDLE fd_t;
+#else
+typedef int fd_t;
+#endif
+
+struct platform_process;
+struct process {
+ uint64_t id;
+ fd_t stdin;
+ fd_t stdout;
+ fd_t stderr;
+ struct platform_process *impl;
+};
+
+struct process_create_result {
+ bool ok;
+ const char *error_message;
+};
+
+struct process_create_result process_create(char *const command[],
+ struct process *result);
+
+void process_destroy(struct process *p);
+
+bool process_running(const struct process *p);
+bool process_kill(const struct process *p);
+
+#endif
diff --git a/src/dged/reactor-epoll.c b/src/dged/reactor-epoll.c
index 4c83b49..beee7ec 100644
--- a/src/dged/reactor-epoll.c
+++ b/src/dged/reactor-epoll.c
@@ -22,15 +22,15 @@ struct events {
uint32_t nevents;
};
-struct reactor *reactor_create() {
+struct reactor *reactor_create(void) {
int epollfd = epoll_create1(0);
if (epollfd == -1) {
- perror("epoll_create1");
+ return NULL;
}
int inotifyfd = inotify_init1(IN_NONBLOCK);
if (inotifyfd == -1) {
- perror("inotify_init1");
+ return NULL;
}
struct reactor *r = (struct reactor *)calloc(1, sizeof(struct reactor));
@@ -55,7 +55,6 @@ uint32_t reactor_register_interest(struct reactor *reactor, int fd,
ev.events |= (interest & WriteInterest) != 0 ? EPOLLOUT : 0;
ev.data.fd = fd;
if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
- perror("epoll_ctl");
return -1;
}
@@ -71,7 +70,7 @@ bool reactor_poll_event(struct reactor *reactor, uint32_t ev_id) {
for (uint32_t ei = 0; ei < events->nevents; ++ei) {
struct epoll_event *ev = &events->events[ei];
- if (ev->data.fd == ev_id) {
+ if ((uint32_t)ev->data.fd == ev_id) {
return true;
}
}
@@ -118,7 +117,8 @@ void reactor_update(struct reactor *reactor) {
int nfds = epoll_wait(reactor->epoll_fd, events->events, 10, -1);
if (nfds == -1) {
- // TODO: log failure
+ events->nevents = 0;
+ message("failed update epoll reactor: %s", strerror(errno));
}
events->nevents = nfds;
diff --git a/src/dged/reactor-kqueue.c b/src/dged/reactor-kqueue.c
index 58ab7af..f30cb9a 100644
--- a/src/dged/reactor-kqueue.c
+++ b/src/dged/reactor-kqueue.c
@@ -16,7 +16,7 @@ struct reactor {
uint32_t nevents;
};
-struct reactor *reactor_create() {
+struct reactor *reactor_create(void) {
int queue = kqueue();
if (queue < 0) {
return NULL;
diff --git a/src/dged/reactor.h b/src/dged/reactor.h
index 39a94a9..82ff3fe 100644
--- a/src/dged/reactor.h
+++ b/src/dged/reactor.h
@@ -18,7 +18,7 @@ struct file_event {
struct reactor;
-struct reactor *reactor_create();
+struct reactor *reactor_create(void);
void reactor_destroy(struct reactor *reactor);
void reactor_update(struct reactor *reactor);
bool reactor_poll_event(struct reactor *reactor, uint32_t ev_id);
diff --git a/src/dged/settings.c b/src/dged/settings.c
index e63862f..68256e8 100644
--- a/src/dged/settings.c
+++ b/src/dged/settings.c
@@ -20,11 +20,11 @@ void settings_init(uint32_t initial_capacity) {
HASHMAP_INIT(&g_settings.settings, initial_capacity, hash_name);
}
-void settings_destroy() {
+void settings_destroy(void) {
HASHMAP_FOR_EACH(&g_settings.settings, struct setting_entry * entry) {
struct setting *setting = &entry->value;
if (setting->value.type == Setting_String) {
- free(setting->value.string_value);
+ free(setting->value.data.string_value);
}
}
@@ -33,8 +33,9 @@ void settings_destroy() {
void setting_set_value(struct setting *setting, struct setting_value val) {
if (setting->value.type == val.type) {
- if (setting->value.type == Setting_String && val.string_value != NULL) {
- setting->value.string_value = strdup(val.string_value);
+ if (setting->value.type == Setting_String &&
+ val.data.string_value != NULL) {
+ setting->value.data.string_value = strdup(val.data.string_value);
} else {
setting->value = val;
}
@@ -99,13 +100,13 @@ void settings_set_default(const char *path, struct setting_value value) {
void setting_to_string(struct setting *setting, char *buf, size_t n) {
switch (setting->value.type) {
case Setting_Bool:
- snprintf(buf, n, "%s", setting->value.bool_value ? "true" : "false");
+ snprintf(buf, n, "%s", setting->value.data.bool_value ? "true" : "false");
break;
case Setting_Number:
- snprintf(buf, n, "%" PRId64, setting->value.number_value);
+ snprintf(buf, n, "%" PRId64, setting->value.data.number_value);
break;
case Setting_String:
- snprintf(buf, n, "%s", setting->value.string_value);
+ snprintf(buf, n, "%s", setting->value.data.string_value);
break;
}
}
@@ -113,7 +114,6 @@ void setting_to_string(struct setting *setting, char *buf, size_t n) {
static int32_t parse_toml(struct parser *state, char **errmsgs[]) {
char *curtbl = NULL;
char *curkey = NULL;
- uint32_t errcnt = 0;
VEC(char *) errs;
VEC_INIT(&errs, 16);
@@ -160,20 +160,20 @@ static int32_t parse_toml(struct parser *state, char **errmsgs[]) {
case Token_IntValue:
i = *((int64_t *)t.data);
settings_set(curkey, (struct setting_value){.type = Setting_Number,
- .number_value = i});
+ .data.number_value = i});
break;
case Token_BoolValue:
b = *((bool *)t.data);
settings_set(curkey, (struct setting_value){.type = Setting_Bool,
- .bool_value = b});
+ .data.bool_value = b});
break;
case Token_StringValue:
v = calloc(t.len + 1, 1);
strncpy(v, (char *)t.data, t.len);
settings_set(curkey, (struct setting_value){.type = Setting_String,
- .string_value = v});
+ .data.string_value = v});
free(v);
break;
diff --git a/src/dged/settings.h b/src/dged/settings.h
index b88e483..fb79c75 100644
--- a/src/dged/settings.h
+++ b/src/dged/settings.h
@@ -26,7 +26,7 @@ struct setting_value {
/** Type of setting. */
enum setting_type type;
- union {
+ union setting_data {
/** String setting. */
char *string_value;
@@ -35,7 +35,7 @@ struct setting_value {
/** Boolean setting value. */
bool bool_value;
- };
+ } data;
};
/**
@@ -73,7 +73,7 @@ void settings_init(uint32_t initial_capacity);
/**
* Destroy the global collection of settings.
*/
-void settings_destroy();
+void settings_destroy(void);
/**
* Retrieve a single setting by path.
diff --git a/src/dged/syntax.c b/src/dged/syntax.c
index 569dc70..67ab3a2 100644
--- a/src/dged/syntax.c
+++ b/src/dged/syntax.c
@@ -48,6 +48,8 @@ struct highlight {
};
static void delete_parser(struct buffer *buffer, void *userdata) {
+ (void)buffer;
+
struct highlight *highlight = (struct highlight *)userdata;
if (highlight->query != NULL) {
@@ -72,6 +74,7 @@ static void delete_parser(struct buffer *buffer, void *userdata) {
static const char *read_text(void *payload, uint32_t byte_offset,
TSPoint position, uint32_t *bytes_read) {
+ (void)byte_offset;
struct text *text = (struct text *)payload;
@@ -97,7 +100,7 @@ static const char *read_text(void *payload, uint32_t byte_offset,
static const char *grammar_name_from_buffer(struct buffer *buffer) {
struct setting *s = lang_setting(&buffer->lang, "grammar");
if (s != NULL && s->value.type == Setting_String) {
- return s->value.string_value;
+ return s->value.data.string_value;
}
return buffer->lang.name;
@@ -124,6 +127,10 @@ static const char *lang_folder(struct buffer *buffer, const char *path) {
static bool eval_eq(struct s8 capname, uint32_t argc, struct s8 argv[],
struct s8 value, void *data) {
+ (void)capname;
+ (void)argc;
+ (void)argv;
+
const struct s8 *cmp_to = (const struct s8 *)data;
if (data == NULL) {
return false;
@@ -143,6 +150,10 @@ static void cleanup_eq(void *data) {
static bool eval_match(struct s8 capname, uint32_t argc, struct s8 argv[],
struct s8 value, void *data) {
+ (void)capname;
+ (void)argc;
+ (void)argv;
+
regex_t *regex = (regex_t *)data;
if (regex == NULL) {
return false;
@@ -325,6 +336,8 @@ static void update_parser(struct buffer *buffer, void *userdata,
struct location origin, uint32_t width,
uint32_t height) {
+ (void)width;
+
struct highlight *h = (struct highlight *)userdata;
if (h->query == NULL) {
@@ -411,7 +424,7 @@ static void update_parser(struct buffer *buffer, void *userdata,
end.column > 0 ? end.column - 1 : 0,
(struct text_property){
.type = TextProperty_Colors,
- .colors =
+ .data.colors =
(struct text_property_colors){
.set_fg = true,
.fg = color,
@@ -509,8 +522,9 @@ static void text_inserted(struct buffer *buffer, struct edit_location inserted,
}
static void create_parser(struct buffer *buffer, void *userdata) {
+ (void)userdata;
- TSLanguage *(*langsym)() = NULL;
+ TSLanguage *(*langsym)(void) = NULL;
const char *lang_root = NULL, *langname = NULL;
void *h = NULL;
@@ -601,7 +615,7 @@ void syntax_init(uint32_t grammar_path_len, const char *grammar_path[]) {
lang_setting_set_default(
&l, "grammar",
(struct setting_value){.type = Setting_String,
- .string_value = "gitcommit"});
+ .data.string_value = "gitcommit"});
lang_destroy(&l);
}
@@ -609,14 +623,15 @@ void syntax_init(uint32_t grammar_path_len, const char *grammar_path[]) {
if (!lang_is_fundamental(&l)) {
lang_setting_set_default(
&l, "grammar",
- (struct setting_value){.type = Setting_String, .string_value = "cpp"});
+ (struct setting_value){.type = Setting_String,
+ .data.string_value = "cpp"});
lang_destroy(&l);
}
buffer_add_create_hook(create_parser, NULL);
}
-void syntax_teardown() {
+void syntax_teardown(void) {
for (uint32_t i = 0; i < treesitter_path_len; ++i) {
free((void *)treesitter_path[i]);
}
diff --git a/src/dged/syntax.h b/src/dged/syntax.h
index 488406b..015f5be 100644
--- a/src/dged/syntax.h
+++ b/src/dged/syntax.h
@@ -4,6 +4,6 @@
#include <stdint.h>
void syntax_init(uint32_t grammar_path_len, const char *grammar_path[]);
-void syntax_teardown();
+void syntax_teardown(void);
#endif
diff --git a/src/dged/text.h b/src/dged/text.h
index 28bd325..505c86a 100644
--- a/src/dged/text.h
+++ b/src/dged/text.h
@@ -66,10 +66,10 @@ struct text_property_colors {
struct text_property {
enum text_property_type type;
- union {
+ union property_data {
struct text_property_colors colors;
void *userdata;
- };
+ } data;
};
void text_add_property(struct text *text, uint32_t start_line,
diff --git a/src/dged/timers.c b/src/dged/timers.c
index 798c003..2fd5fc9 100644
--- a/src/dged/timers.c
+++ b/src/dged/timers.c
@@ -23,21 +23,21 @@ static struct timers {
HASHMAP(struct timer_entry) timers;
} g_timers;
-void timers_init() {
+void timers_init(void) {
HASHMAP_INIT(&g_timers.timers, 32, hash_name);
g_timers.frame_index = 0;
}
-void timers_destroy() { HASHMAP_DESTROY(&g_timers.timers); }
+void timers_destroy(void) { HASHMAP_DESTROY(&g_timers.timers); }
-void timers_start_frame() {
+void timers_start_frame(void) {
HASHMAP_FOR_EACH(&g_timers.timers, struct timer_entry * entry) {
struct timer *timer = &entry->value;
timer->samples[g_timers.frame_index] = 0;
}
}
-void timers_end_frame() {
+void timers_end_frame(void) {
g_timers.frame_index = (g_timers.frame_index + 1) % NUM_FRAME_SAMPLES;
}
diff --git a/src/dged/timers.h b/src/dged/timers.h
index ae79a8b..03ec742 100644
--- a/src/dged/timers.h
+++ b/src/dged/timers.h
@@ -5,8 +5,8 @@
struct timer;
-void timers_init();
-void timers_start_frame();
+void timers_init(void);
+void timers_start_frame(void);
struct timer *timer_start(const char *name);
uint64_t timer_stop(struct timer *timer);
@@ -19,7 +19,7 @@ const char *timer_name(const struct timer *timer);
typedef void (*timer_callback)(const struct timer *timer, void *userdata);
void timers_for_each(timer_callback callback, void *userdata);
-void timers_end_frame();
-void timers_destroy();
+void timers_end_frame(void);
+void timers_destroy(void);
#endif
diff --git a/src/dged/undo.c b/src/dged/undo.c
index 8f00f0f..ad167c3 100644
--- a/src/dged/undo.c
+++ b/src/dged/undo.c
@@ -18,9 +18,9 @@ void undo_clear(struct undo_stack *undo) {
void undo_destroy(struct undo_stack *undo) {
VEC_FOR_EACH(&undo->records, struct undo_record * rec) {
- if (rec->type == Undo_Delete && rec->delete.data != NULL &&
- rec->delete.nbytes > 0) {
- free(rec->delete.data);
+ if (rec->type == Undo_Delete && rec->data.delete.data != NULL &&
+ rec->data.delete.nbytes > 0) {
+ free(rec->data.delete.data);
}
}
@@ -35,15 +35,15 @@ uint32_t undo_push_boundary(struct undo_stack *undo,
// we can only have one save point
if (boundary.save_point) {
VEC_FOR_EACH(&undo->records, struct undo_record * rec) {
- if (rec->type == Undo_Boundary && rec->boundary.save_point) {
- rec->boundary.save_point = false;
+ if (rec->type == Undo_Boundary && rec->data.boundary.save_point) {
+ rec->data.boundary.save_point = false;
}
}
}
VEC_APPEND(&undo->records, struct undo_record * rec);
rec->type = Undo_Boundary;
- rec->boundary = boundary;
+ rec->data.boundary = boundary;
if (!undo->undo_in_progress) {
undo->top = VEC_SIZE(&undo->records) - 1;
@@ -61,12 +61,12 @@ uint32_t undo_push_add(struct undo_stack *undo, struct undo_add add) {
// "compress"
if (!VEC_EMPTY(&undo->records) &&
VEC_BACK(&undo->records)->type == Undo_Add &&
- pos_equal(&VEC_BACK(&undo->records)->add.end, &add.begin)) {
- VEC_BACK(&undo->records)->add.end = add.end;
+ pos_equal(&VEC_BACK(&undo->records)->data.add.end, &add.begin)) {
+ VEC_BACK(&undo->records)->data.add.end = add.end;
} else {
VEC_APPEND(&undo->records, struct undo_record * rec);
rec->type = Undo_Add;
- rec->add = add;
+ rec->data.add = add;
}
if (!undo->undo_in_progress) {
@@ -79,7 +79,7 @@ uint32_t undo_push_add(struct undo_stack *undo, struct undo_add add) {
uint32_t undo_push_delete(struct undo_stack *undo, struct undo_delete delete) {
VEC_APPEND(&undo->records, struct undo_record * rec);
rec->type = Undo_Delete;
- rec->delete = delete;
+ rec->data.delete = delete;
if (!undo->undo_in_progress) {
undo->top = VEC_SIZE(&undo->records) - 1;
@@ -150,15 +150,15 @@ size_t rec_to_str(struct undo_record *rec, char *buffer, size_t n) {
switch (rec->type) {
case Undo_Add:
return snprintf(buffer, n, "add { begin: (%d, %d) end: (%d, %d)}",
- rec->add.begin.row, rec->add.begin.col, rec->add.end.row,
- rec->add.end.col);
+ rec->data.add.begin.row, rec->data.add.begin.col,
+ rec->data.add.end.row, rec->data.add.end.col);
case Undo_Delete:
return snprintf(buffer, n, "delete { pos: (%d, %d), ptr: 0x%p, nbytes: %d}",
- rec->delete.pos.row, rec->delete.pos.col, rec->delete.data,
- rec->delete.nbytes);
+ rec->data.delete.pos.row, rec->data.delete.pos.col,
+ (void *)rec->data.delete.data, rec->data.delete.nbytes);
default:
return snprintf(buffer, n, "boundary { save_point: %s }",
- rec->boundary.save_point ? "yes" : "no");
+ rec->data.boundary.save_point ? "yes" : "no");
}
}
diff --git a/src/dged/undo.h b/src/dged/undo.h
index 1ce3a8a..2f308f9 100644
--- a/src/dged/undo.h
+++ b/src/dged/undo.h
@@ -31,14 +31,14 @@ struct undo_delete {
struct undo_record {
enum undo_record_type type;
- union {
+ union undo_record_data {
struct undo_boundary boundary;
struct undo_add add;
struct undo_delete delete;
- };
+ } data;
};
-#define INVALID_TOP -1
+#define INVALID_TOP (uint32_t) - 1
struct undo_stack {
VEC(struct undo_record) records;
diff --git a/src/dged/utf8.c b/src/dged/utf8.c
index ede4fb1..01dcdbd 100644
--- a/src/dged/utf8.c
+++ b/src/dged/utf8.c
@@ -112,7 +112,6 @@ uint32_t utf8_nchars(uint8_t *bytes, uint32_t nbytes) {
uint32_t utf8_nbytes(uint8_t *bytes, uint32_t nbytes, uint32_t nchars) {
uint32_t bi = 0;
uint32_t chars = 0;
- uint32_t expected = 0;
while (chars < nchars && bi < nbytes) {
struct codepoint codepoint = next_utf8_codepoint(bytes + bi, nbytes - bi);
@@ -127,7 +126,7 @@ uint32_t utf8_nbytes(uint8_t *bytes, uint32_t nbytes, uint32_t nchars) {
uint32_t unicode_visual_char_width(const struct codepoint *codepoint) {
if (codepoint->nbytes > 0) {
// TODO: use unicode classification instead
- size_t w = wcwidth(codepoint->codepoint);
+ int w = wcwidth(codepoint->codepoint);
return w >= 0 ? w : 2;
} else {
return 0;
diff --git a/src/dged/vec.h b/src/dged/vec.h
index 929c8d5..1289a08 100644
--- a/src/dged/vec.h
+++ b/src/dged/vec.h
@@ -48,8 +48,7 @@
}
#define VEC_SWAP(vec, idx1, idx2) \
- if (idx1 < (vec)->nentries && idx2 < (vec)->nentries && idx1 >= 0 && \
- idx2 >= 0) { \
+ if (idx1 < (vec)->nentries && idx2 < (vec)->nentries) { \
*((vec)->temp) = (vec)->entries[idx1]; \
(vec)->entries[idx1] = (vec)->entries[idx2]; \
(vec)->entries[idx2] = *((vec)->temp); \
diff --git a/src/dged/window.c b/src/dged/window.c
index 20cb22f..702f97a 100644
--- a/src/dged/window.c
+++ b/src/dged/window.c
@@ -124,25 +124,25 @@ static void window_tree_clear_sub(struct window_node *root_node) {
BINTREE_FREE_NODES(root_node, window_node);
}
-static void window_tree_clear() {
+static void window_tree_clear(void) {
window_tree_clear_sub(BINTREE_ROOT(&g_windows.windows));
}
-void windows_destroy() { window_tree_clear(); }
+void windows_destroy(void) { window_tree_clear(); }
-struct window *root_window() {
+struct window *root_window(void) {
return &BINTREE_VALUE(BINTREE_ROOT(&g_windows.windows));
}
-struct window *minibuffer_window() {
+struct window *minibuffer_window(void) {
return &g_minibuffer_window;
}
-struct window *popup_window() {
+struct window *popup_window(void) {
return &g_popup_window;
}
-bool popup_window_visible() { return g_popup_visible; }
+bool popup_window_visible(void) { return g_popup_visible; }
static void window_tree_resize(struct window_node *root, uint32_t height,
uint32_t width) {
@@ -412,7 +412,7 @@ struct window *window_find_by_buffer(struct buffer *b) {
return NULL;
}
-struct window *windows_get_active() {
+struct window *windows_get_active(void) {
return g_windows.active;
}
@@ -630,7 +630,7 @@ void window_split(struct window *window, struct window **new_window_a,
: window_vsplit(window, new_window_a, new_window_b);
}
-struct window *windows_focus_next() {
+struct window *windows_focus_next(void) {
struct window *active = windows_get_active();
struct window_node *n = find_window(active);
BINTREE_NEXT(n);
@@ -693,4 +693,4 @@ void windows_show_popup(uint32_t row, uint32_t col, uint32_t width,
g_popup_visible = true;
}
-void windows_close_popup() { g_popup_visible = false; }
+void windows_close_popup(void) { g_popup_visible = false; }
diff --git a/src/dged/window.h b/src/dged/window.h
index e1b1d25..7738e16 100644
--- a/src/dged/window.h
+++ b/src/dged/window.h
@@ -25,20 +25,20 @@ void windows_init(uint32_t height, uint32_t width,
struct buffer *initial_buffer, struct buffer *minibuffer,
struct buffers *buffers);
-void windows_destroy();
+void windows_destroy(void);
void windows_resize(uint32_t height, uint32_t width);
void windows_update(void *(*frame_alloc)(size_t), float frame_time);
void windows_render(struct display *display);
-struct window *root_window();
-struct window *minibuffer_window();
-struct window *popup_window();
-bool popup_window_visible();
+struct window *root_window(void);
+struct window *minibuffer_window(void);
+struct window *popup_window(void);
+bool popup_window_visible(void);
void windows_set_active(struct window *window);
struct window *windows_focus(uint32_t id);
-struct window *windows_get_active();
-struct window *windows_focus_next();
+struct window *windows_get_active(void);
+struct window *windows_focus_next(void);
struct window *window_find_by_buffer(struct buffer *b);
void window_set_buffer(struct window *window, struct buffer *buffer);
@@ -63,6 +63,6 @@ void window_vsplit(struct window *window, struct window **new_window_a,
void windows_show_popup(uint32_t row, uint32_t col, uint32_t width,
uint32_t height);
-void windows_close_popup();
+void windows_close_popup(void);
#endif
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.