synID now returns a list.
synIDattr now takes a list.

They both still handle the single-id case, but the code's a bit messy and the 
name is stale. I think we should add synActive and synActiveAttr, which 
take/return lists instead of single numbers, and then deprecate synID*.

-- 
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
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 2bcd21e..a8e481b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5721,21 +5721,22 @@ substitute({expr}, {pat}, {sub}, {flags})		*substitute()*
 			   \ '\=nr2char("0x" . submatch(1))', 'g')
 
 synID({lnum}, {col}, {trans})				*synID()*
-		The result is a Number, which is the syntax ID at the position
-		{lnum} and {col} in the current window.
-		The syntax ID can be used with |synIDattr()| and
+		The result is a Number or a list, which is/are the syntax
+		ID(s) at the position {lnum} and {col} in the current window.
+		The syntax ID(s) can be used with |synIDattr()| and
 		|synIDtrans()| to obtain syntax information about text.
 
 		{col} is 1 for the leftmost column, {lnum} is 1 for the first
 		line.  'synmaxcol' applies, in a longer line zero is returned.
 
 		When {trans} is non-zero, transparent items are reduced to the
-		item that they reveal.	This is useful when wanting to know
-		the effective color.  When {trans} is zero, the transparent
-		item is returned.  This is useful when wanting to know which
-		syntax item is effective (e.g. inside parens).
-		Warning: This function can be very slow.  Best speed is
-		obtained by going through the file in forward direction.
+		item that they reveal.	Non-transparent groups may use
+		|syn-combine|, you'll need to use |synIDattr| in combination
+		with |synstack| to find the effective color.  When {trans} is
+		zero, the transparent item is returned.  This is useful when
+		wanting to know which syntax item is effective (e.g. inside
+		parens).  Warning: This function can be very slow.  Best speed
+		is obtained by going through the file in forward direction.
 
 		Example (echoes the name of the syntax item under the cursor): >
 			:echo synIDattr(synID(line("."), col("."), 1), "name")
@@ -5752,6 +5753,8 @@ synIDattr({synID}, {what} [, {mode}])			*synIDattr()*
 		Use synIDtrans() to follow linked highlight groups.
 		{what}		result
 		"name"		the name of the syntax item
+		"combine"	"1" if the syntax group combines with others
+				in the stack. See |syn-combine|
 		"fg"		foreground color (GUI: color name used to set
 				the color, cterm: color number as a string,
 				term: empty string)
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 5b56585..a8a66a4 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -3459,6 +3459,7 @@ can not be used for all commands:
 :syntax region		yes	yes	yes	yes	yes    yes
 
 These arguments can be used for all three commands:
+	combine
 	conceal
 	cchar
 	contained
@@ -3469,6 +3470,24 @@ These arguments can be used for all three commands:
 	skipnl
 	skipempty
 
+
+combine							*:syn-combine*
+
+When the "combine" argument is given, the highlight attributes of the group
+will be combined with the attributes of other matching syntax groups. The
+"combine" group takes precedence.
+
+Multiple groups may be combined, with the innermost groups taking precedence.
+Example: >
+
+    syntax region Italic start="_" end="_" combine contains=Bold
+    syntax region Bold start="\*" end="\*" combine contains=Italic
+    highlight Italic term=italic
+    highlight Bold term=bold
+
+    _The inner text is italic *and bold*_.
+
+
 conceal						*conceal* *:syn-conceal*
 
 When the "conceal" argument is given, the item is marked as concealable.
@@ -3750,6 +3769,7 @@ Note that this example doesn't work for nested "if"s.  You need to add
 "contains" arguments to make that work (omitted for simplicity of the
 example).
 
+
 IMPLICIT CONCEAL					*:syn-conceal-implicit*
 
 :sy[ntax] conceal [on|off]
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 391e650..aafb1ea 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -421,14 +421,14 @@ syn cluster vimFuncBodyList add=vimSynType
 syn cluster	vimSynKeyGroup	contains=vimSynNextgroup,vimSynKeyOpt,vimSynKeyContainedin
 syn keyword	vimSynType	contained	keyword	skipwhite nextgroup=vimSynKeyRegion
 syn region	vimSynKeyRegion	contained oneline keepend	matchgroup=vimGroupName start="\k\+" skip="\\\\\|\\|" matchgroup=vimSep end="|\|$" contains=@vimSynKeyGroup
