diff src/screen.c @ 18068:1101eacc1444 v8.1.2029

patch 8.1.2029: cannot control 'cursorline' highlighting well Commit: https://github.com/vim/vim/commit/017ba07fa2cdc578245618717229444fd50c470d Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 14 21:01:23 2019 +0200 patch 8.1.2029: cannot control 'cursorline' highlighting well Problem: Cannot control 'cursorline' highlighting well. Solution: Add "screenline". (Christian Brabandt, closes https://github.com/vim/vim/issues/4933)
author Bram Moolenaar <Bram@vim.org>
date Sat, 14 Sep 2019 21:15:04 +0200
parents 6650e3dff8d4
children 5f1554b2587c
line wrap: on
line diff
--- a/src/screen.c
+++ b/src/screen.c
@@ -158,6 +158,9 @@ static void win_redr_custom(win_T *wp, i
 #ifdef FEAT_CMDL_INFO
 static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
 #endif
+#ifdef FEAT_SYN_HL
+static void margin_columns_win(win_T *wp, int *left_col, int *right_col);
+#endif
 
 /* Ugly global: overrule attribute used by screen_char() */
 static int screen_char_attr = 0;
@@ -3270,7 +3273,8 @@ win_line(
 #if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
 	|| defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
 # define LINE_ATTR
-    int		line_attr = 0;		/* attribute for the whole line */
+    int		line_attr = 0;		// attribute for the whole line
+    int		line_attr_save;
 #endif
 #ifdef FEAT_SIGNS
     int		sign_present = FALSE;
@@ -3286,6 +3290,17 @@ win_line(
 #ifdef FEAT_TERMINAL
     int		get_term_attr = FALSE;
 #endif
+#ifdef FEAT_SYN_HL
+    int		cul_attr = 0;		// set when 'cursorline' active
+
+    // 'cursorlineopt' has "screenline" and cursor is in this line
+    int		cul_screenline = FALSE;
+
+    // margin columns for the screen line, needed for when 'cursorlineopt'
+    // contains "screenline"
+    int		left_curline_col = 0;
+    int		right_curline_col = 0;
+#endif
 
     /* draw_state: items that are drawn in sequence: */
 #define WL_START	0		/* nothing done yet */
@@ -3815,14 +3830,33 @@ win_line(
     // Cursor line highlighting for 'cursorline' in the current window.
     if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
     {
-	// Do not show the cursor line when Visual mode is active, because it's
-	// not clear what is selected then.  Do update w_last_cursorline.
-	if (!(wp == curwin && VIsual_active) && *wp->w_p_culopt != 'n')
-	{
-	    line_attr = HL_ATTR(HLF_CUL);
+	// Do not show the cursor line in the text when Visual mode is active,
+	// because it's not clear what is selected then.  Do update
+	// w_last_cursorline.
+	if (!(wp == curwin && VIsual_active)
+					 && wp->w_p_culopt_flags != CULOPT_NBR)
+	{
+	    cul_screenline = (wp->w_p_wrap
+				   && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
+
+	    // Only set line_attr here when "screenline" is not present in
+	    // 'cursorlineopt'.  Otherwise it's done later.
+	    if (!cul_screenline)
+	    {
+		cul_attr = HL_ATTR(HLF_CUL);
+		line_attr = cul_attr;
+		wp->w_last_cursorline = wp->w_cursor.lnum;
+	    }
+	    else
+	    {
+		line_attr_save = line_attr;
+		wp->w_last_cursorline = 0;
+		margin_columns_win(wp, &left_curline_col, &right_curline_col);
+	    }
 	    area_highlighting = TRUE;
 	}
-	wp->w_last_cursorline = wp->w_cursor.lnum;
+	else
+	    wp->w_last_cursorline = wp->w_cursor.lnum;
     }
 #endif
 
@@ -4016,13 +4050,17 @@ win_line(
 		      n_extra = number_width(wp) + 1;
 		      char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_N));
 #ifdef FEAT_SYN_HL
-		      /* When 'cursorline' is set highlight the line number of
-		       * the current line differently.
-		       * TODO: Can we use CursorLine instead of CursorLineNr
-		       * when CursorLineNr isn't set? */
+		      // When 'cursorline' is set highlight the line number of
+		      // the current line differently.
+		      // When 'cursorlineopt' has "screenline" only highlight
+		      // the line number itself.
+		      // TODO: Can we use CursorLine instead of CursorLineNr
+		      // when CursorLineNr isn't set?
 		      if ((wp->w_p_cul || wp->w_p_rnu)
-						 && *wp->w_p_culopt != 'l'
-						 && lnum == wp->w_cursor.lnum)
+			      && (wp->w_p_culopt_flags & CULOPT_NBR)
+			      && (row == startrow
+				  || wp->w_p_culopt_flags & CULOPT_LINE)
+			      && lnum == wp->w_cursor.lnum)
 			char_attr = hl_combine_attr(wcr_attr, HL_ATTR(HLF_CLN));
 #endif
 		    }
@@ -4056,10 +4094,8 @@ win_line(
 		    {
 			char_attr = HL_ATTR(diff_hlf);
 #  ifdef FEAT_SYN_HL
-			if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-						    && *wp->w_p_culopt != 'n')
-			    char_attr = hl_combine_attr(char_attr,
-							    HL_ATTR(HLF_CUL));
+			if (cul_attr != 0)
+			    char_attr = hl_combine_attr(char_attr, cul_attr);
 #  endif
 		    }
 # endif
@@ -4117,13 +4153,11 @@ win_line(
 		     * required when 'linebreak' is also set. */
 		    if (tocol == vcol)
 			tocol += n_extra;
-#ifdef FEAT_SYN_HL
-		    /* combine 'showbreak' with 'cursorline' */
-		    if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-						    && *wp->w_p_culopt != 'n')
-			char_attr = hl_combine_attr(char_attr,
-							    HL_ATTR(HLF_CUL));
-#endif
+#  ifdef FEAT_SYN_HL
+		    // combine 'showbreak' with 'cursorline'
+		    if (cul_attr != 0)
+			char_attr = hl_combine_attr(char_attr, cul_attr);
+#  endif
 		}
 # endif
 	    }
@@ -4145,6 +4179,23 @@ win_line(
 		    char_attr = win_attr;
 	    }
 	}
