summaryrefslogtreecommitdiff
path: root/examples/dte/screen-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/dte/screen-view.c')
-rw-r--r--examples/dte/screen-view.c427
1 files changed, 0 insertions, 427 deletions
diff --git a/examples/dte/screen-view.c b/examples/dte/screen-view.c
deleted file mode 100644
index 0f8d72c..0000000
--- a/examples/dte/screen-view.c
+++ /dev/null
@@ -1,427 +0,0 @@
-#include "screen.h"
-#include "indent.h"
-#include "selection.h"
-#include "syntax/highlight.h"
-#include "util/ascii.h"
-#include "util/debug.h"
-#include "util/str-util.h"
-#include "util/utf8.h"
-
-typedef struct {
- const View *view;
- size_t line_nr;
- size_t offset;
- ssize_t sel_so;
- ssize_t sel_eo;
-
- const unsigned char *line;
- size_t size;
- size_t pos;
- size_t indent_size;
- size_t trailing_ws_offset;
- const TermColor **colors;
-} LineInfo;
-
-// Like mask_color() but can change bg color only if it has not been changed yet
-static void mask_color2(const ColorScheme *colors, TermColor *color, const TermColor *over)
-{
- int32_t default_bg = colors->builtin[BC_DEFAULT].bg;
- if (over->bg != COLOR_KEEP && (color->bg == default_bg || color->bg < 0)) {
- color->bg = over->bg;
- }
-
- if (over->fg != COLOR_KEEP) {
- color->fg = over->fg;
- }
-
- if (!(over->attr & ATTR_KEEP)) {
- color->attr = over->attr;
- }
-}
-
-static void mask_selection_and_current_line (
- const ColorScheme *colors,
- const LineInfo *info,
- TermColor *color
-) {
- if (info->offset >= info->sel_so && info->offset < info->sel_eo) {
- mask_color(color, &colors->builtin[BC_SELECTION]);
- } else if (info->line_nr == info->view->cy) {
- mask_color2(colors, color, &colors->builtin[BC_CURRENTLINE]);
- }
-}
-
-static bool is_non_text(CodePoint u, bool display_special)
-{
- if (u == '\t') {
- return display_special;
- }
- return u < 0x20 || u == 0x7F || u_is_unprintable(u);
-}
-
-static WhitespaceErrorFlags get_ws_error(const LocalOptions *opts)
-{
- WhitespaceErrorFlags taberrs = WSE_TAB_INDENT | WSE_TAB_AFTER_INDENT;
- WhitespaceErrorFlags extra = opts->expand_tab ? taberrs : WSE_SPACE_INDENT;
- return opts->ws_error | ((opts->ws_error & WSE_AUTO_INDENT) ? extra : 0);
-}
-
-static bool whitespace_error(const LineInfo *info, CodePoint u, size_t i)
-{
- const View *view = info->view;
- WhitespaceErrorFlags flags = get_ws_error(&view->buffer->options);
- WhitespaceErrorFlags trailing = flags & (WSE_TRAILING | WSE_ALL_TRAILING);
- if (i >= info->trailing_ws_offset && trailing) {
- // Trailing whitespace
- if (
- // Cursor is not on this line
- info->line_nr != view->cy
- // or is positioned before any trailing whitespace
- || view->cx < info->trailing_ws_offset
- // or user explicitly wants trailing space under cursor highlighted
- || flags & WSE_ALL_TRAILING
- ) {
- return true;
- }
- }
-
- bool in_indent = (i < info->indent_size);
- if (u == '\t') {
- WhitespaceErrorFlags mask = in_indent ? WSE_TAB_INDENT : WSE_TAB_AFTER_INDENT;
- return (flags & mask) != 0;
- }
- if (!in_indent) {
- // All checks below here only apply to indentation
- return false;
- }
-
- const char *line = info->line;
- size_t pos = i;
- size_t count = 0;
- while (pos > 0 && line[pos - 1] == ' ') {
- pos--;
- }
- while (pos < info->size && line[pos] == ' ') {
- pos++;
- count++;
- }
-
- WhitespaceErrorFlags mask;
- if (count >= view->buffer->options.tab_width) {
- // Spaces used instead of tab
- mask = WSE_SPACE_INDENT;
- } else if (pos < info->size && line[pos] == '\t') {
- // Space before tab
- mask = WSE_SPACE_INDENT;
- } else {
- // Less than tab width spaces at end of indentation
- mask = WSE_SPACE_ALIGN;
- }
- return (flags & mask) != 0;
-}
-
-static CodePoint screen_next_char(EditorState *e, LineInfo *info)
-{
- size_t count, pos = info->pos;
- CodePoint u = info->line[pos];
- TermColor color;
- bool ws_error = false;
-
- if (likely(u < 0x80)) {
- info->pos++;
- count = 1;
- if (u == '\t' || u == ' ') {
- ws_error = whitespace_error(info, u, pos);
- }
- } else {
- u = u_get_nonascii(info->line, info->size, &info->pos);
- count = info->pos - pos;
-
- if (
- u_is_special_whitespace(u) // Highly annoying no-break space etc.
- && (info->view->buffer->options.ws_error & WSE_SPECIAL)
- ) {
- ws_error = true;
- }
- }
-
- if (info->colors && info->colors[pos]) {
- color = *info->colors[pos];
- } else {
- color = e->colors.builtin[BC_DEFAULT];
- }
- if (is_non_text(u, e->options.display_special)) {
- mask_color(&color, &e->colors.builtin[BC_NONTEXT]);
- }
- if (ws_error) {
- mask_color(&color, &e->colors.builtin[BC_WSERROR]);
- }
- mask_selection_and_current_line(&e->colors, info, &color);
- set_color(&e->terminal, &e->colors, &color);
-
- info->offset += count;
- return u;
-}
-
-static void screen_skip_char(TermOutputBuffer *obuf, LineInfo *info)
-{
- CodePoint u = info->line[info->pos++];
- info->offset++;
- if (likely(u < 0x80)) {
- if (likely(!ascii_iscntrl(u))) {
- obuf->x++;
- } else if (u == '\t' && obuf->tab_mode != TAB_CONTROL) {
- obuf->x = next_indent_width(obuf->x, obuf->tab_width);
- } else {
- // Control
- obuf->x += 2;
- }
- } else {
- size_t pos = info->pos;
- info->pos--;
- u = u_get_nonascii(info->line, info->size, &info->pos);
- obuf->x += u_char_width(u);
- info->offset += info->pos - pos;
- }
-}
-
-static bool is_notice(const char *word, size_t len)
-{
- switch (len) {
- case 3: return mem_equal(word, "XXX", 3);
- case 4: return mem_equal(word, "TODO", 4);
- case 5: return mem_equal(word, "FIXME", 5);
- }
- return false;
-}
-
-// Highlight certain words inside comments
-static void hl_words(Terminal *term, const ColorScheme *colors, const LineInfo *info)
-{
- const TermColor *cc = find_color(colors, "comment");
- const TermColor *nc = find_color(colors, "notice");
-
- if (!info->colors || !cc || !nc) {
- return;
- }
-
- size_t i = info->pos;
- if (i >= info->size) {
- return;
- }
-
- // Go to beginning of partially visible word inside comment
- while (i > 0 && info->colors[i] == cc && is_word_byte(info->line[i])) {
- i--;
- }
-
- // This should be more than enough. I'm too lazy to iterate characters
- // instead of bytes and calculate text width.
- const size_t max = info->pos + term->width * 4 + 8;
-
- size_t si;
- while (i < info->size) {
- if (info->colors[i] != cc || !is_word_byte(info->line[i])) {
- if (i > max) {
- break;
- }
- i++;
- } else {
- // Beginning of a word inside comment
- si = i++;
- while (
- i < info->size && info->colors[i] == cc
- && is_word_byte(info->line[i])
- ) {
- i++;
- }
- if (is_notice(info->line + si, i - si)) {
- for (size_t j = si; j < i; j++) {
- info->colors[j] = nc;
- }
- }
- }
- }
-}
-
-static void line_info_init (
- LineInfo *info,
- const View *view,
- const BlockIter *bi,
- size_t line_nr
-) {
- *info = (LineInfo) {
- .view = view,
- .line_nr = line_nr,
- .offset = block_iter_get_offset(bi),
- };
-
- if (!view->selection) {
- info->sel_so = -1;
- info->sel_eo = -1;
- } else if (view->sel_eo != SEL_EO_RECALC) {
- // Already calculated
- info->sel_so = view->sel_so;
- info->sel_eo = view->sel_eo;
- BUG_ON(info->sel_so > info->sel_eo);
- } else {
- SelectionInfo sel;
- init_selection(view, &sel);
- info->sel_so = sel.so;
- info->sel_eo = sel.eo;
- }
-}
-
-static void line_info_set_line (
- LineInfo *info,
- const StringView *line,
- const TermColor **colors
-) {
- BUG_ON(line->length == 0);
- BUG_ON(line->data[line->length - 1] != '\n');
-
- info->line = line->data;
- info->size = line->length - 1;
- info->pos = 0;
- info->colors = colors;
-
- {
- size_t i, n;
- for (i = 0, n = info->size; i < n; i++) {
- char ch = info->line[i];
- if (ch != '\t' && ch != ' ') {
- break;
- }
- }
- info->indent_size = i;
- }
-
- static_assert_compatible_types(info->trailing_ws_offset, size_t);
- info->trailing_ws_offset = SIZE_MAX;
- for (ssize_t i = info->size - 1; i >= 0; i--) {
- char ch = info->line[i];
- if (ch != '\t' && ch != ' ') {
- break;
- }
- info->trailing_ws_offset = i;
- }
-}
-
-static void print_line(EditorState *e, LineInfo *info)
-{
- // Screen might be scrolled horizontally. Skip most invisible
- // characters using screen_skip_char(), which is much faster than
- // buf_skip(screen_next_char(info)).
- //
- // There can be a wide character (tab, control code etc.) that is
- // partially visible and can't be skipped using screen_skip_char().
- Terminal *term = &e->terminal;
- TermOutputBuffer *obuf = &term->obuf;
- while (obuf->x + 8 < obuf->scroll_x && info->pos < info->size) {
- screen_skip_char(obuf, info);
- }
-
- const ColorScheme *colors = &e->colors;
- hl_words(term, colors, info);
-
- while (info->pos < info->size) {
- BUG_ON(obuf->x > obuf->scroll_x + obuf->width);
- CodePoint u = screen_next_char(e, info);
- if (!term_put_char(obuf, u)) {
- // +1 for newline
- info->offset += info->size - info->pos + 1;
- return;
- }
- }
-
- TermColor color;
- if (e->options.display_special && obuf->x >= obuf->scroll_x) {
- // Syntax highlighter highlights \n but use default color anyway
- color = colors->builtin[BC_DEFAULT];
- mask_color(&color, &colors->builtin[BC_NONTEXT]);
- mask_selection_and_current_line(colors, info, &color);
- set_color(term, colors, &color);
- term_put_char(obuf, '$');
- }
-
- color = colors->builtin[BC_DEFAULT];
- mask_selection_and_current_line(colors, info, &color);
- set_color(term, colors, &color);
- info->offset++;
- term_clear_eol(term);
-}
-
-void update_range(EditorState *e, const View *view, long y1, long y2)
-{
- const int edit_x = view->window->edit_x;
- const int edit_y = view->window->edit_y;
- const int edit_w = view->window->edit_w;
- const int edit_h = view->window->edit_h;
-
- Terminal *term = &e->terminal;
- TermOutputBuffer *obuf = &term->obuf;
- term_output_reset(term, edit_x, edit_w, view->vx);
- obuf->tab_width = view->buffer->options.tab_width;
- obuf->tab_mode = e->options.display_special ? TAB_SPECIAL : TAB_NORMAL;
-
- BlockIter bi = view->cursor;
- for (long i = 0, n = view->cy - y1; i < n; i++) {
- block_iter_prev_line(&bi);
- }
- for (long i = 0, n = y1 - view->cy; i < n; i++) {
- block_iter_eat_line(&bi);
- }
- block_iter_bol(&bi);
-
- LineInfo info;
- line_info_init(&info, view, &bi, y1);
-
- y1 -= view->vy;
- y2 -= view->vy;
-
- bool got_line = !block_iter_is_eof(&bi);
- hl_fill_start_states(view->buffer, &e->colors, info.line_nr);
- long i;
- for (i = y1; got_line && i < y2; i++) {
- obuf->x = 0;
- term_move_cursor(obuf, edit_x, edit_y + i);
-
- StringView line;
- fill_line_nl_ref(&bi, &line);
- bool next_changed;
- const TermColor **colors = hl_line(view->buffer, &e->colors, &line, info.line_nr, &next_changed);
- line_info_set_line(&info, &line, colors);
- print_line(e, &info);
-
- got_line = !!block_iter_next_line(&bi);
- info.line_nr++;
-
- if (next_changed && i + 1 == y2 && y2 < edit_h) {
- // More lines need to be updated not because their contents have
- // changed but because their highlight state has
- y2++;
- }
- }
-
- if (i < y2 && info.line_nr == view->cy) {
- // Dummy empty line is shown only if cursor is on it
- TermColor color = e->colors.builtin[BC_DEFAULT];
-
- obuf->x = 0;
- mask_color2(&e->colors, &color, &e->colors.builtin[BC_CURRENTLINE]);
- set_color(term, &e->colors, &color);
-
- term_move_cursor(obuf, edit_x, edit_y + i++);
- term_clear_eol(term);
- }
-
- if (i < y2) {
- set_builtin_color(term, &e->colors, BC_NOLINE);
- }
- for (; i < y2; i++) {
- obuf->x = 0;
- term_move_cursor(obuf, edit_x, edit_y + i);
- term_put_char(obuf, '~');
- term_clear_eol(term);
- }
-}