changeset 6947:1efa7c2b9368 v7.4.792

patch 7.4.792 Problem: Can only conceal text by defining syntax items. Solution: Use matchadd() to define concealing. (Christian Brabandt)
author Bram Moolenaar <bram@vim.org>
date Tue, 21 Jul 2015 15:48:27 +0200
parents c56ef0540cd5
children 50dfc96920a8
files runtime/doc/eval.txt src/eval.c src/ex_docmd.c src/proto/window.pro src/screen.c src/structs.h src/testdir/Make_amiga.mak src/testdir/Make_dos.mak src/testdir/Make_ming.mak src/testdir/Make_os2.mak src/testdir/Make_vms.mms src/testdir/Makefile src/testdir/test_match_conceal.in src/testdir/test_match_conceal.ok src/version.c src/window.c
diffstat 16 files changed, 331 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -4430,9 +4430,18 @@ matchadd({group}, {pattern}[, {priority}
 		message will appear and the match will not be added.  An ID
 		is specified as a positive integer (zero excluded).  IDs 1, 2
 		and 3 are reserved for |:match|, |:2match| and |:3match|,
-		respectively.  If the {id} argument is not specified,
+		respectively.  If the {id} argument is not specified or -1,
 		|matchadd()| automatically chooses a free ID.
 
+		The optional {dict} argmument allows for further custom
+		values. Currently this is used to specify a match specifc
+		conceal character that will be shown for |hl-Conceal|
+		highlighted matches. The dict can have the following members:
+
+			conceal	    Special character to show instead of the
+				    match (only for |hl-Conceal| highlighed
+				    matches, see |:syn-cchar|)
+
 		The number of matches is not limited, as it is the case with
 		the |:match| commands.
 
@@ -4446,7 +4455,7 @@ matchadd({group}, {pattern}[, {priority}
 		available from |getmatches()|.	All matches can be deleted in
 		one operation by |clearmatches()|.
 
-matchaddpos({group}, {pos}[, {priority}[, {id}]])		*matchaddpos()*
+matchaddpos({group}, {pos}[, {priority}[, {id}[, {dict}]]])		*matchaddpos()*
 		Same as |matchadd()|, but requires a list of positions {pos}
 		instead of a pattern. This command is faster than |matchadd()|
 		because it does not require to handle regular expressions and
--- a/src/eval.c
+++ b/src/eval.c
@@ -8224,8 +8224,8 @@ static struct fst
     {"maparg",		1, 4, f_maparg},
     {"mapcheck",	1, 3, f_mapcheck},
     {"match",		2, 4, f_match},
-    {"matchadd",	2, 4, f_matchadd},
-    {"matchaddpos",	2, 4, f_matchaddpos},
+    {"matchadd",	2, 5, f_matchadd},
+    {"matchaddpos",	2, 5, f_matchaddpos},
     {"matcharg",	1, 1, f_matcharg},
     {"matchdelete",	1, 1, f_matchdelete},
     {"matchend",	2, 4, f_matchend},
@@ -12031,6 +12031,15 @@ f_getmatches(argvars, rettv)
 	    dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
 	    dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
 	    dict_add_nr_str(dict, "id", (long)cur->id, NULL);
+# ifdef FEAT_CONCEAL
+	    if (cur->conceal_char)
+	    {
+		char_u buf[MB_MAXBYTES + 1];
+
+		buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
+		dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
+	    }
+# endif
 	    list_append_dict(rettv->vval.v_list, dict);
 	    cur = cur->next;
 	}
@@ -14589,6 +14598,7 @@ f_matchadd(argvars, rettv)
     int		prio = 10;	/* default priority */
     int		id = -1;
     int		error = FALSE;
+    char_u	*conceal_char = NULL;
 
     rettv->vval.v_number = -1;
 
@@ -14598,7 +14608,21 @@ f_matchadd(argvars, rettv)
     {
 	prio = get_tv_number_chk(&argvars[2], &error);
 	if (argvars[3].v_type != VAR_UNKNOWN)
+	{
 	    id = get_tv_number_chk(&argvars[3], &error);
+	    if (argvars[4].v_type != VAR_UNKNOWN)
+	    {
+		if (argvars[4].v_type != VAR_DICT)
+		{
+		    EMSG(_(e_dictreq));
+		    return;
+		}
+		if (dict_find(argvars[4].vval.v_dict,
+					     (char_u *)"conceal", -1) != NULL)
+		    conceal_char = get_dict_string(argvars[4].vval.v_dict,
+						  (char_u *)"conceal", FALSE);
+	    }
+	}
     }
     if (error == TRUE)
 	return;
@@ -14608,7 +14632,8 @@ f_matchadd(argvars, rettv)
 	return;
     }
 
-    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
+								conceal_char);
 #endif
 }
 
