diff options
Diffstat (limited to 'src/nvim')
57 files changed, 5302 insertions, 5252 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 9bb3c680aa..5e90e40dd3 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -18,6 +18,7 @@ #include "nvim/change.h" #include "nvim/cursor.h" #include "nvim/decoration.h" +#include "nvim/drawscreen.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/extmark.h" @@ -28,7 +29,6 @@ #include "nvim/memory.h" #include "nvim/move.h" #include "nvim/ops.h" -#include "nvim/screen.h" #include "nvim/undo.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index b8295601c1..933aa85530 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -10,11 +10,11 @@ #include "nvim/api/private/helpers.h" #include "nvim/charset.h" #include "nvim/decoration_provider.h" +#include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/memline.h" -#include "nvim/screen.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.c.generated.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 53ffac1474..e4dc219e9a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -23,6 +23,7 @@ #include "nvim/context.h" #include "nvim/decoration.h" #include "nvim/decoration_provider.h" +#include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" @@ -55,7 +56,6 @@ #include "nvim/os/process.h" #include "nvim/popupmenu.h" #include "nvim/runtime.h" -#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/types.h" #include "nvim/ui.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index a153f746b6..6c37df6af8 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -10,9 +10,9 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/win_config.h" #include "nvim/ascii.h" +#include "nvim/drawscreen.h" #include "nvim/highlight_group.h" #include "nvim/option.h" -#include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index d0a2ff766e..580dfd8639 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -12,12 +12,12 @@ #include "nvim/ascii.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/drawscreen.h" #include "nvim/ex_docmd.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" #include "nvim/move.h" #include "nvim/option.h" -#include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 218aad0099..b5b2a73be1 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -11,6 +11,7 @@ #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/userfunc.h" @@ -29,7 +30,6 @@ #include "nvim/profile.h" #include "nvim/regexp.h" #include "nvim/runtime.h" -#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/state.h" #include "nvim/ui_compositor.h" diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 08c2746d7b..f9bce2476f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -38,6 +38,7 @@ #include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/digraph.h" +#include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" @@ -73,7 +74,6 @@ #include "nvim/quickfix.h" #include "nvim/regexp.h" #include "nvim/runtime.h" -#include "nvim/screen.h" #include "nvim/sign.h" #include "nvim/spell.h" #include "nvim/strings.h" diff --git a/src/nvim/change.c b/src/nvim/change.c index f0ca5f3af3..5184dc0689 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -10,6 +10,7 @@ #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/diff.h" +#include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/extmark.h" @@ -23,7 +24,6 @@ #include "nvim/move.h" #include "nvim/option.h" #include "nvim/plines.h" -#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/state.h" #include "nvim/ui.h" diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 1446257f7e..d4670dedc7 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -9,6 +9,7 @@ #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/fold.h" #include "nvim/mark.h" @@ -17,7 +18,6 @@ #include "nvim/move.h" #include "nvim/option.h" #include "nvim/plines.h" -#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/vim.h" diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 72d776d1e4..a061bd961b 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -8,6 +8,7 @@ #include "nvim/ascii.h" #include "nvim/charset.h" #include "nvim/debugger.h" +#include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" @@ -18,7 +19,6 @@ #include "nvim/pos.h" #include "nvim/regexp.h" #include "nvim/runtime.h" -#include "nvim/screen.h" #include "nvim/types.h" #include "nvim/vim.h" diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index ef4162a143..a93fb599c4 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -4,12 +4,12 @@ #include "nvim/api/ui.h" #include "nvim/buffer.h" #include "nvim/decoration.h" +#include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/move.h" -#include "nvim/screen.h" #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/diff.c b/src/nvim/diff.c index d483e22a30..c1fdbc1b9a 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -20,6 +20,7 @@ #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/diff.h" +#include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" @@ -36,7 +37,6 @@ #include "nvim/os/os.h" #include "nvim/os/shell.h" #include "nvim/path.h" -#include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/ui.h" #include "nvim/undo.h" diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index c4e5f25719..0f511bd37c 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -12,6 +12,7 @@ #include "nvim/ascii.h" #include "nvim/charset.h" #include "nvim/digraph.h" +#include "nvim/drawscreen.h" #include "nvim/eval/typval.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" @@ -24,7 +25,6 @@ #include "nvim/normal.h" #include "nvim/os/input.h" #include "nvim/runtime.h" -#include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/vim.h" diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c new file mode 100644 index 0000000000..95026ff8ed --- /dev/null +++ b/src/nvim/drawline.c @@ -0,0 +1,2706 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +// drawline.c: Functions for drawing window lines on the screen. +// This is the middle level, drawscreen.c is the top and grid.c/screen.c the lower level. + +#include <assert.h> +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> + +#include "nvim/arabic.h" +#include "nvim/buffer.h" +#include "nvim/charset.h" +#include "nvim/cursor.h" +#include "nvim/cursor_shape.h" +#include "nvim/diff.h" +#include "nvim/drawline.h" +#include "nvim/fold.h" +#include "nvim/grid.h" +#include "nvim/highlight.h" +#include "nvim/highlight_group.h" +#include "nvim/indent.h" +#include "nvim/match.h" +#include "nvim/move.h" +#include "nvim/option.h" +#include "nvim/plines.h" +#include "nvim/quickfix.h" +#include "nvim/search.h" +#include "nvim/sign.h" +#include "nvim/spell.h" +#include "nvim/state.h" +#include "nvim/syntax.h" +#include "nvim/undo.h" +#include "nvim/window.h" + +#define MB_FILLER_CHAR '<' // character used when a double-width character + // doesn't fit. + +/// for line_putchar. Contains the state that needs to be remembered from +/// putting one character to the next. +typedef struct { + const char *p; + int prev_c; ///< previous Arabic character + int prev_c1; ///< first composing char for prev_c +} LineState; +#define LINE_STATE(p) { p, 0, 0 } + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "drawline.c.generated.h" +#endif + +/// Advance **color_cols +/// +/// @return true when there are columns to draw. +static bool advance_color_col(int vcol, int **color_cols) +{ + while (**color_cols >= 0 && vcol > **color_cols) { + (*color_cols)++; + } + return **color_cols >= 0; +} + +/// Used when 'cursorlineopt' contains "screenline": compute the margins between +/// which the highlighting is used. +static void margin_columns_win(win_T *wp, int *left_col, int *right_col) +{ + // cache previous calculations depending on w_virtcol + static int saved_w_virtcol; + static win_T *prev_wp; + static int prev_left_col; + static int prev_right_col; + static int prev_col_off; + + int cur_col_off = win_col_off(wp); + int width1; + int width2; + + if (saved_w_virtcol == wp->w_virtcol && prev_wp == wp + && prev_col_off == cur_col_off) { + *right_col = prev_right_col; + *left_col = prev_left_col; + return; + } + + width1 = wp->w_width - cur_col_off; + width2 = width1 + win_col_off2(wp); + + *left_col = 0; + *right_col = width1; + + if (wp->w_virtcol >= (colnr_T)width1) { + *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; + } + if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) { + *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1; + } + + // cache values + prev_left_col = *left_col; + prev_right_col = *right_col; + prev_wp = wp; + saved_w_virtcol = wp->w_virtcol; + prev_col_off = cur_col_off; +} + +/// Put a single char from an UTF-8 buffer into a line buffer. +/// +/// Handles composing chars and arabic shaping state. +static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol) +{ + const char_u *p = (char_u *)s->p; + int cells = utf_ptr2cells((char *)p); + int c_len = utfc_ptr2len((char *)p); + int u8c, u8cc[MAX_MCO]; + if (cells > maxcells) { + return -1; + } + u8c = utfc_ptr2char(p, u8cc); + if (*p == TAB) { + cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells); + for (int c = 0; c < cells; c++) { + schar_from_ascii(dest[c], ' '); + } + goto done; + } else if (*p < 0x80 && u8cc[0] == 0) { + schar_from_ascii(dest[0], (char)(*p)); + s->prev_c = u8c; + } else { + if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) { + // Do Arabic shaping. + int pc, pc1, nc; + int pcc[MAX_MCO]; + int firstbyte = *p; + + // The idea of what is the previous and next + // character depends on 'rightleft'. + if (rl) { + pc = s->prev_c; + pc1 = s->prev_c1; + nc = utf_ptr2char((char *)p + c_len); + s->prev_c1 = u8cc[0]; + } else { + pc = utfc_ptr2char(p + c_len, pcc); + nc = s->prev_c; + pc1 = pcc[0]; + } + s->prev_c = u8c; + + u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc); + } else { + s->prev_c = u8c; + } + schar_from_cc(dest[0], u8c, u8cc); + } + if (cells > 1) { + dest[1][0] = 0; + } +done: + s->p += c_len; + return cells; +} + +static inline void provider_err_virt_text(linenr_T lnum, char *err) +{ + Decoration err_decor = DECORATION_INIT; + int hl_err = syn_check_group(S_LEN("ErrorMsg")); + kv_push(err_decor.virt_text, + ((VirtTextChunk){ .text = err, + .hl_id = hl_err })); + err_decor.virt_text_width = (int)mb_string2cells(err); + decor_add_ephemeral(lnum - 1, 0, lnum - 1, 0, &err_decor, 0, 0); +} + +static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int max_col, + int win_row) +{ + DecorState *state = &decor_state; + int right_pos = max_col; + bool do_eol = state->eol_col > -1; + for (size_t i = 0; i < kv_size(state->active); i++) { + DecorRange *item = &kv_A(state->active, i); + if (!(item->start_row == state->row + && (kv_size(item->decor.virt_text) || item->decor.ui_watched))) { + continue; + } + if (item->win_col == -1) { + if (item->decor.virt_text_pos == kVTRightAlign) { + right_pos -= item->decor.virt_text_width; + item->win_col = right_pos; + } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { + item->win_col = state->eol_col; + } else if (item->decor.virt_text_pos == kVTWinCol) { + item->win_col = MAX(item->decor.col + col_off, 0); + } + } + if (item->win_col < 0) { + continue; + } + int col; + if (item->decor.ui_watched) { + // send mark position to UI + col = item->win_col; + WinExtmark m = { (NS)item->ns_id, item->mark_id, win_row, col }; + kv_push(win_extmark_arr, m); + } + if (kv_size(item->decor.virt_text)) { + col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text, + item->decor.hl_mode, max_col, item->win_col - col_off); + } + item->win_col = -2; // deactivate + if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { + state->eol_col = col + 1; + } + + *end_col = MAX(*end_col, col); + } +} + +static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col, + int vcol) +{ + LineState s = LINE_STATE(""); + int virt_attr = 0; + size_t virt_pos = 0; + + while (col < max_col) { + if (!*s.p) { + if (virt_pos >= kv_size(vt)) { + break; + } + virt_attr = 0; + do { + s.p = kv_A(vt, virt_pos).text; + int hl_id = kv_A(vt, virt_pos).hl_id; + virt_attr = hl_combine_attr(virt_attr, + hl_id > 0 ? syn_id2attr(hl_id) : 0); + virt_pos++; + } while (!s.p && virt_pos < kv_size(vt)); + if (!s.p) { + break; + } + } + if (!*s.p) { + continue; + } + int attr; + bool through = false; + if (hl_mode == kHlModeCombine) { + attr = hl_combine_attr(linebuf_attr[col], virt_attr); + } else if (hl_mode == kHlModeBlend) { + through = (*s.p == ' '); + attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through); + } else { + attr = virt_attr; + } + schar_T dummy[2]; + int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col], + max_col - col, false, vcol); + // if we failed to emit a char, we still need to advance + cells = MAX(cells, 1); + + for (int c = 0; c < cells; c++) { + linebuf_attr[col++] = attr; + } + vcol += cells; + } + return col; +} + +/// Return true if CursorLineSign highlight is to be used. +static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) +{ + return wp->w_p_cul + && lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR); +} + +// Get information needed to display the sign in line 'lnum' in window 'wp'. +// If 'nrcol' is TRUE, the sign is going to be displayed in the number column. +// Otherwise the sign is going to be displayed in the sign column. +// +// @param count max number of signs +// @param[out] n_extrap number of characters from pp_extra to display +// @param sign_idxp Index of the displayed sign +static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, SignTextAttrs sattrs[], + int row, int startrow, int filler_lines, int filler_todo, + int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size, + char_u **pp_extra, int *n_extrap, int *char_attrp, int sign_idx, + int cul_attr) +{ + // Draw cells with the sign value or blank. + *c_extrap = ' '; + *c_finalp = NUL; + if (nrcol) { + *n_extrap = number_width(wp) + 1; + } else { + if (use_cursor_line_sign(wp, lnum)) { + *char_attrp = win_hl_attr(wp, HLF_CLS); + } else { + *char_attrp = win_hl_attr(wp, HLF_SC); + } + *n_extrap = win_signcol_width(wp); + } + + if (row == startrow + filler_lines && filler_todo <= 0) { + SignTextAttrs *sattr = sign_get_attr(sign_idx, sattrs, wp->w_scwidth); + if (sattr != NULL) { + *pp_extra = sattr->text; + if (*pp_extra != NULL) { + *c_extrap = NUL; + *c_finalp = NUL; + + if (nrcol) { + int n, width = number_width(wp) - 2; + for (n = 0; n < width; n++) { + extra[n] = ' '; + } + extra[n] = NUL; + STRCAT(extra, *pp_extra); + STRCAT(extra, " "); + *pp_extra = extra; + *n_extrap = (int)STRLEN(*pp_extra); + } else { + size_t symbol_blen = STRLEN(*pp_extra); + + // TODO(oni-link): Is sign text already extended to + // full cell width? + assert((size_t)win_signcol_width(wp) >= mb_string2cells((char *)(*pp_extra))); + // symbol(s) bytes + (filling spaces) (one byte each) + *n_extrap = (int)symbol_blen + win_signcol_width(wp) - + (int)mb_string2cells((char *)(*pp_extra)); + + assert(extra_size > symbol_blen); + memset(extra, ' ', extra_size); + memcpy(extra, *pp_extra, symbol_blen); + + *pp_extra = extra; + (*pp_extra)[*n_extrap] = NUL; + } + } + + if (use_cursor_line_sign(wp, lnum) && cul_attr > 0) { + *char_attrp = cul_attr; + } else { + *char_attrp = sattr->hl_attr_id; + } + } + } +} + +static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int *line_attr, + int *num_attr, int *cul_attr) +{ + HlPriAttr line_attrs = { *line_attr, 0 }; + HlPriAttr num_attrs = { *num_attr, 0 }; + HlPriAttr cul_attrs = { *cul_attr, 0 }; + + // TODO(bfredl, vigoux): line_attr should not take priority over decoration! + int num_signs = buf_get_signattrs(buf, lnum, sattrs, &num_attrs, &line_attrs, &cul_attrs); + decor_redraw_signs(buf, lnum - 1, &num_signs, sattrs, &num_attrs, &line_attrs, &cul_attrs); + + *line_attr = line_attrs.attr_id; + *num_attr = num_attrs.attr_id; + *cul_attr = cul_attrs.attr_id; + + return num_signs; +} + +/// Return true if CursorLineNr highlight is to be used for the number column. +/// +/// - 'cursorline' must be set +/// - lnum must be the cursor line +/// - 'cursorlineopt' has "number" +/// - don't highlight filler lines (when in diff mode) +/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number +/// itself on the first screenline of the wrapped line, otherwise highlight the number column of +/// all screenlines of the wrapped line. +static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) +{ + return wp->w_p_cul + && lnum == wp->w_cursor.lnum + && (wp->w_p_culopt_flags & CULOPT_NBR) + && (row == startrow + filler_lines + || (row > startrow + filler_lines + && (wp->w_p_culopt_flags & CULOPT_LINE))); +} + +static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, size_t buf_len) +{ + long num; + char *fmt = "%*ld "; + + if (wp->w_p_nu && !wp->w_p_rnu) { + // 'number' + 'norelativenumber' + num = (long)lnum; + } else { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { + // 'number' + 'relativenumber' + num = lnum; + fmt = "%-*ld "; + } + } + + snprintf((char *)buf, buf_len, fmt, number_width(wp), num); +} + +static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) +{ + if (wp |