-syn match	vimSynKeyOpt	contained	"\<\(conceal\|contained\|transparent\|skipempty\|skipwhite\|skipnl\)\>"
+syn match	vimSynKeyOpt	contained	"\<\(conceal\|contained\|transparent\|skipempty\|skipwhite\|skipnl\|combine\)\>"
 syn cluster vimFuncBodyList add=vimSynType
 
 " Syntax: match {{{2
 syn cluster	vimSynMtchGroup	contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation
 syn keyword	vimSynType	contained	match	skipwhite nextgroup=vimSynMatchRegion
 syn region	vimSynMatchRegion	contained keepend	matchgroup=vimGroupName start="\k\+" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup
-syn match	vimSynMtchOpt	contained	"\<\(conceal\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\)\>"
+syn match	vimSynMtchOpt	contained	"\<\(conceal\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\|combine\)\>"
 if has("conceal")
  syn match	vimSynMtchOpt	contained	"\<cchar="	nextgroup=vimSynMtchCchar
  syn match	vimSynMtchCchar	contained	"\S"
@@ -443,7 +443,7 @@ syn cluster	vimSynRegPatGroup	contains=vimPatSep,vimNotPatSep,vimSynPatRange,vim
 syn cluster	vimSynRegGroup	contains=vimSynContains,vimSynNextgroup,vimSynRegOpt,vimSynReg,vimSynMtchGrp
 syn keyword	vimSynType	contained	region	skipwhite nextgroup=vimSynRegion
 syn region	vimSynRegion	contained keepend	matchgroup=vimGroupName start="\k\+" skip="\\\\\|\\|" end="|\|$" contains=@vimSynRegGroup
-syn match	vimSynRegOpt	contained	"\<\(conceal\(ends\)\=\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|keepend\|oneline\|extend\|skipnl\|fold\)\>"
+syn match	vimSynRegOpt	contained	"\<\(conceal\(ends\)\=\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|keepend\|oneline\|extend\|skipnl\|fold\|combine\)\>"
 syn match	vimSynReg	contained	"\(start\|skip\|end\)="he=e-1	nextgroup=vimSynRegPat
 syn match	vimSynMtchGrp	contained	"matchgroup="	nextgroup=vimGroup,vimHLGroup
 syn region	vimSynRegPat	contained extend	start="\z([-`~!@#$%^&*_=+;:'",./?]\)"  skip="\\\\\|\\\z1"  end="\z1"  contains=@vimSynRegPatGroup skipwhite nextgroup=vimSynPatMod,vimSynReg
diff --git a/src/eval.c b/src/eval.c
index 7c57557..1124184 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -17565,6 +17565,7 @@ f_synID(argvars, rettv)
 #ifdef FEAT_SYN_HL
     long	lnum;
     long	col;
+    int		i;
     int		trans;
     int		transerr = FALSE;
 
@@ -17574,9 +17575,30 @@ f_synID(argvars, rettv)
 
     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
+    {
 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
+	if (highlight_combines(id))
+	{
+	    rettv->v_type = VAR_LIST;
+	    rettv->vval.v_list = NULL;
+	    if (rettv_list_alloc(rettv) == FAIL)
+		return;
+	    (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
+	    for (i = syn_get_stack_length() - 1; i >= 0; --i)
+	    {
+		id = syn_get_stack_item(i);
+		if (trans)
+		    id = syn_get_final_id(id);
+		if (list_append_number(rettv->vval.v_list, id) == FAIL)
+		    break;
+		if (!highlight_combines(id))
+		    break;
+	    }
+	    return;
+	}
+    }
 #endif
-
+    rettv->v_type = VAR_NUMBER;
     rettv->vval.v_number = id;
 }
 
@@ -17590,13 +17612,26 @@ f_synIDattr(argvars, rettv)
 {
     char_u	*p = NULL;
 #ifdef FEAT_SYN_HL
-    int		id;
+    char_u	c;			/* The first char of {what}. */
+    int		id;			/* The current highlight id */
+    int		attr;			/* The accumulated hl attrs */
+    int		flag;			/* The HL_* flag {what} requests */
+    list_T	*l = NULL;		/* The list of highlight ids */
+    listitem_T	*item;			/* The current list item */
     char_u	*what;
     char_u	*mode;
     char_u	modebuf[NUMBUFLEN];
     int		modec;
 
-    id = get_tv_number(&argvars[0]);
+    if (argvars[0].v_type == VAR_NUMBER)
+	id = get_tv_number(&argvars[0]);
+    else if (argvars[0].v_type == VAR_LIST)
+    {
+	l = argvars[0].vval.v_list;
+	if (l == NULL || l->lv_len < 1)
+	    return;
+	id = get_tv_number(&(l->lv_first->li_tv));
+    }
     what = get_tv_string(&argvars[1]);
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
@@ -17612,56 +17647,53 @@ f_synIDattr(argvars, rettv)
 	    modec = 'g';
 	else
 #endif
-	    if (t_colors > 1)
+	     if (t_colors > 1)
 	    modec = 'c';
 	else
 	    modec = 't';
     }
 