@@ -14627,6 +14652,7 @@ f_matchaddpos(argvars, rettv)
     int		id = -1;
     int		error = FALSE;
     list_T	*l;
+    char_u	*conceal_char = NULL;
 
     rettv->vval.v_number = -1;
 
@@ -14647,7 +14673,21 @@ f_matchaddpos(argvars, rettv)
     {
 	prio = get_tv_number_chk(&argvars[2], &error);
 	if (argvars[3].v_type != VAR_UNKNOWN)
+	{
 	    id = get_tv_number_chk(&argvars[3], &error);
+	    if (argvars[4].v_type != VAR_UNKNOWN)
+	    {
+		if (argvars[4].v_type != VAR_DICT)
+		{
+		    EMSG(_(e_dictreq));
+		    return;
+		}
+		if (dict_find(argvars[4].vval.v_dict,
+					     (char_u *)"conceal", -1) != NULL)
+		    conceal_char = get_dict_string(argvars[4].vval.v_dict,
+						  (char_u *)"conceal", FALSE);
+	    }
+	}
     }
     if (error == TRUE)
 	return;
@@ -14659,7 +14699,8 @@ f_matchaddpos(argvars, rettv)
 	return;
     }
 
-    rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l);
+    rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
+								conceal_char);
 #endif
 }
 
@@ -17165,9 +17206,12 @@ f_setmatches(argvars, rettv)
 	    int		i = 0;
 	    char_u	buf[5];
 	    dictitem_T  *di;
+	    char_u	*group;
+	    int		priority;
+	    int		id;
+	    char_u	*conceal;
 
 	    d = li->li_tv.vval.v_dict;
-
 	    if (dict_find(d, (char_u *)"pattern", -1) == NULL)
 	    {
 		if (s == NULL)
@@ -17193,18 +17237,22 @@ f_setmatches(argvars, rettv)
 			break;
 		}
 	    }
+
+	    group = get_dict_string(d, (char_u *)"group", FALSE);
+	    priority = (int)get_dict_number(d, (char_u *)"priority");
+	    id = (int)get_dict_number(d, (char_u *)"id");
+	    conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
+			      ? get_dict_string(d, (char_u *)"conceal", FALSE)
+			      : NULL;
 	    if (i == 0)
 	    {
-		match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
+		match_add(curwin, group,
 		    get_dict_string(d, (char_u *)"pattern", FALSE),
-		    (int)get_dict_number(d, (char_u *)"priority"),
-		    (int)get_dict_number(d, (char_u *)"id"), NULL);
-	    }
-	    else
-	    {
-		match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
-		    NULL, (int)get_dict_number(d, (char_u *)"priority"),
-		    (int)get_dict_number(d, (char_u *)"id"), s);
+		    priority, id, NULL, conceal);
+	    }
+	    else
+	    {
+		match_add(curwin, group, NULL, priority, id, s, conceal);
 		list_unref(s);
 		s = NULL;
 	    }
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -12079,7 +12079,7 @@ ex_match(eap)
 
 	    c = *end;
 	    *end = NUL;
-	    match_add(curwin, g, p + 1, 10, id, NULL);
+	    match_add(curwin, g, p + 1, 10, id, NULL, NULL);
 	    vim_free(g);
 	    *end = c;
 	}
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -76,7 +76,7 @@ void restore_win __ARGS((win_T *save_cur
 void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf));
 void restore_buffer __ARGS((buf_T *save_curbuf));
 int win_hasvertsplit __ARGS((void));
