diff options
Diffstat (limited to 'src/dged')
38 files changed, 997 insertions, 276 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 |
