diff options
| -rw-r--r-- | src/buffer.c | 33 | ||||
| -rw-r--r-- | src/display.c | 260 | ||||
| -rw-r--r-- | src/display.h | 4 |
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); |
