summaryrefslogtreecommitdiff
path: root/src/dged
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2023-11-26 23:08:06 +0100
committerAlbert Cervin <albert@acervin.com>2024-01-15 10:39:56 +0100
commit64d6816a36567274551dd4f067fe4d05b1445cc0 (patch)
tree50f8dc895d363ab391d30226f665870d8ce263b5 /src/dged
parentc87888f10dfb54590c5aae8311b7aff887193d9a (diff)
downloaddged-64d6816a36567274551dd4f067fe4d05b1445cc0.tar.gz
dged-64d6816a36567274551dd4f067fe4d05b1445cc0.tar.xz
dged-64d6816a36567274551dd4f067fe4d05b1445cc0.zip
Completion rework
- Add support for building with clang Also fix some annoying bugs: - Visual column was wrong when using tabs - Add shift-tab for inserting an actual tab - Fix minibuffer sometimes having dot above it
Diffstat (limited to 'src/dged')
-rw-r--r--src/dged/buffer.c209
-rw-r--r--src/dged/buffer.h91
-rw-r--r--src/dged/buffer_view.c35
-rw-r--r--src/dged/buffer_view.h1
-rw-r--r--src/dged/display.c88
-rw-r--r--src/dged/keyboard.c2
-rw-r--r--src/dged/minibuffer.c49
-rw-r--r--src/dged/minibuffer.h4
-rw-r--r--src/dged/reactor-epoll.c2
-rw-r--r--src/dged/settings-parse.c3
-rw-r--r--src/dged/settings.c16
-rw-r--r--src/dged/text.c2
-rw-r--r--src/dged/utf8.c2
-rw-r--r--src/dged/vec.h17
-rw-r--r--src/dged/window.c1
15 files changed, 331 insertions, 191 deletions
diff --git a/src/dged/buffer.c b/src/dged/buffer.c
index c95da91..f1ce2ce 100644
--- a/src/dged/buffer.c
+++ b/src/dged/buffer.c
@@ -21,11 +21,6 @@
#include <unistd.h>
#include <wchar.h>
-struct modeline {
- uint8_t *buffer;
- uint32_t sz;
-};
-
#define KILL_RING_SZ 64
static struct kill_ring {
struct text_chunk buffer[KILL_RING_SZ];
@@ -39,23 +34,78 @@ static struct kill_ring {
.paste_idx = 0,
.paste_up_to_date = false};
-#define MAX_CREATE_HOOKS 32
-static struct create_hook {
- create_hook_cb callback;
- void *userdata;
-} g_create_hooks[MAX_CREATE_HOOKS];
-static uint32_t g_num_create_hooks = 0;
+#define DECLARE_HOOK(name, callback_type, vec_type) \
+ struct name##_hook { \
+ uint32_t id; \
+ callback_type callback; \
+ void *userdata; \
+ }; \
+ \
+ static uint32_t insert_##name##_hook( \
+ vec_type *hooks, uint32_t *id, callback_type callback, void *userdata) { \
+ uint32_t iid = ++(*id); \
+ struct name##_hook hook = (struct name##_hook){ \
+ .id = iid, \
+ .callback = callback, \
+ .userdata = userdata, \
+ }; \
+ VEC_PUSH(hooks, hook); \
+ \
+ return iid; \
+ } \
+ \
+ static void remove_##name##_hook(vec_type *hooks, uint32_t id, \
+ remove_hook_cb callback) { \
+ uint64_t found_at = -1; \
+ VEC_FOR_EACH_INDEXED(hooks, struct name##_hook *h, idx) { \
+ if (h->id == id) { \
+ callback(h->userdata); \
+ found_at = idx; \
+ break; \
+ } \
+ } \
+ if (found_at != -1) { \
+ if (found_at < VEC_SIZE(hooks) - 1) { \
+ VEC_SWAP(hooks, found_at, VEC_SIZE(hooks) - 1); \
+ } \
+ VEC_POP(hooks, struct name##_hook removed); \
+ } \
+ }
+
+typedef VEC(struct create_hook) create_hook_vec;
+typedef VEC(struct insert_hook) insert_hook_vec;
+typedef VEC(struct update_hook) update_hook_vec;
+typedef VEC(struct delete_hook) delete_hook_vec;
+
+DECLARE_HOOK(create, create_hook_cb, create_hook_vec);
+DECLARE_HOOK(insert, insert_hook_cb, insert_hook_vec);
+DECLARE_HOOK(update, update_hook_cb, update_hook_vec);
+DECLARE_HOOK(delete, delete_hook_cb, delete_hook_vec);
+
+static create_hook_vec g_create_hooks;
+uint32_t g_create_hook_id;
+
+struct hooks {
+ create_hook_vec create_hooks;
+ uint32_t create_hook_id;
+
+ insert_hook_vec insert_hooks;
+ uint32_t insert_hook_id;
+
+ update_hook_vec update_hooks;
+ uint32_t update_hook_id;
+
+ delete_hook_vec delete_hooks;
+ uint32_t delete_hook_id;
+};
-uint32_t buffer_add_create_hook(create_hook_cb hook, void *userdata) {
- if (g_num_create_hooks < MAX_CREATE_HOOKS) {
- g_create_hooks[g_num_create_hooks] = (struct create_hook){
- .callback = hook,
- .userdata = userdata,
- };
- ++g_num_create_hooks;
- }
+uint32_t buffer_add_create_hook(create_hook_cb callback, void *userdata) {
+ return insert_create_hook(&g_create_hooks, &g_create_hook_id, callback,
+ userdata);
+}
- return g_num_create_hooks - 1;
+void buffer_remove_create_hook(uint32_t hook_id, remove_hook_cb callback) {
+ remove_create_hook(&g_create_hooks, hook_id, callback);
}
void buffer_static_init() {
@@ -88,7 +138,10 @@ static struct buffer create_internal(const char *name, char *filename) {
.last_write = {0},
};
- VEC_INIT(&b.update_hooks, 32);
+ b.hooks = calloc(1, sizeof(struct hooks));
+ VEC_INIT(&b.hooks->insert_hooks, 8);
+ VEC_INIT(&b.hooks->update_hooks, 8);
+ VEC_INIT(&b.hooks->delete_hooks, 8);
undo_init(&b.undo, 100);
@@ -136,31 +189,9 @@ static bool moveh(struct buffer *buffer, int64_t coldelta,
return true;
}
-static void delete_with_undo(struct buffer *buffer, struct location start,
- struct location end) {
- if (buffer->readonly) {
- minibuffer_echo_timeout(4, "buffer is read-only");
- return;
- }
-
- struct text_chunk txt =
- text_get_region(buffer->text, start.line, start.col, end.line, end.col);
-
- undo_push_delete(
- &buffer->undo,
- (struct undo_delete){.data = txt.text,
- .nbytes = txt.nbytes,
- .pos = {.row = start.line, .col = start.col}});
- undo_push_boundary(&buffer->undo,
- (struct undo_boundary){.save_point = false});
-
- text_delete(buffer->text, start.line, start.col, end.line, end.col);
- buffer->modified = true;
-}
-
static void maybe_delete_region(struct buffer *buffer, struct region region) {
if (region_has_size(region)) {
- delete_with_undo(buffer, region.begin, region.end);
+ buffer_delete(buffer, region);
}
}
@@ -254,8 +285,8 @@ struct buffer buffer_create(const char *name) {
struct buffer b = create_internal(name, NULL);
- for (uint32_t hooki = 0; hooki < g_num_create_hooks; ++hooki) {
- g_create_hooks[hooki].callback(&b, g_create_hooks[hooki].userdata);
+ VEC_FOR_EACH(&g_create_hooks, struct create_hook * h) {
+ h->callback(&b, h->userdata);
}
return b;
@@ -266,8 +297,8 @@ struct buffer buffer_from_file(const char *path) {
struct buffer b = create_internal(basename((char *)path), full_path);
buffer_read_from_file(&b);
- for (uint32_t hooki = 0; hooki < g_num_create_hooks; ++hooki) {
- g_create_hooks[hooki].callback(&b, g_create_hooks[hooki].userdata);
+ VEC_FOR_EACH(&g_create_hooks, struct create_hook * h) {
+ h->callback(&b, h->userdata);
}
return b;
@@ -343,6 +374,11 @@ void buffer_destroy(struct buffer *buffer) {
free(buffer->filename);
buffer->filename = NULL;
+ VEC_DESTROY(&buffer->hooks->update_hooks);
+ VEC_DESTROY(&buffer->hooks->insert_hooks);
+ VEC_DESTROY(&buffer->hooks->delete_hooks);
+ free(buffer->hooks);
+
undo_destroy(&buffer->undo);
}
@@ -381,6 +417,10 @@ struct location buffer_add(struct buffer *buffer, struct location at,
(struct undo_boundary){.save_point = false});
}
+ VEC_FOR_EACH(&buffer->hooks->insert_hooks, struct insert_hook * h) {
+ h->callback(buffer, region_new(initial, final), h->userdata);
+ }
+
buffer->modified = true;
return final;
}
@@ -473,8 +513,8 @@ struct location buffer_newline(struct buffer *buffer, struct location at) {
struct location buffer_indent(struct buffer *buffer, struct location at) {
uint32_t tab_width = buffer->lang.tab_width;
- buffer_add(buffer, at, (uint8_t *)" ",
- tab_width > 16 ? 16 : tab_width);
+ return buffer_add(buffer, at, (uint8_t *)" ",
+ tab_width > 16 ? 16 : tab_width);
}
struct location buffer_undo(struct buffer *buffer, struct location dot) {
@@ -557,7 +597,7 @@ static void search_line(struct text_chunk *chunk, void *userdata) {
uint32_t pattern_nchars = utf8_nchars((uint8_t *)data->pattern, pattern_len);
char *line = malloc(chunk->nbytes + 1);
- strncpy(line, chunk->text, chunk->nbytes);
+ strncpy(line, (const char *)chunk->text, chunk->nbytes);
line[chunk->nbytes] = '\0';
char *hit = NULL;
uint32_t byteidx = 0;
@@ -632,6 +672,10 @@ struct location buffer_delete(struct buffer *buffer, struct region region) {
region.end.line, region.end.col);
buffer->modified = true;
+ VEC_FOR_EACH(&buffer->hooks->delete_hooks, struct delete_hook * h) {
+ h->callback(buffer, region, h->userdata);
+ }
+
return region.begin;
}
@@ -660,7 +704,7 @@ struct location buffer_paste_older(struct buffer *buffer, struct location at) {
// remove previous paste
struct text_chunk *curr = &g_kill_ring.buffer[g_kill_ring.curr_idx];
- delete_with_undo(buffer, g_kill_ring.last_paste, at);
+ buffer_delete(buffer, region_new(g_kill_ring.last_paste, at));
// paste older
if (g_kill_ring.paste_idx - 1 > 0) {
@@ -669,10 +713,10 @@ struct location buffer_paste_older(struct buffer *buffer, struct location at) {
g_kill_ring.paste_idx = g_kill_ring.curr_idx;
}
- paste(buffer, g_kill_ring.last_paste, g_kill_ring.paste_idx);
+ return paste(buffer, g_kill_ring.last_paste, g_kill_ring.paste_idx);
} else {
- buffer_paste(buffer, at);
+ return buffer_paste(buffer, at);
}
}
@@ -680,15 +724,42 @@ struct text_chunk buffer_line(struct buffer *buffer, uint32_t line) {
return text_get_line(buffer->text, line);
}
+struct text_chunk buffer_region(struct buffer *buffer, struct region region) {
+ return text_get_region(buffer->text, region.begin.line, region.begin.col,
+ region.end.line, region.end.col);
+}
+
+uint32_t buffer_add_insert_hook(struct buffer *buffer, insert_hook_cb hook,
+ void *userdata) {
+ return insert_insert_hook(&buffer->hooks->insert_hooks,
+ &buffer->hooks->insert_hook_id, hook, userdata);
+}
+
+void buffer_remove_insert_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback) {
+ remove_insert_hook(&buffer->hooks->insert_hooks, hook_id, callback);
+}
+
+uint32_t buffer_add_delete_hook(struct buffer *buffer, delete_hook_cb hook,
+ void *userdata) {
+ return insert_delete_hook(&buffer->hooks->delete_hooks,
+ &buffer->hooks->delete_hook_id, hook, userdata);
+}
+
+void buffer_remove_delete_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback) {
+ remove_delete_hook(&buffer->hooks->delete_hooks, hook_id, callback);
+}
+
uint32_t buffer_add_update_hook(struct buffer *buffer, update_hook_cb hook,
void *userdata) {
- VEC_APPEND(&buffer->update_hooks, struct update_hook_entry * e);
- struct update_hook *h = &e->hook;
- h->callback = hook;
- h->userdata = userdata;
+ return insert_update_hook(&buffer->hooks->update_hooks,
+ &buffer->hooks->update_hook_id, hook, userdata);
+}
- // TODO: cant really have this if we actually want to remove a hook
- return VEC_SIZE(&buffer->update_hooks) - 1;
+void buffer_remove_update_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback) {
+ remove_update_hook(&buffer->hooks->update_hooks, hook_id, callback);
}
struct cmdbuf {
@@ -710,8 +781,8 @@ static uint32_t visual_char_width(uint8_t *byte, uint32_t maxlen) {
}
}
-static uint32_t visual_string_width(uint8_t *txt, uint32_t len,
- uint32_t start_col, uint32_t end_col) {
+uint32_t visual_string_width(uint8_t *txt, uint32_t len, uint32_t start_col,
+ uint32_t end_col) {
uint32_t start_byte = utf8_nbytes(txt, len, start_col);
uint32_t end_byte = utf8_nbytes(txt, len, end_col);
@@ -780,9 +851,10 @@ void render_line(struct text_chunk *line, void *userdata) {
// apply new properties
for (uint32_t propi = 0; propi < nnew_props; ++propi) {
struct text_property *prop = new_props[propi];
+ struct text_property_colors *colors = &prop->colors;
+
switch (prop->type) {
case TextProperty_Colors:
- struct text_property_colors *colors = &prop->colors;
if (colors->set_bg) {
command_list_set_index_color_bg(cmdbuf->cmds, colors->bg);
}
@@ -821,13 +893,14 @@ void render_line(struct text_chunk *line, void *userdata) {
}
void buffer_update(struct buffer *buffer, struct buffer_update_params *params) {
- if (params->width == 0 || params->height == 0) {
- return;
+ VEC_FOR_EACH(&buffer->hooks->update_hooks, struct update_hook * h) {
+ h->callback(buffer, h->userdata);
}
+}
- VEC_FOR_EACH(&buffer->update_hooks, struct update_hook_entry * entry) {
- struct update_hook *h = &entry->hook;
- h->callback(buffer, params->width, params->height, h->userdata);
+void buffer_render(struct buffer *buffer, struct buffer_render_params *params) {
+ if (params->width == 0 || params->height == 0) {
+ return;
}
struct setting *show_ws = settings_get("editor.show-whitespace");
diff --git a/src/dged/buffer.h b/src/dged/buffer.h
index e29e3e1..7e4ef78 100644
--- a/src/dged/buffer.h
+++ b/src/dged/buffer.h
@@ -14,29 +14,7 @@
#include "window.h"
struct command_list;
-
-/** Buffer update hook callback function */
-typedef void (*update_hook_cb)(struct buffer *buffer, uint32_t width,
- uint32_t height, void *userdata);
-
-/**
- * A buffer update hook.
- *
- * Can be used to implement custom behavior on top of a buffer. Used for
- * minibuffer.
- */
-struct update_hook {
- /** Callback function */
- update_hook_cb callback;
-
- /** Optional userdata to pass to the callback function unmodified */
- void *userdata;
-};
-
-struct update_hook_entry {
- uint32_t id;
- struct update_hook hook;
-};
+struct hooks;
/**
* A buffer of text that can be modified, read from and written to disk.
@@ -55,12 +33,12 @@ struct buffer {
/** Time when buffer was last written to disk */
struct timespec last_write;
+ /** Hooks for this buffer */
+ struct hooks *hooks;
+
/** Text data structure */
struct text *text;
- /** Buffer update hooks */
- VEC(struct update_hook_entry) update_hooks;
-
/** Buffer undo stack */
struct undo_stack undo;
@@ -396,6 +374,16 @@ struct location buffer_paste_older(struct buffer *buffer, struct location at);
*/
struct text_chunk buffer_line(struct buffer *buffer, uint32_t line);
+/**
+ * Get a region of text from the buffer.
+ *
+ * @param buffer The buffer to get text from.
+ * @param region A region representing the buffer area to get text from.
+ *
+ * @returns A text chunk describing the region.
+ */
+struct text_chunk buffer_region(struct buffer *buffer, struct region region);
+
void buffer_add_text_property(struct buffer *buffer, struct location start,
struct location end,
struct text_property property);
@@ -407,6 +395,12 @@ void buffer_get_text_properties(struct buffer *buffer, struct location location,
void buffer_clear_text_properties(struct buffer *buffer);
+/** Callback when removing hooks to clean up userdata */
+typedef void (*remove_hook_cb)(void *userdata);
+
+/** Buffer update hook callback function */
+typedef void (*update_hook_cb)(struct buffer *buffer, void *userdata);
+
/**
* Add a buffer update hook.
*
@@ -418,23 +412,51 @@ void buffer_clear_text_properties(struct buffer *buffer);
uint32_t buffer_add_update_hook(struct buffer *buffer, update_hook_cb hook,
void *userdata);
+void buffer_remove_update_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback);
+
+/** Buffer insert hook callback function */
+typedef void (*insert_hook_cb)(struct buffer *buffer, struct region inserted,
+ void *userdata);
+
+uint32_t buffer_add_insert_hook(struct buffer *buffer, insert_hook_cb callback,
+ void *userdata);
+void buffer_remove_insert_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback);
+
+/** Buffer delete hook callback function */
+typedef void (*delete_hook_cb)(struct buffer *buffer, struct region removed,
+ void *userdata);
+
+uint32_t buffer_add_delete_hook(struct buffer *buffer, delete_hook_cb callback,
+ void *userdata);
+void buffer_remove_delete_hook(struct buffer *buffer, uint32_t hook_id,
+ remove_hook_cb callback);
+
/** Buffer create hook callback function */
typedef void (*create_hook_cb)(struct buffer *buffer, void *userdata);
/**
* Add a buffer create hook.
*
- * @param [in] hook Create hook callback.
+ * @param [in] callback Create hook callback.
* @param [in] userdata Pointer to data that is passed unmodified to the update
* hook.
* @returns The hook id.
*/
-uint32_t buffer_add_create_hook(create_hook_cb hook, void *userdata);
+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 {
+struct buffer_update_params {};
+
+/**
+ * Parameters for rendering a buffer.
+ */
+struct buffer_render_params {
/** Command list to add rendering commands for the buffer */
struct command_list *commands;
@@ -459,4 +481,15 @@ struct buffer_update_params {
*/
void buffer_update(struct buffer *buffer, struct buffer_update_params *params);
+/**
+ * Render a buffer.
+ * @param [in] buffer The buffer to render.
+ * @param [inout] params The parameters for the rendering.
+ */
+void buffer_render(struct buffer *buffer, struct buffer_render_params *params);
+
+// TODO: move this to where it makes sense
+uint32_t visual_string_width(uint8_t *txt, uint32_t len, uint32_t start_col,
+ uint32_t end_col);
+
#endif
diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c
index a95e3b0..05d3caa 100644
--- a/src/dged/buffer_view.c
+++ b/src/dged/buffer_view.c
@@ -3,6 +3,7 @@
#include "buffer.h"
#include "buffer_view.h"
#include "display.h"
+#include "utf8.h"
struct modeline {
uint8_t *buffer;
@@ -240,6 +241,24 @@ struct location buffer_view_dot_to_relative(struct buffer_view *view) {
};
}
+struct location buffer_view_dot_to_visual(struct buffer_view *view) {
+ // calculate visual column index for dot column
+ struct text_chunk c = buffer_line(view->buffer, view->dot.line);
+ uint32_t width = visual_string_width(c.text, c.nbytes, 0, view->dot.col);
+ if (view->scroll.col > 0) {
+ width -= visual_string_width(c.text, c.nbytes, 0, view->scroll.col);
+ }
+
+ struct location l = buffer_view_dot_to_relative(view);
+ l.col = width + view->fringe_width;
+
+ if (c.allocated) {
+ free(c.text);
+ }
+
+ return l;
+}
+
void buffer_view_undo(struct buffer_view *view) {
view->dot = buffer_undo(view->buffer, view->dot);
}
@@ -345,6 +364,9 @@ static void render_modeline(struct modeline *modeline, struct buffer_view *view,
void buffer_view_update(struct buffer_view *view,
struct buffer_view_update_params *params) {
+ struct buffer_update_params update_params = {};
+ buffer_update(view->buffer, &update_params);
+
uint32_t height = params->height;
uint32_t width = params->width;
@@ -409,22 +431,13 @@ void buffer_view_update(struct buffer_view *view,
struct command_list *buf_cmds = command_list_create(
width * height, params->frame_alloc, params->window_x + linum_width,
params->window_y, view->buffer->name);
- struct buffer_update_params bufparams = {
+ struct buffer_render_params render_params = {
.commands = buf_cmds,
.origin = view->scroll,
.width = width,
.height = height,
};
- buffer_update(view->buffer, &bufparams);
-
- /* Make sure the dot is always inside buffer limits.
- * Updating the buffer above could have removed text.
- * TODO: this is not really correct, since it may have caused
- * changes that would need a re-eval of scroll and redraw.
- * Hooks should prob not get width and height and be ran before rendering.
- */
- view->dot = buffer_clamp(view->buffer, (int64_t)view->dot.line,
- (int64_t)view->dot.col);
+ buffer_render(view->buffer, &render_params);
// draw buffer commands nested inside this command list
command_list_draw_command_list(params->commands, buf_cmds);
diff --git a/src/dged/buffer_view.h b/src/dged/buffer_view.h
index 0002b95..1c8fa6a 100644
--- a/src/dged/buffer_view.h
+++ b/src/dged/buffer_view.h
@@ -80,6 +80,7 @@ void buffer_view_clear_mark(struct buffer_view *view);
void buffer_view_set_mark_at(struct buffer_view *view, struct location mark);
struct location buffer_view_dot_to_relative(struct buffer_view *view);
+struct location buffer_view_dot_to_visual(struct buffer_view *view);
void buffer_view_undo(struct buffer_view *view);
diff --git a/src/dged/display.c b/src/dged/display.c
index b779d5f..85a6e0b 100644
--- a/src/dged/display.c
+++ b/src/dged/display.c
@@ -5,6 +5,7 @@
#include "utf8.h"
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -130,24 +131,49 @@ uint32_t display_width(struct display *display) { return display->width; }
uint32_t display_height(struct display *display) { return display->height; }
void putch(uint8_t c) {
- if (c != '\r') {
+ // TODO: move this to buffer rendering
+ if (c < ' ') {
+ fprintf(stdout, "^%c", c + 0x40);
+ } else if (c == 0x7f) {
+ fprintf(stdout, "^?");
+ } else if (utf8_byte_is_unicode_start(c) ||
+ utf8_byte_is_unicode_continuation(c)) {
putc(c, stdout);
+ } else if (c >= ' ' && c < 0x7f) {
+ putc(c, stdout);
+ } else {
+ fprintf(stdout, "|0x%02x|", c);
+ }
+}
+
+static void apply_fmt(uint8_t *fmt_stack, uint32_t fmt_stack_len) {
+ if (fmt_stack == NULL || fmt_stack_len == 0) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < fmt_stack_len; ++i) {
+ putc(fmt_stack[i], stdout);
}
+ putc('m', stdout);
}
-void putch_ws(uint8_t c, bool show_whitespace) {
+void putch_ws(uint8_t c, bool show_whitespace, uint8_t *fmt_stack,
+ uint32_t fmt_stack_len) {
if (show_whitespace && c == '\t') {
fputs("\x1b[90m → \x1b[39m", stdout);
+ apply_fmt(fmt_stack, fmt_stack_len);
} else if (show_whitespace && c == ' ') {
fputs("\x1b[90m·\x1b[39m", stdout);
+ apply_fmt(fmt_stack, fmt_stack_len);
} else {
putch(c);
}
}
-void putbytes(uint8_t *line_bytes, uint32_t line_length, bool show_whitespace) {
+void putbytes(uint8_t *line_bytes, uint32_t line_length, bool show_whitespace,
+ uint8_t *fmt_stack, uint32_t fmt_stack_len) {
for (uint32_t bytei = 0; bytei < line_length; ++bytei) {
- putch_ws(line_bytes[bytei], show_whitespace);
+ putch_ws(line_bytes[bytei], show_whitespace, fmt_stack, fmt_stack_len);
}
}
@@ -156,26 +182,28 @@ void put_ansiparm(int n) {
if (q != 0) {
int r = q / 10;
if (r != 0) {
- putch((r % 10) + '0');
+ putc((r % 10) + '0', stdout);
}
- putch((q % 10) + '0');
+ putc((q % 10) + '0', stdout);
}
- putch((n % 10) + '0');
+ putc((n % 10) + '0', stdout);
}
void display_move_cursor(struct display *display, uint32_t row, uint32_t col) {
- putch(ESC);
- putch('[');
+ putc(ESC, stdout);
+ putc('[', stdout);
put_ansiparm(row + 1);
- putch(';');
+ putc(';', stdout);
put_ansiparm(col + 1);
- putch('H');
+ putc('H', stdout);
}
void display_clear(struct display *display) {
display_move_cursor(display, 0, 0);
uint8_t bytes[] = {ESC, '[', 'J'};
- putbytes(bytes, 3, false);
+ putc(ESC, stdout);
+ putc('[', stdout);
+ putc('J', stdout);
}
struct command_list *command_list_create(uint32_t initial_capacity,
@@ -346,9 +374,9 @@ void display_render(struct display *display,
struct draw_text_cmd *txt_cmd = cmd->draw_txt;
display_move_cursor(display, txt_cmd->row + cl->yoffset,
txt_cmd->col + cl->xoffset);
- putbytes(fmt_stack, fmt_stack_len, false);
- putch('m');
- putbytes(txt_cmd->data, txt_cmd->len, show_whitespace_state);
+ apply_fmt(fmt_stack, fmt_stack_len);
+ putbytes(txt_cmd->data, txt_cmd->len, show_whitespace_state, fmt_stack,
+ fmt_stack_len);
break;
}
@@ -356,11 +384,11 @@ void display_render(struct display *display,
struct repeat_cmd *repeat_cmd = cmd->repeat;
display_move_cursor(display, repeat_cmd->row + cl->yoffset,
repeat_cmd->col + cl->xoffset);
- putbytes(fmt_stack, fmt_stack_len, false);
- putch('m');
+ apply_fmt(fmt_stack, fmt_stack_len);
uint32_t nbytes = utf8_nbytes((uint8_t *)&repeat_cmd->c, 4, 1);
for (uint32_t i = 0; i < repeat_cmd->nrepeat; ++i) {
- putbytes((uint8_t *)&repeat_cmd->c, nbytes, show_whitespace_state);
+ putbytes((uint8_t *)&repeat_cmd->c, nbytes, show_whitespace_state,
+ fmt_stack, fmt_stack_len);
}
break;
}
@@ -394,21 +422,21 @@ void display_render(struct display *display,
}
void hide_cursor() {
- putch(ESC);
- putch('[');
- putch('?');
- putch('2');
- putch('5');
- putch('l');
+ putc(ESC, stdout);
+ putc('[', stdout);
+ putc('?', stdout);
+ putc('2', stdout);
+ putc('5', stdout);
+ putc('l', stdout);
}
void show_cursor() {
- putch(ESC);
- putch('[');
- putch('?');
- putch('2');
- putch('5');
- putch('h');
+ putc(ESC, stdout);
+ putc('[', stdout);
+ putc('?', stdout);
+ putc('2', stdout);
+ putc('5', stdout);
+ putc('h', stdout);
}
void display_begin_render(struct display *display) { hide_cursor(); }
diff --git a/src/dged/keyboard.c b/src/dged/keyboard.c
index 63b7b6e..4d4526e 100644
--- a/src/dged/keyboard.c
+++ b/src/dged/keyboard.c
@@ -163,4 +163,6 @@ uint32_t key_name(struct key *key, char *buf, size_t capacity) {
}
snprintf(buf, capacity, "%s%c", mod, tolower(key->key));
+
+ return 0;
}
diff --git a/src/dged/minibuffer.c b/src/dged/minibuffer.c
index d31d634..2105c52 100644
--- a/src/dged/minibuffer.c
+++ b/src/dged/minibuffer.c
@@ -1,6 +1,7 @@
#include "minibuffer.h"
#include "binding.h"
#include "buffer.h"
+#include "buffer_view.h"
#include "command.h"
#include "display.h"
@@ -19,9 +20,6 @@ static struct minibuffer {
bool clear;
struct window *prev_window;
- void (*update_callback)(void *);
- void *update_callback_userdata;
-
} g_minibuffer = {0};
uint32_t minibuffer_draw_prompt(struct command_list *commands) {
@@ -76,8 +74,7 @@ int32_t minibuffer_execute() {
}
}
-void update(struct buffer *buffer, uint32_t width, uint32_t height,
- void *userdata) {
+void update(struct buffer *buffer, void *userdata) {
struct timespec current;
struct minibuffer *mb = (struct minibuffer *)userdata;
clock_gettime(CLOCK_MONOTONIC, &current);
@@ -86,10 +83,6 @@ void update(struct buffer *buffer, uint32_t width, uint32_t height,
buffer_clear(buffer);
mb->clear = false;
}
-
- if (mb->update_callback != NULL) {
- mb->update_callback(mb->update_callback_userdata);
- }
}
void minibuffer_init(struct buffer *buffer) {
@@ -150,14 +143,15 @@ void minibuffer_set_prompt_internal(const char *fmt, va_list args) {
vsnprintf(g_minibuffer.prompt, sizeof(g_minibuffer.prompt), fmt, args);
}
-int32_t minibuffer_prompt_internal(struct command_ctx command_ctx,
- void (*update_callback)(void *),
- void *userdata, const char *fmt,
- va_list args) {
+int32_t minibuffer_prompt(struct command_ctx command_ctx, const char *fmt,
+ ...) {
if (g_minibuffer.buffer == NULL) {
return 1;
}
+ va_list args;
+ va_start(args, fmt);
+
minibuffer_clear();
g_minibuffer.prompt_active = true;
@@ -166,39 +160,13 @@ int32_t minibuffer_prompt_internal(struct command_ctx command_ctx,
minibuffer_set_prompt_internal(fmt, args);
- if (update_callback != NULL) {
- g_minibuffer.update_callback = update_callback;
- g_minibuffer.update_callback_userdata = userdata;
- }
-
if (windows_get_active() != minibuffer_window()) {
g_minibuffer.prev_window = windows_get_active();
windows_set_active(minibuffer_window());
}
-
- return 0;
-}
-
-int32_t minibuffer_prompt(struct command_ctx command_ctx, const char *fmt,
- ...) {
- va_list args;
- va_start(args, fmt);
- int32_t r = minibuffer_prompt_internal(command_ctx, NULL, NULL, fmt, args);
- va_end(args);
-
- return r;
-}
-
-int32_t minibuffer_prompt_interactive(struct command_ctx command_ctx,
- void (*update_callback)(void *),
- void *userdata, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- int32_t r = minibuffer_prompt_internal(command_ctx, update_callback, userdata,
- fmt, args);
va_end(args);
- return r;
+ return 0;
}
void minibuffer_set_prompt(const char *fmt, ...) {
@@ -210,7 +178,6 @@ void minibuffer_set_prompt(const char *fmt, ...) {
void minibuffer_abort_prompt() {
minibuffer_clear();
- g_minibuffer.update_callback = NULL;
g_minibuffer.prompt_active = false;
if (g_minibuffer.prev_window != NULL) {
diff --git a/src/dged/minibuffer.h b/src/dged/minibuffer.h
index fb6eae4..727aac5 100644
--- a/src/dged/minibuffer.h
+++ b/src/dged/minibuffer.h
@@ -59,10 +59,6 @@ void minibuffer_echo_timeout(uint32_t timeout, const char *fmt, ...);
*/
int32_t minibuffer_prompt(struct command_ctx command_ctx, const char *fmt, ...);
-int32_t minibuffer_prompt_interactive(struct command_ctx command_ctx,
- void (*update_callback)(void *),
- void *userdata, const char *fmt, ...);
-
void minibuffer_set_prompt(const char *fmt, ...);
uint32_t minibuffer_draw_prompt(struct command_list *commands);
diff --git a/src/dged/reactor-epoll.c b/src/dged/reactor-epoll.c
index 96c6da4..22888f6 100644
--- a/src/dged/reactor-epoll.c
+++ b/src/dged/reactor-epoll.c
@@ -109,7 +109,7 @@ bool reactor_next_file_event(struct reactor *reactor, struct file_event *out) {
struct inotify_event *ev = (struct inotify_event *)buf;
// TODO: change when adding more of these
out->mask = FileWritten;
- if (ev->mask & IN_IGNORED != 0) {
+ if ((ev->mask & IN_IGNORED) != 0) {
out->mask |= LastEvent;
}
out->id = (uint32_t)ev->wd;
diff --git a/src/dged/settings-parse.c b/src/dged/settings-parse.c
index 6c1c482..c63a0cf 100644
--- a/src/dged/settings-parse.c
+++ b/src/dged/settings-parse.c
@@ -115,6 +115,7 @@ bool parser_next_token(struct parser *state, struct token *token_out) {
memset(token_out, 0, sizeof(struct token));
while (state->reader.getbytes(1, &byte, state->reader.userdata) > 0) {
+ bool multiline = false;
switch (classify(byte)) {
case Byte_Alphanumeric: // unquoted key / value
if (!parse_value) {
@@ -223,7 +224,7 @@ bool parser_next_token(struct parser *state, struct token *token_out) {
return true;
case '"': // quoted key or string value
- bool multiline = false;
+ multiline = false;
if (parse_value) {
token_out->type = Token_StringValue;
} else {
diff --git a/src/dged/settings.c b/src/dged/settings.c
index 4370aa9..7b5e4dc 100644
--- a/src/dged/settings.c
+++ b/src/dged/settings.c
@@ -116,6 +116,9 @@ static int32_t parse_toml(struct parser *state, char **errmsgs[]) {
VEC_INIT(&errs, 16);
struct token t = {0};
+ int64_t i = 0;
+ bool b = false;
+ char *v = NULL, *err = NULL;
while (parser_next_token(state, &t)) {
switch (t.type) {
case Token_Table:
@@ -145,26 +148,26 @@ static int32_t parse_toml(struct parser *state, char **errmsgs[]) {
curkey = calloc(len, 1);
if (curtbl != NULL) {
strcpy(curkey, curtbl);
- strncat(curkey, ".", 1);
+ curkey[strlen(curtbl)] = '.';
}
strncat(curkey, (char *)t.data, t.len);
break;
case Token_IntValue:
- int64_t i = *((int64_t *)t.data);
+ i = *((int64_t *)t.data);
settings_upsert(curkey, (struct setting_value){.type = Setting_Number,
.number_value = i});
break;
case Token_BoolValue:
- bool b = *((bool *)t.data);
+ b = *((bool *)t.data);
settings_upsert(curkey, (struct setting_value){.type = Setting_Bool,
.bool_value = b});
break;
case Token_StringValue:
- char *v = calloc(t.len + 1, 1);
+ v = calloc(t.len + 1, 1);
strncpy(v, (char *)t.data, t.len);
settings_upsert(curkey, (struct setting_value){.type = Setting_String,
.string_value = v});
@@ -172,11 +175,14 @@ static int32_t parse_toml(struct parser *state, char **errmsgs[]) {
break;
case Token_Error:
- char *err = malloc(t.len + 128);
+ err = malloc(t.len + 128);
snprintf(err, t.len + 128, "error (%d:%d): %.*s\n", t.row, t.col, t.len,
(char *)t.data);
VEC_PUSH(&errs, err);
break;
+
+ case Token_Comment:
+ break;
}
}
diff --git a/src/dged/text.c b/src/dged/text.c
index b3eb4ad..4d9a073 100644
--- a/src/dged/text.c
+++ b/src/dged/text.c
@@ -47,6 +47,8 @@ struct text *text_create(uint32_t initial_capacity) {
}
void text_destroy(struct text *text) {
+ VEC_DESTROY(&text->properties);
+
for (uint32_t li = 0; li < text->nlines; ++li) {
free(text->lines[li].data);
text->lines[li].data = NULL;
diff --git a/src/dged/utf8.c b/src/dged/utf8.c
index 30344be..b71a7e1 100644
--- a/src/dged/utf8.c
+++ b/src/dged/utf8.c
@@ -71,7 +71,7 @@ uint32_t utf8_visual_char_width(uint8_t *bytes, uint32_t len) {
if (utf8_byte_is_unicode_start(*bytes)) {
wchar_t wc;
size_t nbytes = 0;
- if (nbytes = mbrtowc(&wc, (char *)bytes, len, NULL) > 0) {
+ if ((nbytes = mbrtowc(&wc, (char *)bytes, len, NULL)) > 0) {
return wcwidth(wc);
} else {
return 0;
diff --git a/src/dged/vec.h b/src/dged/vec.h
index df5cd0e..8b17fa5 100644
--- a/src/dged/vec.h
+++ b/src/dged/vec.h
@@ -5,6 +5,7 @@
#define VEC(entry) \
struct { \
+ entry *temp; \
entry *entries; \
uint32_t nentries; \
uint32_t capacity; \
@@ -12,10 +13,12 @@
#define VEC_INIT(vec, initial_capacity) \
(vec)->entries = malloc(sizeof((vec)->entries[0]) * initial_capacity); \
+ (vec)->temp = calloc(1, sizeof((vec)->entries[0])); \
(vec)->capacity = initial_capacity; \
(vec)->nentries = 0;
#define VEC_DESTROY(vec) \
+ free((vec)->temp); \
free((vec)->entries); \
(vec)->entries = NULL; \
(vec)->capacity = 0; \
@@ -36,6 +39,20 @@
(vec)->entries[(vec)->nentries] = entry; \
++(vec)->nentries;
+#define VEC_POP(vec, var) \
+ var = (vec)->entries[(vec)->nentries - 1]; \
+ if ((vec)->nentries > 0) { \
+ --(vec)->nentries; \
+ }
+
+#define VEC_SWAP(vec, idx1, idx2) \
+ if (idx1 < (vec)->nentries && idx2 < (vec)->nentries && idx1 >= 0 && \
+ idx2 >= 0) { \
+ *((vec)->temp) = (vec)->entries[idx1]; \
+ (vec)->entries[idx1] = (vec)->entries[idx2]; \
+ (vec)->entries[idx2] = *((vec)->temp); \
+ }
+
#define VEC_APPEND(vec, var) \
if ((vec)->nentries + 1 >= (vec)->capacity) { \
VEC_GROW(vec, (vec)->capacity * 2); \
diff --git a/src/dged/window.c b/src/dged/window.c
index a25154a..da2cebe 100644
--- a/src/dged/window.c
+++ b/src/dged/window.c
@@ -178,6 +178,7 @@ void windows_update(void *(*frame_alloc)(size_t), uint64_t frame_time) {
.window_y = w->y,
.frame_alloc = frame_alloc,
};
+
buffer_view_update(&w->buffer_view, &p);
command_list_draw_command_list(w->commands, inner_commands);