changeset 12580:ba55861aa52c v8.0.1168

patch 8.0.1168: wrong highlighting with combination of match and 'cursorline' commit https://github.com/vim/vim/commit/0aa398f55a327282c70f56e0bac2dcb9521da378 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 30 21:23:55 2017 +0200 patch 8.0.1168: wrong highlighting with combination of match and 'cursorline' Problem: wrong highlighting with combination of match and 'cursorline'. Solution: Use "line_attr" when appropriate. (Ozaki Kiichi, closes https://github.com/vim/vim/issues/2111) But don't highlight more than one character.
author Christian Brabandt <cb@256bit.org>
date Sat, 30 Sep 2017 21:30:05 +0200
parents 64b98c8e200a
children 727965036b90
files src/screen.c src/testdir/test_highlight.vim src/testdir/view_util.vim src/version.c
diffstat 4 files changed, 491 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/screen.c
+++ b/src/screen.c
@@ -4168,6 +4168,9 @@ win_line(
 		    if (shl != &search_hl && cur != NULL)
 			cur = cur->next;
 		}
+		/* Only highlight one character after the last column. */
+		if (*ptr == NUL && did_line_attr >= 1)
+		    search_attr = 0;
 	    }
 #endif
 
@@ -5064,7 +5067,9 @@ win_line(
 		    ++did_line_attr;
 
 		    /* don't do search HL for the rest of the line */
-		    if (line_attr != 0 && char_attr == search_attr && col > 0)
+		    if (line_attr != 0 && char_attr == search_attr
+					&& (did_line_attr > 1
+					    || (wp->w_p_list && lcs_eol > 0)))
 			char_attr = line_attr;
 # ifdef FEAT_DIFF
 		    if (diff_hlf == HLF_TXD)
@@ -5320,6 +5325,13 @@ win_line(
 #ifdef FEAT_SEARCH_EXTRA
 			/* highlight 'hlsearch' match at end of line */
 			|| (prevcol_hl_flag == TRUE
+# ifdef FEAT_SYN_HL
+			    && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
+				    && !(wp == curwin && VIsual_active))
+# endif
+# ifdef FEAT_DIFF
+			    && diff_hlf == (hlf_T)0
+# endif
 # if defined(LINE_ATTR)
 			    && did_line_attr <= 1
 # endif
--- a/src/testdir/test_highlight.vim
+++ b/src/testdir/test_highlight.vim
@@ -1,4 +1,7 @@
-" Tests for ":highlight".
+" Tests for ":highlight" and highlighting.
+
+source view_util.vim
+
 func Test_highlight()
   " basic test if ":highlight" doesn't crash
   highlight
@@ -34,3 +37,454 @@ func Test_highlight()
 				\ split(execute("hi Group3"), "\n")[0])
   call assert_fails("hi Crash term='asdf", "E475:")
 endfunc
+
+function! HighlightArgs(name)
+  return 'hi ' . substitute(split(execute('hi ' . a:name), '\n')[0], '\<xxx\>', '', '')
+endfunction
+
+function! IsColorable()
+  return has('gui_running') || str2nr(&t_Co) >= 8
+endfunction
+
+function! HiCursorLine()
+  let hiCursorLine = HighlightArgs('CursorLine')
+  if has('gui_running')
+    let guibg = matchstr(hiCursorLine, 'guibg=\w\+')
+    let hi_ul = 'hi CursorLine gui=underline guibg=NONE'
+    let hi_bg = 'hi CursorLine gui=NONE ' . guibg
+  else
+    let hi_ul = 'hi CursorLine cterm=underline ctermbg=NONE'
+    let hi_bg = 'hi CursorLine cterm=NONE ctermbg=Gray'
+  endif
+  return [hiCursorLine, hi_ul, hi_bg]
+endfunction
+
+func Test_highlight_eol_with_cursorline()
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 20)
+  call setline(1, 'abcd')
+  call matchadd('Search', '\n')
+
+  " expected:
+  " 'abcd      '
+  "  ^^^^ ^^^^^   no highlight
+  "      ^        'Search' highlight
+  let attrs0 = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
+  call assert_equal(repeat([attrs0[0]], 5), attrs0[5:9])
+  call assert_notequal(attrs0[0], attrs0[4])
+
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " 'abcd      '
+  "  ^^^^         underline
+  "      ^^^^^^   'Search' highlight with underline
+  let attrs = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+  call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9])
+  call assert_notequal(attrs[0], attrs[4])
+  call assert_notequal(attrs[4], attrs[5])
+  call assert_notequal(attrs0[0], attrs[0])
+  call assert_notequal(attrs0[4], attrs[4])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " 'abcd      '
+    "  ^^^^         bg-color of 'CursorLine'
+    "      ^        'Search' highlight
+    "       ^^^^^   bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(1, 10)[0]
+    call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+    call assert_equal(repeat([attrs[5]], 5), attrs[5:9])
+    call assert_equal(attrs0[4], attrs[4])
+    call assert_notequal(attrs[0], attrs[4])
+    call assert_notequal(attrs[4], attrs[5])
+    call assert_notequal(attrs0[0], attrs[0])
+    call assert_notequal(attrs0[5], attrs[5])
+  endif
+
+  call CloseWindow()
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_vertsplit()
+  if !has('vertsplit')
+    return
+  endif
+
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 5)
+  call setline(1, 'abcd')
+  call matchadd('Search', '\n')
+
+  let expected = "abcd |abcd     "
+  let actual = ScreenLines(1, 15)[0]
+  call assert_equal(expected, actual)
+
+  " expected:
+  " 'abcd |abcd     '
+  "  ^^^^  ^^^^^^^^^   no highlight
+  "      ^             'Search' highlight
+  "       ^            'VertSplit' highlight
+  let attrs0 = ScreenAttrs(1, 15)[0]
+  call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
+  call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14])
+  call assert_notequal(attrs0[0], attrs0[4])
+  call assert_notequal(attrs0[0], attrs0[5])
+  call assert_notequal(attrs0[4], attrs0[5])
+
+  setlocal cursorline
+
+  " expected:
+  " 'abcd |abcd     '
+  "  ^^^^              underline
+  "      ^             'Search' highlight with underline
+  "       ^            'VertSplit' highlight
+  "        ^^^^^^^^^   no highlight
+
+  " underline
+  exe hi_ul
+
+  let actual = ScreenLines(1, 15)[0]
+  call assert_equal(expected, actual)
+
+  let attrs = ScreenAttrs(1, 15)[0]
+  call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+  call assert_equal(repeat([attrs[6]], 9), attrs[6:14])
+  call assert_equal(attrs0[5:14], attrs[5:14])
+  call assert_notequal(attrs[0], attrs[4])
+  call assert_notequal(attrs[0], attrs[5])
+  call assert_notequal(attrs[0], attrs[6])
+  call assert_notequal(attrs[4], attrs[5])
+  call assert_notequal(attrs[5], attrs[6])
+  call assert_notequal(attrs0[0], attrs[0])
+  call assert_notequal(attrs0[4], attrs[4])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    let actual = ScreenLines(1, 15)[0]
+    call assert_equal(expected, actual)
+
+    let attrs = ScreenAttrs(1, 15)[0]
+    call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+    call assert_equal(repeat([attrs[6]], 9), attrs[6:14])
+    call assert_equal(attrs0[5:14], attrs[5:14])
+    call assert_notequal(attrs[0], attrs[4])
+    call assert_notequal(attrs[0], attrs[5])
+    call assert_notequal(attrs[0], attrs[6])
+    call assert_notequal(attrs[4], attrs[5])
+    call assert_notequal(attrs[5], attrs[6])
+    call assert_notequal(attrs0[0], attrs[0])
+    call assert_equal(attrs0[4], attrs[4])
+  endif
+
+  call CloseWindow()
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_rightleft()
+  if !has('rightleft')
+    return
+  endif
+
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 10)
+  setlocal rightleft
+  call setline(1, 'abcd')
+  call matchadd('Search', '\n')
+  let attrs0 = ScreenAttrs(1, 10)[0]
+
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " '      dcba'
+  "        ^^^^   underline
+  "       ^       'Search' highlight with underline
+  "  ^^^^^        underline
+  let attrs = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs[9]], 4), attrs[6:9])
+  call assert_equal(repeat([attrs[4]], 5) + [attrs[5]], attrs[0:5])
+  call assert_notequal(attrs[9], attrs[5])
+  call assert_notequal(attrs[4], attrs[5])
+  call assert_notequal(attrs0[9], attrs[9])
+  call assert_notequal(attrs0[5], attrs[5])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " '      dcba'
+    "        ^^^^   bg-color of 'CursorLine'
+    "       ^       'Search' highlight
+    "  ^^^^^        bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(1, 10)[0]
+    call assert_equal(repeat([attrs[9]], 4), attrs[6:9])
+    call assert_equal(repeat([attrs[4]], 5), attrs[0:4])
+    call assert_equal(attrs0[5], attrs[5])
+    call assert_notequal(attrs[9], attrs[5])
+    call assert_notequal(attrs[5], attrs[4])
+    call assert_notequal(attrs0[9], attrs[9])
+    call assert_notequal(attrs0[4], attrs[4])
+  endif
+
+  call CloseWindow()
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_linewrap()
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 10)
+  call setline(1, [repeat('a', 51) . 'bcd', ''])
+  call matchadd('Search', '\n')
+
+  setlocal wrap
+  normal! gg$
+  let attrs0 = ScreenAttrs(5, 10)[0]
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " 'abcd      '
+  "  ^^^^         underline
+  "      ^        'Search' highlight with underline
+  "       ^^^^^   underline
+  let attrs = ScreenAttrs(5, 10)[0]
+  call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+  call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9])
+  call assert_notequal(attrs[0], attrs[4])
+  call assert_notequal(attrs[4], attrs[5])
+  call assert_notequal(attrs0[0], attrs[0])
+  call assert_notequal(attrs0[4], attrs[4])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " 'abcd      '
+    "  ^^^^         bg-color of 'CursorLine'
+    "      ^        'Search' highlight
+    "       ^^^^^   bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(5, 10)[0]
+    call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+    call assert_equal(repeat([attrs[5]], 5), attrs[5:9])
+    call assert_equal(attrs0[4], attrs[4])
+    call assert_notequal(attrs[0], attrs[4])
+    call assert_notequal(attrs[4], attrs[5])
+    call assert_notequal(attrs0[0], attrs[0])
+    call assert_notequal(attrs0[5], attrs[5])
+  endif
+
+  setlocal nocursorline nowrap
+  normal! gg$
+  let attrs0 = ScreenAttrs(1, 10)[0]
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " 'aaabcd    '
+  "  ^^^^^^       underline
+  "        ^      'Search' highlight with underline
+  "         ^^^   underline
+  let attrs = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs[0]], 6), attrs[0:5])
+  call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+  call assert_notequal(attrs[0], attrs[6])
+  call assert_notequal(attrs[6], attrs[7])
+  call assert_notequal(attrs0[0], attrs[0])
+  call assert_notequal(attrs0[6], attrs[6])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " 'aaabcd    '
+    "  ^^^^^^       bg-color of 'CursorLine'
+    "        ^      'Search' highlight
+    "         ^^^   bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(1, 10)[0]
+    call assert_equal(repeat([attrs[0]], 6), attrs[0:5])
+    call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+    call assert_equal(attrs0[6], attrs[6])
+    call assert_notequal(attrs[0], attrs[6])
+    call assert_notequal(attrs[6], attrs[7])
+    call assert_notequal(attrs0[0], attrs[0])
+    call assert_notequal(attrs0[7], attrs[7])
+  endif
+
+  call CloseWindow()
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_sign()
+  if !has('signs')
+    return
+  endif
+
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 10)
+  call setline(1, 'abcd')
+  call matchadd('Search', '\n')
+
+  sign define Sign text=>>
+  exe 'sign place 1 line=1 name=Sign buffer=' . bufnr('')
+  let attrs0 = ScreenAttrs(1, 10)[0]
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " '>>abcd    '
+  "  ^^           sign
+  "    ^^^^       underline
+  "        ^      'Search' highlight with underline
+  "         ^^^   underline
+  let attrs = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+  call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+  call assert_notequal(attrs[2], attrs[6])
+  call assert_notequal(attrs[6], attrs[7])
+  call assert_notequal(attrs0[2], attrs[2])
+  call assert_notequal(attrs0[6], attrs[6])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " '>>abcd    '
+    "  ^^           sign
+    "    ^^^^       bg-color of 'CursorLine'
+    "        ^      'Search' highlight
+    "         ^^^   bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(1, 10)[0]
+    call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+    call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+    call assert_equal(attrs0[6], attrs[6])
+    call assert_notequal(attrs[2], attrs[6])
+    call assert_notequal(attrs[6], attrs[7])
+    call assert_notequal(attrs0[2], attrs[2])
+    call assert_notequal(attrs0[7], attrs[7])
+  endif
+
+  sign unplace 1
+  call CloseWindow()
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_breakindent()
+  if !has('linebreak')
+    return
+  endif
+
+  let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+  call NewWindow('topleft 5', 10)
+  setlocal breakindent breakindentopt=min:0,shift:1 showbreak=>
+  call setline(1, ' ' . repeat('a', 9) . 'bcd')
+  call matchadd('Search', '\n')
+  let attrs0 = ScreenAttrs(2, 10)[0]
+  setlocal cursorline
+
+  " underline
+  exe hi_ul
+
+  " expected:
+  " '  >bcd    '
+  "  ^^^          breakindent and showbreak
+  "     ^^^       underline
+  "        ^      'Search' highlight with underline
+  "         ^^^   underline
+  let attrs = ScreenAttrs(2, 10)[0]
+  call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+  call assert_equal(repeat([attrs[3]], 3), attrs[3:5])
+  call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+  call assert_equal(attrs0[0], attrs[0])
+  call assert_notequal(attrs[0], attrs[2])
+  call assert_notequal(attrs[2], attrs[3])
+  call assert_notequal(attrs[3], attrs[6])
+  call assert_notequal(attrs[6], attrs[7])
+  call assert_notequal(attrs0[2], attrs[2])
+  call assert_notequal(attrs0[3], attrs[3])
+  call assert_notequal(attrs0[6], attrs[6])
+
+  if IsColorable()
+    " bg-color
+    exe hi_bg
+
+    " expected:
+    " '  >bcd    '
+    "  ^^^          breakindent and showbreak
+    "     ^^^       bg-color of 'CursorLine'
+    "        ^      'Search' highlight
+    "         ^^^   bg-color of 'CursorLine'
+    let attrs = ScreenAttrs(2, 10)[0]
+    call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+    call assert_equal(repeat([attrs[3]], 3), attrs[3:5])
+    call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+    call assert_equal(attrs0[0], attrs[0])
+    call assert_equal(attrs0[6], attrs[6])
+    call assert_notequal(attrs[0], attrs[2])
+    call assert_notequal(attrs[2], attrs[3])
+    call assert_notequal(attrs[3], attrs[6])
+    call assert_notequal(attrs[6], attrs[7])
+    call assert_notequal(attrs0[2], attrs[2])
+    call assert_notequal(attrs0[3], attrs[3])
+    call assert_notequal(attrs0[7], attrs[7])
+  endif
+
+  call CloseWindow()
+  set showbreak=
+  exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_on_diff()
+  call setline(1, ['abcd', ''])
+  call matchadd('Search', '\n')
+  let attrs0 = ScreenAttrs(1, 10)[0]
+
+  diffthis
+  botright new
+  diffthis
+
+  " expected:
+  " '  abcd    '
+  "  ^^           sign
+  "    ^^^^ ^^^   'DiffAdd' highlight
+  "        ^      'Search' highlight
+  let attrs = ScreenAttrs(1, 10)[0]
+  call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+  call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+  call assert_equal(repeat([attrs[2]], 3), attrs[7:9])
+  call assert_equal(attrs0[4], attrs[6])
+  call assert_notequal(attrs[0], attrs[2])
+  call assert_notequal(attrs[0], attrs[6])
+  call assert_notequal(attrs[2], attrs[6])
+
+  bwipe!
+  diffoff
+endfunc
--- a/src/testdir/view_util.vim
+++ b/src/testdir/view_util.vim
@@ -1,5 +1,10 @@
 " Functions about view shared by several tests
 
+" Only load this script once.
+if exists('*ScreenLines')
+  finish
+endif
+
 " ScreenLines(lnum, width) or
 " ScreenLines([start, end], width)
 function! ScreenLines(lnum, width) abort
@@ -18,6 +23,22 @@ function! ScreenLines(lnum, width) abort
   return lines
 endfunction
 
+function! ScreenAttrs(lnum, width) abort
+  redraw!
+  if type(a:lnum) == v:t_list
+    let start = a:lnum[0]
+    let end = a:lnum[1]
+  else
+    let start = a:lnum
+    let end = a:lnum
+  endif
+  let attrs = []
+  for l in range(start, end)
+    let attrs += [map(range(1, a:width), 'screenattr(l, v:val)')]
+  endfor
+  return attrs
+endfunction
+
 function! NewWindow(height, width) abort
   exe a:height . 'new'
   exe a:width . 'vsp'
--- a/src/version.c
+++ b/src/version.c
@@ -762,6 +762,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1168,
+/**/
     1167,
 /**/
     1166,