summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c33
-rw-r--r--src/display.c260
-rw-r--r--src/display.h4
3 files changed, 206 insertions, 91 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 5e05a73..2e54d30 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -258,6 +258,7 @@ struct cmdbuf {
uint32_t scroll_line;
uint32_t line_offset;
uint32_t col_offset;
+ uint32_t width;
struct line_render_hook *line_render_hooks;
uint32_t nlinerender_hooks;
};
@@ -270,8 +271,19 @@ void render_line(struct text_chunk *line, void *userdata) {
hook->callback(line, visual_line, cmdbuf->cmds, hook->userdata);
}
+ command_list_set_show_whitespace(cmdbuf->cmds, true);
command_list_draw_text(cmdbuf->cmds, cmdbuf->col_offset, visual_line,
line->text, line->nbytes);
+ command_list_set_show_whitespace(cmdbuf->cmds, false);
+
+ uint32_t col = line->nchars + cmdbuf->col_offset;
+ for (uint32_t bytei = 0; bytei < line->nbytes; ++bytei) {
+ if (line->text[bytei] == '\t') {
+ col += 3;
+ }
+ }
+ command_list_draw_repeated(cmdbuf->cmds, col, visual_line, ' ',
+ cmdbuf->width - line->nchars);
}
void scroll(struct buffer *buffer, int line_delta, int col_delta) {
@@ -342,13 +354,13 @@ struct update_hook_result buffer_modeline_hook(struct buffer *buffer,
if (strcmp(buf, (char *)modeline->buffer) != 0) {
modeline->buffer = realloc(modeline->buffer, width * 4);
strcpy((char *)modeline->buffer, buf);
-
- command_list_set_index_color_bg(commands, 8);
- command_list_draw_text(commands, 0, height - 1, modeline->buffer,
- strlen((char *)modeline->buffer));
- command_list_reset_color(commands);
}
+ command_list_set_index_color_bg(commands, 8);
+ command_list_draw_text(commands, 0, height - 1, modeline->buffer,
+ strlen((char *)modeline->buffer));
+ command_list_reset_color(commands);
+
struct update_hook_result res = {0};
res.margins.bottom = 1;
return res;
@@ -356,6 +368,7 @@ struct update_hook_result buffer_modeline_hook(struct buffer *buffer,
struct linenumdata {
uint32_t longest_nchars;
+ uint32_t dot_line;
} linenum_data;
void linenum_render_hook(struct text_chunk *line_data, uint32_t line,
@@ -364,9 +377,10 @@ void linenum_render_hook(struct text_chunk *line_data, uint32_t line,
struct linenumdata *data = (struct linenumdata *)userdata;
static char buf[16];
command_list_set_index_color_bg(commands, 236);
- command_list_set_index_color_fg(commands, 244);
+ command_list_set_index_color_fg(
+ commands, line_data->line == data->dot_line ? 253 : 244);
uint32_t chars =
- snprintf(buf, 16, "%*d", data->longest_nchars, line_data->line + 1);
+ snprintf(buf, 16, "%*d", data->longest_nchars + 1, line_data->line + 1);
command_list_draw_text_copy(commands, 0, line, (uint8_t *)buf, chars);
command_list_reset_color(commands);
command_list_draw_text(commands, data->longest_nchars + 1, line,
@@ -401,6 +415,7 @@ struct update_hook_result buffer_linenum_hook(struct buffer *buffer,
}
linenum_data.longest_nchars = longest_nchars;
+ linenum_data.dot_line = buffer->dot_line;
struct update_hook_result res = {0};
res.margins.left = longest_nchars + 2;
res.line_render_hook.callback = linenum_render_hook;
@@ -416,6 +431,7 @@ void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height,
return;
}
+ uint32_t total_width = width, total_height = height;
struct margin total_margins = {0};
struct line_render_hook line_hooks[16];
uint32_t nlinehooks = 0;
@@ -461,6 +477,7 @@ void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height,
.cmds = commands,
.scroll_line = buffer->scroll_line,
.col_offset = total_margins.left,
+ .width = width,
.line_offset = total_margins.top,
.line_render_hooks = line_hooks,
.nlinerender_hooks = nlinehooks,
@@ -472,7 +489,7 @@ void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height,
uint32_t nlines = text_num_lines(buffer->text);
for (uint32_t linei = nlines - buffer->scroll_line + total_margins.top;
linei < height; ++linei) {
- command_list_draw_text(commands, total_margins.left, linei, NULL, 0);
+ command_list_draw_repeated(commands, 0, linei, ' ', total_width);
}
// update the visual cursor position
diff --git a/src/display.c b/src/display.c
index 146d31e..7116e94 100644
--- a/src/display.c
+++ b/src/display.c
@@ -11,15 +11,46 @@
#define ESC 0x1b
+enum render_cmd_type {
+ RenderCommand_DrawText = 0,
+ RenderCommand_PushFormat = 1,
+ RenderCommand_Repeat = 2,
+ RenderCommand_ClearFormat = 3,
+ RenderCommand_SetShowWhitespace = 4,
+};
+
struct render_command {
+ enum render_cmd_type type;
+ union {
+ struct draw_text_cmd *draw_txt;
+ struct push_fmt_cmd *push_fmt;
+ struct repeat_cmd *repeat;
+ struct show_ws_cmd *show_ws;
+ };
+};
+
+struct draw_text_cmd {
uint32_t col;
uint32_t row;
uint8_t *data;
uint32_t len;
+};
+
+struct push_fmt_cmd {
+ uint8_t fmt[64];
+ uint32_t len;
+};
+
+struct repeat_cmd {
+ uint32_t col;
+ uint32_t row;
+ uint8_t c;
+ uint32_t nrepeat;
+};
- uint8_t *fmt;
- uint32_t fmt_len;
+struct show_ws_cmd {
+ bool show;
};
struct command_list {
@@ -30,9 +61,6 @@ struct command_list {
uint32_t xoffset;
uint32_t yoffset;
- uint8_t format[64];
- uint32_t format_len;
-
alloc_fn allocator;
char name[16];
@@ -77,19 +105,24 @@ void display_destroy(struct display *display) {
tcsetattr(0, TCSADRAIN, &display->orig_term);
}
-void putbytes(uint8_t *line_bytes, uint32_t line_length) {
- for (uint32_t bytei = 0; bytei < line_length; ++bytei) {
- uint8_t byte = line_bytes[bytei];
+void putbyte(uint8_t c) { putc(c, stdout); }
- if (byte == '\t') {
- fputs(" ", stdout);
- } else {
- fputc(byte, stdout);
- }
+void putbyte_ws(uint8_t c, bool show_whitespace) {
+ if (show_whitespace && c == '\t') {
+ fputs("\x1b[90m → \x1b[0m", stdout);
+ } else if (show_whitespace && c == ' ') {
+ fputs("\x1b[90m·\x1b[0m", stdout);
+ } else {
+ fputc(c, stdout);
}
}
-void putbyte(uint8_t c) { putc(c, stdout); }
+void putbytes(uint8_t *line_bytes, uint32_t line_length, bool show_whitespace) {
+ for (uint32_t bytei = 0; bytei < line_length; ++bytei) {
+ uint8_t byte = line_bytes[bytei];
+ putbyte_ws(byte, show_whitespace);
+ }
+}
void put_ansiparm(int n) {
int q = n / 10;
@@ -103,19 +136,6 @@ void put_ansiparm(int n) {
putbyte((n % 10) + '0');
}
-void put_format(uint8_t *bytes, uint32_t nbytes) {
- putbyte(ESC);
- putbyte('[');
- putbyte('0');
-
- if (nbytes > 0) {
- putbyte(';');
- putbytes(bytes, nbytes);
- }
-
- putbyte('m');
-}
-
void display_move_cursor(struct display *display, uint32_t row, uint32_t col) {
putbyte(ESC);
putbyte('[');
@@ -128,12 +148,7 @@ void display_move_cursor(struct display *display, uint32_t row, uint32_t col) {
void display_clear(struct display *display) {
display_move_cursor(display, 0, 0);
uint8_t bytes[] = {ESC, '[', 'J'};
- putbytes(bytes, 3);
-}
-
-void delete_to_eol() {
- uint8_t bytes[] = {ESC, '[', 'K'};
- putbytes(bytes, 3);
+ putbytes(bytes, 3, false);
}
struct command_list *command_list_create(uint32_t capacity, alloc_fn allocator,
@@ -145,7 +160,6 @@ struct command_list *command_list_create(uint32_t capacity, alloc_fn allocator,
command_list->ncmds = 0;
command_list->xoffset = xoffset;
command_list->yoffset = yoffset;
- command_list->format_len = 0;
strncpy(command_list->name, name, 15);
command_list->cmds = allocator(sizeof(struct render_command) * capacity);
@@ -154,51 +168,43 @@ struct command_list *command_list_create(uint32_t capacity, alloc_fn allocator,
return command_list;
}
-void push_format(struct command_list *list, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
-
- if (list->format_len > 0) {
- list->format[list->format_len] = ';';
- ++list->format_len;
+struct render_command *add_command(struct command_list *list,
+ enum render_cmd_type tp) {
+ if (list->ncmds == list->capacity) {
+ // TODO: better
+ return NULL;
}
- uint32_t format_space_left = sizeof(list->format) - list->format_len;
- list->format_len += vsnprintf((char *)(list->format + list->format_len),
- format_space_left, fmt, args);
-
- va_end(args);
-}
-
-void set_cmd_format(struct command_list *list, struct render_command *cmd) {
- if (list->format_len > 0) {
- cmd->fmt = list->allocator(list->format_len);
- memcpy(cmd->fmt, list->format, list->format_len);
- cmd->fmt_len = list->format_len;
- } else {
- cmd->fmt = NULL;
- cmd->fmt_len = 0;
+ struct render_command *cmd = &list->cmds[list->ncmds];
+ cmd->type = tp;
+ switch (tp) {
+ case RenderCommand_DrawText:
+ cmd->draw_txt = list->allocator(sizeof(struct draw_text_cmd));
+ break;
+ case RenderCommand_Repeat:
+ cmd->repeat = list->allocator(sizeof(struct repeat_cmd));
+ break;
+ case RenderCommand_PushFormat:
+ cmd->push_fmt = list->allocator(sizeof(struct push_fmt_cmd));
+ break;
+ case RenderCommand_SetShowWhitespace:
+ cmd->show_ws = list->allocator(sizeof(struct show_ws_cmd));
+ break;
+ case RenderCommand_ClearFormat:
+ break;
}
+ ++list->ncmds;
+ return cmd;
}
-void reset_format(struct command_list *list) { list->format_len = 0; }
-
void command_list_draw_text(struct command_list *list, uint32_t col,
uint32_t row, uint8_t *data, uint32_t len) {
- if (list->ncmds == list->capacity) {
- // TODO: better
- return;
- }
-
- struct render_command *cmd = &list->cmds[list->ncmds];
+ struct draw_text_cmd *cmd =
+ add_command(list, RenderCommand_DrawText)->draw_txt;
cmd->data = data;
cmd->col = col + list->xoffset;
cmd->row = row + list->yoffset;
cmd->len = len;
-
- set_cmd_format(list, cmd);
-
- ++list->ncmds;
}
void command_list_draw_text_copy(struct command_list *list, uint32_t col,
@@ -209,52 +215,140 @@ void command_list_draw_text_copy(struct command_list *list, uint32_t col,
command_list_draw_text(list, col, row, bytes, len);
}
+void command_list_draw_repeated(struct command_list *list, uint32_t col,
+ uint32_t row, uint8_t c, uint32_t nrepeat) {
+ struct repeat_cmd *cmd = add_command(list, RenderCommand_Repeat)->repeat;
+ cmd->col = col;
+ cmd->row = row;
+ cmd->c = c;
+ cmd->nrepeat = nrepeat;
+}
+
void command_list_set_index_color_fg(struct command_list *list,
uint8_t color_idx) {
+ struct push_fmt_cmd *cmd =
+ add_command(list, RenderCommand_PushFormat)->push_fmt;
+
if (color_idx < 8) {
- push_format(list, "%d", 30 + color_idx);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 30 + color_idx);
} else if (color_idx < 16) {
- push_format(list, "%d", 90 + color_idx - 8);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 90 + color_idx - 8);
} else {
- push_format(list, "38;5;%d", color_idx);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "38;5;%d", color_idx);
}
}
+
void command_list_set_color_fg(struct command_list *list, uint8_t red,
uint8_t green, uint8_t blue) {
- push_format(list, "38;2;%d;%d;%d", red, green, blue);
+ struct push_fmt_cmd *cmd =
+ add_command(list, RenderCommand_PushFormat)->push_fmt;
+ cmd->len = snprintf((char *)cmd->fmt, 64, "38;2;%d;%d;%d", red, green, blue);
}
void command_list_set_index_color_bg(struct command_list *list,
uint8_t color_idx) {
+ struct push_fmt_cmd *cmd =
+ add_command(list, RenderCommand_PushFormat)->push_fmt;
if (color_idx < 8) {
- push_format(list, "%d", 40 + color_idx);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 40 + color_idx);
} else if (color_idx < 16) {
- push_format(list, "%d", 100 + color_idx - 8);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "%d", 100 + color_idx - 8);
} else {
- push_format(list, "48;5;%d", color_idx);
+ cmd->len = snprintf((char *)cmd->fmt, 64, "48;5;%d", color_idx);
}
}
void command_list_set_color_bg(struct command_list *list, uint8_t red,
uint8_t green, uint8_t blue) {
- push_format(list, "48;2;%d;%d;%d", red, green, blue);
+ struct push_fmt_cmd *cmd =
+ add_command(list, RenderCommand_PushFormat)->push_fmt;
+ cmd->len = snprintf((char *)cmd->fmt, 64, "48;2;%d;%d;%d", red, green, blue);
+}
+
+void command_list_reset_color(struct command_list *list) {
+ add_command(list, RenderCommand_ClearFormat);
}
-void command_list_reset_color(struct command_list *list) { reset_format(list); }
+void command_list_set_show_whitespace(struct command_list *list, bool show) {
+ add_command(list, RenderCommand_SetShowWhitespace)->show_ws->show = show;
+}
void display_render(struct display *display,
struct command_list *command_list) {
struct command_list *cl = command_list;
+ uint8_t fmt_stack[256] = {0};
+ fmt_stack[0] = ESC;
+ fmt_stack[1] = '[';
+ fmt_stack[2] = '0';
+ uint32_t fmt_stack_len = 3;
+ bool show_whitespace_state = false;
for (uint64_t cmdi = 0; cmdi < cl->ncmds; ++cmdi) {
struct render_command *cmd = &cl->cmds[cmdi];
- display_move_cursor(display, cmd->row, cmd->col);
- put_format(cmd->fmt, cmd->fmt_len);
- putbytes(cmd->data, cmd->len);
- delete_to_eol();
+ switch (cmd->type) {
+ case RenderCommand_DrawText: {
+ struct draw_text_cmd *txt_cmd = cmd->draw_txt;
+ display_move_cursor(display, txt_cmd->row, txt_cmd->col);
+ putbytes(fmt_stack, fmt_stack_len, false);
+ putbyte('m');
+ putbytes(txt_cmd->data, txt_cmd->len, show_whitespace_state);
+ break;
+ }
+
+ case RenderCommand_Repeat: {
+ struct repeat_cmd *repeat_cmd = cmd->repeat;
+ display_move_cursor(display, repeat_cmd->row, repeat_cmd->col);
+ putbytes(fmt_stack, fmt_stack_len, false);
+ putbyte('m');
+ for (uint32_t i = 0; i < repeat_cmd->nrepeat; ++i) {
+ putbyte_ws(repeat_cmd->c, show_whitespace_state);
+ }
+ break;
+ }
+
+ case RenderCommand_PushFormat: {
+ struct push_fmt_cmd *fmt_cmd = cmd->push_fmt;
+
+ fmt_stack[fmt_stack_len] = ';';
+ ++fmt_stack_len;
+
+ memcpy(fmt_stack + fmt_stack_len, fmt_cmd->fmt, fmt_cmd->len);
+ fmt_stack_len += fmt_cmd->len;
+ break;
+ }
+
+ case RenderCommand_ClearFormat:
+ fmt_stack_len = 3;
+ break;
+
+ case RenderCommand_SetShowWhitespace:
+ show_whitespace_state = cmd->show_ws->show;
+ break;
+ }
}
}
-void display_begin_render(struct display *display) {}
-void display_end_render(struct display *display) { fflush(stdout); }
+void hide_cursor() {
+ putbyte(ESC);
+ putbyte('[');
+ putbyte('?');
+ putbyte('2');
+ putbyte('5');
+ putbyte('l');
+}
+
+void show_cursor() {
+ putbyte(ESC);
+ putbyte('[');
+ putbyte('?');
+ putbyte('2');
+ putbyte('5');
+ putbyte('h');
+}
+
+void display_begin_render(struct display *display) { hide_cursor(); }
+void display_end_render(struct display *display) {
+ show_cursor();
+ fflush(stdout);
+}
diff --git a/src/display.h b/src/display.h
index e518b34..9a1cee5 100644
--- a/src/display.h
+++ b/src/display.h
@@ -1,3 +1,4 @@
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -29,6 +30,7 @@ struct command_list *command_list_create(uint32_t capacity, alloc_fn allocator,
uint32_t xoffset, uint32_t yoffset,
const char *name);
+void command_list_set_show_whitespace(struct command_list *list, bool show);
void command_list_set_index_color_bg(struct command_list *list,
uint8_t color_idx);
void command_list_set_color_bg(struct command_list *list, uint8_t red,
@@ -42,3 +44,5 @@ void command_list_draw_text(struct command_list *list, uint32_t col,
uint32_t row, uint8_t *data, uint32_t len);
void command_list_draw_text_copy(struct command_list *list, uint32_t col,
uint32_t row, uint8_t *data, uint32_t len);
+void command_list_draw_repeated(struct command_list *list, uint32_t col,
+ uint32_t row, uint8_t c, uint32_t nrepeat);