aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/drawline.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/drawline.c')
-rw-r--r--src/nvim/drawline.c1471
1 files changed, 680 insertions, 791 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index e0887ed1d0..4281cdff33 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -11,10 +11,12 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
#include "nvim/decoration.h"
+#include "nvim/decoration_defs.h"
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawline.h"
@@ -24,59 +26,53 @@
#include "nvim/fold_defs.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
-#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
+#include "nvim/marktree_defs.h"
#include "nvim/match.h"
#include "nvim/mbyte.h"
+#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/option_vars.h"
+#include "nvim/os/os_defs.h"
#include "nvim/plines.h"
#include "nvim/pos_defs.h"
#include "nvim/quickfix.h"
-#include "nvim/sign.h"
+#include "nvim/sign_defs.h"
#include "nvim/spell.h"
#include "nvim/state.h"
+#include "nvim/state_defs.h"
#include "nvim/statusline.h"
+#include "nvim/statusline_defs.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/terminal.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
+#include "nvim/ui_defs.h"
#include "nvim/vim_defs.h"
#define MB_FILLER_CHAR '<' // character used when a double-width character doesn't fit.
-/// possible draw states in win_line(), drawn in sequence.
-typedef enum {
- WL_START = 0, // nothing done yet
- WL_CMDLINE, // cmdline window column
- WL_FOLD, // 'foldcolumn'
- WL_SIGN, // column for signs
- WL_NR, // line number
- WL_STC, // 'statuscolumn'
- WL_BRI, // 'breakindent'
- WL_SBR, // 'showbreak' or 'diff'
- WL_LINE, // text in the line
-} LineDrawState;
-
/// structure with variables passed between win_line() and other functions
typedef struct {
- LineDrawState draw_state; ///< what to draw next
-
- linenr_T lnum; ///< line number to be drawn
- foldinfo_T foldinfo; ///< fold info for this line
+ const linenr_T lnum; ///< line number to be drawn
+ const foldinfo_T foldinfo; ///< fold info for this line
- int startrow; ///< first row in the window to be drawn
+ const int startrow; ///< first row in the window to be drawn
int row; ///< row in the window, excl w_winrow
colnr_T vcol; ///< virtual column, before wrapping
int col; ///< visual column on screen, after wrapping
int boguscols; ///< nonexistent columns added to "col" to force wrapping
+ int old_boguscols; ///< bogus boguscols
int vcol_off; ///< offset for concealed characters
int off; ///< offset relative start of line
@@ -96,24 +92,14 @@ typedef struct {
int n_extra; ///< number of extra bytes
int n_attr; ///< chars with special attr
char *p_extra; ///< string of extra chars, plus NUL, only used
- ///< when c_extra and c_final are NUL
+ ///< when sc_extra and sc_final are NUL
int extra_attr; ///< attributes for p_extra
- int c_extra; ///< extra chars, all the same
- int c_final; ///< final char, mandatory if set
-
- int n_closing; ///< number of chars in fdc which will be closing
+ schar_T sc_extra; ///< extra chars, all the same
+ schar_T sc_final; ///< final char, mandatory if set
bool extra_for_extmark; ///< n_extra set for inline virtual text
- // saved "extra" items for when draw_state becomes WL_LINE (again)
- int saved_n_extra;
- char *saved_p_extra;
- bool saved_extra_for_extmark;
- int saved_c_extra;
- int saved_c_final;
- int saved_char_attr;
-
- char extra[57]; ///< sign, line number and 'fdc' must fit in here
+ char extra[11]; ///< must be as large as transchar_charbuf[] in charset.c
hlf_T diff_hlf; ///< type of diff highlighting
@@ -135,6 +121,8 @@ typedef struct {
///< or w_skipcol or concealing
int skipped_cells; ///< nr of skipped cells for virtual text
///< to be added to wlv.vcol later
+
+ int *color_cols; ///< if not NULL, highlight colorcolumn using according columns array
} winlinevars_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -162,15 +150,17 @@ void drawline_free_all_mem(void)
}
#endif
-/// Advance **color_cols
-///
-/// @return true when there are columns to draw.
-static bool advance_color_col(int vcol, int **color_cols)
+/// Advance wlv->color_cols if not NULL
+static void advance_color_col(winlinevars_T *wlv, int vcol)
{
- while (**color_cols >= 0 && vcol > **color_cols) {
- (*color_cols)++;
+ if (wlv->color_cols) {
+ while (*wlv->color_cols >= 0 && vcol > *wlv->color_cols) {
+ wlv->color_cols++;
+ }
+ if (*wlv->color_cols < 0) {
+ wlv->color_cols = NULL;
+ }
}
- return **color_cols >= 0;
}
/// Used when 'cursorlineopt' contains "screenline": compute the margins between
@@ -224,6 +214,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
/// Handles composing chars
static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells, int vcol)
{
+ // Caller should handle overwriting the right half of a double-width char.
+ assert(dest[0] != 0);
+
const char *p = *pp;
int cells = utf_ptr2cells(p);
int c_len = utfc_ptr2len(p);
@@ -237,6 +230,7 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
}
+ // When overwriting the left half of a double-width char, clear the right half.
if (cells < maxcells && dest[cells] == 0) {
dest[cells] = schar_from_ascii(' ');
}
@@ -305,10 +299,12 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
int vcol = item->draw_col - col_off;
col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text,
vt->hl_mode, max_col, vcol);
+ if (vt->pos == kVPosEndOfLine && do_eol) {
+ state->eol_col = col + 1;
+ }
}
- item->draw_col = INT_MIN; // deactivate
- if (vt && vt->pos == kVPosEndOfLine && do_eol) {
- state->eol_col = col + 1;
+ if (!vt || !(vt->flags & kVTRepeatLinebreak)) {
+ item->draw_col = INT_MIN; // deactivate
}
*end_col = MAX(*end_col, col);
@@ -346,8 +342,15 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
} else {
attr = virt_attr;
}
- schar_T dummy[2];
+ schar_T dummy[2] = { schar_from_ascii(' '), schar_from_ascii(' ') };
int maxcells = max_col - col;
+ // When overwriting the right half of a double-width char, clear the left half.
+ if (!through && linebuf_char[col] == 0) {
+ assert(col > 0);
+ linebuf_char[col - 1] = schar_from_ascii(' ');
+ // Clear the right half as well for the assertion in line_putchar().
+ linebuf_char[col] = schar_from_ascii(' ');
+ }
int cells = line_putchar(buf, &p, through ? dummy : &linebuf_char[col],
maxcells, vcol);
for (int c = 0; c < cells; c++) {
@@ -359,6 +362,38 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
return col;
}
+// TODO(bfredl): integrate with grid.c linebuf code? madness?
+static void draw_col_buf(win_T *wp, winlinevars_T *wlv, const char *text, size_t len, int attr,
+ bool vcol)
+{
+ const char *ptr = text;
+ while (ptr < text + len && wlv->off < wp->w_grid.cols) {
+ int cells = line_putchar(wp->w_buffer, &ptr, &linebuf_char[wlv->off],
+ wp->w_grid.cols - wlv->off, wlv->off);
+ int myattr = attr;
+ if (vcol) {
+ advance_color_col(wlv, wlv->vcol);
+ if (wlv->color_cols && wlv->vcol == *wlv->color_cols) {
+ myattr = hl_combine_attr(win_hl_attr(wp, HLF_MC), myattr);
+ }
+ }
+ for (int c = 0; c < cells; c++) {
+ linebuf_attr[wlv->off] = myattr;
+ linebuf_vcol[wlv->off] = vcol ? wlv->vcol++ : -1;
+ wlv->off++;
+ }
+ }
+}
+
+static void draw_col_fill(winlinevars_T *wlv, schar_T fillchar, int width, int attr)
+{
+ for (int i = 0; i < width; i++) {
+ linebuf_char[wlv->off] = fillchar;
+ linebuf_attr[wlv->off] = attr;
+ wlv->off++;
+ }
+}
+
/// Return true if CursorLineSign highlight is to be used.
static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum)
{
@@ -367,129 +402,78 @@ static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum)
&& (wp->w_p_culopt_flags & CULOPT_NBR);
}
-static char fdc_buf[MB_MAXCHAR * 10 + 1];
-
/// Setup for drawing the 'foldcolumn', if there is one.
-static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv)
+static void draw_foldcolumn(win_T *wp, winlinevars_T *wlv)
{
int fdc = compute_foldcolumn(wp, 0);
- if (fdc <= 0) {
- return;
- }
-
- // Use a separate buffer as `extra_buf` might be in use.
- wlv->n_extra = (int)fill_foldcolumn(fdc_buf, wp, wlv->foldinfo, wlv->lnum,
- &wlv->n_closing);
- fdc_buf[wlv->n_extra] = NUL;
- wlv->p_extra = fdc_buf;
- wlv->c_extra = NUL;
- wlv->c_final = NUL;
- if (use_cursor_line_highlight(wp, wlv->lnum)) {
- wlv->char_attr = win_hl_attr(wp, HLF_CLF);
- } else {
- wlv->char_attr = win_hl_attr(wp, HLF_FC);
+ if (fdc > 0) {
+ int attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLF : HLF_FC);
+ fill_foldcolumn(wp, wlv->foldinfo, wlv->lnum, attr, fdc, &wlv->off, NULL);
}
}
-/// Fills the foldcolumn at "p" for window "wp".
-/// Only to be called when 'foldcolumn' > 0.
-///
-/// @param[out] p Char array to write into
-/// @param lnum Absolute current line number
-/// @param closed Whether it is in 'foldcolumn' mode
+/// Draw the foldcolumn or fill "out_buffer". Assume monocell characters.
///
-/// Assume monocell characters
-/// @return number of chars added to \param p
-size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int *n_closing)
+/// @param fdc Current width of the foldcolumn
+/// @param[out] wlv_off Pointer to linebuf offset, incremented for default column
+/// @param[out] out_buffer Char array to fill, only used for 'statuscolumn'
+void fill_foldcolumn(win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int attr, int fdc, int *wlv_off,
+ schar_T *out_buffer)
{
- int i = 0;
- int fdc = compute_foldcolumn(wp, 0); // available cell width
- size_t char_counter = 0;
- int symbol = 0;
- int len = 0;
bool closed = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
- // Init to all spaces.
- memset(p, ' ', MB_MAXCHAR * (size_t)fdc + 1);
-
int level = foldinfo.fi_level;
// If the column is too narrow, we start at the lowest level that
// fits and use numbers to indicate the depth.
- int first_level = level - fdc - closed + 1;
- if (first_level < 1) {
- first_level = 1;
- }
-
- for (i = 0; i < MIN(fdc, level); i++) {
- if (foldinfo.fi_lnum == lnum
- && first_level + i >= foldinfo.fi_low_level) {
+ int first_level = MAX(level - fdc - closed + 1, 1);
+ int closedcol = MIN(fdc, level);
+
+ for (int i = 0; i < fdc; i++) {
+ schar_T symbol = 0;
+ if (i >= level) {
+ symbol = schar_from_ascii(' ');
+ } else if (i == closedcol - 1 && closed) {
+ symbol = wp->w_p_fcs_chars.foldclosed;
+ } else if (foldinfo.fi_lnum == lnum && first_level + i >= foldinfo.fi_low_level) {
symbol = wp->w_p_fcs_chars.foldopen;
} else if (first_level == 1) {
symbol = wp->w_p_fcs_chars.foldsep;
} else if (first_level + i <= 9) {
- symbol = '0' + first_level + i;
+ symbol = schar_from_ascii('0' + first_level + i);
} else {
- symbol = '>';
- }
-
- len = utf_char2bytes(symbol, &p[char_counter]);
- char_counter += (size_t)len;
- if (first_level + i >= level) {
- i++;
- break;
+ symbol = schar_from_ascii('>');
}
- }
- int n_closing_val = i;
-
- if (closed) {
- if (symbol != 0) {
- // rollback previous write
- char_counter -= (size_t)len;
- memset(&p[char_counter], ' ', (size_t)len);
- n_closing_val--;
+ if (out_buffer) {
+ out_buffer[i] = symbol;
+ } else {
+ linebuf_vcol[*wlv_off] = i >= level ? -1 : (i == closedcol - 1 && closed) ? -2 : -3;
+ linebuf_attr[*wlv_off] = attr;
+ linebuf_char[(*wlv_off)++] = symbol;
}
- len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, &p[char_counter]);
- char_counter += (size_t)len;
- }
-
- if (n_closing) {
- *n_closing = n_closing_val;
}
-
- return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc);
}
/// Get information needed to display the sign in line "wlv->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. If there is no
/// sign, draw blank cells instead.
-static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx,
- int sign_cul_attr)
+static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, int sign_cul_attr)
{
SignTextAttrs sattr = wlv->sattrs[sign_idx];
- wlv->c_final = NUL;
-
- if (sattr.text && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) {
- size_t fill = nrcol ? (size_t)number_width(wp) - SIGN_WIDTH : 0;
- size_t sign_len = strlen(sattr.text);
-
- // Spaces + sign: " " + ">>" + ' '
- wlv->n_extra = (int)(fill + sign_len + nrcol);
- if (nrcol) {
- memset(wlv->extra, ' ', (size_t)wlv->n_extra);
- }
- memcpy(wlv->extra + fill, sattr.text, sign_len);
- wlv->p_extra = wlv->extra;
- wlv->c_extra = NUL;
- wlv->char_attr = (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr)
- ? sign_cul_attr : sattr.hl_id ? syn_id2attr(sattr.hl_id) : 0;
+
+ if (sattr.text[0] && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) {
+ int attr = (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr)
+ ? sign_cul_attr : sattr.hl_id ? syn_id2attr(sattr.hl_id) : 0;
+ int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH;
+ draw_col_fill(wlv, schar_from_ascii(' '), fill, attr);
+ int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol;
+ linebuf_char[sign_pos] = sattr.text[0];
+ linebuf_char[sign_pos + 1] = sattr.text[1];
} else {
- wlv->c_extra = ' ';
- wlv->n_extra = nrcol ? number_width(wp) + 1 : SIGN_WIDTH;
- if (!nrcol) {
- wlv->char_attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLS : HLF_SC);
- }
+ assert(!nrcol); // handled in draw_lnum_col()
+ int attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLS : HLF_SC);
+ draw_col_fill(wlv, schar_from_ascii(' '), SIGN_WIDTH, attr);
}
}
@@ -556,7 +540,7 @@ static int get_line_number_attr(win_T *wp, winlinevars_T *wlv)
/// Display the absolute or relative line number. After the first row fill with
/// blanks when the 'n' flag isn't in 'cpo'.
-static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, int sign_cul_attr)
+static void draw_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, int sign_cul_attr)
{
bool has_cpo_n = vim_strchr(p_cpo, CPO_NUMCOL) != NULL;
@@ -567,221 +551,186 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, in
&& !((has_cpo_n && !wp->w_p_bri) && wp->w_skipcol > 0 && wlv->lnum == wp->w_topline)) {
// If 'signcolumn' is set to 'number' and a sign is present in "lnum",
// then display the sign instead of the line number.
- if (wp->w_minscwidth == SCL_NUM && wlv->sattrs[0].text) {
- get_sign_display_info(true, wp, wlv, 0, sign_cul_attr);
+ if (wp->w_minscwidth == SCL_NUM && wlv->sattrs[0].text[0]
+ && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) {
+ draw_sign(true, wp, wlv, 0, sign_cul_attr);
} else {
// Draw the line number (empty space after wrapping).
+ int width = number_width(wp) + 1;
+ int attr = (sign_num_attr > 0 && wlv->filler_todo <= 0)
+ ? sign_num_attr : get_line_number_attr(wp, wlv);
if (wlv->row == wlv->startrow + wlv->filler_lines
&& (wp->w_skipcol == 0 || wlv->row > 0 || (wp->w_p_nu && wp->w_p_rnu))) {
- get_line_number_str(wp, wlv->lnum, wlv->extra, sizeof(wlv->extra));
+ char buf[32];
+ get_line_number_str(wp, wlv->lnum, buf, sizeof(buf));
if (wp->w_skipcol > 0 && wlv->startrow == 0) {
- for (wlv->p_extra = wlv->extra; *wlv->p_extra == ' '; wlv->p_extra++) {
- *wlv->p_extra = '-';
+ for (char *c = buf; *c == ' '; c++) {
+ *c = '-';
}
}
if (wp->w_p_rl) { // reverse line numbers
- char *num = skipwhite(wlv->extra);
+ char *num = skipwhite(buf);
rl_mirror_ascii(num, skiptowhite(num));
}
- wlv->p_extra = wlv->extra;
- wlv->c_extra = NUL;
- } else {
- wlv->c_extra = ' ';
- }
- wlv->c_final = NUL;
- wlv->n_extra = number_width(wp) + 1;
- if (sign_num_attr > 0) {
- wlv->char_attr = sign_num_attr;
+ draw_col_buf(wp, wlv, buf, (size_t)width, attr, false);
} else {
- wlv->char_attr = get_line_number_attr(wp, wlv);
+ draw_col_fill(wlv, schar_from_ascii(' '), width, attr);
}
}
}
}
-/// Prepare and build the 'statuscolumn' string for line "lnum" in window "wp".
-/// Fill "stcp" with the built status column string and attributes.
-/// This can be called three times per win_line(), once for virt_lines, once for
-/// the start of the buffer line "lnum" and once for the wrapped lines.
-///
-/// @param[out] stcp Status column attributes
-static void get_statuscol_str(win_T *wp, linenr_T lnum, int virtnum, statuscol_T *stcp)
+/// Build and draw the 'statuscolumn' string for line "lnum" in window "wp".
+static void draw_statuscol(win_T *wp, winlinevars_T *wlv, linenr_T lnum, int virtnum, int col_rows,
+ statuscol_T *stcp)
{
// When called for the first non-filler row of line "lnum" set num v:vars
linenr_T relnum = virtnum == 0 ? abs(get_cursor_rel_lnum(wp, lnum)) : -1;
+ char buf[MAXPATHL];
// When a buffer's line count has changed, make a best estimate for the full
// width of the status column by building with "w_nrwidth_line_count". Add
// potentially truncated width and rebuild before drawing anything.
if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) {
wp->w_statuscol_line_count = wp->w_nrwidth_line_count;
set_vim_var_nr(VV_VIRTNUM, 0);
- build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, stcp);
- if (stcp->truncate > 0) {
- // Add truncated width to avoid unnecessary redraws
- int addwidth = MIN(stcp->truncate, MAX_NUMBERWIDTH - wp->w_nrwidth);
- stcp->truncate = 0;
- stcp->width += addwidth;
+ int width = build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, buf, stcp);
+ if (width > stcp->width) {
+ int addwidth = MIN(width - stcp->width, MAX_STCWIDTH - stcp->width);
wp->w_nrwidth += addwidth;
wp->w_nrwidth_width = wp->w_nrwidth;
+ if (col_rows > 0) {
+ // If only column is being redrawn, we now need to redraw the text as well
+ wp->w_redr_statuscol = true;
+ return;
+ }
+ stcp->width += addwidth;
wp->w_valid &= ~VALID_WCOL;
}
}
set_vim_var_nr(VV_VIRTNUM, virtnum);
- int width = build_statuscol_str(wp, lnum, relnum, stcp);
+ int width = build_statuscol_str(wp, lnum, relnum, buf, stcp);
// Force a redraw in case of error or when truncated
- if (*wp->w_p_stc == NUL || (stcp->truncate > 0 && wp->w_nrwidth < MAX_NUMBERWIDTH)) {
- if (stcp->truncate > 0) { // Avoid truncating 'statuscolumn'
- wp->w_nrwidth = MIN(MAX_NUMBERWIDTH, wp->w_nrwidth + stcp->truncate);
- wp->w_nrwidth_width = wp->w_nrwidth;
- } else { // 'statuscolumn' reset due to error
+ if (*wp->w_p_stc == NUL || (width > stcp->width && stcp->width < MAX_STCWIDTH)) {
+ if (*wp->w_p_stc == NUL) { // 'statuscolumn' reset due to error
wp->w_nrwidth_line_count = 0;
wp->w_nrwidth = (wp->w_p_nu || wp->w_p_rnu) * number_width(wp);
+ } else { // Avoid truncating 'statuscolumn'
+ wp->w_nrwidth += MIN(width - stcp->width, MAX_STCWIDTH - stcp->width);
+ wp->w_nrwidth_width = wp->w_nrwidth;
}
wp->w_redr_statuscol = true;
return;
}
- // Reset text/highlight pointer and current attr for new line
- stcp->textp = stcp->text;
- stcp->hlrecp = stcp->hlrec;
- stcp->cur_attr = stcp->num_attr;
- stcp->text_end = stcp->text + strlen(stcp->text);
-
- int fill = stcp->width - width;
- if (fill > 0) {
- // Fill up with ' '
- memset(stcp->text_end, ' ', (size_t)fill);
- *(stcp->text_end += fill) = NUL;
- }
-}
-
-/// Get information needed to display the next segment in the 'statuscolumn'.
-/// If not yet at the end, prepare for next segment and decrement "wlv->draw_state".
-///
-/// @param stcp Status column attributes
-/// @param[in,out] wlv
-static void get_statuscol_display_info(statuscol_T *stcp, winlinevars_T *wlv)
-{
- wlv->c_extra = NUL;
- wlv->c_final = NUL;
- do {
- wlv->draw_state = WL_STC;
- wlv->char_attr = stcp->cur_attr;
- wlv->p_extra = stcp->textp;
- char *const section_end = stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end;
- wlv->n_extra = (int)(section_end - stcp->textp);
- // Prepare for next highlight section if not yet at the end
- if (section_end < stcp->text_end) {
- int hl = stcp->hlrecp->userhl;
- stcp->textp = stcp->hlrecp->start;
- stcp->cur_attr = hl < 0 ? syn_id2attr(-hl) : stcp->num_attr;
- stcp->hlrecp++;
- wlv->draw_state = WL_STC - 1;
- }
- // Skip over empty highlight sections
- } while (wlv->n_extra == 0 && stcp->textp < stcp->text_end);
- if (wlv->n_extra > 0) {
- static char transbuf[(MAX_NUMBERWIDTH + 9 + 9 * 2) * MB_MAXBYTES + 1];
- wlv->n_extra = (int)transstr_buf(wlv->p_extra, wlv->n_extra, transbuf, sizeof transbuf, true);
- wlv->p_extra = transbuf;
+ char *p = buf;
+ char transbuf[MAXPATHL];
+ int attr = stcp->num_attr;
+ size_t len = strlen(buf);
+
+ // Draw each segment with the specified highlighting.
+ for (stl_hlrec_t *sp = stcp->hlrec; sp->start != NULL; sp++) {
+ ptrdiff_t textlen = sp->start - p;
+ // Make all characters printable.
+ size_t translen = transstr_buf(p, textlen, transbuf, MAXPATHL, true);
+ draw_col_buf(wp, wlv, transbuf, translen, attr, false);
+ p = sp->start;
+ int hl = sp->userhl;
+ attr = hl < 0 ? syn_id2attr(-hl) : stcp->num_attr;
}
+ size_t translen = transstr_buf(p, buf + len - p, transbuf, MAXPATHL, true);
+ draw_col_buf(wp, wlv, transbuf, translen, attr, false);
+ draw_col_fill(wlv, schar_from_ascii(' '), stcp->width - width, stcp->num_attr);
}
static void handle_breakindent(win_T *wp, winlinevars_T *wlv)
{
- if (wp->w_briopt_sbr && wlv->draw_state == WL_BRI - 1
- && *get_showbreak_value(wp) != NUL) {
- // draw indent after showbreak value
- wlv->draw_state = WL_BRI;
- } else if (wp->w_briopt_sbr && wlv->draw_state == WL_SBR) {
- // after the showbreak, draw the breakindent
- wlv->draw_state = WL_BRI - 1;
- }
-
// draw 'breakindent': indent wrapped text accordingly
- if (wlv->draw_state == WL_BRI - 1 && wlv->n_extra == 0) {
- wlv->draw_state = WL_BRI;
- // if wlv->need_showbreak is set, breakindent also applies
- if (wp->w_p_bri && (wlv->row != wlv->startrow || wlv->need_showbreak)
- && wlv->filler_lines == 0) {
- wlv->char_attr = 0;
- if (wlv->diff_hlf != (hlf_T)0) {
- wlv->char_attr = win_hl_attr(wp, (int)wlv->diff_hlf);
- }
- wlv->p_extra = NULL;
- wlv->c_extra = ' ';
- wlv->c_final = NUL;
- wlv->n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum));
- if (wlv->row == wlv->startrow) {
- wlv->n_extra -= win_col_off2(wp);
- if (wlv->n_extra < 0) {
- wlv->n_extra = 0;
- }
- }
- if (wp->w_skipcol > 0 && wlv->startrow == 0 && wp->w_p_wrap && wp->w_briopt_sbr) {
- wlv->need_showbreak = false;
+ // if wlv->need_showbreak is set, breakindent also applies
+ if (wp->w_p_bri && (wlv->row > wlv->startrow + wlv->filler_lines
+ || wlv->need_showbreak)) {
+ int attr = 0;
+ if (wlv->diff_hlf != (hlf_T)0) {
+ attr = win_hl_attr(wp, (int)wlv->diff_hlf);
+ }
+ int num = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum));
+ if (wlv->row == wlv->startrow) {
+ num -= win_col_off2(wp);
+ if (wlv->n_extra < 0) {
+ num = 0;
}
- // Correct end of highlighted area for 'breakindent',
- // required wen 'linebreak' is also set.
- if (wlv->tocol == wlv->vcol) {
- wlv->tocol += wlv->n_extra;
+ }
+
+ colnr_T vcol_before = wlv->vcol;
+
+ for (int i = 0; i < num; i++) {
+ linebuf_char[wlv->off] = schar_from_ascii(' ');
+
+ advance_color_col(wlv, wlv->vcol);
+ int myattr = attr;
+ if (wlv->color_cols && wlv->vcol == *wlv->color_cols) {
+ myattr = hl_combine_attr(win_hl_attr(wp, HLF_MC), myattr);
}
+ linebuf_attr[wlv->off] = myattr;
+ linebuf_vcol[wlv->off] = wlv->vcol++; // These are vcols, sorry I don't make the rules
+ wlv->off++;
}
+
+ // Correct start of highlighted area for 'breakindent',
+ if (wlv->fromcol >= vcol_before && wlv->fromcol < wlv->vcol) {
+ wlv->fromcol = wlv->vcol;
+ }
+
+ // Correct end of highlighted area for 'breakindent',
+ // required wen 'linebreak' is also set.
+ if (wlv->tocol == vcol_before) {
+ wlv->tocol = wlv->vcol;
+ }
+ }
+
+ if (wp->w_skipcol > 0 && wlv->startrow == 0 && wp->w_p_wrap && wp->w_briopt_sbr) {
+ wlv->need_showbreak = false;
}
}
static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv)
{
+ int remaining = wp->w_grid.cols - wlv->off;
if (wlv->filler_todo > wlv->filler_lines - wlv->n_virt_lines) {
// TODO(bfredl): check this doesn't inhibit TUI-style
// clear-to-end-of-line.
- wlv->c_extra = ' ';
- wlv->c_final = NUL;
- wlv->n_extra = wp->w_grid.cols - wlv->col;
- wlv->char_attr = 0;
+ draw_col_fill(wlv, schar_from_ascii(' '), remaining, 0);
} else if (wlv->filler_todo > 0) {
// Draw "deleted" diff line(s)
- if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
- wlv->c_extra = '-';
- wlv->c_final = NUL;
- } else {
- wlv->c_extra = wp->w_p_fcs_chars.diff;
- wlv->c_final = NUL;
- }
- wlv->n_extra = wp->w_grid.cols - wlv->col;
- wlv->char_attr = win_hl_attr(wp, HLF_DED);
+ schar_T c = wp->w_p_fcs_chars.diff;
+ draw_col_fill(wlv, c, remaining, win_hl_attr(wp, HLF_DED));
}
char *const sbr = get_showbreak_value(wp);
if (*sbr != NUL && wlv->need_showbreak) {
// Draw 'showbreak' at the start of each broken line.
- wlv->p_extra = sbr;
- wlv->c_extra = NUL;
- wlv->c_final = NUL;
- wlv->n_extra = (int)strlen(sbr);
- wlv->char_attr = win_hl_attr(wp, HLF_AT);
- if (wp->w_skipcol == 0 || wlv->startrow != 0 || !wp->w_p_wrap) {
- wlv->need_showbreak = false;
- }
- wlv->vcol_sbr = wlv->vcol + mb_charlen(sbr);
+ // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'.
+ int attr = hl_combine_attr(wlv->cul_attr, win_hl_attr(wp, HLF_AT));
+ colnr_T vcol_before = wlv->vcol;
+ draw_col_buf(wp, wlv, sbr, strlen(sbr), attr, true);
+ wlv->vcol_sbr = wlv->vcol;
// Correct start of highlighted area for 'showbreak'.
- if (wlv->fromcol >= wlv->vcol && wlv->fromcol < wlv->vcol_sbr) {
- wlv->fromcol = wlv->vcol_sbr;
+ if (wlv->fromcol >= vcol_before && wlv->fromcol < wlv->vcol) {
+ wlv->fromcol = wlv->vcol;
}
// Correct end of highlighted area for 'showbreak',
// required when 'linebreak' is also set.
- if (wlv->tocol == wlv->vcol) {
- wlv->tocol += wlv->n_extra;
- }
- // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'.
- if (wlv->cul_attr) {
- wlv->char_attr = hl_combine_attr(wlv->cul_attr, wlv->char_attr);
+ if (wlv->tocol == vcol_before) {
+ wlv->tocol = wlv->vcol;
}
}
+
+ if (wp->w_skipcol == 0 || wlv->startrow > 0 || !wp->w_p_wrap || !wp->w_briopt_sbr) {
+ wlv->need_showbreak = false;
+ }
}
static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
@@ -825,7 +774,7 @@ static bool has_more_inline_virt(winlinevars_T *wlv, ptrdiff_t v)
return false;
}
-static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v)
+static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v, bool selected)
{
while (wlv->n_extra == 0) {
if (wlv->virt_inline_i >= kv_size(wlv->virt_inline)) {
@@ -835,6 +784,11 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
DecorState *state = &decor_state;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
+ if (item->draw_col == -3) {
+ // No more inline virtual text before this non-inline virtual text item,
+ // so its position can be decided now.
+ decor_init_draw_col(wlv->off, selected, item);
+ }
if (item->start_row != state->row
|| item->kind != kDecorKindVirtText
|| item->data.vt->pos != kVPosInline
@@ -864,8 +818,8 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
if (wlv->n_extra == 0) {
continue;
}
- wlv->c_extra = NUL;
- wlv->c_final = NUL;
+ wlv->sc_extra = NUL;
+ wlv->sc_final = NUL;
wlv->extra_attr = attr;
wlv->n_attr = mb_charlen(text);
// If the text didn't reach until the first window
@@ -937,42 +891,46 @@ static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line)
}
/// Start a screen line at column zero.
-static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra)
+static void win_line_start(win_T *wp, winlinevars_T *wlv)
{
wlv->col = 0;
wlv->off = 0;
wlv->need_lbr = false;
-
- if (save_extra) {
- // reset the drawing state for the start of a wrapped line
- wlv->draw_state = WL_START;
- wlv->saved_n_extra = wlv->n_extra;
- wlv->saved_p_extra = wlv->p_extra;
- wlv->saved_extra_for_extmark = wlv->extra_for_extmark;
- wlv->saved_c_extra = wlv->c_extra;
- wlv->saved_c_final = wlv->c_final;
- wlv->need_lbr = true;
- wlv->saved_char_attr = wlv->char_attr;
-
- wlv->n_extra = 0;
+ for (int i = 0; i < wp->w_grid.cols; i++) {
+ linebuf_char[i] = schar_from_ascii(' ');
+ linebuf_attr[i] = -1;
+ linebuf_vcol[i] = -1;
}
}
-/// Called when wlv->draw_state is set to WL_LINE.
-static void win_line_continue(winlinevars_T *wlv)
+static void fix_for_boguscols(winlinevars_T *wlv)
{
- if (wlv->saved_n_extra > 0) {
- // Continue item from end of wrapped line.
- wlv->n_extra = wlv->saved_n_extra;
- wlv->saved_n_extra = 0;
- wlv->c_extra = wlv->saved_c_extra;
- wlv->c_final = wlv->saved_c_final;
- wlv->p_extra = wlv->saved_p_extra;
- wlv->extra_for_extmark = wlv->saved_extra_for_extmark;
- wlv->char_attr = wlv->saved_char_attr;
- } else {
- wlv->char_attr = 0;
+ wlv->n_extra += wlv->vcol_off;
+ wlv->vcol -= wlv->vcol_off;
+ wlv->vcol_off = 0;
+ wlv->col -= wlv->boguscols;
+ wlv->old_boguscols = wlv->boguscols;
+ wlv->boguscols = 0;
+}
+
+static int get_rightmost_vcol(win_T *wp, const int *color_cols)
+{
+ int ret = 0;
+
+ if (wp->w_p_cuc) {
+ ret = wp->w_virtcol;
}
+
+ if (color_cols) {
+ // determine rightmost colorcolumn to possibly draw
+ for (int i = 0; color_cols[i] >= 0; i++) {
+ if (ret < color_cols[i]) {
+ ret = color_cols[i];
+ }
+ }
+ }
+
+ return ret;
}
/// Display line "lnum" of window "wp" on the screen.
@@ -981,7 +939,8 @@ static void win_line_continue(winlinevars_T *wlv)
/// @param lnum line to display
/// @param startrow first row relative to window grid
/// @param endrow last grid row to be redrawn
-/// @param number_only only update the number column
+/// @param col_rows set to the height of the line when only updating the columns,
+/// otherwise set to 0
/// @param spv 'spell' related variables kept between calls for "wp"
/// @param foldinfo fold info for this line
/// @param[in, out] providers decoration providers active this line
@@ -989,19 +948,17 @@ static void win_line_continue(winlinevars_T *wlv)
/// or explicitly return `false`.
///
/// @return the number of last row the line occupies.
-int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_only, spellvars_T *spv,
- foldinfo_T foldinfo, DecorProviders *providers)
+int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, spellvars_T *spv,
+ foldinfo_T foldinfo)
{
- winlinevars_T wlv; // variables passed between functions
-
colnr_T vcol_prev = -1; // "wlv.vcol" of previous character
- char *line; // current line
- char *ptr; // current position in "line"
ScreenGrid *grid = &wp->w_grid; // grid specific to the window
- static char *at_end_str = ""; // used for p_extra when displaying curwin->w_p_lcs_chars.eol
- // at end-of-line
const bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
+ const bool has_foldtext = has_fold && *wp->w_p_fdt != NUL;
+
+ const bool is_wrapped = wp->w_p_wrap
+ && !has_fold; // Never wrap folded lines
int saved_attr2 = 0; // char_attr saved for n_attr
int n_attr3 = 0; // chars with overruling special attr
@@ -1010,8 +967,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
bool lnum_in_visual_area = false;
- pos_T pos;
- ptrdiff_t v;
bool attr_pri = false; // char_attr has priority
bool area_highlighting = false; // Visual or incsearch highlighting in this line
@@ -1022,10 +977,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int decor_attr = 0; // attributes desired by syntax and extmarks
bool has_syntax = false; // this buffer has syntax highl.
int folded_attr = 0; // attributes for folded line
- int save_did_emsg;
int eol_hl_off = 0; // 1 if highlighted char after EOL
- bool draw_color_col = false; // highlight colorcolumn
- int *color_cols = NULL; // pointer to according columns array
#define SPWORDLEN 150
char nextline[SPWORDLEN * 2]; // text with start of the next line
int nextlinecol = 0; // column where nextline[] starts
@@ -1034,17 +986,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int spell_attr = 0; // attributes desired by spelling
int word_end = 0; // last byte with same spell_attr
int cur_checked_col = 0; // checked column for current line
- int extra_check = 0; // has syntax or linebreak
+ bool extra_check = 0; // has syntax or linebreak
int multi_attr = 0; // attributes desired by multibyte
int mb_l = 1; // multi-byte byte length
int mb_c = 0; // decoded multi-byte character
- schar_T mb_schar; // complete screen char
+ schar_T mb_schar = 0; // complete screen char
int change_start = MAXCOL; // first col of changed area
int change_end = -1; // last col of changed area
bool in_multispace = false; // in multiple consecutive spaces
int multispace_pos = 0; // position in lcs-multispace string
- int line_attr_save;
- int line_attr_lowprio_save;
bool search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
@@ -1076,43 +1026,35 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int prev_syntax_id = 0;
int conceal_attr = win_hl_attr(wp, HLF_CONCEAL);
bool is_concealing = false;
- int did_wcol = false;
- int old_boguscols = 0;
-#define VCOL_HLC (wlv.vcol - wlv.vcol_off)
-#define FIX_FOR_BOGUSCOLS \
- { \
- wlv.n_extra += wlv.vcol_off; \
- wlv.vcol -= wlv.vcol_off; \
- wlv.vcol_off = 0; \
- wlv.col -= wlv.boguscols; \
- old_boguscols = wlv.boguscols; \
- wlv.boguscols = 0; \
- }
+ bool did_wcol = false;
+#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off)
assert(startrow < endrow);
- CLEAR_FIELD(wlv);
-
- wlv.lnum = lnum;
- wlv.foldinfo = foldinfo;
- wlv.startrow = startrow;
- wlv.row = startrow;
- wlv.fromcol = -10;
- wlv.tocol = MAXCOL;
- wlv.vcol_sbr = -1;
+ // variables passed between functions
+ winlinevars_T wlv = {
+ .lnum = lnum,
+ .foldinfo = foldinfo,
+ .startrow = startrow,
+ .row = startrow,
+ .fromcol = -10,
+ .tocol = MAXCOL,
+ .vcol_sbr = -1,
+ .old_boguscols = 0,
+ };
buf_T *buf = wp->w_buffer;
const bool end_fill = (lnum == buf->b_ml.ml_line_count + 1);
- if (!number_only) {
+ if (col_rows == 0) {
// To speed up the loop below, set extra_check when there is linebreak,
// trailing white space and/or syntax processing to be done.
extra_check = wp->w_p_lbr;
if (syntax_present(wp) && !wp->w_s->b_syn_error && !wp->w_s->b_syn_slow
- && !has_fold && !end_fill) {
+ && !has_foldtext && !end_fill) {
// Prepare for syntax highlighting in this line. When there is an
// error, stop syntax highlighting.
- save_did_emsg = did_emsg;
+ int save_did_emsg = did_emsg;
did_emsg = false;
syntax_start(wp, lnum);
if (did_emsg) {
@@ -1128,17 +1070,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
has_decor = decor_redraw_line(wp, lnum - 1, &decor_state);
- decor_providers_invoke_line(wp, providers, lnum - 1, &has_decor);
+ decor_providers_invoke_line(wp, lnum - 1, &has_decor);
if (has_decor) {
extra_check = true;
}
// Check for columns to display for 'colorcolumn'.
- color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols;
- if (color_cols != NULL) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
- }
+ wlv.color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols;
+ advance_color_col(&wlv, vcol_hlc(wlv));
// handle Visual active in this window
if (VIsual_active && wp->w_buffer == curwin->w_buffer) {
@@ -1182,7 +1122,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
} else if (bot->col == MAXCOL) {
wlv.tocol = MAXCOL;
} else {
- pos = *bot;
+ pos_T pos = *bot;
if (*p_sel == 'e') {
getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, NULL, NULL);
} else {
@@ -1207,7 +1147,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// handle 'incsearch' and ":s///c" highlighting
} else if (highlight_match
&& wp == curwin
- && !has_fold
+ && !has_foldtext
&& lnum >= curwin->w_cursor.lnum
&& lnum <= curwin->w_cursor.lnum + search_match_lines) {
if (lnum == curwin->w_cursor.lnum) {
@@ -1217,8 +1157,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.fromcol = 0;
}
if (lnum == curwin->w_cursor.lnum + search_match_lines) {
- pos.lnum = lnum;
- pos.col = search_match_endcol;
+ pos_T pos = {
+ .lnum = lnum,
+ .col = search_match_endcol,
+ };
getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL);
}
// do at least one character; happens when past end of line
@@ -1265,7 +1207,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Do not show the cursor line in the text when Visual mode is active,
// because it's not clear what is selected then.
&& !(wp == curwin && VIsual_active)) {
- cul_screenline = (wp->w_p_wrap && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
+ cul_screenline = (is_wrapped && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
if (!cul_screenline) {
apply_cursorline_highlight(wp, &wlv);
} else {
@@ -1286,7 +1228,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
statuscol.draw = true;
statuscol.sattrs = wlv.sattrs;
statuscol.foldinfo = foldinfo;
- statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin);
+ statuscol.width = win_col_off(wp) - (wp == cmdwin_win);
statuscol.use_cul = use_cursor_line_highlight(wp, lnum);
statuscol.sign_cul_id = statuscol.use_cul ? sign_cul_attr : 0;
statuscol.num_attr = sign_num_attr > 0 ? syn_id2attr(sign_num_attr) : 0;
@@ -1311,12 +1253,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
area_highlighting = true;
}
- if (cul_screenline) {
- line_attr_save = wlv.line_attr;
- line_attr_lowprio_save = wlv.line_attr_lowprio;
- }
+ int line_attr_save = wlv.line_attr;
+ int line_attr_lowprio_save = wlv.line_attr_lowprio;
- if (spv->spv_has_spell && !number_only) {
+ if (spv->spv_has_spell && col_rows == 0) {
// Prepare for spell checking.
extra_check = true;
@@ -1339,14 +1279,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Trick: skip a few chars for C/shell/Vim comments
nextline[SPWORDLEN] = NUL;
if (lnum < wp->w_buffer->b_ml.ml_line_count) {
- line = ml_get_buf(wp->w_buffer, lnum + 1);
+ char *line = ml_get_buf(wp->w_buffer, lnum + 1);
spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
}
assert(!end_fill);
- line = ml_get_buf(wp->w_buffer, lnum);
+ char *line = ml_get_buf(wp->w_buffer, lnum);
// If current line is empty, check first word in next line for capital.
- ptr = skipwhite(line);
+ char *ptr = skipwhite(line);
if (*ptr == NUL) {
spv->spv_cap_col = 0;
spv->spv_capcol_lnum = lnum + 1;
@@ -1361,33 +1301,36 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
nextlinecol = MAXCOL;
nextline_idx = 0;
} else {
- v = (ptrdiff_t)strlen(line);
- if (v < SPWORDLEN) {
+ const size_t line_len = strlen(line);
+ if (line_len < SPWORDLEN) {
// Short line, use it completely and append the start of the
// next line.
nextlinecol = 0;
- memmove(nextline, line, (size_t)v);
- STRMOVE(nextline + v, nextline + SPWORDLEN);
- nextline_idx = (int)v + 1;
+ memmove(nextline, line, line_len);
+ STRMOVE(nextline + line_len, nextline + SPWORDLEN);
+ nextline_idx = (int)line_len + 1;
} else {
// Long line, use only the last SPWORDLEN bytes.
- nextlinecol = (int)v - SPWORDLEN;
+ nextlinecol = (int)line_len - SPWORDLEN;
memmove(nextline, line + nextlinecol, SPWORDLEN);
nextline_idx = SPWORDLEN + 1;
}
}
}
- line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum);
- ptr = line;
+ // current line
+ char *line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum);
+ // current position in "line"
+ char *ptr = line;
colnr_T trailcol = MAXCOL; // start of trailing spaces
colnr_T leadcol = 0; // start of leading spaces
- int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used
- int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used
+ bool lcs_eol_todo = true; // need to keep track of this even if lcs_eol is NUL
+ const schar_T lcs_eol = wp->w_p_lcs_chars.eol; // 'eol' value
+ schar_T lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used, then NUL
- if (wp->w_p_list && !has_fold && !end_fill) {
+ if (wp->w_p_list && !has_foldtext && !end_fill) {
if (wp->w_p_lcs_chars.space
|| wp->w_p_lcs_chars.multispace != NULL
|| wp->w_p_lcs_chars.leadmultispace != NULL
@@ -1402,37 +1345,36 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
// first character to be displayed.
- if (wp->w_p_wrap) {
- v = startrow == 0 ? wp->w_skipcol : 0;
- } else {
- v = wp->w_leftcol;
- }
- if (v > 0 && !number_only) {
+ const int start_col = wp->w_p_wrap
+ ? (startrow == 0 ? wp->w_skipcol : 0)
+ : wp->w_leftcol;
+
+ if (start_col > 0 && col_rows == 0) {
char *prev_ptr = ptr;
- chartabsize_T cts;
- int charsize = 0;
- int head = 0;
-
- init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr);
- cts.cts_max_head_vcol = (int)v;
- while (cts.cts_vcol < v && *cts.cts_ptr != NUL) {
- head = 0;
- charsize = win_lbr_chartabsize(&cts, &head);
- cts.cts_vcol += charsize;
- prev_ptr = cts.cts_ptr;
- MB_PTR_ADV(cts.cts_ptr);
+ CharSize cs = { 0 };
+
+ CharsizeArg csarg;
+ CSType cstype = init_charsize_arg(&csarg, wp, lnum, line);
+ csarg.max_head_vcol = start_col;
+ int vcol = wlv.vcol;
+ StrCharInfo ci = utf_ptr2StrCharInfo(ptr);
+ while (vcol < start_col && *ci.ptr != NUL) {
+ cs = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg);
+ vcol += cs.width;
+ prev_ptr = ci.ptr;
+ ci = utfc_next(ci);
if (wp->w_p_list) {
- in_multispace = *prev_ptr == ' ' && (*cts.cts_ptr == ' '
+ in_multispace = *prev_ptr == ' ' && (*ci.ptr == ' '
|| (prev_ptr > line && prev_ptr[-1] == ' '));
if (!in_multispace) {
multispace_pos = 0;
- } else if (cts.cts_ptr >= line + leadcol
+ } else if (ci.ptr >= line + leadcol
&& wp->w_p_lcs_chars.multispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
- } else if (cts.cts_ptr < line + leadcol
+ } else if (ci.ptr < line + leadcol
&& wp->w_p_lcs_chars.leadmultispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
@@ -1441,9 +1383,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
}
}
- wlv.vcol = cts.cts_vcol;
- ptr = cts.cts_ptr;
- clear_chartabsize_arg(&cts);
+ wlv.vcol = vcol;
+ ptr = ci.ptr;
+ int charsize = cs.width;
+ int head = cs.head;
// When:
// - 'cuc' is set, or
@@ -1451,22 +1394,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// - 'virtualedit' is set, or
// - the visual mode is active,
// the end of the line may be before the start of the displayed part.
- if (wlv.vcol < v && (wp->w_p_cuc
- || draw_color_col
- || virtual_active()
- || (VIsual_active && wp->w_buffer == curwin->w_buffer))) {
- wlv.vcol = (colnr_T)v;
+ if (wlv.vcol < start_col && (wp->w_p_cuc
+ || wlv.color_cols
+ || virtual_active()
+ || (VIsual_active && wp->w_buffer == curwin->w_buffer))) {
+ wlv.vcol = start_col;
}
// Handle a character that's not completely on the screen: Put ptr at
// that character but skip the first few screen characters.
- if (wlv.vcol > v) {
+ if (wlv.vcol > start_col) {
wlv.vcol -= charsize;
ptr = prev_ptr;
}
- if (v > wlv.vcol) {
- wlv.skip_cells = (int)v - wlv.vcol - head;
+ if (start_col > wlv.vcol) {
+ wlv.skip_cells = start_col - wlv.vcol - head;
}
// Adjust for when the inverted text is before the screen,
@@ -1484,14 +1427,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// When spell checking a word we need to figure out the start of the
// word and if it's badly spelled or not.
if (spv->spv_has_spell) {
- size_t len;
colnr_T linecol = (colnr_T)(ptr - line);
hlf_T spell_hlf = HLF_COUNT;
- pos = wp->w_cursor;
+ pos_T pos = wp->w_cursor;
wp->w_cursor.lnum = lnum;
wp->w_cursor.col = linecol;
- len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
+ size_t len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
// spell_move_to() may call ml_get() and make "line" invalid
line = ml_get_buf(wp->w_buffer, lnum);
@@ -1540,15 +1482,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
}
- if (!number_only && !has_fold && !end_fill) {
- v = ptr - line;
- area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
+ if (col_rows == 0 && !has_foldtext && !end_fill) {
+ const int v = (int)(ptr - line);
+ area_highlighting |= prepare_search_hl_line(wp, lnum, v,
&line, &screen_search_hl, &search_attr,
&search_attr_from_match);
ptr = line + v; // "line" may have been updated
}
- win_line_start(wp, &wlv, false);
+ win_line_start(wp, &wlv);
+ bool draw_cols = true;
+ int leftcols_width = 0;
// won't highlight after TERM_ATTRS_MAX columns
int term_attrs[TERM_ATTRS_MAX] = { 0 };
@@ -1557,7 +1501,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
extra_check = true;
}
- int sign_idx = 0;
+ const bool may_have_inline_virt
+ = !has_foldtext && buf_meta_total(wp->w_buffer, kMTMetaInline) > 0;
int virt_line_index;
int virt_line_offset = -1;
// Repeat for the whole displayed line.
@@ -1568,129 +1513,116 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
bool did_decrement_ptr = false;
// Skip this quickly when working on the text.
- if (wlv.draw_state != WL_LINE) {
+ if (draw_cols) {
if (cul_screenline) {
wlv.cul_attr = 0;
wlv.line_attr = line_attr_save;
wlv.line_attr_lowprio = line_attr_lowprio_save;
}
- if (wlv.draw_state == WL_CMDLINE - 1 && wlv.n_extra == 0) {
- wlv.draw_state = WL_CMDLINE;
- if (cmdwin_type != 0 && wp == curwin) {
- // Draw the cmdline character.
- wlv.n_extra = 1;
- wlv.c_extra = cmdwin_type;
- wlv.c_final = NUL;
- wlv.char_attr = win_hl_attr(wp, HLF_AT);
- }
+ assert(wlv.off == 0);
+
+ if (wp == cmdwin_win) {
+ // Draw the cmdline character.
+ draw_col_fill(&wlv, schar_from_ascii(cmdwin_type), 1, win_hl_attr(wp, HLF_AT));
}
- if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
- if (wlv.filler_todo > 0) {
- int index = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines);
- if (index > 0) {
- virt_line_index = (int)kv_size(virt_lines) - index;
- assert(virt_line_index >= 0);
- virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
- }
- }
- if (virt_line_offset == 0) {
- // Skip the column states if there is a "virt_left_col" line.
- wlv.draw_state = WL_BRI - 1;
- } else if (statuscol.draw) {
- // Skip fold, sign and number states if 'statuscolumn' is set.
- wlv.draw_state = WL_STC - 1;
+ if (wlv.filler_todo > 0) {
+ int index = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines);
+ if (index > 0) {
+ virt_line_index = (int)kv_size(virt_lines) - index;
+ assert(virt_line_index >= 0);
+ virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
}
}
- if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
- wlv.draw_state = WL_FOLD;
- handle_foldcolumn(wp, &wlv);
- }
+ if (virt_line_offset == 0) {
+ // skip columns
+ } else if (statuscol.draw) {
+ // Draw 'statuscolumn' if it is set.
+ if (sign_num_attr == 0) {
+ statuscol.num_attr = get_line_number_attr(wp, &wlv);
+ }
+ const int v = (int)(ptr - line);
+ draw_statuscol(wp, &wlv, lnum, wlv.row - startrow - wlv.filler_lines, col_rows, &statuscol);
+ if (wp->w_redr_statuscol) {
+ break;
+ }
+ if (!end_fill) {
+ // Get the line again as evaluating 'statuscolumn' may free it.
+ line = ml_get_buf(wp->w_buffer, lnum);
+ ptr = line + v;
+ }
+ } else {
+ // draw builtin info columns: fold, sign, number
+ draw_foldcolumn(wp, &wlv);
- // sign column, this is hit until sign_idx reaches count
- if (wlv.draw_state == WL_SIGN - 1 && wlv.n_extra == 0) {
- // Show the sign column when desired.
- wlv.draw_state = WL_SIGN;
- if (wp->w_scwidth > 0) {
- get_sign_display_info(false, wp, &wlv, sign_idx, sign_cul_attr);
- if (++sign_idx < wp->w_scwidth) {
- wlv.draw_state = WL_SIGN - 1;
- } else {
- sign_idx = 0;
- }
+ // wp->w_scwidth is zero if signcol=number is used
+ for (int sign_idx = 0; sign_idx < wp->w_scwidth; sign_idx++) {
+ draw_sign(false, wp, &wlv, sign_idx, sign_cul_attr);
}
- }
- if (wlv.draw_state == WL_NR - 1 && wlv.n_extra == 0) {
- // Show the line number, if desired.
- wlv.draw_state = WL_NR;
- handle_lnum_col(wp, &wlv, sign_num_attr, sign_cul_attr);
+ draw_lnum_col(wp, &wlv, sign_num_attr, sign_cul_attr);
}
- if (wlv.draw_state == WL_STC - 1 && wlv.n_extra == 0) {
- wlv.draw_state = WL_STC;
- // Draw the 'statuscolumn' if option is set.
- if (statuscol.draw) {
- if (sign_num_attr == 0) {
- statuscol.num_attr = get_line_number_attr(wp, &wlv);
+ win_col_offset = wlv.off;
+
+ // When only updating the columns and that's done, stop here.
+ if (col_rows > 0) {
+ win_put_linebuf(wp, wlv.row, 0, wlv.off, wlv.off, bg_attr, false);
+ // Need to update more screen lines if:
+ // - 'statuscolumn' needs to be drawn, or
+ // - LineNrAbove or LineNrBelow is used, or
+ // - still drawing filler lines.
+ if ((wlv.row + 1 - wlv.startrow < col_rows
+ && (statuscol.draw
+ || win_hl_attr(wp, HLF_LNA) != win_hl_attr(wp, HLF_N)
+ || win_hl_attr(wp, HLF_LNB) != win_hl_attr(wp, HLF_N)))
+ || wlv.filler_todo > 0) {
+ wlv.row++;
+ if (wlv.row == endrow) {
+ break;
}
- if (statuscol.textp == NULL) {
- v = (ptr - line);
- get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol);
- if (!end_fill) {
- // Get the line again as evaluating 'statuscolumn' may free it.
- line = ml_get_buf(wp->w_buffer, lnum);
- ptr = line + v;
- }
- if (wp->w_redr_statuscol) {
- break;
- }
+ wlv.filler_todo--;
+ if (wlv.filler_todo == 0 && (wp->w_botfill || end_fill)) {
+ break;
}
- get_statuscol_display_info(&statuscol, &wlv);
+ // win_line_start(wp, &wlv);
+ wlv.col = 0;
+ wlv.off = 0;
+ continue;
+ } else {
+ break;
}
}
- if (wlv.draw_state == WL_STC && wlv.n_extra == 0) {
- win_col_offset = wlv.off;
- }
-
// Check if 'breakindent' applies and show it.
- // May change wlv.draw_state to WL_BRI or WL_BRI - 1.
- if (wlv.n_extra == 0) {
+ if (!wp->w_briopt_sbr) {
handle_breakindent(wp, &wlv);
}
-
- if (wlv.draw_state == WL_SBR - 1 && wlv.n_extra == 0) {
- wlv.draw_state = WL_SBR;
- handle_showbreak_and_filler(wp, &wlv);
+ handle_showbreak_and_filler(wp, &wlv);
+ if (wp->w_briopt_sbr) {
+ handle_breakindent(wp, &wlv);
}
- if (wlv.draw_state == WL_LINE - 1 && wlv.n_extra == 0) {
- sign_idx = 0;
- wlv.draw_state = WL_LINE;
- if (has_decor && wlv.row == startrow + wlv.filler_lines) {
- // hide virt_text on text hidden by 'nowrap' or 'smoothscroll'
- decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state);
- }
- win_line_continue(&wlv); // use wlv.saved_ values
+ wlv.col = wlv.off;
+ draw_cols = false;
+ if (wlv.filler_todo <= 0) {
+ leftcols_width = wlv.off;
+ }
+ if (has_decor && wlv.row == startrow + wlv.filler_lines) {
+ // hide virt_text on text hidden by 'nowrap' or 'smoothscroll'
+ decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state);
}
}
- if (cul_screenline && wlv.draw_state == WL_LINE
- && wlv.vcol >= left_curline_col
- && wlv.vcol < right_curline_col) {
+ if (cul_screenline && wlv.vcol >= left_curline_col && wlv.vcol < right_curline_col) {
apply_cursorline_highlight(wp, &wlv);
}
- // When still displaying '$' of change command, stop at cursor
- if (((dollar_vcol >= 0
- && wp == curwin
- && lnum == wp->w_cursor.lnum
- && wlv.vcol >= wp->w_virtcol)
- || (number_only && wlv.draw_state > WL_STC))
- && wlv.filler_todo <= 0) {
+ // When still displaying '$' of change command, stop at cursor.
+ if (dollar_vcol >= 0 && wp == curwin
+ && lnum == wp->w_cursor.lnum && wlv.vcol >= wp->w_virtcol) {
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
// don't clear anything after wlv.col
win_put_linebuf(wp, wlv.row, 0, wlv.col, wlv.col, bg_attr, false);
@@ -1704,15 +1636,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
break;
}
- const bool draw_folded = wlv.draw_state == WL_LINE && has_fold
- && wlv.row == startrow + wlv.filler_lines;
+ const bool draw_folded = has_fold && wlv.row == startrow + wlv.filler_lines;
if (draw_folded && wlv.n_extra == 0) {
wlv.char_attr = folded_attr = win_hl_attr(wp, HLF_FL);
+ decor_attr = 0;
}
int extmark_attr = 0;
- if (wlv.draw_state == WL_LINE
- && (area_highlighting || spv->spv_has_spell || extra_check)) {
+ if (area_highlighting || spv->spv_has_spell || extra_check) {
if (wlv.n_extra == 0 || !wlv.extra_for_extmark) {
wlv.reset_extra_attr = false;
}
@@ -1735,14 +1666,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
bool selected = (area_active || (area_highlighting && noinvcur
&& wlv.vcol == wp->w_virtcol));
+ // When there may be inline virtual text, position of non-inline virtual text
+ // can only be decided after drawing inline virtual text with lower priority.
if (decor_need_recheck) {
- decor_recheck_draw_col(wlv.off, selected, &decor_state);
+ if (!may_have_inline_virt) {
+ decor_recheck_draw_col(wlv.off, selected, &decor_state);
+ }
decor_need_recheck = false;
}
- extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, selected, &decor_state);
-
- if (!has_fold && wp->w_buffer->b_virt_text_inline > 0) {
- handle_inline_virtual_text(wp, &wlv, v);
+ if (wlv.filler_todo <= 0) {
+ extmark_attr = decor_redraw_col(wp, (colnr_T)(ptr - line),
+ may_have_inline_virt ? -3 : wlv.off,
+ selected, &decor_state);
+ }
+ if (may_have_inline_virt) {
+ handle_inline_virtual_text(wp, &wlv, ptr - line, selected);
if (wlv.n_extra > 0 && wlv.virt_inline_hl_mode <= kHlModeReplace) {
// restore search_attr and area_attr when n_extra is down to zero
// TODO(bfredl): this is ugly as fuck. look if we can do this some other way.
@@ -1758,9 +1696,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
}
- int *area_attr_p
- = wlv.extra_for_extmark && wlv.virt_inline_hl_mode <= kHlModeReplace
- ? &saved_area_attr : &area_attr;
+ int *area_attr_p = wlv.extra_for_extmark && wlv.virt_inline_hl_mode <= kHlModeReplace
+ ? &saved_area_attr : &area_attr;
// handle Visual or match highlighting in this line
if (wlv.vcol == wlv.fromcol
@@ -1780,13 +1717,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
area_active = false;
}
- if (!has_fold && wlv.n_extra == 0) {
+ if (!has_foldtext && wlv.n_extra == 0) {
// Check for start/end of 'hlsearch' and other matches.
// After end, check for start/end of next match.
// When another match, have to check for start again.
- v = (ptr - line);
- search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
- &has_match_conc, &match_conc, lcs_eol_one,
+ const int v = (int)(ptr - line);
+ search_attr = update_search_hl(wp, lnum, v, &line, &screen_search_hl,
+ &has_match_conc, &match_conc, lcs_eol_todo,
&on_last_col, &search_attr_from_match);
ptr = line + v; // "line" may have been changed
@@ -1847,7 +1784,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
}
- if (draw_folded && wlv.n_extra == 0 && wlv.col == win_col_offset) {
+ if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
+ const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
memset(buf_fold, ' ', FOLD_TEXT_LEN);
wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold, &fold_vt);
@@ -1856,8 +1794,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.p_extra != buf_fold) {
foldtext_free = wlv.p_extra;
}
- wlv.c_extra = NUL;
- wlv.c_final = NUL;
+ wlv.sc_extra = NUL;
+ wlv.sc_final = NUL;
wlv.p_extra[wlv.n_extra] = NUL;
// Get the line again as evaluating 'foldtext' may free it.
@@ -1865,10 +1803,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
ptr = line + v;
}
- if (draw_folded && wlv.n_extra == 0 && wlv.col < grid->cols) {
+ if (draw_folded && wlv.n_extra == 0 && wlv.col < grid->cols && (has_foldtext || *ptr == NUL)) {
// Fill rest of line with 'fold'.
- wlv.c_extra = wp->w_p_fcs_chars.fold;
- wlv.c_final = NUL;
+ wlv.sc_extra = wp->w_p_fcs_chars.fold;
+ wlv.sc_final = NUL;
wlv.n_extra = grid->cols - wlv.col;
}
@@ -1881,15 +1819,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
//
// The "p_extra" points to the extra stuff that is inserted to
// represent special characters (non-printable stuff) and other
- // things. When all characters are the same, c_extra is used.
- // If c_final is set, it will compulsorily be used at the end.
+ // things. When all characters are the same, sc_extra is used.
+ // If sc_final is set, it will compulsorily be used at the end.
// "p_extra" must end in a NUL to avoid utfc_ptr2len() reads past
// "p_extra[n_extra]".
// For the '$' of the 'list' option, n_extra == 1, p_extra == "".
if (wlv.n_extra > 0) {
- if (wlv.c_extra != NUL || (wlv.n_extra == 1 && wlv.c_final != NUL)) {
- mb_c = (wlv.n_extra == 1 && wlv.c_final != NUL) ? wlv.c_final : wlv.c_extra;
- mb_schar = schar_from_char(mb_c);
+ if (wlv.sc_extra != NUL || (wlv.n_extra == 1 && wlv.sc_final != NUL)) {
+ mb_schar = (wlv.n_extra == 1 && wlv.sc_final != NUL) ? wlv.sc_final : wlv.sc_extra;
+ mb_c = schar_get_first_codepoint(mb_schar);
wlv.n_extra--;
} else {
assert(wlv.p_extra != NULL);
@@ -1923,33 +1861,36 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Only restore search_attr and area_attr after "n_extra" in
// the next screen line is also done.
if (wlv.n_extra <= 0) {
- if (wlv.saved_n_extra <= 0) {
- if (search_attr == 0) {
- search_attr = saved_search_attr;
- saved_search_attr = 0;
- }
- if (area_attr == 0 && *ptr != NUL) {
- area_attr = saved_area_attr;
- saved_area_attr = 0;
- }
- if (decor_attr == 0) {
- decor_attr = saved_decor_attr;
- saved_decor_attr = 0;
- }
+ if (search_attr == 0) {
+ search_attr = saved_search_attr;
+ saved_search_attr = 0;
+ }
+ if (area_attr == 0 && *ptr != NUL) {
+ area_attr = saved_area_attr;
+ saved_area_attr = 0;
+ }
+ if (decor_attr == 0) {
+ decor_attr = saved_decor_attr;
+ saved_decor_attr = 0;
+ }
- if (wlv.extra_for_extmark) {
- // wlv.extra_attr should be used at this position but not
- // any further.
- wlv.reset_extra_attr = true;
- }
+ if (wlv.extra_for_extmark) {
+ // wlv.extra_attr should be used at this position but not
+ // any further.
+ wlv.reset_extra_attr = true;
}
wlv.extra_for_extmark = false;
}
- } else if (has_fold) {
+ } else if (wlv.filler_todo > 0) {
+ // Wait with reading text until filler lines are done. Still need to
+ // initialize these.
+ mb_c = ' ';
+ mb_schar = schar_from_ascii(' ');
+ } else if (has_foldtext || (has_fold && wlv.col >= grid->cols)) {
// skip writing the buffer line itself
- mb_c = NUL;
+ mb_schar = NUL;
} else {
- char *prev_ptr = ptr;
+ const char *prev_ptr = ptr;
// first byte of next char
int c0 = (uint8_t)(*ptr);
@@ -1982,8 +1923,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
mb_c = mb_ptr2char_adv((const char **)&wlv.p_extra);
mb_schar = schar_from_char(mb_c);
wlv.n_extra = (int)strlen(wlv.p_extra);
- wlv.c_extra = NUL;
- wlv.c_final = NUL;
+ wlv.sc_extra = NUL;
+ wlv.sc_final = NUL;
if (area_attr == 0 && search_attr == 0) {
wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_8);
@@ -1996,9 +1937,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// last column; the character is displayed at the start of the
// next line.
if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) {
+ mb_schar = schar_from_ascii('>');
mb_c = '>';
mb_l = 1;
- mb_schar = schar_from_ascii(mb_c);
multi_attr = win_hl_attr(wp, HLF_AT);
// Put pointer back so that the character will be
// displayed at the start of the next line.
@@ -2012,11 +1953,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// the first column. Don't do this for unprintable characters.
if (wlv.skip_cells > 0 && mb_l > 1 && wlv.n_extra == 0) {
wlv.n_extra = 1;
- wlv.c_extra = MB_FILLER_CHAR;
- wlv.c_final = NUL;
+ wlv.sc_extra = schar_from_ascii(MB_FILLER_CHAR);
+ wlv.sc_final = NUL;
+ mb_schar = schar_from_ascii(' ');
mb_c = ' ';
mb_l = 1;
- mb_schar = schar_from_ascii(mb_c);
if (area_attr == 0 && search_attr == 0) {
wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
@@ -2027,20 +1968,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
decor_attr = 0;
if (extra_check) {
- bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
+ const bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
bool can_spell = !no_plain_buffer;
// Get extmark and syntax attributes, unless still at the start of the line
// (double-wide char that doesn't fit).
- v = (ptr - line);
+ const int v = (int)(ptr - line);
+ const ptrdiff_t prev_v = prev_ptr - line;
if (has_syntax && v > 0) {
// Get the syntax attribute for the character. If there
// is an error, disable syntax highlighting.
- save_did_emsg = did_emsg;
+ int save_did_emsg = did_emsg;
did_emsg = false;
- decor_attr = get_syntax_attr((colnr_T)v - 1,
- spv->spv_has_spell ? &can_spell : NULL, false);
+ decor_attr = get_syntax_attr(v - 1, spv->spv_has_spell ? &can_spell : NULL, false);
if (did_emsg) {
wp->w_s->b_syn_error = true;
@@ -2057,10 +1998,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// have made it invalid.
line = ml_get_buf(wp->w_buffer, lnum);
ptr = line + v;
+ prev_ptr = line + prev_v;
// no concealing past the end of the line, it interferes
// with line highlighting.
- syntax_flags = (mb_c == 0) ? 0 : get_syntax_info(&syntax_seqnr);
+ syntax_flags = (mb_schar == 0) ? 0 : get_syntax_info(&syntax_seqnr);
}
if (has_decor && v > 0) {
@@ -2070,6 +2012,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell);
}
+ if (folded_attr) {
+ decor_attr = hl_combine_attr(folded_attr, decor_attr);
+ }
+
if (decor_attr) {
if (!attr_pri) {
if (wlv.cul_attr) {
@@ -2090,28 +2036,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Only do this when there is no syntax highlighting, the
// @Spell cluster is not used or the current syntax item
// contains the @Spell cluster.
- v = (ptr - line);
- if (spv->spv_has_spell && v >= word_end && v > cur_checked_col) {
+ int v1 = (int)(ptr - line);
+ if (spv->spv_has_spell && v1 >= word_end && v1 > cur_checked_col) {
spell_attr = 0;
// do not calculate cap_col at the end of the line or when
// only white space is following
- if (mb_c != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) {
+ if (mb_schar != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) {
char *p;
hlf_T spell_hlf = HLF_COUNT;
- v -= mb_l - 1;
+ v1 -= mb_l - 1;
// Use nextline[] if possible, it has the start of the
// next line concatenated.
if ((prev_ptr - line) - nextlinecol >= 0) {
p = nextline + ((prev_ptr - line) - nextlinecol);
} else {
- p = prev_ptr;
+ p = (char *)prev_ptr;
}
spv->spv_cap_col -= (int)(prev_ptr - line);
size_t tmplen = spell_check(wp, p, &spell_hlf, &spv->spv_cap_col, spv->spv_unchanged);
assert(tmplen <= INT_MAX);
int len = (int)tmplen;
- word_end = (int)v + len;
+ word_end = v1 + len;
// In Insert mode only highlight a word that
// doesn't touch the cursor.
@@ -2169,7 +2115,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
//
// So only allow to linebreak, once we have found chars not in
// 'breakat' in the line.
- if (wp->w_p_lbr && !wlv.need_lbr && mb_c != NUL
+ if (wp->w_p_lbr && !wlv.need_lbr && mb_schar != NUL
&& !vim_isbreak((uint8_t)(*ptr))) {
wlv.need_lbr = true;
}
@@ -2178,13 +2124,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& vim_isbreak(mb_c) && !vim_isbreak((uint8_t)(*ptr))) {
int mb_off = utf_head_off(line, ptr - 1);
char *p = ptr - (mb_off + 1);
- chartabsize_T cts;
- init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p);
- // do not want virtual text to be counted here
- cts.cts_has_virt_text = false;
- wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
- clear_chartabsize_arg(&cts);
+ CharsizeArg csarg;
+ // lnum == 0, do not want virtual text to be counted here
+ CSType cstype = init_charsize_arg(&csarg, wp, 0, line);
+ wlv.n_extra = win_charsize(cstype, wlv.vcol, p, utf_ptr2CharInfo(p).value,
+ &csarg).width - 1;
if (on_last_col && mb_c != TAB) {
// Do not continue search/match highlighting over the
@@ -2197,12 +2142,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.n_extra = tabstop_padding(wlv.vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
}
- wlv.c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
- wlv.c_final = NUL;
+ wlv.sc_extra = schar_from_ascii(mb_off > 0 ? MB_FILLER_CHAR : ' ');
+ wlv.sc_final = NUL;
if (mb_c < 128 && ascii_iswhite(mb_c)) {
if (mb_c == TAB) {
// See "Tab alignment" below.
- FIX_FOR_BOGUSCOLS;
+ fix_for_boguscols(&wlv);
}
if (!wp->w_p_list) {
mb_c = ' ';
@@ -2231,39 +2176,39 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& ptr - line >= leadcol
&& ptr - line <= trailcol))) {
if (in_multispace && wp->w_p_lcs_chars.multispace != NULL) {
- mb_c = wp->w_p_lcs_chars.multispace[multispace_pos++];
+ mb_schar = wp->w_p_lcs_chars.multispace[multispace_pos++];
if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
} else {
- mb_c = (mb_c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
+ mb_schar = (mb_c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
}
wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
- mb_schar = schar_from_char(mb_c);
+ mb_c = schar_get_first_codepoint(mb_schar);
}
if (mb_c == ' ' && mb_l == 1 && ((trailcol != MAXCOL && ptr > line + trailcol)
|| (leadcol != 0 && ptr < line + leadcol))) {
if (leadcol != 0 && in_multispace && ptr < line + leadcol
&& wp->w_p_lcs_chars.leadmultispace != NULL) {
- mb_c = wp->w_p_lcs_chars.leadmultispace[multispace_pos++];
+ mb_schar = wp->w_p_lcs_chars.leadmultispace[multispace_pos++];
if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
} else if (ptr > line + trailcol && wp->w_p_lcs_chars.trail) {
- mb_c = wp->w_p_lcs_chars.trail;
+ mb_schar = wp->w_p_lcs_chars.trail;
} else if (ptr < line + leadcol && wp->w_p_lcs_chars.lead) {
- mb_c = wp->w_p_lcs_chars.lead;
+ mb_schar = wp->w_p_lcs_chars.lead;
} else if (leadcol != 0 && wp->w_p_lcs_chars.space) {
- mb_c = wp->w_p_lcs_chars.space;
+ mb_schar = wp->w_p_lcs_chars.space;
}
wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
- mb_schar = schar_from_char(mb_c);
+ mb_c = schar_get_first_codepoint(mb_schar);
}
}
@@ -2289,15 +2234,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (!wp->w_p_lbr || !wp->w_p_list) {
wlv.n_extra = tab_len;
} else {
- char *p;
int saved_nextra = wlv.n_extra;
if (wlv.vcol_off > 0) {
// there are characters to conceal
tab_len += wlv.vcol_off;
}
- // boguscols before FIX_FOR_BOGUSCOLS macro from above.
- if (wp->w_p_lcs_chars.tab1 && old_boguscols > 0
+ // boguscols before fix_for_boguscols() from above.
+ if (wp->w_p_lcs_chars.tab1 && wlv.old_boguscols > 0
&& wlv.n_extra > tab_len) {
tab_len += wlv.n_extra - tab_len;
}
@@ -2306,17 +2250,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// If wlv.n_extra > 0, it gives the number of chars
// to use for a tab, else we need to calculate the
// width for a tab.
- int tab2_len = utf_char2len(wp->w_p_lcs_chars.tab2);
- int len = tab_len * tab2_len;
+ size_t tab2_len = schar_len(wp->w_p_lcs_chars.tab2);
+ size_t len = (size_t)tab_len * tab2_len;
if (wp->w_p_lcs_chars.tab3) {
- len += utf_char2len(wp->w_p_lcs_chars.tab3) - tab2_len;
+ len += schar_len(wp->w_p_lcs_chars.tab3) - tab2_len;
}
if (wlv.n_extra > 0) {
- len += wlv.n_extra - tab_len;
+ len += (size_t)(wlv.n_extra - tab_len);
}
- mb_c = wp->w_p_lcs_chars.tab1;
- p = get_extra_buf((size_t)len + 1);
- memset(p, ' ', (size_t)len);
+ mb_schar = wp->w_p_lcs_chars.tab1;
+ mb_c = schar_get_first_codepoint(mb_schar);
+ char *p = get_extra_buf(len + 1);
+ memset(p, ' ', len);
p[len] = NUL;
wlv.p_extra = p;
for (int i = 0; i < tab_len; i++) {
@@ -2324,17 +2269,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
tab_len = i;
break;
}
- int lcs = wp->w_p_lcs_chars.tab2;
+ schar_T lcs = wp->w_p_lcs_chars.tab2;
// if tab3 is given, use it for the last char
if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) {
lcs = wp->w_p_lcs_chars.tab3;
}
- p += utf_char2bytes(lcs, p);
- wlv.n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0);
+ size_t slen = schar_get_adv(&p, lcs);
+ wlv.n_extra += (int)slen - (saved_nextra > 0 ? 1 : 0);
}
- // n_extra will be increased by FIX_FOX_BOGUSCOLS
+ // n_extra will be increased by fix_for_boguscols()
// macro below, so need to adjust for that here
if (wlv.vcol_off > 0) {
wlv.n_extra -= wlv.vcol_off;
@@ -2351,7 +2296,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// vcol_off and boguscols accumulated so far in the
// line. Note that the tab can be longer than
// 'tabstop' when there are concealed characters.
- FIX_FOR_BOGUSCOLS;
+ fix_for_boguscols(&wlv);
// Make sure, the highlighting for the tab char will be
// correctly set further below (effectively reverts the
@@ -2363,24 +2308,24 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
if (wp->w_p_list) {
- mb_c = (wlv.n_extra == 0 && wp->w_p_lcs_chars.tab3)
- ? wp->w_p_lcs_chars.tab3 : wp->w_p_lcs_chars.tab1;
+ mb_schar = (wlv.n_extra == 0 && wp->w_p_lcs_chars.tab3)
+ ? wp->w_p_lcs_chars.tab3 : wp->w_p_lcs_chars.tab1;
if (wp->w_p_lbr && wlv.p_extra != NULL && *wlv.p_extra != NUL) {
- wlv.c_extra = NUL; // using p_extra from above
+ wlv.sc_extra = NUL; // using p_extra from above
} else {
- wlv.c_extra = wp->w_p_lcs_chars.tab2;
+ wlv.sc_extra = wp->w_p_lcs_chars.tab2;
}
- wlv.c_final = wp->w_p_lcs_chars.tab3;
+ wlv.sc_final = wp->w_p_lcs_chars.tab3;
wlv.n_attr = tab_len + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
} else {
- wlv.c_final = NUL;
- wlv.c_extra = ' ';
- mb_c = ' ';
+ wlv.sc_final = NUL;
+ wlv.sc_extra = schar_from_ascii(' ');
+ mb_schar = schar_from_ascii(' ');
}
- mb_schar = schar_from_char(mb_c);
- } else if (mb_c == NUL
+ mb_c = schar_get_first_codepoint(mb_schar);
+ } else if (mb_schar == NUL
&& (wp->w_p_list
|| ((wlv.fromcol >= 0 || fromcol_prev >= 0)
&& wlv.tocol > wlv.vcol
@@ -2389,7 +2334,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& wlv.vcol == wp->w_virtcol)))
- && lcs_eol_one > 0) {
+ && lcs_eol_todo && lcs_eol != NUL) {
// Display a '$' after the line or highlight an extra
// character if the line break is included.
// For a diff line the highlighting continues after the "$".
@@ -2399,21 +2344,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// In virtualedit, visual selections may extend beyond end of line
if (!(area_highlighting && virtual_active()
&& wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol)) {
- wlv.p_extra = at_end_str;
+ wlv.p_extra = "";
}
wlv.n_extra = 0;
}
if (wp->w_p_list && wp->w_p_lcs_chars.eol > 0) {
- mb_c = wp->w_p_lcs_chars.eol;
+ mb_schar = wp->w_p_lcs_chars.eol;
} else {
- mb_c = ' ';
+ mb_schar = schar_from_ascii(' ');
}
- lcs_eol_one = -1;
+ lcs_eol_todo = false;
ptr--; // put it back at the NUL
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
wlv.n_attr = 1;
- mb_schar = schar_from_char(mb_c);
- } else if (mb_c != NUL) {
+ mb_c = schar_get_first_codepoint(mb_schar);
+ } else if (mb_schar != NUL) {
wlv.p_extra = transchar_buf(wp->w_buffer, mb_c);
if (wlv.n_extra == 0) {
wlv.n_extra = byte2cells(mb_c) - 1;
@@ -2421,17 +2366,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if ((dy_flags & DY_UHEX) && wp->w_p_rl) {
rl_mirror_ascii(wlv.p_extra, NULL); // reverse "<12>"
}
- wlv.c_extra = NUL;
- wlv.c_final = NUL;
+ wlv.sc_extra = NUL;
+ wlv.sc_final = NUL;
if (wp->w_p_lbr) {
- char *p;
-
mb_c = (uint8_t)(*wlv.p_extra);
- p = get_extra_buf((size_t)wlv.n_extra + 1);
+ char *p = get_extra_buf((size_t)wlv.n_extra + 1);
memset(p, ' ', (size_t)wlv.n_extra);
- strncpy(p, // NOLINT(runtime/printf)
- wlv.p_extra + 1,
- (size_t)strlen(wlv.p_extra) - 1);
+ memcpy(p, wlv.p_extra + 1, strlen(wlv.p_extra) - 1);
p[wlv.n_extra] = NUL;
wlv.p_extra = p;
} else {
@@ -2459,7 +2400,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0 || decor_conceal > 0)
&& !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) {
wlv.char_attr = conceal_attr;
- bool is_conceal_char = false;
if (((prev_syntax_id != syntax_seqnr && (syntax_flags & HL_CONCEAL) != 0)
|| has_match_conc > 1 || decor_conceal > 1)
&& (syn_get_sub_char() != NUL
@@ -2470,21 +2410,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// First time at this concealed item: display one
// character.
if (has_match_conc && match_conc) {
- mb_c = match_conc;
+ mb_schar = schar_from_char(match_conc);
} else if (decor_conceal && decor_state.conceal_char) {
mb_schar = decor_state.conceal_char;
- mb_c = schar_get_first_codepoint(mb_schar);
- is_conceal_char = true;
if (decor_state.conceal_attr) {
wlv.char_attr = decor_state.conceal_attr;
}
} else if (syn_get_sub_char() != NUL) {
- mb_c = syn_get_sub_char();
+ mb_schar = schar_from_char(syn_get_sub_char());
} else if (wp->w_p_lcs_chars.conceal != NUL) {
- mb_c = wp->w_p_lcs_chars.conceal;
+ mb_schar = wp->w_p_lcs_chars.conceal;
} else {
- mb_c = ' ';
+ mb_schar = schar_from_ascii(' ');
}
+ mb_c = schar_get_first_codepoint(mb_schar);
prev_syntax_id = syntax_seqnr;
@@ -2492,7 +2431,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.vcol_off += wlv.n_extra;
}
wlv.vcol += wlv.n_extra;
- if (wp->w_p_wrap && wlv.n_extra > 0) {
+ if (is_wrapped && wlv.n_extra > 0) {
wlv.boguscols += wlv.n_extra;
wlv.col += wlv.n_extra;
}
@@ -2502,9 +2441,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
is_concealing = true;
wlv.skip_cells = 1;
}
- if (!is_conceal_char) {
- mb_schar = schar_from_char(mb_c);
- }
} else {
prev_syntax_id = 0;
is_concealing = false;
@@ -2518,7 +2454,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// In the cursor line and we may be concealing characters: correct
// the cursor column when we reach its position.
- if (!did_wcol && wlv.draw_state == WL_LINE
+ if (!did_wcol
&& wp == curwin && lnum == wp->w_cursor.lnum
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) {
@@ -2529,7 +2465,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
// Don't override visual selection highlighting.
- if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) {
+ if (wlv.n_attr > 0 && !search_attr_from_match) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, wlv.extra_attr);
if (wlv.reset_extra_attr) {
wlv.reset_extra_attr = false;
@@ -2546,37 +2482,36 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& wp->w_p_list
&& (wp->w_p_wrap ? (wp->w_skipcol > 0 && wlv.row == 0) : wp->w_leftcol > 0)
&& wlv.filler_todo <= 0
- && wlv.draw_state > WL_STC
- && mb_c != NUL) {
- mb_c = wp->w_p_lcs_chars.prec;
+ && mb_schar != NUL) {
+ mb_schar = wp->w_p_lcs_chars.prec;
lcs_prec_todo = NUL;
if (utf_char2cells(mb_c) > 1) {
// Double-width character being overwritten by the "precedes"
// character, need to fill up half the character.
- wlv.c_extra = MB_FILLER_CHAR;
- wlv.c_final = NUL;
+ wlv.sc_extra = schar_from_ascii(MB_FILLER_CHAR);
+ wlv.sc_final = NUL;
wlv.n_extra = 1;
wlv.n_attr = 2;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
}
- mb_schar = schar_from_char(mb_c);
+ mb_c = schar_get_first_codepoint(mb_schar);
saved_attr3 = wlv.char_attr; // save current attr
wlv.char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr
n_attr3 = 1;
}
// At end of the text line or just after the last character.
- if (mb_c == NUL && eol_hl_off == 0) {
+ if (mb_schar == NUL && eol_hl_off == 0) {
// flag to indicate whether prevcol equals startcol of search_hl or
// one of the matches
- bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl,
- (colnr_T)(ptr - line) - 1);
+ const bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl,
+ (colnr_T)(ptr - line) - 1);
// Invert at least one char, used for Visual and empty line or
// highlight match at end of line. If it's beyond the last
// char on the screen, just overwrite that one (tricky!) Not
// needed when a '$' was displayed for 'list'.
- if (wp->w_p_lcs_chars.eol == lcs_eol_one
+ if (lcs_eol_todo
&& ((area_attr != 0 && wlv.vcol == wlv.fromcol
&& (VIsual_mode != Ctrl_V
|| lnum == VIsual.lnum
@@ -2597,7 +2532,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Add a blank character to highlight.
linebuf_char[wlv.off] = schar_from_ascii(' ');
}
- if (area_attr == 0 && !has_fold) {
+ if (area_attr == 0 && !has_foldtext) {
// Use attributes from match with highest priority among
// 'search_hl' and the match list.
get_search_match_hl(wp,
@@ -2606,10 +2541,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&wlv.char_attr);
}
- int eol_attr = wlv.char_attr;
- if (wlv.cul_attr) {
- eol_attr = hl_combine_attr(wlv.cul_attr, eol_attr);
- }
+ const int eol_attr = wlv.cul_attr
+ ? hl_combine_attr(wlv.cul_attr, wlv.char_attr)
+ : wlv.char_attr;
+
linebuf_attr[wlv.off] = eol_attr;
linebuf_vcol[wlv.off] = MAXCOL;
wlv.col++;
@@ -2620,70 +2555,48 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
// At end of the text line.
- if (mb_c == NUL) {
+ if (mb_schar == NUL) {
// Highlight 'cursorcolumn' & 'colorcolumn' past end of the line.
- if (wp->w_p_wrap) {
- v = wlv.startrow == 0 ? wp->w_skipcol : 0;
- } else {
- v = wp->w_leftcol;
- }
// check if line ends before left margin
- if (wlv.vcol < v + wlv.col - win_col_off(wp)) {
- wlv.vcol = (colnr_T)v + wlv.col - win_col_off(wp);
+ if (wlv.vcol < start_col + wlv.col - win_col_off(wp)) {
+ wlv.vcol = start_col + wlv.col - win_col_off(wp);
}
// Get rid of the boguscols now, we want to draw until the right
// edge for 'cursorcolumn'.
wlv.col -= wlv.boguscols;
wlv.boguscols = 0;
- if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
- }
+ advance_color_col(&wlv, vcol_hlc(wlv));
bool has_virttext = false;
// Make sure alignment is the same regardless
// if listchars=eol:X is used or not.
- int eol_skip = (wp->w_p_lcs_chars.eol == lcs_eol_one && eol_hl_off == 0
- ? 1 : 0);
+ const int eol_skip = (lcs_eol_todo && eol_hl_off == 0 ? 1 : 0);
if (has_decor) {
has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip);
}
if (((wp->w_p_cuc
- && wp->w_virtcol >= VCOL_HLC - eol_hl_off
- && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + v
+ && wp->w_virtcol >= vcol_hlc(wlv) - eol_hl_off
+ && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + start_col
&& lnum != wp->w_cursor.lnum)
- || draw_color_col || wlv.line_attr_lowprio || wlv.line_attr
+ || wlv.color_cols || wlv.line_attr_lowprio || wlv.line_attr
|| wlv.diff_hlf != 0 || has_virttext)) {
- int rightmost_vcol = 0;
-
- if (wp->w_p_cuc) {
- rightmost_vcol = wp->w_virtcol;
- }
-
- if (draw_color_col) {
- // determine rightmost colorcolumn to possibly draw
- for (int i = 0; color_cols[i] >= 0; i++) {
- if (rightmost_vcol < color_cols[i]) {
- rightmost_vcol = color_cols[i];
- }
- }
- }
+ int rightmost_vcol = get_rightmost_vcol(wp, wlv.color_cols);
+ const int cuc_attr = win_hl_attr(wp, HLF_CUC);
+ const int mc_attr = win_hl_attr(wp, HLF_MC);
- int cuc_attr = win_hl_attr(wp, HLF_CUC);
- int mc_attr = win_hl_attr(wp, HLF_MC);
-
- int diff_attr = 0;
if (wlv.diff_hlf == HLF_TXD) {
wlv.diff_hlf = HLF_CHD;
}
- if (wlv.diff_hlf != 0) {
- diff_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
- }
- int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr);
+ const int diff_attr = wlv.diff_hlf != 0
+ ? win_hl_attr(wp, (int)wlv.diff_hlf)
+ : 0;
+
+ const int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr);
if (base_attr || wlv.line_attr || has_virttext) {
rightmost_vcol = INT_MAX;
}
@@ -2692,15 +2605,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_char[wlv.off] = schar_from_ascii(' ');
linebuf_vcol[wlv.off] = MAXCOL;
wlv.col++;
- if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
- }
+ advance_color_col(&wlv, vcol_hlc(wlv));
int col_attr = base_attr;
- if (wp->w_p_cuc && VCOL_HLC == wp->w_virtcol) {
+ if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol) {
col_attr = cuc_attr;
- } else if (draw_color_col && VCOL_HLC == *color_cols) {
+ } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) {
col_attr = hl_combine_attr(wlv.line_attr_lowprio, mc_attr);
}
@@ -2709,7 +2620,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_attr[wlv.off] = col_attr;
wlv.off++;
- if (VCOL_HLC >= rightmost_vcol) {
+ if (vcol_hlc(wlv) >= rightmost_vcol) {
break;
}
@@ -2746,73 +2657,72 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
conceal_cursor_used = conceal_cursor_line(curwin);
}
+
+ // When the window is too narrow draw all "@" lines.
+ if (leftcols_width >= wp->w_grid.cols && is_wrapped) {
+ win_draw_end(wp, schar_from_ascii('@'), true, wlv.row, wp->w_grid.rows, HLF_AT);
+ set_empty_rows(wp, wlv.row);
+ wlv.row = endrow;
+ }
+
break;
}
// Show "extends" character from 'listchars' if beyond the line end and
// 'list' is set.
+ // Don't show this with 'wrap' as the line can't be scrolled horizontally.
if (wp->w_p_lcs_chars.ext != NUL
- && wlv.draw_state == WL_LINE
&& wp->w_p_list
&& !wp->w_p_wrap
&& wlv.filler_todo <= 0
&& wlv.col == grid->cols - 1
- && !has_fold) {
- if (has_decor && *ptr == NUL && lcs_eol_one == 0) {
+ && !has_foldtext) {
+ if (has_decor && *ptr == NUL && lcs_eol == 0 && lcs_eol_todo) {
// Tricky: there might be a virtual text just _after_ the last char
- decor_redraw_col(wp, (colnr_T)v, wlv.off, false, &decor_state);
+ decor_redraw_col(wp, (colnr_T)(ptr - line), -1, false, &decor_state);
}
if (*ptr != NUL
- || lcs_eol_one > 0
- || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
- || has_more_inline_virt(&wlv, v)) {
- mb_c = wp->w_p_lcs_chars.ext;
+ || (lcs_eol > 0 && lcs_eol_todo)
+ || (wlv.n_extra > 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
+ || (may_have_inline_virt && has_more_inline_virt(&wlv, ptr - line))) {
+ mb_schar = wp->w_p_lcs_chars.ext;
wlv.char_attr = win_hl_attr(wp, HLF_AT);
- mb_schar = schar_from_char(mb_c);
+ mb_c = schar_get_first_codepoint(mb_schar);
}
}
- // advance to the next 'colorcolumn'
- if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
- }
+ advance_color_col(&wlv, vcol_hlc(wlv));
// Highlight the cursor column if 'cursorcolumn' is set. But don't
// highlight the cursor position itself.
// Also highlight the 'colorcolumn' if it is different than
// 'cursorcolumn'
- // Also highlight the 'colorcolumn' if 'breakindent' and/or 'showbreak'
- // options are set
vcol_save_attr = -1;
- if ((wlv.draw_state == WL_LINE
- || wlv.draw_state == WL_BRI
- || wlv.draw_state == WL_SBR)
- && !lnum_in_visual_area
+ if (!lnum_in_visual_area
&& search_attr == 0
&& area_attr == 0
&& wlv.filler_todo <= 0) {
- if (wp->w_p_cuc && VCOL_HLC == wp->w_virtcol
+ if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol
&& lnum != wp->w_cursor.lnum) {
vcol_save_attr = wlv.char_attr;
wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), wlv.char_attr);
- } else if (draw_color_col && VCOL_HLC == *color_cols) {
+ } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) {
vcol_save_attr = wlv.char_attr;
wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), wlv.char_attr);
}
}
// Apply lowest-priority line attr now, so everything can override it.
- if (wlv.draw_state == WL_LINE) {
- wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr);
- }
+ wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr);
- if (wlv.draw_state == WL_LINE) {
- vcol_prev = wlv.vcol;
- }
+ vcol_prev = wlv.vcol;
// Store character to be displayed.
// Skip characters that are left of the screen for 'nowrap'.
- if (wlv.draw_state < WL_LINE || wlv.skip_cells <= 0) {
+ if (wlv.filler_todo > 0) {
+ // TODO(bfredl): the main render loop should get called also with the virtual
+ // lines chunks, so we get line wrapping and other Nice Things.
+ } else if (wlv.skip_cells <= 0) {
// Store the character.
linebuf_char[wlv.off] = mb_schar;
if (multi_attr) {
@@ -2822,18 +2732,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_attr[wlv.off] = wlv.char_attr;
}
- if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) {
- linebuf_vcol[wlv.off] = wlv.vcol;
- } else if (wlv.draw_state == WL_FOLD) {
- if (wlv.n_closing > 0) {
- linebuf_vcol[wlv.off] = -3;
- wlv.n_closing--;
- } else {
- linebuf_vcol[wlv.off] = -2;
- }
- } else {
- linebuf_vcol[wlv.off] = -1;
- }
+ linebuf_vcol[wlv.off] = wlv.vcol;
if (utf_char2cells(mb_c) > 1) {
// Need to fill two screen columns.
@@ -2843,11 +2742,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_char[wlv.off] = 0;
linebuf_attr[wlv.off] = linebuf_attr[wlv.off - 1];
- if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) {
- linebuf_vcol[wlv.off] = ++wlv.vcol;
- } else {
- linebuf_vcol[wlv.off] = -1;
- }
+ linebuf_vcol[wlv.off] = ++wlv.vcol;
// When "wlv.tocol" is halfway through a character, set it to the end
// of the character, otherwise highlighting won't stop.
@@ -2863,7 +2758,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.n_extra > 0) {
wlv.vcol_off += wlv.n_extra;
}
- if (wp->w_p_wrap) {
+ if (is_wrapped) {
// Special voodoo required if 'wrap' is on.
//
// Advance the column indicator to force the line
@@ -2903,15 +2798,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
// The skipped cells need to be accounted for in vcol.
- if (wlv.draw_state > WL_STC && wlv.skipped_cells > 0) {
+ if (wlv.skipped_cells > 0) {
wlv.vcol += wlv.skipped_cells;
wlv.skipped_cells = 0;
}
// Only advance the "wlv.vcol" when after the 'number' or
// 'relativenumber' column.
- if (wlv.draw_state > WL_STC
- && wlv.filler_todo <= 0) {
+ if (wlv.filler_todo <= 0) {
wlv.vcol++;
}
@@ -2920,46 +2814,45 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
// restore attributes after "predeces" in 'listchars'
- if (wlv.draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) {
+ if (n_attr3 > 0 && --n_attr3 == 0) {
wlv.char_attr = saved_attr3;
}
// restore attributes after last 'listchars' or 'number' char
- if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && --wlv.n_attr == 0) {
+ if (wlv.n_attr > 0 && --wlv.n_attr == 0) {
wlv.char_attr = saved_attr2;
}
if (has_decor && wlv.filler_todo <= 0 && wlv.col >= grid->cols) {
// At the end of screen line: might need to peek for decorations just after
// this position.
- if (!has_fold && wp->w_p_wrap && wlv.n_extra == 0) {
- decor_redraw_col(wp, (int)(ptr - line), -3, false, &decor_state);
+ if (is_wrapped && wlv.n_extra == 0) {
+ decor_redraw_col(wp, (colnr_T)(ptr - line), -3, false, &decor_state);
// Check position/hiding of virtual text again on next screen line.
decor_need_recheck = true;
- } else if (has_fold || !wp->w_p_wrap) {
+ } else if (!is_wrapped) {
// Without wrapping, we might need to display right_align and win_col
// virt_text for the entire text line.
+ decor_recheck_draw_col(-1, true, &decor_state);
decor_redraw_col(wp, MAXCOL, -1, true, &decor_state);
}
}
// At end of screen line and there is more to come: Display the line
// so far. If there is no more to display it is caught above.
- if (wlv.col >= grid->cols && (!has_fold || virt_line_offset >= 0)
- && (wlv.draw_state != WL_LINE
- || *ptr != NUL
+ if (wlv.col >= grid->cols && (!has_foldtext || virt_line_offset >= 0)
+ && (*ptr != NUL
|| wlv.filler_todo > 0
- || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
- && wlv.p_extra != at_end_str)
- || (wlv.n_extra != 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
- || has_more_inline_virt(&wlv, v))) {
- bool wrap = wp->w_p_wrap // Wrapping enabled.
- && wlv.filler_todo <= 0 // Not drawing diff filler lines.
- && lcs_eol_one != -1 // Haven't printed the lcs_eol character.
- && wlv.row != endrow - 1 // Not the last line being displayed.
- && (grid->cols == Columns // Window spans the width of the screen,
- || ui_has(kUIMultigrid)) // or has dedicated grid.
- && !wp->w_p_rl; // Not right-to-left.
+ || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && lcs_eol_todo)
+ || (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
+ || (may_have_inline_virt && has_more_inline_virt(&wlv, ptr - line)))) {
+ const bool wrap = is_wrapped // Wrapping enabled (not a folded line).
+ && wlv.filler_todo <= 0 // Not drawing diff filler lines.
+ && lcs_eol_todo // Haven't printed the lcs_eol character.
+ && wlv.row != endrow - 1 // Not the last line being displayed.
+ && (grid->cols == Columns // Window spans the width of the screen,
+ || ui_has(kUIMultigrid)) // or has dedicated grid.
+ && !wp->w_p_rl; // Not right-to-left.
int draw_col = wlv.col - wlv.boguscols;
if (virt_line_offset >= 0) {
@@ -2984,15 +2877,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.vcol_off = 0;
wlv.row++;
- // When not wrapping and finished diff lines, or when displayed
- // '$' and highlighting until last column, break here.
- if ((!wp->w_p_wrap && wlv.filler_todo <= 0) || lcs_eol_one == -1) {
+ // When not wrapping and finished diff lines, break here.
+ if (!is_wrapped && wlv.filler_todo <= 0) {
break;
}
// When the window is too narrow draw all "@" lines.
- if (wlv.draw_state != WL_LINE && wlv.filler_todo <= 0) {
- win_draw_end(wp, '@', ' ', true, wlv.row, wp->w_grid.rows, HLF_AT);
+ if (wlv.col <= leftcols_width) {
+ win_draw_end(wp, schar_from_ascii('@'), true, wlv.row, wp->w_grid.rows, HLF_AT);
set_empty_rows(wp, wlv.row);
wlv.row = endrow;
}
@@ -3003,18 +2895,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
break;
}
- win_line_start(wp, &wlv, true);
+ win_line_start(wp, &wlv);
+ draw_cols = true;
lcs_prec_todo = wp->w_p_lcs_chars.prec;
if (wlv.filler_todo <= 0) {
wlv.need_showbreak = true;
}
- if (statuscol.draw) {
- if (vim_strchr(p_cpo, CPO_NUMCOL) && wlv.row > startrow + wlv.filler_lines) {
- statuscol.draw = false; // don't draw status column if "n" is in 'cpo'
- } else {
- statuscol.textp = NULL; // re-evaluate with new v:virtnum
- }
+ if (statuscol.draw && vim_strchr(p_cpo, CPO_NUMCOL)
+ && wlv.row > startrow + wlv.filler_lines) {
+ statuscol.draw = false; // don't draw status column if "n" is in 'cpo'
}
wlv.filler_todo--;
virt_line_offset = -1;
@@ -3040,8 +2930,7 @@ static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clea
int start_col = 0;
if (wp->w_p_rl) {
- linebuf_mirror(&start_col, &clear_width, grid->cols);
- endcol = grid->cols - 1 - endcol;
+ linebuf_mirror(&start_col, &endcol, &clear_width, grid->cols);
}
// Take care of putting "<<<" on the first line for 'smoothscroll'.