diff options
Diffstat (limited to 'src')
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(¤t->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(¤t->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(®ex, val, REG_EXTENDED) == 0 && regexec(®ex, 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, ¤t); @@ -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. |
