aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/screen.c')
-rw-r--r--src/nvim/screen.c207
1 files changed, 141 insertions, 66 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 2e27bef3de..fe6a15c5fc 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -132,6 +132,15 @@ static schar_T *current_ScreenLine;
StlClickDefinition *tab_page_click_defs = NULL;
long tab_page_click_defs_size = 0;
+// for line_putchar. Contains the state that needs to be remembered from
+// putting one character to the next.
+typedef struct {
+ const char_u *p;
+ int prev_c; // previous Arabic character
+ int prev_c1; // first composing char for prev_c
+} LineState;
+#define LINE_STATE(p) { p, 0, 0 }
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
@@ -1731,6 +1740,56 @@ static int compute_foldcolumn(win_T *wp, int col)
return fdc;
}
+/// Put a single char from an UTF-8 buffer into a line buffer.
+///
+/// Handles composing chars and arabic shaping state.
+static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
+{
+ const char_u *p = s->p;
+ int cells = utf_ptr2cells(p);
+ int c_len = utfc_ptr2len(p);
+ int u8c, u8cc[MAX_MCO];
+ if (cells > maxcells) {
+ return -1;
+ }
+ u8c = utfc_ptr2char(p, u8cc);
+ if (*p < 0x80 && u8cc[0] == 0) {
+ schar_from_ascii(dest[0], *p);
+ s->prev_c = u8c;
+ } else {
+ if (p_arshape && !p_tbidi && arabic_char(u8c)) {
+ // Do Arabic shaping.
+ int pc, pc1, nc;
+ int pcc[MAX_MCO];
+ int firstbyte = *p;
+
+ // The idea of what is the previous and next
+ // character depends on 'rightleft'.
+ if (rl) {
+ pc = s->prev_c;
+ pc1 = s->prev_c1;
+ nc = utf_ptr2char(p + c_len);
+ s->prev_c1 = u8cc[0];
+ } else {
+ pc = utfc_ptr2char(p + c_len, pcc);
+ nc = s->prev_c;
+ pc1 = pcc[0];
+ }
+ s->prev_c = u8c;
+
+ u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc);
+ } else {
+ s->prev_c = u8c;
+ }
+ schar_from_cc(dest[0], u8c, u8cc);
+ }
+ if (cells > 1) {
+ dest[1][0] = 0;
+ }
+ s->p += c_len;
+ return cells;
+}
+
/*
* Display one folded line.
*/
@@ -1863,13 +1922,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
* Right-left text is put in columns 0 - number-col, normal text is put
* in columns number-col - window-width.
*/
- int cells;
- int u8c, u8cc[MAX_MCO];
int idx;
- int c_len;
- char_u *p;
- int prev_c = 0; // previous Arabic character
- int prev_c1 = 0; // first composing char for prev_c
if (wp->w_p_rl) {
idx = off;
@@ -1877,50 +1930,20 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
idx = off + col;
}
- // Store multibyte characters in ScreenLines[] et al. correctly.
- for (p = text; *p != NUL; ) {
- cells = utf_ptr2cells(p);
- c_len = utfc_ptr2len(p);
- if (col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) {
- break;
- }
- u8c = utfc_ptr2char(p, u8cc);
- if (*p < 0x80 && u8cc[0] == 0) {
- schar_from_ascii(ScreenLines[idx], *p);
- prev_c = u8c;
- } else {
- if (p_arshape && !p_tbidi && arabic_char(u8c)) {
- // Do Arabic shaping.
- int pc, pc1, nc;
- int pcc[MAX_MCO];
- int firstbyte = *p;
-
- // The idea of what is the previous and next
- // character depends on 'rightleft'.
- if (wp->w_p_rl) {
- pc = prev_c;
- pc1 = prev_c1;
- nc = utf_ptr2char(p + c_len);
- prev_c1 = u8cc[0];
- } else {
- pc = utfc_ptr2char(p + c_len, pcc);
- nc = prev_c;
- pc1 = pcc[0];
- }
- prev_c = u8c;
+ LineState s = LINE_STATE(text);
- u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc);
- } else {
- prev_c = u8c;
- }
- schar_from_cc(ScreenLines[idx], u8c, u8cc);
- }
- if (cells > 1) {
- ScreenLines[idx + 1][0] = 0;
+ while (*s.p != NUL) {
+ // TODO(bfredl): cargo-culted from the old Vim code:
+ // if(col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { break; }
+ // This is obvious wrong. If Vim ever fixes this, solve for "cells" again
+ // in the correct condition.
+ int maxcells = wp->w_width - col - (wp->w_p_rl ? col : 0);
+ int cells = line_putchar(&s, &ScreenLines[idx], maxcells, wp->w_p_rl);
+ if (cells == -1) {
+ break;
}
col += cells;
idx += cells;
- p += c_len;
}
/* Fill the rest of the line with the fold filler */
@@ -2215,9 +2238,9 @@ win_line (
int did_line_attr = 0;
bool search_attr_from_match = false; // if search_attr is from :match
- bool has_bufhl = false; // this buffer has highlight matches
- int bufhl_attr = 0; // attributes desired by bufhl
BufhlLineInfo bufhl_info; // bufhl data for this line
+ bool has_bufhl = false; // this buffer has highlight matches
+ bool do_virttext = false; // draw virtual text for this line
/* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */
@@ -2279,8 +2302,13 @@ win_line (
}
if (bufhl_start_line(wp->w_buffer, lnum, &bufhl_info)) {
- has_bufhl = true;
- extra_check = true;
+ if (kv_size(bufhl_info.line->items)) {
+ has_bufhl = true;
+ extra_check = true;
+ }
+ if (kv_size(bufhl_info.line->virt_text)) {
+ do_virttext = true;
+ }
}
// Check for columns to display for 'colorcolumn'.
@@ -3429,7 +3457,7 @@ win_line (
}
if (has_bufhl && v > 0) {
- bufhl_attr = bufhl_get_attr(&bufhl_info, (colnr_T)v);
+ int bufhl_attr = bufhl_get_attr(&bufhl_info, (colnr_T)v);
if (bufhl_attr != 0) {
if (!attr_pri) {
char_attr = hl_combine_attr(char_attr, bufhl_attr);
@@ -3949,40 +3977,87 @@ win_line (
&& (int)wp->w_virtcol <
wp->w_width * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
- || draw_color_col)
- && !wp->w_p_rl
- ) {
+ || draw_color_col || do_virttext)
+ && !wp->w_p_rl) {
int rightmost_vcol = 0;
int i;
- if (wp->w_p_cuc)
+ VirtText virt_text = do_virttext ? bufhl_info.line->virt_text
+ : (VirtText)KV_INITIAL_VALUE;
+ size_t virt_pos = 0;
+ LineState s = LINE_STATE((char_u *)"");
+ int virt_attr = 0;
+
+ // Make sure alignment is the same regardless
+ // if listchars=eol:X is used or not.
+ bool delay_virttext = lcs_eol <= 0;
+
+ if (wp->w_p_cuc) {
rightmost_vcol = wp->w_virtcol;
- if (draw_color_col)
- /* determine rightmost colorcolumn to possibly draw */
- for (i = 0; color_cols[i] >= 0; ++i)
- if (rightmost_vcol < color_cols[i])
+ }
+
+ if (draw_color_col) {
+ // determine rightmost colorcolumn to possibly draw
+ for (i = 0; color_cols[i] >= 0; i++) {
+ if (rightmost_vcol < color_cols[i]) {
rightmost_vcol = color_cols[i];
+ }
+ }
+ }
int cuc_attr = win_hl_attr(wp, HLF_CUC);
int mc_attr = win_hl_attr(wp, HLF_MC);
while (col < wp->w_width) {
- schar_from_ascii(ScreenLines[off], ' ');
- col++;
+ int cells = -1;
+ if (do_virttext && !delay_virttext) {
+ if (*s.p == NUL) {
+ if (virt_pos < virt_text.size) {
+ s.p = (char_u *)kv_A(virt_text, virt_pos).text;
+ int hl_id = kv_A(virt_text, virt_pos).hl_id;
+ virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
+ virt_pos++;
+ } else {
+ do_virttext = false;
+ }
+ }
+ if (*s.p != NUL) {
+ cells = line_putchar(&s, &ScreenLines[off], wp->w_width - col,
+ false);
+ }
+ }
+ delay_virttext = false;
+
+ if (cells == -1) {
+ schar_from_ascii(ScreenLines[off], ' ');
+ cells = 1;
+ }
+ col += cells;
if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
}
+ int attr = 0;
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) {
- ScreenAttrs[off++] = cuc_attr;
+ attr = cuc_attr;
} else if (draw_color_col && VCOL_HLC == *color_cols) {
- ScreenAttrs[off++] = mc_attr;
- } else {
- ScreenAttrs[off++] = wp->w_hl_attr_normal;
+ attr = mc_attr;
+ }
+
+ if (do_virttext) {
+ attr = hl_combine_attr(attr, virt_attr);
}
- if (VCOL_HLC >= rightmost_vcol)
+ ScreenAttrs[off] = attr;
+ if (cells == 2) {
+ ScreenAttrs[off+1] = attr;
+ }
+ off += cells;
+
+ if (VCOL_HLC >= rightmost_vcol && *s.p == NUL
+ && virt_pos >= virt_text.size) {
break;
+ }
++vcol;
}