On 10/14/2016 04:04 PM, Bram Moolenaar wrote:
> Either this needs to be donein the C syntax, or we need an folding
> option to enable this behavior.

Thanks for taking a look.  It can't currently be done purely in syntax
definitions so I've revised the change to add a new syntax command:

    :syntax foldlevel [start | minimum]

that can be used to enable this.

With this we will later be able to edit `runtime/syntax/c.vim`
(and possibly others) to add:

    syntax foldlevel minimum

(possibly guarded by an option) in order to get this folding behavior.

Thanks,
-Brad



-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
>From c43347369e3eebc63613801052002c1c89383abd Mon Sep 17 00:00:00 2001
Message-Id: <c43347369e3eebc63613801052002c1c89383abd.1476727922.git.brad.k...@kitware.com>
From: Brad King <brad.k...@kitware.com>
Date: Mon, 17 Oct 2016 13:42:53 -0400
Subject: [PATCH] syntax: Add command to control how foldlevel is computed for
 a line

With `foldmethod=syntax` the foldlevel of a line is computed based
on syntax items on the line.  Previously we always used the level
of the syntax item containing the start of the line.  This works
well in cases such as:

    if (...) {
      ...
    }
    else if (...) {
      ...
    }
    else {
      ...
    }

which folds like this:

    +---  3 lines: if (...) {---------------------------
    +---  3 lines: else if (...) {----------------------
    +---  3 lines: else {-------------------------------

However, the code:

    if (...) {
      ...
    } else if (...) {
      ...
    } else {
      ...
    }

folds like this:

    +---  7 lines: if (...) {---------------------------

We can make the latter case fold like this:

    +---  2 lines: if (...) {---------------------------
    +---  2 lines: } else if (...) {--------------------
    +---  3 lines: } else {-----------------------------

by choosing on each line the lowest fold level that is followed
by a higher fold level.

Add a syntax command

    :syntax foldlevel [start | minimum]

to choose between these two methods of computing the foldlevel of
a line.
---
 runtime/doc/syntax.txt | 19 ++++++++++++++
 src/structs.h          |  7 +++++
 src/syntax.c           | 70 +++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index ae80a44..2cf4b54 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -3480,6 +3480,23 @@ DEFINING CASE						*:syn-case* *E390*
 	items until the next ":syntax case" command are affected.
 
 
+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.
+
+	{not available when Vim was compiled without |+folding| feature}
+
+
 SPELL CHECKING						*:syn-spell*
 
 :sy[ntax] spell [toplevel | notoplevel | default]
@@ -3938,6 +3955,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.
 {not available when Vim was compiled without |+folding| feature}
 
 
diff --git a/src/structs.h b/src/structs.h
index 7a4d7fb..6a76cf1 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1710,6 +1710,12 @@ typedef struct list_stack_S
 #define SYNSPL_TOP	1	/* spell check toplevel text */
 #define SYNSPL_NOTOP	2	/* don't spell check toplevel text */
 
+#ifdef FEAT_FOLDING
+/* 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 */
+#endif
+
 /* avoid #ifdefs for when b_spell is not available */
 #ifdef FEAT_SPELL
 # define B_SPELL(buf)  ((buf)->b_spell)
@@ -1786,6 +1792,7 @@ typedef struct {
 # ifdef FEAT_FOLDING
     int		b_syn_folditems;	/* number of patterns with the HL_FOLD
 					   flag set */
+    int		b_syn_foldlevel;	/* how to compute foldlevel on a line */
 # endif
     /*
      * b_sst_array[] contains the state stack for a number of lines, for the
diff --git a/src/syntax.c b/src/syntax.c
index 75ede36..f06a3cf 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -435,6 +435,9 @@ static char_u *syn_getcurline(void);
 static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st);
 static int check_keyword_id(char_u *line, int startcol, int *endcol, long *flags, short **next_list, stateitem_T *cur_si, int *ccharp);
 static void syn_cmd_case(exarg_T *eap, int syncing);
+#ifdef FEAT_FOLDING
+static void syn_cmd_foldlevel(exarg_T *eap, int syncing);
+#endif
 static void syn_cmd_spell(exarg_T *eap, int syncing);
 static void syntax_sync_clear(void);
 static void syn_remove_pattern(synblock_T *block, int idx);
@@ -3465,6 +3468,33 @@ syn_cmd_case(exarg_T *eap, int syncing UNUSED)
 	EMSG2(_("E390: Illegal argument: %s"), arg);
 }
 
+#ifdef FEAT_FOLDING
+/*
+ * Handle ":syntax foldlevel" command.
+ */
+    static void
+syn_cmd_foldlevel(exarg_T *eap, int syncing UNUSED)
+{
+    char_u	*arg = eap->arg;
+    char_u	*next;
+
+    eap->nextcmd = find_nextcmd(arg);
+    if (eap->skip)
+	return;
+
+    next = skiptowhite(arg);
+    if (STRNICMP(arg, "start", 5) == 0 && next - arg == 5)
+	curwin->w_s->b_syn_foldlevel = SYNFLD_START;
+    else if (STRNICMP(arg, "minimum", 7) == 0 && next - arg == 7)
+	curwin->w_s->b_syn_foldlevel = SYNFLD_MINIMUM;
+    else
+    {
+	EMSG2(_("E390: Illegal argument: %s"), arg);
+	return;
+    }
+}
+#endif
+
 /*
  * Handle ":syntax spell" command.
  */
@@ -3584,6 +3614,7 @@ syntax_clear(synblock_T *block)
     block->b_syn_linecont_pat = NULL;
 #ifdef FEAT_FOLDING
     block->b_syn_folditems = 0;
+    block->b_syn_foldlevel = SYNFLD_START;
 #endif
     clear_string_option(&block->b_syn_isk);
 
@@ -6262,6 +6293,9 @@ static struct subcommand subcommands[] =
     {"cluster",		syn_cmd_cluster},
     {"conceal",		syn_cmd_conceal},
     {"enable",		syn_cmd_enable},
+#ifdef FEAT_FOLDING
+    {"foldlevel",	syn_cmd_foldlevel},
+#endif
     {"include",		syn_cmd_include},
     {"iskeyword",	syn_cmd_iskeyword},
     {"keyword",		syn_cmd_keyword},
@@ -6537,6 +6571,17 @@ syn_get_stack_item(int i)
 #endif
 
 #if defined(FEAT_FOLDING) || defined(PROTO)
+    static int
+syn_cur_foldlevel(void)
+{
+    int		level = 0;
+    int		i;
+    for (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".
  */
@@ -6544,16 +6589,33 @@ syn_get_stack_item(int i)
 syn_get_foldlevel(win_T *wp, long lnum)
 {
     int		level = 0;
-    int		i;
+    int		low_level;
+    int		cur_level;
 
     /* Return quickly when there are no fold items at all. */
     if (wp->w_s->b_syn_folditems != 0)
     {
 	syntax_start(wp, lnum);
 
-	for (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. */
+	    cur_level = level;
+	    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)
     {
-- 
2.9.3


Raspunde prin e-mail lui