diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/keysets.lua | 4 | ||||
-rw-r--r-- | src/nvim/buffer.c | 49 | ||||
-rw-r--r-- | src/nvim/eval.c | 9 | ||||
-rw-r--r-- | src/nvim/eval.lua | 4 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 56 | ||||
-rw-r--r-- | src/nvim/highlight.c | 4 | ||||
-rw-r--r-- | src/nvim/option.c | 7 | ||||
-rw-r--r-- | src/nvim/screen.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_search.vim | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_syntax.vim | 50 | ||||
-rw-r--r-- | src/nvim/testdir/test_winbuf_close.vim | 19 | ||||
-rw-r--r-- | src/nvim/window.c | 14 |
12 files changed, 180 insertions, 40 deletions
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 075e2c48d2..f6dce1905e 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -81,10 +81,12 @@ return { highlight = { "bold"; "standout"; + "strikethrough"; "underline"; "undercurl"; "italic"; "reverse"; + "nocombine"; "default"; "global"; "cterm"; @@ -100,10 +102,12 @@ return { highlight_cterm = { "bold"; "standout"; + "strikethrough"; "underline"; "undercurl"; "italic"; "reverse"; + "nocombine"; }; } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ee704bd1bd..38b045b31c 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -5455,30 +5455,43 @@ bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp) return false; } -int buf_signcols(buf_T *buf) +static int buf_signcols_inner(buf_T *buf, int maximum) { - if (!buf->b_signcols_valid) { - sign_entry_T *sign; // a sign in the sign list - int signcols = 0; - int linesum = 0; - linenr_T curline = 0; - - FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if (sign->se_lnum > curline) { - if (linesum > signcols) { - signcols = linesum; + sign_entry_T *sign; // a sign in the sign list + int signcols = 0; + int linesum = 0; + linenr_T curline = 0; + + FOR_ALL_SIGNS_IN_BUF(buf, sign) { + if (sign->se_lnum > curline) { + if (linesum > signcols) { + signcols = linesum; + if (signcols >= maximum) { + return maximum; } - curline = sign->se_lnum; - linesum = 0; - } - if (sign->se_has_text_or_icon) { - linesum++; } + curline = sign->se_lnum; + linesum = 0; + } + if (sign->se_has_text_or_icon) { + linesum++; } - if (linesum > signcols) { - signcols = linesum; + } + + if (linesum > signcols) { + signcols = linesum; + if (signcols >= maximum) { + return maximum; } + } + + return signcols; +} +int buf_signcols(buf_T *buf, int maximum) +{ + if (!buf->b_signcols_valid) { + int signcols = buf_signcols_inner(buf, maximum); // Check if we need to redraw if (signcols != buf->b_signcols) { buf->b_signcols = signcols; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c197754685..4b83bda804 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -766,6 +766,15 @@ static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate) return ret; } +/// @return whether a typval is a valid expression to pass to eval_expr_typval() +/// or eval_expr_to_bool(). An empty string returns false; +bool eval_expr_valid_arg(const typval_T *const tv) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_CONST +{ + return tv->v_type != VAR_UNKNOWN + && (tv->v_type != VAR_STRING || (tv->vval.v_string != NULL && *tv->vval.v_string != NUL)); +} + int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) FUNC_ATTR_NONNULL_ARG(1, 2, 4) { diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 1e39854c86..05e91a658f 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -307,12 +307,12 @@ return { screenpos={args=3, base=1}, screenrow={}, screenstring={args=2, base=1}, - search={args={1, 4}, base=1}, + search={args={1, 5}, base=1}, searchcount={args={0, 1}, base=1}, searchdecl={args={1, 3}, base=1}, searchpair={args={3, 7}}, searchpairpos={args={3, 7}}, - searchpos={args={1, 4}, base=1}, + searchpos={args={1, 5}, base=1}, serverlist={}, serverstart={args={0, 1}}, serverstop={args=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index db4fb06a73..8beacc9988 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8237,6 +8237,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) int options = SEARCH_KEEP; int subpatnum; searchit_arg_T sia; + bool use_skip = false; const char *const pat = tv_get_string(&argvars[0]); dir = get_search_arg(&argvars[1], flagsp); // May set p_ws. @@ -8254,7 +8255,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) options |= SEARCH_COL; } - // Optional arguments: line number to stop searching and timeout. + // Optional arguments: line number to stop searching, timeout and skip. if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { lnum_stop = tv_get_number_chk(&argvars[2], NULL); if (lnum_stop < 0) { @@ -8265,6 +8266,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) if (time_limit < 0) { goto theend; } + use_skip = eval_expr_valid_arg(&argvars[4]); } } @@ -8284,11 +8286,46 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) } pos = save_cursor = curwin->w_cursor; + pos_T firstpos = { 0 }; memset(&sia, 0, sizeof(sia)); sia.sa_stop_lnum = (linenr_T)lnum_stop; sia.sa_tm = &tm; - subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1, - options, RE_SEARCH, &sia); + + // Repeat until {skip} returns false. + for (;;) { + subpatnum + = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1, options, RE_SEARCH, &sia); + // finding the first match again means there is no match where {skip} + // evaluates to zero. + if (firstpos.lnum != 0 && equalpos(pos, firstpos)) { + subpatnum = FAIL; + } + + if (subpatnum == FAIL || !use_skip) { + // didn't find it or no skip argument + break; + } + firstpos = pos; + + // If the skip expression matches, ignore this match. + { + const pos_T save_pos = curwin->w_cursor; + + curwin->w_cursor = pos; + bool err = false; + const bool do_skip = eval_expr_to_bool(&argvars[4], &err); + curwin->w_cursor = save_pos; + if (err) { + // Evaluating {skip} caused an error, break here. + subpatnum = FAIL; + break; + } + if (!do_skip) { + break; + } + } + } + if (subpatnum != FAIL) { if (flags & SP_SUBPAT) { retval = subpatnum; @@ -8748,13 +8785,9 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) || argvars[4].v_type == VAR_UNKNOWN) { skip = NULL; } else { + // Type is checked later. skip = &argvars[4]; - if (skip->v_type != VAR_FUNC - && skip->v_type != VAR_PARTIAL - && skip->v_type != VAR_STRING) { - semsg(_(e_invarg2), tv_get_string(&argvars[4])); - goto theend; // Type error. - } + if (argvars[5].v_type != VAR_UNKNOWN) { lnum_stop = tv_get_number_chk(&argvars[5], NULL); if (lnum_stop < 0) { @@ -8865,10 +8898,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir } if (skip != NULL) { - // Empty string means to not use the skip expression. - if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) { - use_skip = skip->vval.v_string != NULL && *skip->vval.v_string != NUL; - } + use_skip = eval_expr_valid_arg(skip); } save_cursor = curwin->w_cursor; diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 87c090e594..fcd91cdf16 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -815,6 +815,8 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL); CHECK_FLAG(dict, mask, italic, , HL_ITALIC); CHECK_FLAG(dict, mask, reverse, , HL_INVERSE); + CHECK_FLAG(dict, mask, strikethrough, , HL_STRIKETHROUGH); + CHECK_FLAG(dict, mask, nocombine, , HL_NOCOMBINE); CHECK_FLAG(dict, mask, default, _, HL_DEFAULT); CHECK_FLAG(dict, mask, global, , HL_GLOBAL); @@ -871,6 +873,8 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e CHECK_FLAG(cterm, cterm_mask, undercurl, , HL_UNDERCURL); CHECK_FLAG(cterm, cterm_mask, italic, , HL_ITALIC); CHECK_FLAG(cterm, cterm_mask, reverse, , HL_INVERSE); + CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH); + CHECK_FLAG(cterm, cterm_mask, nocombine, , HL_NOCOMBINE); } else if (HAS_KEY(dict->cterm)) { api_set_error(err, kErrorTypeValidation, "'cterm' must be a Dictionary."); diff --git a/src/nvim/option.c b/src/nvim/option.c index dddf926b9a..df5f352258 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -8046,7 +8046,6 @@ int win_signcol_count(win_T *wp) /// Return the number of requested sign columns, based on user / configuration. int win_signcol_configured(win_T *wp, int *is_fixed) { - int minimum = 0, maximum = 1, needed_signcols; const char *scl = (const char *)wp->w_p_scl; if (is_fixed) { @@ -8059,7 +8058,6 @@ int win_signcol_configured(win_T *wp, int *is_fixed) && (wp->w_p_nu || wp->w_p_rnu)))) { return 0; } - needed_signcols = buf_signcols(wp->w_buffer); // yes or yes if (!strncmp(scl, "yes:", 4)) { @@ -8075,6 +8073,8 @@ int win_signcol_configured(win_T *wp, int *is_fixed) *is_fixed = 0; } + int minimum = 0, maximum = 1; + if (!strncmp(scl, "auto:", 5)) { // Variable depending on a configuration maximum = scl[5] - '0'; @@ -8085,7 +8085,8 @@ int win_signcol_configured(win_T *wp, int *is_fixed) } } - int ret = MAX(minimum, MIN(maximum, needed_signcols)); + int needed_signcols = buf_signcols(wp->w_buffer, maximum); + int ret = MAX(minimum, needed_signcols); assert(ret <= SIGN_SHOW_MAX); return ret; } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 0644a08210..6dcabffb7d 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -794,7 +794,7 @@ static void win_update(win_T *wp, Providers *providers) // If we can compute a change in the automatic sizing of the sign column // under 'signcolumn=auto:X' and signs currently placed in the buffer, better // figuring it out here so we can redraw the entire screen for it. - buf_signcols(buf); + win_signcol_count(wp); type = wp->w_redr_type; diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 2a1a93b5e3..a3d5ca96a1 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -378,7 +378,6 @@ func Test_searchpair_errors() call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String') call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String') call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags') - call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0') call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99') call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100') call assert_fails("call searchpair('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e') @@ -390,7 +389,6 @@ func Test_searchpairpos_errors() call assert_fails("call searchpairpos('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String') call assert_fails("call searchpairpos('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String') call assert_fails("call searchpairpos('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags') - call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0') call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99') call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100') call assert_fails("call searchpairpos('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e') diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index 757866f5dc..b047b53b6f 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -728,6 +728,56 @@ func Test_syntax_foldlevel() quit! endfunc +func Test_search_syntax_skip() + new + let lines =<< trim END + + /* This is VIM */ + Another Text for VIM + let a = "VIM" + END + call setline(1, lines) + syntax on + syntax match Comment "^/\*.*\*/" + syntax match String '".*"' + + " Skip argument using string evaluation. + 1 + call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"') + call assert_equal('Another Text for VIM', getline('.')) + 1 + call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") !~? "string"') + call assert_equal(' let a = "VIM"', getline('.')) + + " Skip argument using Lambda. + 1 + call search('VIM', 'w', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"}) + call assert_equal('Another Text for VIM', getline('.')) + + 1 + call search('VIM', 'w', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") !~? "string"}) + call assert_equal(' let a = "VIM"', getline('.')) + + " Skip argument using funcref. + func InComment() + return synIDattr(synID(line("."), col("."), 1), "name") =~? "comment" + endfunc + func InString() + return synIDattr(synID(line("."), col("."), 1), "name") !~? "string" + endfunc + 1 + call search('VIM', 'w', '', 0, function('InComment')) + call assert_equal('Another Text for VIM', getline('.')) + + 1 + call search('VIM', 'w', '', 0, function('InString')) + call assert_equal(' let a = "VIM"', getline('.')) + + delfunc InComment + delfunc InString + bwipe! +endfunc + func Test_syn_include_contains_TOP() let l:case = "TOP in included syntax means its group list name" new diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim index 7f5b80e8d3..f4878c2397 100644 --- a/src/nvim/testdir/test_winbuf_close.vim +++ b/src/nvim/testdir/test_winbuf_close.vim @@ -194,3 +194,22 @@ func Test_tabwin_close() call assert_true(v:true) %bwipe! endfunc + +" Test when closing a split window (above/below) restores space to the window +" below when 'noequalalways' and 'splitright' are set. +func Test_window_close_splitright_noequalalways() + set noequalalways + set splitright + new + let w1 = win_getid() + new + let w2 = win_getid() + execute "normal \<c-w>b" + let h = winheight(0) + let w = win_getid() + new + q + call assert_equal(h, winheight(0), "Window height does not match eight before opening and closing another window") + call assert_equal(w, win_getid(), "Did not return to original window after opening and closing a window") +endfunc + diff --git a/src/nvim/window.c b/src/nvim/window.c index 4861b71995..e09af7a7bb 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3079,9 +3079,21 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp) return frp->fr_prev; } + // By default the next window will get the space that was abandoned by this + // window frame_T *target_fr = frp->fr_next; frame_T *other_fr = frp->fr_prev; - if (p_spr || p_sb) { + + // If this is part of a column of windows and 'splitbelow' is true then the + // previous window will get the space. + if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_COL && p_sb) { + target_fr = frp->fr_prev; + other_fr = frp->fr_next; + } + + // If this is part of a row of windows, and 'splitright' is true then the + // previous window will get the space. + if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW && p_spr) { target_fr = frp->fr_prev; other_fr = frp->fr_next; } |