From c27f5c5ed4bce91eaa50d7d1daa5335f186dcc36 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Wed, 24 Jan 2024 13:00:09 +0100 Subject: Relative find file and small fixes - Save text was not always displaying - Files were sometimes not reloaded properly --- src/dged/buffer.c | 16 ++++++++-- src/dged/buffer_view.c | 2 +- src/dged/minibuffer.c | 66 ++++++++++++++++++++++++++++++---------- src/dged/minibuffer.h | 3 ++ src/main/bindings.c | 1 + src/main/cmds.c | 81 +++++++++++++++++++++++++++++++++++++++----------- 6 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/dged/buffer.c b/src/dged/buffer.c index f1ce2ce..8e63e1f 100644 --- a/src/dged/buffer.c +++ b/src/dged/buffer.c @@ -356,11 +356,10 @@ void buffer_reload(struct buffer *buffer) { return; } - if (sb.st_mtim.tv_sec != buffer->last_write.tv_sec) { + if (sb.st_mtim.tv_sec != buffer->last_write.tv_sec || + sb.st_mtim.tv_nsec != buffer->last_write.tv_nsec) { text_clear(buffer->text); buffer_read_from_file(buffer); - } else { - minibuffer_echo_timeout(2, "buffer %s not changed", buffer->filename); } } @@ -488,9 +487,20 @@ struct location buffer_next_line(struct buffer *buffer, struct location dot) { struct location buffer_clamp(struct buffer *buffer, int64_t line, int64_t col) { struct location location = {.line = 0, .col = 0}; + if (buffer_is_empty(buffer)) { + return location; + } + movev(buffer, line, &location); moveh(buffer, col, &location); + // when clamping we want to stay inside + // the actual bounds + if (location.line >= buffer_num_lines(buffer)) { + location.line = buffer_num_lines(buffer) - 1; + location.col = buffer_num_chars(buffer, location.line); + } + return location; } diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c index 05d3caa..aeee2f6 100644 --- a/src/dged/buffer_view.c +++ b/src/dged/buffer_view.c @@ -78,7 +78,7 @@ void buffer_view_add(struct buffer_view *view, uint8_t *txt, uint32_t nbytes) { } void buffer_view_goto_beginning(struct buffer_view *view) { - view->dot = (struct location){.line = 1, .col = 0}; + view->dot = (struct location){.line = 0, .col = 0}; } void buffer_view_goto_end(struct buffer_view *view) { diff --git a/src/dged/minibuffer.c b/src/dged/minibuffer.c index 2105c52..eacf8da 100644 --- a/src/dged/minibuffer.c +++ b/src/dged/minibuffer.c @@ -91,7 +91,10 @@ void minibuffer_init(struct buffer *buffer) { } g_minibuffer.buffer = buffer; + g_minibuffer.expires.tv_sec = 0; + g_minibuffer.expires.tv_nsec = 0; g_minibuffer.clear = false; + g_minibuffer.prompt_active = false; buffer_add_update_hook(g_minibuffer.buffer, update, &g_minibuffer); } @@ -100,6 +103,10 @@ void echo(uint32_t timeout, const char *fmt, va_list args) { return; } + clock_gettime(CLOCK_MONOTONIC, &g_minibuffer.expires); + g_minibuffer.expires.tv_sec += timeout; + g_minibuffer.clear = false; + char buff[2048]; size_t nbytes = vsnprintf(buff, 2048, fmt, args); @@ -107,10 +114,6 @@ void echo(uint32_t timeout, const char *fmt, va_list args) { // of overflow buffer_set_text(g_minibuffer.buffer, (uint8_t *)buff, nbytes > 2048 ? 2048 : nbytes); - g_minibuffer.clear = false; - - clock_gettime(CLOCK_MONOTONIC, &g_minibuffer.expires); - g_minibuffer.expires.tv_sec += timeout; } void minibuffer_destroy() { @@ -143,27 +146,59 @@ 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(struct command_ctx command_ctx, const char *fmt, - ...) { +static void minibuffer_setup(struct command_ctx command_ctx, + const char *initial) { + g_minibuffer.prompt_active = true; + + command_ctx_free(&g_minibuffer.prompt_command_ctx); + g_minibuffer.prompt_command_ctx = command_ctx; + + if (windows_get_active() != minibuffer_window()) { + g_minibuffer.prev_window = windows_get_active(); + windows_set_active(minibuffer_window()); + } + + if (initial != NULL) { + buffer_set_text(g_minibuffer.buffer, (uint8_t *)initial, strlen(initial)); + + // there might be an earlier clear request but + // we have sort of taken care of that here + g_minibuffer.clear = false; + + // TODO: what to do with these + buffer_view_goto_end_of_line(window_buffer_view(minibuffer_window())); + } else { + minibuffer_clear(); + } +} + +int32_t minibuffer_prompt_initial(struct command_ctx command_ctx, + const char *initial, const char *fmt, ...) { if (g_minibuffer.buffer == NULL) { return 1; } + minibuffer_setup(command_ctx, initial); + va_list args; va_start(args, fmt); + minibuffer_set_prompt_internal(fmt, args); + va_end(args); - minibuffer_clear(); - g_minibuffer.prompt_active = true; + return 0; +} - command_ctx_free(&g_minibuffer.prompt_command_ctx); - g_minibuffer.prompt_command_ctx = command_ctx; +int32_t minibuffer_prompt(struct command_ctx command_ctx, const char *fmt, + ...) { + if (g_minibuffer.buffer == NULL) { + return 1; + } - minibuffer_set_prompt_internal(fmt, args); + minibuffer_setup(command_ctx, NULL); - if (windows_get_active() != minibuffer_window()) { - g_minibuffer.prev_window = windows_get_active(); - windows_set_active(minibuffer_window()); - } + va_list args; + va_start(args, fmt); + minibuffer_set_prompt_internal(fmt, args); va_end(args); return 0; @@ -193,6 +228,7 @@ bool minibuffer_displaying() { void minibuffer_clear() { g_minibuffer.expires.tv_sec = 0; + g_minibuffer.expires.tv_nsec = 0; g_minibuffer.clear = true; } diff --git a/src/dged/minibuffer.h b/src/dged/minibuffer.h index 727aac5..b7c5171 100644 --- a/src/dged/minibuffer.h +++ b/src/dged/minibuffer.h @@ -59,6 +59,9 @@ 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_initial(struct command_ctx command_ctx, + const char *initial, const char *fmt, ...); + void minibuffer_set_prompt(const char *fmt, ...); uint32_t minibuffer_draw_prompt(struct command_list *commands); diff --git a/src/main/bindings.c b/src/main/bindings.c index 32dcbdb..ad63974 100644 --- a/src/main/bindings.c +++ b/src/main/bindings.c @@ -98,6 +98,7 @@ void init_bindings() { BINDING(Ctrl, 'C', "exit"), BINDING(Ctrl, 'S', "buffer-write-to-file"), BINDING(Ctrl, 'F', "find-file"), + BINDING(Ctrl, 'G', "find-file-relative"), BINDING(Ctrl, 'W', "write-file"), BINDING(None, 'b', "switch-buffer"), BINDING(Ctrl, 'B', "buffer-list"), diff --git a/src/main/cmds.c b/src/main/cmds.c index bf465ed..506054b 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -226,20 +227,8 @@ int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { static void find_file_comp_inserted() { minibuffer_execute(); } -int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { - const char *pth = NULL; - if (argc == 0) { - struct completion_provider providers[] = {path_provider()}; - enable_completion(minibuffer_buffer(), - ((struct completion_trigger){ - .kind = CompletionTrigger_Input, .nchars = 0}), - providers, 1, find_file_comp_inserted); - return minibuffer_prompt(ctx, "find file: "); - } - - disable_completion(minibuffer_buffer()); - - pth = argv[0]; +static int32_t open_file(struct buffers *buffers, struct window *active_window, + const char *pth) { struct stat sb = {0}; if (stat(pth, &sb) < 0 && errno != ENOENT) { minibuffer_echo("stat on %s failed: %s", pth, strerror(errno)); @@ -252,19 +241,74 @@ int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { } const char *filename = to_abspath(pth); - struct buffer *b = buffers_find_by_filename(ctx.buffers, filename); + struct buffer *b = buffers_find_by_filename(buffers, filename); free((char *)filename); if (b == NULL) { - b = buffers_add(ctx.buffers, buffer_from_file((char *)pth)); + b = buffers_add(buffers, buffer_from_file((char *)pth)); } else { buffer_reload(b); } - window_set_buffer(ctx.active_window, b); + window_set_buffer(active_window, b); minibuffer_echo_timeout(4, "buffer \"%s\" loaded", - window_buffer(ctx.active_window)->name); + window_buffer(active_window)->name); + + return 0; +} + +int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { + const char *pth = NULL; + if (argc == 0) { + struct completion_provider providers[] = {path_provider()}; + enable_completion(minibuffer_buffer(), + ((struct completion_trigger){ + .kind = CompletionTrigger_Input, .nchars = 0}), + providers, 1, find_file_comp_inserted); + return minibuffer_prompt(ctx, "find file: "); + } + + disable_completion(minibuffer_buffer()); + + open_file(ctx.buffers, ctx.active_window, argv[0]); + return 0; +} + +COMMAND_FN("find-file-internal", find_file, find_file, NULL); +int32_t find_file_relative(struct command_ctx ctx, int argc, + const char *argv[]) { + struct buffer *b = window_buffer(ctx.active_window); + if (b->filename == NULL) { + minibuffer_echo_timeout(4, "buffer %s is not backed by a file", b->name); + return 1; + } + + char *filename = strdup(b->filename); + char *dir = dirname(filename); + if (argc == 0) { + struct completion_provider providers[] = {path_provider()}; + enable_completion(minibuffer_buffer(), + ((struct completion_trigger){ + .kind = CompletionTrigger_Input, .nchars = 0}), + providers, 1, find_file_comp_inserted); + + ctx.self = &find_file_command; + minibuffer_prompt_initial(ctx, dir, "find file: "); + free(filename); + return 0; + } + disable_completion(minibuffer_buffer()); + size_t dirlen = strlen(dir); + size_t plen = strlen(argv[0]); + char *pth = (char *)malloc(dirlen + plen + 2); + memcpy(pth, dir, dirlen); + pth[dirlen] = '/'; + memcpy(pth + dirlen + 1, argv[0], plen); + pth[dirlen + plen + 1] = '\0'; + open_file(ctx.buffers, ctx.active_window, pth); + + free(filename); return 0; } @@ -272,6 +316,7 @@ void register_global_commands(struct commands *commands, void (*terminate_cb)()) { struct command global_commands[] = { {.name = "find-file", .fn = find_file}, + {.name = "find-file-relative", .fn = find_file_relative}, {.name = "write-file", .fn = write_file}, {.name = "run-command-interactive", .fn = run_interactive}, {.name = "switch-buffer", .fn = switch_buffer}, -- cgit v1.2.3