summaryrefslogtreecommitdiff
path: root/src/dged/buffer_view.c
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-09-17 08:47:03 +0200
committerAlbert Cervin <albert@acervin.com>2025-11-01 22:11:14 +0100
commit4459b8b3aa9d73895391785a99dcc87134e80601 (patch)
treea5204f447a0b2b05f63504c7fe958ef9bbf1918a /src/dged/buffer_view.c
parent4689f3f38277bb64981fc960e8e384e2d065d659 (diff)
downloaddged-4459b8b3aa9d73895391785a99dcc87134e80601.tar.gz
dged-4459b8b3aa9d73895391785a99dcc87134e80601.tar.xz
dged-4459b8b3aa9d73895391785a99dcc87134e80601.zip
More lsp support
This makes the LSP support complete for now: - Completion - Diagnostics - Goto implementation/declaration - Rename - Documentation - Find references
Diffstat (limited to 'src/dged/buffer_view.c')
-rw-r--r--src/dged/buffer_view.c170
1 files changed, 109 insertions, 61 deletions
diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c
index a9bbe19..9d998fe 100644
--- a/src/dged/buffer_view.c
+++ b/src/dged/buffer_view.c
@@ -7,10 +7,10 @@
#include "timers.h"
#include "utf8.h"
-struct modeline {
- uint8_t *buffer;
- uint32_t sz;
-};
+HOOK_IMPL(modeline, modeline_hook_cb);
+
+static modeline_hook_vec g_modeline_hooks = {0};
+static uint32_t g_modeline_hook_id = 0;
static bool maybe_delete_region(struct buffer_view *view) {
struct region reg = region_new(view->dot, view->mark);
@@ -32,18 +32,11 @@ struct buffer_view buffer_view_create(struct buffer *buffer, bool modeline,
.mark_set = false,
.scroll = (struct location){.line = 0, .col = 0},
.buffer = buffer,
- .modeline = NULL,
+ .modeline = modeline,
.line_numbers = line_numbers,
.fringe_width = 0,
};
- if (modeline) {
- v.modeline = calloc(1, sizeof(struct modeline));
- v.modeline->buffer = malloc(1024);
- v.modeline->sz = 1024;
- v.modeline->buffer[0] = '\0';
- }
-
return v;
}
@@ -54,32 +47,22 @@ struct buffer_view buffer_view_clone(const struct buffer_view *view) {
.mark_set = view->mark_set,
.scroll = view->scroll,
.buffer = view->buffer,
- .modeline = NULL,
+ .modeline = view->modeline,
.line_numbers = view->line_numbers,
};
- if (view->modeline) {
- c.modeline = calloc(1, sizeof(struct modeline));
- c.modeline->buffer = malloc(view->modeline->sz);
- memcpy(c.modeline->buffer, view->modeline->buffer, view->modeline->sz);
- }
-
return c;
}
-void buffer_view_destroy(struct buffer_view *view) {
- if (view->modeline != NULL) {
- free(view->modeline->buffer);
- free(view->modeline);
- view->modeline = NULL;
- }
-
- view->buffer = NULL;
-}
+void buffer_view_destroy(struct buffer_view *view) { view->buffer = NULL; }
void buffer_view_add(struct buffer_view *view, uint8_t *txt, uint32_t nbytes) {
maybe_delete_region(view);
+ struct location before = view->dot;
view->dot = buffer_add(view->buffer, view->dot, txt, nbytes);
+ if (view->dot.line > before.line) {
+ buffer_push_undo_boundary(view->buffer);
+ }
}
void buffer_view_goto_beginning(struct buffer_view *view) {
@@ -107,7 +90,11 @@ void buffer_view_forward_word(struct buffer_view *view) {
}
void buffer_view_backward_word(struct buffer_view *view) {
+ struct location before = view->dot;
view->dot = buffer_previous_word(view->buffer, view->dot);
+ if (before.col == 0 && view->dot.col == 0) {
+ buffer_view_backward_char(view);
+ }
}
void buffer_view_forward_line(struct buffer_view *view) {
@@ -138,6 +125,7 @@ void buffer_view_goto_beginning_of_line(struct buffer_view *view) {
void buffer_view_newline(struct buffer_view *view) {
view->dot = buffer_newline(view->buffer, view->dot);
+ buffer_push_undo_boundary(view->buffer);
}
void buffer_view_indent(struct buffer_view *view) {
@@ -202,6 +190,7 @@ void buffer_view_paste_older(struct buffer_view *view) {
}
void buffer_view_forward_delete_char(struct buffer_view *view) {
+ buffer_push_undo_boundary(view->buffer);
if (maybe_delete_region(view)) {
return;
}
@@ -209,9 +198,11 @@ void buffer_view_forward_delete_char(struct buffer_view *view) {
view->dot = buffer_delete(
view->buffer,
region_new(view->dot, buffer_next_char(view->buffer, view->dot)));
+ buffer_push_undo_boundary(view->buffer);
}
void buffer_view_backward_delete_char(struct buffer_view *view) {
+ buffer_push_undo_boundary(view->buffer);
if (maybe_delete_region(view)) {
return;
}
@@ -219,9 +210,11 @@ void buffer_view_backward_delete_char(struct buffer_view *view) {
view->dot = buffer_delete(
view->buffer,
region_new(buffer_previous_char(view->buffer, view->dot), view->dot));
+ buffer_push_undo_boundary(view->buffer);
}
void buffer_view_delete_word(struct buffer_view *view) {
+ buffer_push_undo_boundary(view->buffer);
if (maybe_delete_region(view)) {
return;
}
@@ -232,9 +225,11 @@ void buffer_view_delete_word(struct buffer_view *view) {
buffer_delete(view->buffer, word);
view->dot = word.begin;
}
+ buffer_push_undo_boundary(view->buffer);
}
void buffer_view_kill_line(struct buffer_view *view) {
+ buffer_push_undo_boundary(view->buffer);
uint32_t ncols =
buffer_line_length(view->buffer, view->dot.line) - view->dot.col;
@@ -254,6 +249,7 @@ void buffer_view_kill_line(struct buffer_view *view) {
});
buffer_cut(view->buffer, reg);
+ buffer_push_undo_boundary(view->buffer);
}
void buffer_view_sort_lines(struct buffer_view *view) {
@@ -354,52 +350,87 @@ static uint32_t render_line_numbers(struct buffer_view *view,
return longest_nchars + 2;
}
-static void render_modeline(struct modeline *modeline, struct buffer_view *view,
+static void render_modeline(struct buffer_view *view,
struct command_list *commands, uint32_t window_id,
uint32_t width, uint32_t height, float frame_time) {
- char buf[width * 4];
- memset(buf, 0, width * 4);
-
time_t now = time(NULL);
struct tm *lt = localtime(&now);
- static char left[128] = {0};
- static char right[128] = {0};
-
- snprintf(left, 128, " %c%c %d:%-16s (%d, %d) (%s)",
- view->buffer->modified ? '*' : '-',
- view->buffer->readonly ? '%' : '-', window_id, view->buffer->name,
- view->dot.line + 1, view->dot.col, view->buffer->lang.name);
- snprintf(right, 128, "(%.2f ms) %02d:%02d", frame_time / 1e6, lt->tm_hour,
- lt->tm_min);
-
- snprintf(buf, width * 4, "%s%*s%s", left,
- (int)(width - (strlen(left) + strlen(right))), "", right);
-
- if (strcmp(buf, (char *)modeline->buffer) != 0) {
- modeline->buffer = realloc(modeline->buffer, width * 4);
- modeline->sz = width * 4;
-
- uint32_t len = strlen(buf);
- len = (len + 1) > modeline->sz ? modeline->sz - 1 : len;
- memcpy(modeline->buffer, buf, len);
- modeline->buffer[len] = '\0';
+
+ char left[1024] = {};
+ char right[1024] = {};
+
+ size_t left_len = snprintf(left, 1024, " %c%c %d:%-16s (%d, %d) (%s) ",
+ view->buffer->modified ? '*' : '-',
+ view->buffer->readonly ? '%' : '-', window_id,
+ view->buffer->name, view->dot.line + 1,
+ view->dot.col, view->buffer->lang.name);
+
+ /* insert hook content on the left */
+ VEC_FOR_EACH(&g_modeline_hooks, struct modeline_hook * hook) {
+ struct s8 content = hook->callback(view, hook->userdata);
+ if (content.l > 0) {
+ left_len += snprintf(left + left_len, 1024 - left_len, "[%.*s] ",
+ content.l, content.s);
+ s8delete(content);
+ }
+ }
+
+ size_t right_len = snprintf(right, 1024, " (%.2f ms) %02d:%02d",
+ frame_time / 1e6, lt->tm_hour, lt->tm_min);
+
+ /* clamp all the widths with priority:
+ * 1. left
+ * 2. right
+ * 3. mid
+ */
+ left_len = left_len > width ? width : left_len;
+ right_len = left_len + right_len > width ? width - left_len : right_len;
+ size_t mid_len =
+ left_len + right_len < width ? width - left_len - right_len : 0;
+
+ char mid[mid_len + 1] = {};
+ if (mid_len > 0) {
+ memset(mid, '-', mid_len);
+ mid[0] = ' ';
+ mid[mid_len - 1] = ' ';
+ mid[mid_len] = '\0';
+ }
+
+ if (left_len > 0) {
+ command_list_set_index_color_bg(commands, Color_BrightBlack);
+ command_list_set_index_color_fg(commands, Color_White);
+ command_list_draw_text_copy(commands, 0, height - 1, (uint8_t *)left,
+ left_len);
+ }
+
+ if (mid_len > 0) {
+ command_list_set_index_color_bg(commands, Color_BrightBlack);
+ command_list_set_index_color_fg(commands, Color_White);
+ command_list_draw_text_copy(commands, left_len, height - 1, (uint8_t *)mid,
+ mid_len);
+ }
+
+ if (right_len > 0) {
+ command_list_set_index_color_bg(commands, Color_BrightBlack);
+ command_list_set_index_color_fg(commands, Color_White);
+ command_list_draw_text_copy(commands, left_len + mid_len, height - 1,
+ (uint8_t *)right, right_len);
}
- command_list_set_index_color_bg(commands, Color_BrightBlack);
- command_list_set_index_color_fg(commands, Color_White);
- command_list_draw_text(commands, 0, height - 1, modeline->buffer,
- strlen((char *)modeline->buffer));
command_list_reset_color(commands);
}
-void buffer_view_update(struct buffer_view *view,
+bool buffer_view_update(struct buffer_view *view,
struct buffer_view_update_params *params) {
+ bool needs_render = false;
struct timer *buffer_update_timer =
timer_start("update-windows.buffer-update");
buffer_update(view->buffer);
timer_stop(buffer_update_timer);
+ needs_render |= view->buffer->needs_render;
+
uint32_t height = params->height;
uint32_t width = params->width;
@@ -412,10 +443,10 @@ void buffer_view_update(struct buffer_view *view,
struct timer *render_modeline_timer =
timer_start("update-windows.modeline-render");
uint32_t modeline_height = 0;
- if (view->modeline != NULL) {
+ if (view->modeline) {
modeline_height = 1;
- render_modeline(view->modeline, view, params->commands, params->window_id,
- params->width, params->height, params->frame_time);
+ render_modeline(view, params->commands, params->window_id, params->width,
+ params->height, params->frame_time);
}
height -= modeline_height;
@@ -494,4 +525,21 @@ void buffer_view_update(struct buffer_view *view,
// draw buffer commands nested inside this command list
command_list_draw_command_list(params->commands, buf_cmds);
timer_stop(render_buffer_timer);
+
+ return needs_render;
+}
+
+uint32_t buffer_view_add_modeline_hook(modeline_hook_cb callback,
+ void *userdata) {
+ if (VEC_CAPACITY(&g_modeline_hooks) == 0) {
+ VEC_INIT(&g_modeline_hooks, 8);
+ }
+
+ return insert_modeline_hook(&g_modeline_hooks, &g_modeline_hook_id, callback,
+ userdata);
+}
+
+void buffer_view_remove_modeline_hook(uint32_t hook_id,
+ remove_hook_cb callback) {
+ remove_modeline_hook(&g_modeline_hooks, hook_id, callback);
}