-int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list));
+int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list, char_u *conceal_char));
 int match_delete __ARGS((win_T *wp, int id, int perr));
 void clear_matches __ARGS((win_T *wp));
 matchitem_T *get_match __ARGS((win_T *wp, int id));
--- a/src/screen.c
+++ b/src/screen.c
@@ -3047,6 +3047,8 @@ win_line(wp, lnum, startrow, endrow, noc
 					   wrapping */
     int		vcol_off	= 0;	/* offset for concealed characters */
     int		did_wcol	= FALSE;
+    int		match_conc	= FALSE; /* cchar for match functions */
+    int		has_match_conc  = FALSE; /* match wants to conceal */
     int		old_boguscols   = 0;
 # define VCOL_HLC (vcol - vcol_off)
 # define FIX_FOR_BOGUSCOLS \
@@ -3580,6 +3582,9 @@ win_line(wp, lnum, startrow, endrow, noc
      */
     for (;;)
     {
+#ifdef FEAT_CONCEAL
+	has_match_conc = FALSE;
+#endif
 	/* Skip this quickly when working on the text. */
 	if (draw_state != WL_LINE)
 	{
@@ -3923,13 +3928,26 @@ win_line(wp, lnum, startrow, endrow, noc
 				shl->endcol = tmp_col;
 #endif
 			    shl->attr_cur = shl->attr;
+#ifdef FEAT_CONCEAL
+			    if (cur != NULL && syn_name2id((char_u *)"Conceal")
+							       == cur->hlg_id)
+			    {
+				has_match_conc = TRUE;
+				match_conc = cur->conceal_char;
+			    }
+			    else
+				has_match_conc = match_conc = FALSE;
+#endif
 			}
 			else if (v == (long)shl->endcol)
 			{
 			    shl->attr_cur = 0;
+#ifdef FEAT_CONCEAL
+			    prev_syntax_id = 0;
+#endif
 			    next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
 			    pos_inprogress = cur == NULL || cur->pos.cur == 0
-							      ? FALSE : TRUE;
+							       ? FALSE : TRUE;
 
 			    /* Need to get the line again, a multi-line regexp
 			     * may have made it invalid. */
@@ -4873,19 +4891,22 @@ win_line(wp, lnum, startrow, endrow, noc
 #ifdef FEAT_CONCEAL
 	    if (   wp->w_p_cole > 0
 		&& (wp != curwin || lnum != wp->w_cursor.lnum ||
-						      conceal_cursor_line(wp))
-		&& (syntax_flags & HL_CONCEAL) != 0
+							conceal_cursor_line(wp) )
+		&& ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc)
 		&& !(lnum_in_visual_area
 				    && vim_strchr(wp->w_p_cocu, 'v') == NULL))
 	    {
 		char_attr = conceal_attr;
 		if (prev_syntax_id != syntax_seqnr
-			&& (syn_get_sub_char() != NUL || wp->w_p_cole == 1)
+			&& (syn_get_sub_char() != NUL || match_conc
+							 || wp->w_p_cole == 1)
 			&& wp->w_p_cole != 3)
 		{
 		    /* First time at this concealed item: display one
 		     * character. */
-		    if (syn_get_sub_char() != NUL)
+		    if (match_conc)
+			c = match_conc;
+		    else if (syn_get_sub_char() != NUL)
 			c = syn_get_sub_char();
 		    else if (lcs_conceal != NUL)
 			c = lcs_conceal;
--- a/src/structs.h
+++ b/src/structs.h
@@ -2021,6 +2021,9 @@ struct matchitem
     regmmatch_T	match;	    /* regexp program for pattern */
     posmatch_T	pos;	    /* position matches */
     match_T	hl;	    /* struct for doing the actual highlighting */
+#ifdef FEAT_CONCEAL
+    int		conceal_char; /* cchar for Conceal highlighting */
+#endif
 };
 
 /*
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -54,6 +54,7 @@ SCRIPTS = test1.out test3.out test4.out 
 		test_listlbr_utf8.out \
 		test_mapping.out \
 		test_marks.out \
+		test_match_conceal.out \
 		test_nested_function.out \
 		test_options.out \
 		test_perl.out \
@@ -205,6 +206,7 @@ test_listlbr.out: test_listlbr.in
 test_listlbr_utf8.out: test_listlbr_utf8.in
 test_mapping.out: test_mapping.in
 test_marks.out: test_marks.in
+test_match_conceal.out: test_match_conceal.in
 test_nested_function.out: test_nested_function.in
 test_options.out: test_options.in
 test_perl.out: test_perl.in
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -53,6 +53,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test_listlbr_utf8.out \
 		test_mapping.out \
 		test_marks.out \
+		test_match_conceal.out \
 		test_nested_function.out \
 		test_options.out \
 		test_perl.out \
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -75,6 +75,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test_listlbr_utf8.out \
 		test_mapping.out \
 		test_marks.out \
+		test_match_conceal.out \
 		test_nested_function.out \
 		test_options.out \
 		test_perl.out \
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -55,6 +55,7 @@ SCRIPTS = test1.out test3.out test4.out 
 		test_listlbr_utf8.out \
 		test_mapping.out \
 		test_marks.out \
+		test_match_conceal.out \
 		test_nested_function.out \
 		test_options.out \
 		test_perl.out \
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -114,6 +114,7 @@ SCRIPT = test1.out  test2.out  test3.out
 	 test_listlbr_utf8.out \
 	 test_mapping.out \
 	 test_marks.out \
+	 test_match_conceal.out \
 	 test_nested_function.out \
 	 test_options.out \
 	 test_perl.out \
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -51,6 +51,7 @@ SCRIPTS = test1.out test2.out test3.out 
 		test_listlbr_utf8.out \
 		test_mapping.out \
 		test_marks.out \
+		test_match_conceal.out \
 		test_nested_function.out \
 		test_options.out \
 		test_perl.out \
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_match_conceal.in
@@ -0,0 +1,159 @@
+Test for matchadd() and conceal feature
+
+STARTTEST
+:so small.vim
+:if !has("conceal") | e! test.ok | w! test.out | qa! | endif
+:set term=ansi
+:so mbyte.vim
+:if &enc !=? 'utf-8'|:e! test.ok|:w! test.out|qa!|endif
+:10new|:vsp|:vert resize 20
+:put =\"\#\ This\ is\ a\ Test\"
+:norm! mazt
+:fu! ScreenChar(width, lines)
+:	let c=''
+:	for j in range(1,a:lines)
+:	    for i in range(1,a:width)
+:	    	let c.=nr2char(screenchar(j, i))
+:	    endfor
+:           let c.="\n"
+:	endfor
+:	return c
+:endfu
+:fu! ScreenAttr(line, pos, eval)
+:       let g:attr=[]
+:       for col in a:pos
+:	    call add(g:attr, screenattr(a:line,col))
+:	endfor
+:	" In case all values are zero, probably the terminal
+:       " isn't set correctly, so catch that case
+:	let null = (eval(join(g:attr, '+')) == 0)
+:       let str=substitute(a:eval, '\d\+', 'g:attr[&]', 'g')
+:	if null || eval(str)
+:	    :let g:attr_test="OK: ". str
+:	else
+:	    :let g:attr_test="FAILED: ".str
+:	    :let g:attr_test.="\n". join(g:attr, ' ')
+:	    :let g:attr_test.="\n TERM: ". &term
+:	endif
+:endfu
+:fu! DoRecordScreen()
+:	wincmd l
+:	$put =printf(\"\n%s\", g:test)
+:	$put =g:line
+:       $put =g:attr_test
+:	wincmd p
+:endfu
+:let g:test ="Test 1: simple addmatch()"
+:call matchadd('Conceal', '\%2l ')
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)"
+:norm! 'azt
+:call clearmatches()
+:syntax on
+:set concealcursor=n conceallevel=1
+:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)"
+:norm! 'azt
+:set conceallevel=3
+:call clearmatches()
+:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 1==3 && 1==4 && 0!=5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 4: more match() (should be: #Thisisa Test)"
+:norm! 'azt
+:call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'})
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 0!=3 && 3==4 && 0!=5 && 3!=5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 5/1: default conceal char (should be: # This is a Test)"
+:norm! 'azt
+:call clearmatches()
+:set conceallevel=1
+:call matchadd('Conceal', '\%2l ', 10, -1, {})
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:let g:test ="Test 5/2: default conceal char (should be: #+This+is+a+Test)"
+:norm! 'azt
+:set listchars=conceal:+
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:set listchars&vim
+:
+:let g:test ="Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)"
+:norm! 'azt
+:call clearmatches()
+:set conceallevel=1
+:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+:syn match MyConceal /\%2l / conceal containedin=ALL cchar=*
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:let g:test ="Test 6/2: syn and match conceal (should be: #*This*is*a*Test)"
+:norm! 'azt
+:call clearmatches()
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 7/1: clear matches"
+:norm! 'azt
+:syn on
+:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+:let a=getmatches()
+:call clearmatches()
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 0==2 && 0==3 && 0==4 && 0==5")
+:call DoRecordScreen()
+:$put =a
+:call setmatches(a)
+:norm! 'azt
+:let g:test ="Test 7/2: reset match using setmatches()"
+:norm! 'azt
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:
+:let g:test ="Test 8: using matchaddpos() (should be #Pis a Test"
+:norm! 'azt
+:call clearmatches()
+:call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'})
+:let a=getmatches()
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1!=2 && 0==2 && 0==3 && 0!=4 && 0!=5 && 4==5")
+:call DoRecordScreen()
+:$put =a
+:
+:let g:test ="Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)"
+:norm! 'azt
+:call clearmatches()
+:call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"})
+:redraw!
+:let line=ScreenChar(winwidth(0),1)
+:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+:call DoRecordScreen()
+:
+:"sleep 10
+:%w! test.out
+:qa!
+ENDTEST
+dummy text
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_match_conceal.ok
@@ -0,0 +1,52 @@
+
+# This is a Test
+
+Test 1: simple addmatch()
+# This is a Test    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)
+#XThisXisXaXTest    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)
+#ThisisaTest        
+OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]!=g:attr[5]
+
+Test 4: more match() (should be: #Thisisa Test)
+#Thisisa Test       
+OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[0]!=g:attr[3] && g:attr[3]==g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[3]!=g:attr[5]
+
+Test 5/1: default conceal char (should be: # This is a Test)
+# This is a Test    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 5/2: default conceal char (should be: #+This+is+a+Test)
+#+This+is+a+Test    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)
+#ZThisZisZaZTest    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 6/2: syn and match conceal (should be: #*This*is*a*Test)
+#*This*is*a*Test    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 7/1: clear matches
+# This is a Test    
+OK: g:attr[0]==g:attr[1] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]==g:attr[4] && g:attr[0]==g:attr[5]
+{'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': 10, 'conceal': 'Z'}
+
+Test 7/2: reset match using setmatches()
+#ZThisZisZaZTest    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+Test 8: using matchaddpos() (should be #Pis a Test
+#Pis a Test         
+OK: g:attr[0]!=g:attr[1] && g:attr[1]!=g:attr[2] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]!=g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[4]==g:attr[5]
+{'group': 'Conceal', 'id': 11, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'}
+
+Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)
+#ˑThisˑisˑaˑTest    
+OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    792,
+/**/
     791,
 /**/
     790,
--- a/src/window.c
+++ b/src/window.c
@@ -6943,13 +6943,14 @@ win_hasvertsplit()
  * Return ID of added match, -1 on failure.
  */
     int
-match_add(wp, grp, pat, prio, id, pos_list)
+match_add(wp, grp, pat, prio, id, pos_list, conceal_char)
     win_T	*wp;
     char_u	*grp;
     char_u	*pat;
     int		prio;
     int		id;
     list_T	*pos_list;
+    char_u      *conceal_char UNUSED; /* pointer to conceal replacement char */
 {
     matchitem_T	*cur;
     matchitem_T	*prev;
@@ -7009,6 +7010,11 @@ match_add(wp, grp, pat, prio, id, pos_li
     m->match.regprog = regprog;
     m->match.rmm_ic = FALSE;
     m->match.rmm_maxcol = 0;
+#ifdef FEAT_CONCEAL
+    m->conceal_char = 0;
+    if (conceal_char != NULL)
+	m->conceal_char = (*mb_ptr2char)(conceal_char);
+#endif
 
     /* Set up position matches */
     if (pos_list != NULL)