diff options
Diffstat (limited to 'src/buffer.c')
| -rw-r--r-- | src/buffer.c | 100 |
1 files changed, 90 insertions, 10 deletions
diff --git a/src/buffer.c b/src/buffer.c index d6f3726..14d1b32 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,5 +1,6 @@ #include "buffer.h" #include "binding.h" +#include "bits/stdint-intn.h" #include "bits/stdint-uintn.h" #include "display.h" #include "minibuffer.h" @@ -23,7 +24,8 @@ struct buffer buffer_create(const char *name) { .modeline_buf = (uint8_t *)malloc(1024), .keymaps = calloc(10, sizeof(struct keymap)), .nkeymaps = 1, - .lines_rendered = -1, + .scroll_col = 0, + .scroll_line = 0, .nkeymaps_max = 10}; b.keymaps[0] = keymap_create("buffer-default", 128); @@ -176,6 +178,11 @@ int buffer_add_text(struct buffer *buffer, uint8_t *text, uint32_t nbytes) { text_append(buffer->text, buffer->dot_line, buffer->dot_col, text, nbytes, &lines_added, &cols_added); movev(buffer, lines_added); + + if (lines_added > 0) { + // does not make sense to use position from another line + buffer->dot_col = 0; + } moveh(buffer, cols_added); return lines_added; @@ -218,36 +225,109 @@ bool modeline_update(struct buffer *buffer, uint32_t width, } } +struct cmdbuf { + struct render_cmd *cmds; + uint32_t ncmds; + uint32_t first_line; +}; + +void render_line(struct text_chunk *line, void *userdata) { + struct cmdbuf *cmdbuf = (struct cmdbuf *)userdata; + + struct render_cmd *cmd = &cmdbuf->cmds[cmdbuf->ncmds]; + cmd->col = 0; + cmd->data = line->text; + cmd->len = line->nbytes; + cmd->row = line->line - cmdbuf->first_line; + + ++cmdbuf->ncmds; +} + +void scroll(struct buffer *buffer, int line_delta, int col_delta) { + uint32_t nlines = text_num_lines(buffer->text); + int64_t new_line = (int64_t)buffer->scroll_line + line_delta; + if (new_line >= 0 && new_line < nlines) { + buffer->scroll_line = (uint32_t)new_line; + } + + int64_t new_col = (int64_t)buffer->scroll_col + col_delta; + if (new_col >= 0 && + new_col < text_line_length(buffer->text, buffer->dot_line)) { + buffer->scroll_col = (uint32_t)new_col; + } +} + +void to_relative(struct buffer *buffer, uint32_t line, uint32_t col, + int64_t *rel_line, int64_t *rel_col) { + *rel_col = (int64_t)col - (int64_t)buffer->scroll_col; + *rel_line = (int64_t)line - (int64_t)buffer->scroll_line; +} + struct buffer_update buffer_update(struct buffer *buffer, uint32_t width, uint32_t height, alloc_fn frame_alloc, struct reactor *reactor, uint64_t frame_time) { - struct buffer_update upd = (struct buffer_update){.cmds = 0, .ncmds = 0}; - // reserve space for modeline uint32_t bufheight = height - 1; - uint32_t nlines = - buffer->lines_rendered > bufheight ? bufheight : buffer->lines_rendered; + + int64_t rel_line, rel_col; + to_relative(buffer, buffer->dot_line, buffer->dot_col, &rel_line, &rel_col); + int line_delta = 0, col_delta = 0; + if (rel_line < 0) { + line_delta = -(int)bufheight / 2; + } else if (rel_line >= bufheight) { + line_delta = bufheight / 2; + } + + if (rel_col < 0) { + col_delta = rel_col; + } else if (rel_col > width) { + col_delta = rel_col - width; + } + + scroll(buffer, line_delta, col_delta); struct render_cmd *cmds = (struct render_cmd *)frame_alloc(sizeof(struct render_cmd) * (height)); - uint32_t ncmds = text_render(buffer->text, 0, nlines, cmds, nlines); + struct cmdbuf cmdbuf = (struct cmdbuf){ + .cmds = cmds, + .ncmds = 0, + .first_line = buffer->scroll_line, + }; + text_for_each_line(buffer->text, buffer->scroll_line, bufheight, render_line, + &cmdbuf); - buffer->lines_rendered = text_num_lines(buffer->text); + uint32_t nlines = text_num_lines(buffer->text); + uint32_t ncmds = cmdbuf.ncmds; + for (uint32_t linei = nlines - buffer->scroll_line; linei < bufheight; + ++linei) { + cmds[ncmds] = (struct render_cmd){ + .col = 0, + .row = linei, + .data = NULL, + .len = 0, + }; + ++ncmds; + } if (modeline_update(buffer, width, frame_time)) { cmds[ncmds] = (struct render_cmd){ .col = 0, - .row = height - 1, + .row = bufheight, .data = buffer->modeline_buf, .len = strlen((char *)buffer->modeline_buf), }; ++ncmds; } - upd.cmds = cmds; - upd.ncmds = ncmds; + struct buffer_update upd = + (struct buffer_update){.cmds = cmds, .ncmds = ncmds}; + + int64_t new_line, new_col; + to_relative(buffer, buffer->dot_line, buffer->dot_col, &new_line, &new_col); + upd.dot_line = (uint32_t)new_line; + upd.dot_col = (uint32_t)new_col; return upd; } |
