diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2017-03-14 16:53:53 +0100 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2017-03-14 19:04:21 +0100 |
| commit | 9bcf2667e7e239873597b7ec2172206a9af18071 (patch) | |
| tree | 7e9ccb42fa665ba01be65b93fc995fa76719aaf7 /vis.c | |
| parent | bed289a96e1ed17e4b9fa4f9e22227fcf13cc818 (diff) | |
| download | vis-9bcf2667e7e239873597b7ec2172206a9af18071.tar.gz vis-9bcf2667e7e239873597b7ec2172206a9af18071.tar.xz | |
Restructure display code
Use pull instead of push based model for display code. Previously view.c
was calling into the ui frontend code, with the new scheme this switches
around: the necessary data is fetched by the ui as necessary.
The UI independent display code is moved out of view.c/ui-curses.c into
vis.c. The cell styles are now directly embedded into the Cell struct.
New UI styles are introduced for:
- status bar (focused / non-focused)
- info message
- window separator
- EOF symbol
You will have to update your color themes.
The terminal output code is further abstracted into a generic ui-terminal.c
part which keeps track of the whole in-memory cell matrix and #includes
ui-terminal-curses.c for the actual terminal output. This architecture
currently assumes that there are no overlapping windows. It will also
allow non-curses based terminal user interfaces.
Diffstat (limited to 'vis.c')
| -rw-r--r-- | vis.c | 187 |
1 files changed, 177 insertions, 10 deletions
@@ -305,12 +305,176 @@ static void window_free(Win *win) { free(win); } -static void window_draw(void *ctx) { - Win *win = ctx; - if (!win->ui) +static void window_draw_colorcolumn(Win *win) { + View *view = win->view; + int cc = view_colorcolumn_get(view); + if (cc <= 0) + return; + CellStyle style = win->ui->style_get(win->ui, UI_STYLE_COLOR_COLUMN); + size_t lineno = 0; + int line_cols = 0; /* Track the number of columns we've passed on each line */ + bool line_cc_set = false; /* Has the colorcolumn attribute been set for this line yet */ + int width = view_width_get(view); + + for (Line *l = view_lines_first(view); l; l = l->next) { + if (l->lineno != lineno) { + line_cols = 0; + line_cc_set = false; + lineno = l->lineno; + } + + if (line_cc_set) + continue; + line_cols += width; + + /* This screen line contains the cell we want to highlight */ + if (line_cols >= cc) { + l->cells[(cc - 1) % width].style = style; + line_cc_set = true; + } + } +} + +static void window_draw_cursorline(Win *win) { + Vis *vis = win->vis; + View *view = win->view; + enum UiOption options = view_options_get(view); + if (!(options & UI_OPTION_CURSOR_LINE)) + return; + if (vis->mode->visual || vis->win != win) + return; + if (view_cursors_multiple(view)) + return; + + int width = view_width_get(view); + CellStyle style = win->ui->style_get(win->ui, UI_STYLE_CURSOR_LINE); + Cursor *cursor = view_cursors_primary_get(view); + size_t lineno = view_cursors_line_get(cursor)->lineno; + for (Line *l = view_lines_first(view); l; l = l->next) { + if (l->lineno == lineno) { + for (int x = 0; x < width; x++) { + l->cells[x].style.attr |= style.attr; + l->cells[x].style.bg = style.bg; + } + } else if (l->lineno > lineno) { + break; + } + } +} + +static void window_draw_selection(View *view, Cursor *cur, CellStyle *style) { + Filerange sel = view_cursors_selection_get(cur); + if (!text_range_valid(&sel)) + return; + Line *start_line; int start_col; + Line *end_line; int end_col; + view_coord_get(view, sel.start, &start_line, NULL, &start_col); + view_coord_get(view, sel.end, &end_line, NULL, &end_col); + if (!start_line && !end_line) + return; + if (!start_line) { + start_line = view_lines_first(view); + start_col = 0; + } + if (!end_line) { + end_line = view_lines_last(view); + end_col = end_line->width; + } + for (Line *l = start_line; l != end_line->next; l = l->next) { + int col = (l == start_line) ? start_col : 0; + int end = (l == end_line) ? end_col : l->width; + while (col < end) { + if (cell_color_equal(l->cells[col].style.fg, style->fg)) { + CellStyle old = l->cells[col].style; + l->cells[col].style.fg = old.bg; + l->cells[col].style.bg = old.fg; + } else { + l->cells[col].style.bg = style->bg; + } + col++; + } + } +} + +static void window_draw_cursor_matching(Win *win, Cursor *cur, CellStyle *style) { + if (win->vis->mode->visual) + return; + Line *line_match; int col_match; + size_t pos = view_cursors_pos(cur); + size_t pos_match = text_bracket_match_symbol(win->file->text, pos, "(){}[]\"'`"); + if (pos == pos_match) + return; + if (!view_coord_get(win->view, pos_match, &line_match, NULL, &col_match)) + return; + if (cell_color_equal(line_match->cells[col_match].style.fg, style->fg)) { + CellStyle old = line_match->cells[col_match].style; + line_match->cells[col_match].style.fg = old.bg; + line_match->cells[col_match].style.bg = old.fg; + } else { + line_match->cells[col_match].style.bg = style->bg; + } +} + +static void window_draw_cursor(Win *win, Cursor *cur, CellStyle *style, CellStyle *sel_style) { + if (win->vis->win != win) + return; + Line *line = view_cursors_line_get(cur); + int col = view_cursors_cell_get(cur); + if (!line || col == -1) + return; + line->cells[col].style = *style; + window_draw_cursor_matching(win, cur, sel_style); + return; +} + +static void window_draw_cursors(Win *win) { + View *view = win->view; + Filerange viewport = view_viewport_get(view); + bool multiple_cursors = view_cursors_multiple(view); + Cursor *cursor = view_cursors_primary_get(view); + CellStyle style_cursor = win->ui->style_get(win->ui, UI_STYLE_CURSOR); + CellStyle style_cursor_primary = win->ui->style_get(win->ui, UI_STYLE_CURSOR_PRIMARY); + CellStyle style_selection = win->ui->style_get(win->ui, UI_STYLE_SELECTION); + for (Cursor *c = view_cursors_prev(cursor); c; c = view_cursors_prev(c)) { + window_draw_selection(win->view, c, &style_selection); + size_t pos = view_cursors_pos(c); + if (pos < viewport.start) + break; + window_draw_cursor(win, c, &style_cursor, &style_selection); + } + window_draw_selection(win->view, cursor, &style_selection); + window_draw_cursor(win, cursor, multiple_cursors ? &style_cursor_primary : &style_cursor, &style_selection); + for (Cursor *c = view_cursors_next(cursor); c; c = view_cursors_next(c)) { + window_draw_selection(win->view, c, &style_selection); + size_t pos = view_cursors_pos(c); + if (pos > viewport.end) + break; + window_draw_cursor(win, c, &style_cursor, &style_selection); + } +} + +static void window_draw_eof(Win *win) { + View *view = win->view; + if (view_width_get(view) == 0) + return; + CellStyle style = win->ui->style_get(win->ui, UI_STYLE_EOF); + for (Line *l = view_lines_last(view)->next; l; l = l->next) { + strcpy(l->cells[0].data, "~"); + l->cells[0].style = style; + } +} + +void vis_window_draw(Win *win) { + if (!win->ui || !view_update(win->view)) return; Vis *vis = win->vis; vis_event_emit(vis, VIS_EVENT_WIN_HIGHLIGHT, win); + + window_draw_colorcolumn(win); + window_draw_cursorline(win); + window_draw_cursors(win); + window_draw_eof(win); + vis_event_emit(vis, VIS_EVENT_WIN_STATUS, win); } @@ -321,11 +485,9 @@ Win *window_new_file(Vis *vis, File *file, enum UiOption options) { win->vis = vis; win->file = file; win->jumplist = ringbuf_alloc(31); - win->event.data = win; - win->event.draw = window_draw; win->horizon = 1 << 15; - win->view = view_new(file->text, &win->event); - win->ui = vis->ui->window_new(vis->ui, win->view, file, options); + win->view = view_new(file->text); + win->ui = vis->ui->window_new(vis->ui, win, options); if (!win->jumplist || !win->view || !win->ui) { window_free(win); return NULL; @@ -358,7 +520,7 @@ bool vis_window_reload(Win *win) { file_free(win->vis, win->file); file->refcount = 1; win->file = file; - win->ui->reload(win->ui, file); + view_reload(win->view, file->text); return true; } @@ -411,6 +573,7 @@ const char *vis_window_syntax_get(Win *win) { bool vis_window_syntax_set(Win *win, const char *syntax) { if (!vis_event_emit(win->vis, VIS_EVENT_WIN_SYNTAX, win, syntax)) return false; + view_options_set(win->view, view_options_get(win->view)); free(win->lexer_name); win->lexer_name = syntax ? strdup(syntax) : NULL; return !syntax || win->lexer_name; @@ -435,8 +598,6 @@ void vis_redraw(Vis *vis) { } void vis_update(Vis *vis) { - for (Win *win = vis->windows; win; win = win->next) - view_update(win->view); vis->ui->update(vis->ui); } @@ -1136,6 +1297,8 @@ bool vis_signal_handler(Vis *vis, int signum, const siginfo_t *siginfo, const vo vis->cancel_filter = true; return true; case SIGCONT: + vis->resume = true; + /* fall through */ case SIGWINCH: vis->need_resize = true; return true; @@ -1191,6 +1354,10 @@ int vis_run(Vis *vis, int argc, char *argv[]) { if (vis->terminate) vis_die(vis, "Killed by SIGTERM\n"); + if (vis->resume) { + vis->ui->resume(vis->ui); + vis->resume = false; + } if (vis->need_resize) { vis->ui->resize(vis->ui); vis->need_resize = false; |