-
-    switch (TOLOWER_ASC(what[0]))
+    c = TOLOWER_ASC(what[0]);
+    /* Cases that do not require looking up the stack. */
+    if (c == 'c')
+	p = highlight_combines(id) ? (char_u *)"1" : NULL;
+    else if (c == 'n')
+	p = get_highlight_name(NULL, id - 1);
+    else if ( (c == 'b' && TOLOWER_ASC(what[1]) == 'o' && (flag = HL_BOLD))
+	    || (c == 'i' && TOLOWER_ASC(what[1]) == 't' && (flag = HL_ITALIC))
+	    || (c == 'i' && (flag = HL_INVERSE))
+	    || (c == 'r' && (flag = HL_INVERSE))
+	    || (c == 's' && TOLOWER_ASC(what[1]) == 't' && (flag = HL_STANDOUT))
+	    || (c == 'u' && STRLEN(what) > 5 && TOLOWER_ASC(what[5]) == 'c'
+		    && (flag = HL_UNDERCURL))
+	    || (c == 'u' && (flag = HL_UNDERLINE)))
     {
-	case 'b':
-		if (TOLOWER_ASC(what[1]) == 'g')	/* bg[#] */
-		    p = highlight_color(id, what, modec);
-		else					/* bold */
-		    p = highlight_has_attr(id, HL_BOLD, modec);
-		break;
-
-	case 'f':					/* fg[#] or font */
+	if (l == NULL)
+	    attr = highlight_get_attr(id);
+	else
+	{
+	    attr = 0;
+	    for (item = l->lv_first; item != NULL; item = item->li_next)
+	    {
+		id = get_tv_number(&item->li_tv);
+		attr |= highlight_get_attr(id, modec);
+	    }
+	}
+	p = attr & flag ? ((char_u *)"1") : NULL;
+    }
+    else if (c == 'b' || c == 'f' || c == 's')
+    {
+	if (l == NULL)
+	    p = highlight_color(id, what, modec);
+	else
+	    for (item = l->lv_first; item != NULL; item = item->li_next)
+	    {
+		id = get_tv_number(&item->li_tv);
 		p = highlight_color(id, what, modec);
-		break;
-
-	case 'i':
-		if (TOLOWER_ASC(what[1]) == 'n')	/* inverse */
-		    p = highlight_has_attr(id, HL_INVERSE, modec);
-		else					/* italic */
-		    p = highlight_has_attr(id, HL_ITALIC, modec);
-		break;
-
-	case 'n':					/* name */
-		p = get_highlight_name(NULL, id - 1);
-		break;
-
-	case 'r':					/* reverse */
-		p = highlight_has_attr(id, HL_INVERSE, modec);
-		break;
-
-	case 's':
-		if (TOLOWER_ASC(what[1]) == 'p')	/* sp[#] */
-		    p = highlight_color(id, what, modec);
-		else					/* standout */
-		    p = highlight_has_attr(id, HL_STANDOUT, modec);
-		break;
-
-	case 'u':
-		if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
-							/* underline */
-		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
-		else
-							/* undercurl */
-		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
-		break;
+		/* -1 is an invalid color. */
+		if (p != NULL && p[0] != '-')
+		    break;
+	    }
     }
 
     if (p != NULL)
diff --git a/src/syntax.c b/src/syntax.c
index 4adbaf0..d8db30f 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -59,10 +59,11 @@ struct hl_group
 #endif
 };
 
-#define SG_TERM		1	/* term has been set */
-#define SG_CTERM	2	/* cterm has been set */
-#define SG_GUI		4	/* gui has been set */
-#define SG_LINK		8	/* link has been set */
+#define SG_TERM		0x01	/* term has been set */
+#define SG_CTERM	0x02	/* cterm has been set */
+#define SG_GUI		0x04	/* gui has been set */
+#define SG_LINK		0x08	/* link has been set */
+#define SG_COMBINE	0x10	/* group can combine with other groups. */
 
 static garray_T highlight_ga;	/* highlight groups for 'highlight' option */
 
@@ -289,8 +290,9 @@ typedef struct state_item
     int		si_end_idx;		/* group ID for end pattern or zero */
     int		si_ends;		/* if match ends before si_m_endpos */
     int		si_attr;		/* attributes in this state */
