diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/syntax.c | 54 | ||||
-rw-r--r-- | src/nvim/testdir/test_syntax.vim | 85 |
3 files changed, 143 insertions, 1 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index d696eedbb7..550f8a5e40 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -373,6 +373,10 @@ struct stl_hlrec { #define SYNSPL_TOP 1 // spell check toplevel text #define SYNSPL_NOTOP 2 // don't spell check toplevel text +// values for b_syn_foldlevel: how to compute foldlevel on a line +#define SYNFLD_START 0 // use level of item at start of line +#define SYNFLD_MINIMUM 1 // use lowest local minimum level on line + // avoid #ifdefs for when b_spell is not available # define B_SPELL(buf) ((buf)->b_spell) @@ -398,6 +402,7 @@ typedef struct { int b_syn_error; // TRUE when error occurred in HL bool b_syn_slow; // true when 'redrawtime' reached int b_syn_ic; // ignore case for :syn cmds + int b_syn_foldlevel; // how to compute foldlevel on a line int b_syn_spell; // SYNSPL_ values garray_T b_syn_patterns; // table for syntax patterns garray_T b_syn_clusters; // table for syntax clusters diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 41b8ebe4a2..4aa7c21ce4 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3079,6 +3079,41 @@ static void syn_cmd_case(exarg_T *eap, int syncing) } } +/// Handle ":syntax foldlevel" command. +static void syn_cmd_foldlevel(exarg_T *eap, int syncing) +{ + char_u *arg = eap->arg; + char_u *arg_end; + + eap->nextcmd = find_nextcmd(arg); + if (eap->skip) + return; + + if (*arg == NUL) { + switch (curwin->w_s->b_syn_foldlevel) { + case SYNFLD_START: MSG(_("syntax foldlevel start")); break; + case SYNFLD_MINIMUM: MSG(_("syntax foldlevel minimum")); break; + default: break; + } + return; + } + + arg_end = skiptowhite(arg); + if (STRNICMP(arg, "start", 5) == 0 && arg_end - arg == 5) { + curwin->w_s->b_syn_foldlevel = SYNFLD_START; + } else if (STRNICMP(arg, "minimum", 7) == 0 && arg_end - arg == 7) { + curwin->w_s->b_syn_foldlevel = SYNFLD_MINIMUM; + } else { + EMSG2(_(e_illegal_arg), arg); + return; + } + + arg = skipwhite(arg_end); + if (*arg != NUL) { + EMSG2(_(e_illegal_arg), arg); + } +} + /* * Handle ":syntax spell" command. */ @@ -3163,6 +3198,7 @@ void syntax_clear(synblock_T *block) block->b_syn_error = false; // clear previous error block->b_syn_slow = false; // clear previous timeout block->b_syn_ic = false; // Use case, by default + block->b_syn_foldlevel = SYNFLD_START; block->b_syn_spell = SYNSPL_DEFAULT; // default spell checking block->b_syn_containedin = false; block->b_syn_conceal = false; @@ -5487,6 +5523,7 @@ static struct subcommand subcommands[] = { "cluster", syn_cmd_cluster }, { "conceal", syn_cmd_conceal }, { "enable", syn_cmd_enable }, + { "foldlevel", syn_cmd_foldlevel }, { "include", syn_cmd_include }, { "iskeyword", syn_cmd_iskeyword }, { "keyword", syn_cmd_keyword }, @@ -5789,7 +5826,24 @@ int syn_get_foldlevel(win_T *wp, long lnum) && !wp->w_s->b_syn_slow) { syntax_start(wp, lnum); + // Start with the fold level at the start of the line. level = syn_cur_foldlevel(); + + if (wp->w_s->b_syn_foldlevel == SYNFLD_MINIMUM) { + // Find the lowest fold level that is followed by a higher one. + int cur_level = level; + int low_level = cur_level; + while (!current_finished) { + (void)syn_current_attr(false, false, NULL, false); + cur_level = syn_cur_foldlevel(); + if (cur_level < low_level) { + low_level = cur_level; + } else if (cur_level > low_level) { + level = low_level; + } + current_col++; + } + } } if (level > wp->w_p_fdn) { level = wp->w_p_fdn; diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index 6cada1503f..85ee42420e 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -153,7 +153,7 @@ endfunc func Test_syntax_completion() call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:) + call assert_equal('"syn case clear cluster conceal enable foldlevel include iskeyword keyword list manual match off on region reset spell sync', @:) call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"syn case ignore match', @:) @@ -579,3 +579,86 @@ func Test_syntax_hangs() set redrawtime& bwipe! endfunc + +func Test_syntax_foldlevel() + new + call setline(1, [ + \ 'void f(int a)', + \ '{', + \ ' if (a == 1) {', + \ ' a = 0;', + \ ' } else if (a == 2) {', + \ ' a = 1;', + \ ' } else {', + \ ' a = 2;', + \ ' }', + \ ' if (a > 0) {', + \ ' if (a == 1) {', + \ ' a = 0;', + \ ' } /* missing newline */ } /* end of outer if */ else {', + \ ' a = 1;', + \ ' }', + \ ' if (a == 1)', + \ ' {', + \ ' a = 0;', + \ ' }', + \ ' else if (a == 2)', + \ ' {', + \ ' a = 1;', + \ ' }', + \ ' else', + \ ' {', + \ ' a = 2;', + \ ' }', + \ '}', + \ ]) + setfiletype c + syntax on + set foldmethod=syntax + + call assert_fails('syn foldlevel start start', 'E390') + call assert_fails('syn foldlevel not_an_option', 'E390') + + set foldlevel=1 + + syn foldlevel start + redir @c + syn foldlevel + redir END + call assert_equal("\nsyntax foldlevel start", @c) + syn sync fromstart + let a = map(range(3,9), 'foldclosed(v:val)') + call assert_equal([3,3,3,3,3,3,3], a) " attached cascade folds together + let a = map(range(10,15), 'foldclosed(v:val)') + call assert_equal([10,10,10,10,10,10], a) " over-attached 'else' hidden + let a = map(range(16,27), 'foldclosed(v:val)') + let unattached_results = [-1,17,17,17,-1,21,21,21,-1,25,25,25] + call assert_equal(unattached_results, a) " unattached cascade folds separately + + syn foldlevel minimum + redir @c + syn foldlevel + redir END + call assert_equal("\nsyntax foldlevel minimum", @c) + syn sync fromstart + let a = map(range(3,9), 'foldclosed(v:val)') + call assert_equal([3,3,5,5,7,7,7], a) " attached cascade folds separately + let a = map(range(10,15), 'foldclosed(v:val)') + call assert_equal([10,10,10,13,13,13], a) " over-attached 'else' visible + let a = map(range(16,27), 'foldclosed(v:val)') + call assert_equal(unattached_results, a) " unattached cascade folds separately + + set foldlevel=2 + + syn foldlevel start + syn sync fromstart + let a = map(range(11,14), 'foldclosed(v:val)') + call assert_equal([11,11,11,-1], a) " over-attached 'else' hidden + + syn foldlevel minimum + syn sync fromstart + let a = map(range(11,14), 'foldclosed(v:val)') + call assert_equal([11,11,-1,-1], a) " over-attached 'else' visible + + quit! +endfunc |