mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
Merge pull request #12133 from bradking/syntax-fold
This commit is contained in:
commit
225f0bcd98
@ -3522,6 +3522,24 @@ DEFINING CASE *:syn-case* *E390*
|
||||
:sy[ntax] case
|
||||
Show either "syntax case match" or "syntax case ignore" (translated).
|
||||
|
||||
|
||||
DEFINING FOLDLEVEL *:syn-foldlevel*
|
||||
|
||||
:sy[ntax] foldlevel [start | minimum]
|
||||
This defines how the foldlevel of a line is computed when using
|
||||
foldmethod=syntax (see |fold-syntax| and |:syn-fold|):
|
||||
|
||||
start: Use level of item containing start of line.
|
||||
minimum: Use lowest local-minimum level of items on line.
|
||||
|
||||
The default is 'start'. Use 'minimum' to search a line horizontally
|
||||
for the lowest level contained on the line that is followed by a
|
||||
higher level. This produces more natural folds when syntax items
|
||||
may close and open horizontally within a line.
|
||||
|
||||
:sy[ntax] foldlevel
|
||||
Show either "syntax foldlevel start" or "syntax foldlevel minimum".
|
||||
|
||||
SPELL CHECKING *:syn-spell*
|
||||
|
||||
:sy[ntax] spell [toplevel | notoplevel | default]
|
||||
@ -3985,6 +4003,8 @@ This will make each {} block form one fold.
|
||||
The fold will start on the line where the item starts, and end where the item
|
||||
ends. If the start and end are within the same line, there is no fold.
|
||||
The 'foldnestmax' option limits the nesting of syntax folds.
|
||||
See |:syn-foldlevel| to control how the foldlevel of a line is computed
|
||||
from its syntax items.
|
||||
|
||||
|
||||
*:syn-contains* *E405* *E406* *E407* *E408* *E409*
|
||||
|
@ -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
|
||||
|
@ -121,6 +121,8 @@ static int hl_attr_table[] =
|
||||
{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE,
|
||||
HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
|
||||
|
||||
static char e_illegal_arg[] = N_("E390: Illegal argument: %s");
|
||||
|
||||
// The patterns that are being searched for are stored in a syn_pattern.
|
||||
// A match item consists of one pattern.
|
||||
// A start/end item consists of n start patterns and m end patterns.
|
||||
@ -3045,7 +3047,7 @@ static void syn_cmd_conceal(exarg_T *eap, int syncing)
|
||||
} else if (STRNICMP(arg, "off", 3) == 0 && next - arg == 3) {
|
||||
curwin->w_s->b_syn_conceal = false;
|
||||
} else {
|
||||
EMSG2(_("E390: Illegal argument: %s"), arg);
|
||||
EMSG2(_(e_illegal_arg), arg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3073,7 +3075,42 @@ static void syn_cmd_case(exarg_T *eap, int syncing)
|
||||
} else if (STRNICMP(arg, "ignore", 6) == 0 && next - arg == 6) {
|
||||
curwin->w_s->b_syn_ic = true;
|
||||
} else {
|
||||
EMSG2(_("E390: Illegal argument: %s"), arg);
|
||||
EMSG2(_(e_illegal_arg), arg);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3105,7 +3142,7 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
|
||||
} else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) {
|
||||
curwin->w_s->b_syn_spell = SYNSPL_DEFAULT;
|
||||
} else {
|
||||
EMSG2(_("E390: Illegal argument: %s"), arg);
|
||||
EMSG2(_(e_illegal_arg), arg);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3161,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;
|
||||
@ -5485,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 },
|
||||
@ -5763,6 +5802,17 @@ int syn_get_stack_item(int i)
|
||||
return CUR_STATE(i).si_id;
|
||||
}
|
||||
|
||||
static int syn_cur_foldlevel(void)
|
||||
{
|
||||
int level = 0;
|
||||
for (int i = 0; i < current_state.ga_len; i++) {
|
||||
if (CUR_STATE(i).si_flags & HL_FOLD) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called to get folding level for line "lnum" in window "wp".
|
||||
*/
|
||||
@ -5776,9 +5826,22 @@ int syn_get_foldlevel(win_T *wp, long lnum)
|
||||
&& !wp->w_s->b_syn_slow) {
|
||||
syntax_start(wp, lnum);
|
||||
|
||||
for (int i = 0; i < current_state.ga_len; ++i) {
|
||||
if (CUR_STATE(i).si_flags & HL_FOLD) {
|
||||
++level;
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user