diff options
| author | Albert Cervin <albert@acervin.com> | 2022-12-13 09:01:00 +0100 |
|---|---|---|
| committer | Albert Cervin <albert@acervin.com> | 2022-12-13 09:01:00 +0100 |
| commit | a73225c9b45e110d315a3fc587a82040ce8c9a13 (patch) | |
| tree | f6b00156d203181ecbfd2f02cf7b1589dfd88e91 /src | |
| parent | 31e6fb2ba5fe9fd04722971a13a72ec71e846e46 (diff) | |
| download | dged-a73225c9b45e110d315a3fc587a82040ce8c9a13.tar.gz dged-a73225c9b45e110d315a3fc587a82040ce8c9a13.tar.xz dged-a73225c9b45e110d315a3fc587a82040ce8c9a13.zip | |
Implement scrolling
Buffer now scrolls correcly when reaching top or bottom and puts dot at
the middle of the screen.
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer.c | 100 | ||||
| -rw-r--r-- | src/buffer.h | 5 | ||||
| -rw-r--r-- | src/main.c | 3 | ||||
| -rw-r--r-- | src/text.c | 31 | ||||
| -rw-r--r-- | src/text.h | 4 |
5 files changed, 102 insertions, 41 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; } diff --git a/src/buffer.h b/src/buffer.h index 358aea5..92cc353 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -24,12 +24,15 @@ struct buffer { uint32_t nkeymaps; uint32_t nkeymaps_max; - uint32_t lines_rendered; + uint32_t scroll_line; + uint32_t scroll_col; }; struct buffer_update { struct render_cmd *cmds; uint64_t ncmds; + uint32_t dot_col; + uint32_t dot_line; }; typedef void *(alloc_fn)(size_t); @@ -163,7 +163,8 @@ int main(int argc, char *argv[]) { // update screen clock_gettime(CLOCK_MONOTONIC, &display_begin); if (render_bufs[0].ncmds > 0 || render_bufs[1].ncmds > 0) { - display_update(&display, render_bufs, 2, curbuf.dot_line, curbuf.dot_col); + display_update(&display, render_bufs, 2, buf_upd.dot_line, + buf_upd.dot_col); } clock_gettime(CLOCK_MONOTONIC, &display_end); @@ -282,31 +282,6 @@ void text_delete(struct text *text, uint32_t line, uint32_t col, } } -uint32_t text_render(struct text *text, uint32_t line, uint32_t nlines, - struct render_cmd *cmds, uint32_t max_ncmds) { - uint32_t nlines_max = nlines > text->capacity ? text->capacity : nlines; - - uint32_t ncmds = 0; - for (uint32_t lineidx = line; lineidx < nlines_max; ++lineidx) { - struct line *lp = &text->lines[lineidx]; - if (lp->flags & LineChanged) { - - cmds[ncmds] = (struct render_cmd){ - .row = lineidx, - .col = 0, // TODO: do not redraw full line - .data = lp->data, - .len = lp->nbytes, - }; - - lp->flags &= ~(LineChanged); - - ++ncmds; - } - } - - return ncmds; -} - void text_for_each_chunk(struct text *text, chunk_cb callback, void *userdata) { // if representation of text is changed, this can be changed as well text_for_each_line(text, 0, text->nlines, callback, userdata); @@ -314,12 +289,15 @@ void text_for_each_chunk(struct text *text, chunk_cb callback, void *userdata) { void text_for_each_line(struct text *text, uint32_t line, uint32_t nlines, chunk_cb callback, void *userdata) { - for (uint32_t li = line; li < (line + nlines); ++li) { + uint32_t nlines_max = + (line + nlines) > text->nlines ? text->nlines : (line + nlines); + for (uint32_t li = line; li < nlines_max; ++li) { struct line *src_line = &text->lines[li]; struct text_chunk line = (struct text_chunk){ .text = src_line->data, .nbytes = src_line->nbytes, .nchars = src_line->nchars, + .line = li, }; callback(&line, userdata); } @@ -331,6 +309,7 @@ struct text_chunk text_get_line(struct text *text, uint32_t line) { .text = src_line->data, .nbytes = src_line->nbytes, .nchars = src_line->nchars, + .line = line, }; } @@ -16,9 +16,6 @@ void text_append(struct text *text, uint32_t line, uint32_t col, uint8_t *bytes, void text_delete(struct text *text, uint32_t line, uint32_t col, uint32_t nchars); -uint32_t text_render(struct text *text, uint32_t line, uint32_t nlines, - struct render_cmd *cmds, uint32_t max_ncmds); - uint32_t text_num_lines(struct text *text); uint32_t text_line_length(struct text *text, uint32_t lineidx); uint32_t text_line_size(struct text *text, uint32_t lineidx); @@ -27,6 +24,7 @@ struct text_chunk { uint8_t *text; uint32_t nbytes; uint32_t nchars; + uint32_t line; }; typedef void (*chunk_cb)(struct text_chunk *chunk, void *userdata); |
