From 8d73eace6806bd67852189b1a16de5895c565688 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Mon, 1 May 2023 23:35:16 +0200 Subject: Implement buffer reload Currently only implemented on the buffer itself, and will discard any pending changes to the buffer. Idea is to use a command to detect that state and warn the user. --- src/dged/buffer.c | 70 +++++++++++++++++++++++++++++++++++++++++-------------- src/dged/buffer.h | 4 ++++ src/main/cmds.c | 2 ++ 3 files changed, 59 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/dged/buffer.c b/src/dged/buffer.c index 25a8a4a..958d1bb 100644 --- a/src/dged/buffer.c +++ b/src/dged/buffer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,7 @@ struct buffer buffer_create(char *name) { .modified = false, .readonly = false, .lang = lang_from_id("fnd"), + .last_write = {0}, }; undo_init(&b.undo, 100); @@ -467,15 +469,14 @@ void buffer_end_of_line(struct buffer_view *view) { void buffer_beginning_of_line(struct buffer_view *view) { view->dot.col = 0; } -struct buffer buffer_from_file(char *filename) { - struct buffer b = buffer_create(basename((char *)filename)); - b.filename = strdup(filename); - if (access(b.filename, F_OK) == 0) { - FILE *file = fopen(filename, "r"); +void buffer_read_from_file(struct buffer *b) { + struct stat sb; + if (stat(b->filename, &sb) == 0) { + FILE *file = fopen(b->filename, "r"); if (file == NULL) { - minibuffer_echo("Error opening %s: %s", filename, strerror(errno)); - return b; + minibuffer_echo("Error opening %s: %s", b->filename, strerror(errno)); + return; } while (true) { @@ -483,24 +484,35 @@ struct buffer buffer_from_file(char *filename) { int bytes = fread(buff, 1, 4096, file); if (bytes > 0) { uint32_t ignore; - text_append(b.text, buff, bytes, &ignore, &ignore); + text_append(b->text, buff, bytes, &ignore, &ignore); } else if (bytes == 0) { break; // EOF } else { - minibuffer_echo("error reading from %s: %s", filename, strerror(errno)); + minibuffer_echo("error reading from %s: %s", b->filename, + strerror(errno)); fclose(file); - return b; + return; } } fclose(file); + b->last_write = sb.st_mtim; + } else { + minibuffer_echo("Error opening %s: %s", b->filename, strerror(errno)); + return; } - const char *ext = strrchr(b.filename, '.'); + const char *ext = strrchr(b->filename, '.'); if (ext != NULL) { - b.lang = lang_from_extension(ext + 1); + b->lang = lang_from_extension(ext + 1); } - undo_push_boundary(&b.undo, (struct undo_boundary){.save_point = true}); + undo_push_boundary(&b->undo, (struct undo_boundary){.save_point = true}); +} + +struct buffer buffer_from_file(char *filename) { + struct buffer b = buffer_create(basename((char *)filename)); + b.filename = strdup(filename); + buffer_read_from_file(&b); return b; } @@ -540,6 +552,7 @@ void buffer_to_file(struct buffer *buffer) { buffer->filename); fclose(file); + clock_gettime(CLOCK_REALTIME, &buffer->last_write); buffer->modified = false; undo_push_boundary(&buffer->undo, (struct undo_boundary){.save_point = true}); } @@ -549,6 +562,26 @@ void buffer_write_to(struct buffer *buffer, const char *filename) { buffer_to_file(buffer); } +void buffer_reload(struct buffer *buffer) { + if (buffer->filename == NULL) { + return; + } + + // check if we actually need to reload + struct stat sb; + if (stat(buffer->filename, &sb) < 0) { + minibuffer_echo_timeout(4, "failed to run stat on %s", buffer->filename); + return; + } + + if (sb.st_mtim.tv_sec != buffer->last_write.tv_sec) { + text_clear(buffer->text); + buffer_read_from_file(buffer); + } else { + minibuffer_echo_timeout(2, "buffer %s not changed", buffer->filename); + } +} + struct search_data { VEC(struct match) matches; const char *pattern; @@ -774,15 +807,18 @@ void render_line(struct text_chunk *line, void *userdata) { bytei < text_nbytes_scroll && linewidth < cmdbuf->width; ++bytei) { uint8_t *txt = &text[bytei]; if (*txt == '\t') { - linewidth += 3; + linewidth += 4; } else if (utf8_byte_is_unicode_start(*txt)) { wchar_t wc; - if (mbrtowc(&wc, (char *)txt, 6, NULL) >= 0) { - linewidth += wcwidth(wc) - 1; + size_t nbytes; + if ((nbytes = mbrtowc(&wc, (char *)txt, 6, NULL)) > 0) { + text_nbytes += nbytes - 1; + linewidth += wcwidth(wc); } + } else if (utf8_byte_is_ascii(*txt)) { + ++linewidth; } - ++linewidth; ++text_nbytes; } diff --git a/src/dged/buffer.h b/src/dged/buffer.h index 539c427..b9edf4a 100644 --- a/src/dged/buffer.h +++ b/src/dged/buffer.h @@ -1,6 +1,7 @@ #include #include #include +#include #include "bits/stdint-uintn.h" #include "command.h" @@ -138,6 +139,8 @@ struct buffer { /** Associated filename, this is where the buffer will be saved to */ char *filename; + struct timespec last_write; + /** Text data structure */ struct text *text; @@ -213,6 +216,7 @@ uint32_t buffer_add_create_hook(create_hook_cb hook, void *userdata); struct buffer buffer_from_file(char *filename); void buffer_to_file(struct buffer *buffer); void buffer_write_to(struct buffer *buffer, const char *filename); +void buffer_reload(struct buffer *buffer); void buffer_update(struct buffer_view *view, uint32_t width, uint32_t height, struct command_list *commands, uint64_t frame_time, diff --git a/src/main/cmds.c b/src/main/cmds.c index 2041cba..27b2a77 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -307,6 +307,7 @@ BUFFER_WRAPCMD_POS(buffer_beginning_of_line); BUFFER_WRAPCMD_POS(buffer_newline); BUFFER_WRAPCMD_POS(buffer_indent); BUFFER_WRAPCMD(buffer_to_file); +BUFFER_WRAPCMD(buffer_reload); BUFFER_WRAPCMD_POS(buffer_set_mark); BUFFER_WRAPCMD_POS(buffer_clear_mark); BUFFER_WRAPCMD_POS(buffer_copy); @@ -357,6 +358,7 @@ void register_buffer_commands(struct commands *commands) { {.name = "undo", .fn = buffer_undo_cmd}, {.name = "scroll-down", .fn = buffer_view_scroll_down_cmd}, {.name = "scroll-up", .fn = buffer_view_scroll_up_cmd}, + {.name = "reload", .fn = buffer_reload_cmd}, }; register_commands(commands, buffer_commands, -- cgit v1.2.3