-    long	si_flags;		/* HL_HAS_EOL flag in this state, and
-					 * HL_SKIP* for si_next_list */
+    long	si_flags;		/* HL_HAS_EOL flag in this state,
+					 * HL_SKIP* for si_next_list, and
+					 * HL_COMBINE for combining. */
 #ifdef FEAT_CONCEAL
     int		si_seqnr;		/* sequence number */
     int		si_cchar;		/* substitution character for conceal */
@@ -315,7 +317,8 @@ static int next_seqnr = 0;		/* value to use for si_seqnr */
  */
 typedef struct
 {
-    int		flags;		/* flags for contained and transparent */
+    int		flags;		/* flags for contained, transparent, and
+				   combine. */
     int		keyword;	/* TRUE for ":syn keyword" */
     int		*sync_idx;	/* syntax item for "grouphere" argument, NULL
 				   if not allowed */
@@ -1861,6 +1864,7 @@ syn_current_attr(syncing, displaying, can_spell, keep_state)
     int		cchar;
     short	*next_list;
     int		found_match;		    /* found usable match */
+    int		applied_combiner;	    /* Applied a combining syntax */
     static int	try_next_column = FALSE;    /* must try in next col */
     int		do_keywords;
     regmmatch_T	regmatch;
@@ -2284,6 +2288,8 @@ syn_current_attr(syncing, displaying, can_spell, keep_state)
      * If not, use attributes from the current-but-one state, etc.
      */
     current_attr = 0;
+    applied_combiner = FALSE;
+
 #ifdef FEAT_EVAL
     current_id = 0;
     current_trans_id = 0;
@@ -2307,17 +2313,26 @@ syn_current_attr(syncing, displaying, can_spell, keep_state)
 			|| (current_lnum == sip->si_h_endpos.lnum
 			    && current_col < sip->si_h_endpos.col)))
 	    {
-		current_attr = sip->si_attr;
+		if (applied_combiner)
+		    current_attr = hl_combine_attr(current_attr, sip->si_attr);
+		else
+		{
+		    current_attr = sip->si_attr;
 #ifdef FEAT_EVAL
-		current_id = sip->si_id;
+		    current_id = sip->si_id;
 #endif
-		current_trans_id = sip->si_trans_id;
+		    current_trans_id = sip->si_trans_id;
 #ifdef FEAT_CONCEAL
-		current_flags = sip->si_flags;
-		current_seqnr = sip->si_seqnr;
-		current_sub_char = sip->si_cchar;
+		    current_flags = sip->si_flags;
+		    current_seqnr = sip->si_seqnr;
+		    current_sub_char = sip->si_cchar;
 #endif
-		break;
+		}
+
+		if (sip->si_flags & HL_COMBINE)
+		    applied_combiner = TRUE;
+		else
+		    break;
 	    }
 	}
 
@@ -3914,6 +3929,7 @@ syn_list_one(id, syncing, link_only)
 		    {HL_EXCLUDENL, "excludenl"},
 		    {HL_TRANSP, "transparent"},
 		    {HL_FOLD, "fold"},
+		    {HL_COMBINE, "combine"},
 #ifdef FEAT_CONCEAL
 		    {HL_CONCEAL, "conceal"},
 		    {HL_CONCEALENDS, "concealends"},
@@ -4467,6 +4483,7 @@ get_syn_options(arg, opt, conceal_char)
 		    {"fFoOlLdD",		0,	HL_FOLD},
 		    {"cCoOnNcCeEaAlL",		0,	HL_CONCEAL},
 		    {"cCoOnNcCeEaAlLeEnNdDsS",	0,	HL_CONCEALENDS},
+		    {"cCoOmMbBiInNeE",		0,	HL_COMBINE},
 		    {"cCcChHaArR",		11,	0},
 		    {"cCoOnNtTaAiInNsS",	1,	0},
 		    {"cCoOnNtTaAiInNeEdDiInN",	2,	0},
@@ -4789,6 +4806,11 @@ syn_cmd_keyword(eap, syncing)
 		/* Adjust flags for use of ":syn include". */
 		syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
 
+		/* Mark whether this syntax group combines with other syntax
+		 * groups on the syntax stack. */
+		if (syn_opt_arg.flags & HL_COMBINE)
+		    HL_TABLE()[syn_id - 1].sg_set |= SG_COMBINE;
+
 		/*
 		 * 2: Add an entry for each keyword.
 		 */
@@ -4932,6 +4954,11 @@ syn_cmd_match(eap, syncing)
 	    if (syn_opt_arg.flags & HL_FOLD)
 		++curwin->w_s->b_syn_folditems;
 #endif