+#ifdef FEAT_SYN_HL
+	if (cul_screenline)
+	{
+	    if (draw_state == WL_LINE
+		    && vcol >= left_curline_col
+		    && vcol < right_curline_col)
+	    {
+		cul_attr = HL_ATTR(HLF_CUL);
+		line_attr = cul_attr;
+	    }
+	    else
+	    {
+		cul_attr = 0;
+		line_attr = line_attr_save;
+	    }
+	}
+#endif
 
 	// When still displaying '$' of change command, stop at cursor.
 	// When only displaying the (relative) line number and that's done,
@@ -4216,8 +4267,11 @@ win_line(
 		    diff_hlf = HLF_CHD;		/* changed line */
 		line_attr = HL_ATTR(diff_hlf);
 		if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-						    && *wp->w_p_culopt != 'n')
-		    line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
+			&& wp->w_p_culopt_flags != CULOPT_NBR
+			&& (!cul_screenline || (vcol >= left_curline_col
+						&& vcol <= right_curline_col)))
+		    line_attr = hl_combine_attr(
+					  line_attr, HL_ATTR(HLF_CUL));
 	    }
 #endif
 
@@ -4301,9 +4355,12 @@ win_line(
 	    else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
 				|| vcol < fromcol || vcol_prev < fromcol_prev
 				|| vcol >= tocol))
+	    {
 		// Use line_attr when not in the Visual or 'incsearch' area
 		// (area_attr may be 0 when "noinvcur" is set).
 		char_attr = line_attr;
+		attr_pri = FALSE;
+	    }
 #else
 	    if (area_attr != 0)
 		char_attr = area_attr;
