diff --git a/src/channel.c b/src/channel.c index d952e5bb6e..bea4e9fbea 100644 --- a/src/channel.c +++ b/src/channel.c @@ -3985,6 +3985,8 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval) free_job_options(&opt); } +# define KEEP_OPEN_TIME 20 /* msec */ + # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) /* * Add open channels to the poll struct. @@ -3992,7 +3994,7 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval) * The type of "fds" is hidden to avoid problems with the function proto. */ int -channel_poll_setup(int nfd_in, void *fds_in) +channel_poll_setup(int nfd_in, void *fds_in, int *towait) { int nfd = nfd_in; channel_T *channel; @@ -4007,10 +4009,21 @@ channel_poll_setup(int nfd_in, void *fds_in) if (ch_part->ch_fd != INVALID_FD) { - ch_part->ch_poll_idx = nfd; - fds[nfd].fd = ch_part->ch_fd; - fds[nfd].events = POLLIN; - nfd++; + if (channel->ch_keep_open) + { + /* For unknown reason poll() returns immediately for a + * keep-open channel. Instead of adding it to the fds add + * a short timeout and check, like polling. */ + if (*towait < 0 || *towait > KEEP_OPEN_TIME) + *towait = KEEP_OPEN_TIME; + } + else + { + ch_part->ch_poll_idx = nfd; + fds[nfd].fd = ch_part->ch_fd; + fds[nfd].events = POLLIN; + nfd++; + } } else channel->ch_part[part].ch_poll_idx = -1; @@ -4046,6 +4059,12 @@ channel_poll_check(int ret_in, void *fds_in) channel_read(channel, part, "channel_poll_check"); --ret; } + else if (channel->ch_part[part].ch_fd != INVALID_FD + && channel->ch_keep_open) + { + /* polling a keep-open channel */ + channel_read(channel, part, "channel_poll_check_keep_open"); + } } in_part = &channel->ch_part[PART_IN]; @@ -4062,11 +4081,17 @@ channel_poll_check(int ret_in, void *fds_in) # endif /* UNIX && !HAVE_SELECT */ # if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO) + /* * The "fd_set" type is hidden to avoid problems with the function proto. */ int -channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in) +channel_select_setup( + int maxfd_in, + void *rfds_in, + void *wfds_in, + struct timeval *tv, + struct timeval **tvp) { int maxfd = maxfd_in; channel_T *channel; @@ -4082,9 +4107,25 @@ channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in) if (fd != INVALID_FD) { - FD_SET((int)fd, rfds); - if (maxfd < (int)fd) - maxfd = (int)fd; + if (channel->ch_keep_open) + { + /* For unknown reason select() returns immediately for a + * keep-open channel. Instead of adding it to the rfds add + * a short timeout and check, like polling. */ + if (*tvp == NULL || tv->tv_sec > 0 + || tv->tv_usec > KEEP_OPEN_TIME * 1000) + { + *tvp = tv; + tv->tv_sec = 0; + tv->tv_usec = KEEP_OPEN_TIME * 1000; + } + } + else + { + FD_SET((int)fd, rfds); + if (maxfd < (int)fd) + maxfd = (int)fd; + } } } } @@ -4119,6 +4160,11 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in) FD_CLR(fd, rfds); --ret; } + else if (fd != INVALID_FD && channel->ch_keep_open) + { + /* polling a keep-open channel */ + channel_read(channel, part, "channel_select_check_keep_open"); + } } in_part = &channel->ch_part[PART_IN]; diff --git a/src/eval.c b/src/eval.c index 8b1ceaea80..8670e12403 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1704,7 +1704,10 @@ ex_let_one( &stringval, opt_flags); if ((opt_type == 1 && *op == '.') || (opt_type == 0 && *op != '.')) + { EMSG2(_(e_letwrong), op); + s = NULL; /* don't set the value */ + } else { if (opt_type == 1) /* number */ diff --git a/src/os_unix.c b/src/os_unix.c index 2f45e476ed..0748a33bc9 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5352,6 +5352,9 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) channel = add_channel(); if (channel == NULL) goto failed; + if (job->jv_tty_out != NULL) + ch_log(channel, "using pty %s on fd %d", + job->jv_tty_out, pty_master_fd); } BLOCK_SIGNALS(&curset); @@ -5724,6 +5727,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options) close(pty_master_fd); return FAIL; } + if (job->jv_tty_out != NULL) + ch_log(channel, "using pty %s on fd %d", + job->jv_tty_out, pty_master_fd); job->jv_channel = channel; /* ch_refcount was set by add_channel() */ channel->ch_keep_open = TRUE; @@ -5991,7 +5997,7 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted) } # endif #ifdef FEAT_JOB_CHANNEL - nfd = channel_poll_setup(nfd, &fds); + nfd = channel_poll_setup(nfd, &fds, &towait); #endif if (interrupted != NULL) *interrupted = FALSE; @@ -6043,7 +6049,8 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted) } # endif #ifdef FEAT_JOB_CHANNEL - if (ret > 0) + /* also call when ret == 0, we may be polling a keep-open channel */ + if (ret >= 0) ret = channel_poll_check(ret, &fds); #endif @@ -6119,7 +6126,7 @@ select_eintr: } # endif # ifdef FEAT_JOB_CHANNEL - maxfd = channel_select_setup(maxfd, &rfds, &wfds); + maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp); # endif if (interrupted != NULL) *interrupted = FALSE; @@ -6205,7 +6212,8 @@ select_eintr: } # endif #ifdef FEAT_JOB_CHANNEL - if (ret > 0) + /* also call when ret == 0, we may be polling a keep-open channel */ + if (ret >= 0) ret = channel_select_check(ret, &rfds, &wfds); #endif diff --git a/src/proto/channel.pro b/src/proto/channel.pro index 11929b6c76..3342b49dfa 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -40,9 +40,9 @@ void channel_set_nonblock(channel_T *channel, ch_part_T part); int channel_send(channel_T *channel, ch_part_T part, char_u *buf_arg, int len_arg, char *fun); void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval); void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval); -int channel_poll_setup(int nfd_in, void *fds_in); +int channel_poll_setup(int nfd_in, void *fds_in, int *towait); int channel_poll_check(int ret_in, void *fds_in); -int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in); +int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in, struct timeval *tv, struct timeval **tvp); int channel_select_check(int ret_in, void *rfds_in, void *wfds_in); int channel_parse_messages(void); int channel_any_readahead(void); diff --git a/src/screen.c b/src/screen.c index 0099fe96ab..73fba75d3c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -4168,6 +4168,10 @@ 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 + || (wp->w_p_list && lcs_eol_one == -1))) + search_attr = 0; } #endif @@ -5064,7 +5068,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) @@ -5324,6 +5330,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 diff --git a/src/terminal.c b/src/terminal.c index 291bf4cac2..94fa4d48fc 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -56,6 +56,7 @@ * - GUI: when 'confirm' is set and trying to exit Vim, dialog offers to save * changes to "!shell". * (justrajdeep, 2017 Aug 22) + * - Redrawing is slow with Athena and Motif. * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - if the job in the terminal does not support the mouse, we can use the @@ -2243,6 +2244,12 @@ term_update_window(win_T *wp) screen = vterm_obtain_screen(vterm); state = vterm_obtain_state(vterm); + if (wp->w_redr_type >= NOT_VALID) + { + term->tl_dirty_row_start = 0; + term->tl_dirty_row_end = MAX_ROW; + } + /* * If the window was resized a redraw will be triggered and we get here. * Adjust the size of the vterm unless 'termsize' specifies a fixed size. diff --git a/src/testdir/test_assign.vim b/src/testdir/test_assign.vim index efc9d086be..317d45867f 100644 --- a/src/testdir/test_assign.vim +++ b/src/testdir/test_assign.vim @@ -29,3 +29,17 @@ func Test_let_termcap() let &t_xx = "" call assert_fails('let x = &t_xx', 'E15') endfunc + +func Test_let_option_error() + let _w = &tw + let &tw = 80 + call assert_fails('let &tw .= 1', 'E734') + call assert_equal(80, &tw) + let &tw = _w + + let _w = &fillchars + let &fillchars = "vert:|" + call assert_fails('let &fillchars += "diff:-"', 'E734') + call assert_equal("vert:|", &fillchars) + let &fillchars = _w +endfunc diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim index acc29e2f0a..f3d7d0f2a0 100644 --- 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,480 @@ 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], '\', '', '') +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 + +function! Check_lcs_eol_attrs(attrs, row, col) + let save_lcs = &lcs + set list + + call assert_equal(a:attrs, ScreenAttrs(a:row, a:col)[0]) + + set nolist + let &lcs = save_lcs +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 + " ^^^^^ 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 1, 15) + + 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]) + call Check_lcs_eol_attrs(attrs, 1, 15) + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 5, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 5, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 2, 10) + + 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]) + call Check_lcs_eol_attrs(attrs, 2, 10) + 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]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + bwipe! + diffoff +endfunc diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index 0dfa956fb2..fdd51de51c 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -645,9 +645,8 @@ func Test_popup_and_window_resize() endif let g:buf = term_start([$VIMPROG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3}) call term_sendkeys(g:buf, (h / 3 - 1)."o\G") - call term_wait(g:buf, 100) call term_sendkeys(g:buf, "i\") - call term_wait(g:buf, 100) + call term_wait(g:buf, 200) call term_sendkeys(g:buf, "\") call term_wait(g:buf, 100) " popup first entry "!" must be at the top diff --git a/src/testdir/view_util.vim b/src/testdir/view_util.vim index eb92630761..29ea073f97 100644 --- 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' diff --git a/src/version.c b/src/version.c index 5d903c0988..c61390c6f6 100644 --- a/src/version.c +++ b/src/version.c @@ -776,6 +776,18 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1173, +/**/ + 1172, +/**/ + 1171, +/**/ + 1170, +/**/ + 1169, +/**/ + 1168, /**/ 1167, /**/