+	    /* Mark whether this syntax group combines with other syntax groups
+	     * on the syntax stack. */
+	    if (syn_opt_arg.flags & HL_COMBINE)
+		HL_TABLE()[syn_id - 1].sg_set |= SG_COMBINE;
+
 
 	    redraw_curbuf_later(SOME_VALID);
 	    syn_stack_free_all(curwin->w_s);	/* Need to recompute all syntax. */
@@ -5182,6 +5209,10 @@ syn_cmd_region(eap, syncing)
 		    if (syn_opt_arg.flags & HL_FOLD)
 			++curwin->w_s->b_syn_folditems;
 #endif
+		    /* Mark whether this syntax group combines with other syntax
+		     * groups on the syntax stack. */
+		    if (syn_opt_arg.flags & HL_COMBINE)
+			HL_TABLE()[syn_id - 1].sg_set |= SG_COMBINE;
 		}
 	    }
 
@@ -6438,6 +6469,20 @@ syn_get_stack_item(i)
     }
     return CUR_STATE(i).si_id;
 }
+
+/*
+ * Return the length of the current stack.
+ * Used for functions that need to go through the stack 'backwards', i.e.
+ * innermost-to-outermost.
+ * The caller must have called syn_get_id() before to fill the stack.
+ * Returns -1 when "i" is out of range.
+ */
+    int
+syn_get_stack_length()
+{
+    return current_state.ga_len;
+}
+
 #endif
 
 #if defined(FEAT_FOLDING) || defined(PROTO)
@@ -8620,33 +8665,53 @@ highlight_list_arg(id, didh, type, iarg, sarg, name)
 
 #if (((defined(FEAT_EVAL) || defined(FEAT_PRINTER))) && defined(FEAT_SYN_HL)) || defined(PROTO)
 /*
- * Return "1" if highlight group "id" has attribute "flag".
- * Return NULL otherwise.
+ * Whether or not the highlight group combines with other highlight groups on
+ * the syntax stack.
  */
-    char_u *
-highlight_has_attr(id, flag, modec)
+    int
+highlight_combines(id)
     int		id;
-    int		flag;
-    int		modec;	/* 'g' for GUI, 'c' for cterm, 't' for term */
 {
-    int		attr;
+    if (id <= 0 || id > highlight_ga.ga_len)
+	return 0;
 
+    /* Index is id - 1. */
+    return HL_TABLE()[id - 1].sg_set & SG_COMBINE;
+}
+
+/*
+ * Return the highlight attributes.
+ */
+    int
+highlight_get_attr(id, modec)
+    int		id;
+    int		modec;	/* 'g' for GUI, 'c' for cterm, 't' for term */
+{
     if (id <= 0 || id > highlight_ga.ga_len)
-	return NULL;
+	return 0;
 
 #if defined(FEAT_GUI) || defined(FEAT_EVAL)
     if (modec == 'g')
-	attr = HL_TABLE()[id - 1].sg_gui;
+	return HL_TABLE()[id - 1].sg_gui;
     else
 #endif
 	 if (modec == 'c')
-	attr = HL_TABLE()[id - 1].sg_cterm;
+	return HL_TABLE()[id - 1].sg_cterm;
     else
-	attr = HL_TABLE()[id - 1].sg_term;
+	return HL_TABLE()[id - 1].sg_term;
+}
 
-    if (attr & flag)
-	return (char_u *)"1";
-    return NULL;
+/*
+ * Check if highlight group specified by "id" has attr "flag".
+ * "1" if it does, NULL otherwise.
+ */
+    char_u*
+highlight_has_attr(id, flag, modec)
+    int		id;
+    int		flag;
+    int		modec;	/* 'g' for GUI, 'c' for cterm, 't' for term */
+{
+    return highlight_get_attr(id, modec) & flag ? (char_u *)"1" : NULL;
 }
 #endif
 
@@ -9056,6 +9121,7 @@ syn_unadd_group()
     vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
 }
 
+
 /*
  * Translate a group ID to highlight attributes.
  */
diff --git a/src/vim.h b/src/vim.h
index 35b2310..de42322 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -894,6 +894,7 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
 # define HL_TRANS_CONT	0x10000 /* transparent item without contains arg */
 # define HL_CONCEAL	0x20000 /* can be concealed */
 # define HL_CONCEALENDS	0x40000 /* can be concealed */
+# define HL_COMBINE	0x80000 /* combine attributes with other matches */
 #endif
 
 /* Values for 'options' argument in do_search() and searchit() */

Raspunde prin e-mail lui