@@ -4410,6 +4467,10 @@ win_line(
 			mb_l = 1;
 			mb_utf8 = FALSE;
 			multi_attr = HL_ATTR(HLF_AT);
+#ifdef FEAT_SYN_HL
+			if (cul_attr)
+			    multi_attr = hl_combine_attr(multi_attr, cul_attr);
+#endif
 			/* put the pointer back to output the double-width
 			 * character at the start of the next line. */
 			++n_extra;
@@ -4672,10 +4733,10 @@ win_line(
 		    if (win_attr != 0)
 			syntax_attr = hl_combine_attr(win_attr, syntax_attr);
 
-#ifdef SYN_TIME_LIMIT
+# ifdef SYN_TIME_LIMIT
 		    if (wp->w_s->b_syn_slow)
 			has_syntax = FALSE;
-#endif
+# endif
 
 		    /* Need to get the line again, a multi-line regexp may
 		     * have made it invalid. */
@@ -4692,7 +4753,15 @@ win_line(
 			comb_attr = hl_combine_attr(text_prop_attr, comb_attr);
 # endif
 			if (!attr_pri)
-			    char_attr = comb_attr;
+			{
+#ifdef FEAT_SYN_HL
+			    if (cul_attr)
+				char_attr = hl_combine_attr(
+							  comb_attr, cul_attr);
+			    else
+#endif
+				char_attr = comb_attr;
+			}
 			else
 			    char_attr = hl_combine_attr(comb_attr, char_attr);
 		    }
@@ -5185,9 +5254,12 @@ win_line(
 			{
 			    char_attr = HL_ATTR(diff_hlf);
 			    if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-						    && *wp->w_p_culopt != 'n')
-				char_attr = hl_combine_attr(char_attr,
-							    HL_ATTR(HLF_CUL));
+				    && wp->w_p_culopt_flags != CULOPT_NBR
+				    && (!cul_screenline
+					|| (vcol >= left_curline_col
+						 && vcol <= right_curline_col)))
+				char_attr = hl_combine_attr(
+					  char_attr, HL_ATTR(HLF_CUL));
 			}
 		    }
 # endif
@@ -5196,8 +5268,12 @@ win_line(
 		    {
 			char_attr = win_attr;
 			if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
-			    char_attr = hl_combine_attr(char_attr,
-							    HL_ATTR(HLF_CUL));
+			{
+			    if (!cul_screenline || (vcol >= left_curline_col
+						  && vcol <= right_curline_col))
+				char_attr = hl_combine_attr(
+					      char_attr, HL_ATTR(HLF_CUL));
+			}
 			else if (line_attr)
 			    char_attr = hl_combine_attr(char_attr, line_attr);
 		    }
@@ -5305,7 +5381,12 @@ win_line(
 	if (n_attr > 0
 		&& draw_state == WL_LINE
 		&& !attr_pri)
-	    char_attr = extra_attr;
+	{
+	    if (line_attr)
+		char_attr = hl_combine_attr(extra_attr, line_attr);
+	    else
+		char_attr = extra_attr;
+	}
 
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
 	/* XIM don't send preedit_start and preedit_end, but they send
@@ -5969,7 +6050,16 @@ win_line(
 	    saved_p_extra = p_extra;
 	    saved_c_extra = c_extra;
 	    saved_c_final = c_final;
-	    saved_char_attr = char_attr;
+#ifdef FEAT_SYN_HL
+	    if (!(cul_screenline
+# ifdef FEAT_DIFF
+			&& diff_hlf == (hlf_T)0)
+# endif
+		    )
+		saved_char_attr = char_attr;
+	    else
+#endif
+		saved_char_attr = 0;
 	    n_extra = 0;
 	    lcs_prec_todo = lcs_prec;
 #ifdef FEAT_LINEBREAK
@@ -11024,3 +11114,50 @@ set_chars_option(char_u **varp)
 
     return NULL;	// no error
 }
+
+#ifdef FEAT_SYN_HL
+/*
+ * Used when 'cursorlineopt' contains "screenline": compute the margins between
+ * which the highlighting is used.
+ */
+    static void
+margin_columns_win(win_T *wp, int *left_col, int *right_col)
+{
+    // cache previous calculations depending on w_virtcol
+    static int saved_w_virtcol;
+    static win_T *prev_wp;
+    static int prev_left_col;
+    static int prev_right_col;
+    static int prev_col_off;
+
+    int cur_col_off = win_col_off(wp);
+    int	width1;
+    int	width2;
+
+    if (saved_w_virtcol == wp->w_virtcol
+	    && prev_wp == wp && prev_col_off == cur_col_off)
+    {
+	*right_col = prev_right_col;
+	*left_col = prev_left_col;
+	return;
+    }
+
+    width1 = wp->w_width - cur_col_off;
+    width2 = width1 + win_col_off2(wp);
+
+    *left_col = 0;
+    *right_col = width1;
+
+    if (wp->w_virtcol >= (colnr_T)width1)
+	*right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
+    if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0)
+	*left_col = (wp->w_virtcol - width1) / width2 * width2 + width1;
+
+    // cache values
+    prev_left_col = *left_col;
+    prev_right_col = *right_col;
+    prev_wp = wp;
+    saved_w_virtcol = wp->w_virtcol;
+    prev_col_off = cur_col_off;
+}
+#endif