summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2022-12-13 09:01:00 +0100
committerAlbert Cervin <albert@acervin.com>2022-12-13 09:01:00 +0100
commita73225c9b45e110d315a3fc587a82040ce8c9a13 (patch)
treef6b00156d203181ecbfd2f02cf7b1589dfd88e91
parent31e6fb2ba5fe9fd04722971a13a72ec71e846e46 (diff)
downloaddged-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.
-rw-r--r--GNUmakefile2
-rw-r--r--Makefile2
-rw-r--r--src/buffer.c100
-rw-r--r--src/buffer.h5
-rw-r--r--src/main.c3
-rw-r--r--src/text.c31
-rw-r--r--src/text.h4
7 files changed, 104 insertions, 43 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 706626d..3671e2f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,6 +1,6 @@
# GNU-compatible makefile
include common.mk
-include $(UNAME_S).mk
+sinclude $(UNAME_S).mk
include $(DEPS)
diff --git a/Makefile b/Makefile
index 2e61bd1..e154497 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
.include "common.mk"
-.include "$(UNAME_S).mk"
+.sinclude "$(UNAME_S).mk"
# in this case we need a separate depend target
depend: $(DEPS)
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);
diff --git a/src/main.c b/src/main.c
index 3874691..92e84d1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
diff --git a/src/text.c b/src/text.c
index b2e43f9..952f4ce 100644
--- a/src/text.c
+++ b/src/text.c
@@ -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,
};
}
diff --git a/src/text.h b/src/text.h
index a057a47..708ef09 100644
--- a/src/text.h
+++ b/src/text.h
@@ -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);