changeset 16811:0457d49eb2d9 v8.1.1407

patch 8.1.1407: popup_create() does not support text properties commit https://github.com/vim/vim/commit/7a8d0278bd6bd57e04f61183cb8e2969cf148e3f Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 26 23:32:06 2019 +0200 patch 8.1.1407: popup_create() does not support text properties Problem: Popup_create() does not support text properties. Solution: Support the third form of the text argument.
author Bram Moolenaar <Bram@vim.org>
date Sun, 26 May 2019 23:45:05 +0200
parents 53b2302072d2
children 55ca009f1493
files runtime/doc/popup.txt src/popupwin.c src/proto/textprop.pro src/screen.c src/testdir/dumps/Test_popupwin_02.dump src/testdir/dumps/Test_popupwin_03.dump src/testdir/dumps/Test_popupwin_04.dump src/testdir/test_popupwin.vim src/textprop.c src/version.c
diffstat 10 files changed, 162 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -279,7 +279,6 @@ optionally text properties.  It is in on
 - a string
 - a list of strings
 - a list of dictionaries, where each dictionary has these entries:
-	{not implemented yet}
 	text		String with the text to display.
 	props		A list of text properties.  Optional.
 			Each entry is a dictionary, like the third argument of
@@ -369,12 +368,16 @@ outside of the Vim window will not be di
 
 POPUP TEXT PROPERTIES					*popup-props*
 
-{not implemented yet}
-These are similar to the third argument of |prop_add()|, but not exactly the
-same, since they only apply to one line.
+These are similar to the third argument of |prop_add()| except:
+- "lnum" is always the current line in the list
+- "bufnr" is always the buffer of the popup
+- "col" is in the Dict instead of a separate argument
+- "transparent" is extra
+So we get:
 	col		starting column, counted in bytes, use one for the
 			first column.
 	length		length of text in bytes; can be zero
+	end_lnum	line number for the end of the text
 	end_col		column just after the text; not used when "length" is
 			present; when {col} and "end_col" are equal, this is a
 			zero-width text property
@@ -385,6 +388,7 @@ same, since they only apply to one line.
 	transparent	do not show these characters, show the text under it;
 			if there is an border character to the right or below
 			it will be made transparent as well
+			{not implemented yet}
 
 
 POPUP FILTER						*popup-filter*
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -60,6 +60,91 @@ apply_options(win_T *wp, buf_T *buf UNUS
 }
 
 /*
+ * Add lines to the popup from a list of strings.
+ */
+    static void
+add_popup_strings(buf_T *buf, list_T *l)
+{
+    listitem_T  *li;
+    linenr_T    lnum = 0;
+    char_u	*p;
+
+    for (li = l->lv_first; li != NULL; li = li->li_next)
+	if (li->li_tv.v_type == VAR_STRING)
+	{
+	    p = li->li_tv.vval.v_string;
+	    ml_append_buf(buf, lnum++,
+			       p == NULL ? (char_u *)"" : p, (colnr_T)0, TRUE);
+	}
+}
+
+/*
+ * Add lines to the popup from a list of dictionaries.
+ */
+    static void
+add_popup_dicts(buf_T *buf, list_T *l)
+{
+    listitem_T  *li;
+    listitem_T  *pli;
+    linenr_T    lnum = 0;
+    char_u	*p;
+    dict_T	*dict;
+
+    // first add the text lines
+    for (li = l->lv_first; li != NULL; li = li->li_next)
+    {
+	if (li->li_tv.v_type != VAR_DICT)
+	{
+	    emsg(_(e_dictreq));
+	    return;
+	}
+	dict = li->li_tv.vval.v_dict;
+	p = dict == NULL ? NULL
+			      : dict_get_string(dict, (char_u *)"text", FALSE);
+	ml_append_buf(buf, lnum++,
+			       p == NULL ? (char_u *)"" : p, (colnr_T)0, TRUE);
+    }
+
+    // add the text properties
+    lnum = 1;
+    for (li = l->lv_first; li != NULL; li = li->li_next, ++lnum)
+    {
+	dictitem_T	*di;
+	list_T		*plist;
+
+	dict = li->li_tv.vval.v_dict;
+	di = dict_find(dict, (char_u *)"props", -1);
+	if (di != NULL)
+	{
+	    if (di->di_tv.v_type != VAR_LIST)
+	    {
+		emsg(_(e_listreq));
+		return;
+	    }
+	    plist = di->di_tv.vval.v_list;
+	    if (plist != NULL)
+	    {
+		for (pli = plist->lv_first; pli != NULL; pli = pli->li_next)
+		{
+		    if (pli->li_tv.v_type != VAR_DICT)
+		    {
+			emsg(_(e_dictreq));
+			return;
+		    }
+		    dict = pli->li_tv.vval.v_dict;
+		    if (dict != NULL)
+		    {
+			int col = dict_get_number(dict, (char_u *)"col");
+
+			prop_add_common( lnum, col, dict, buf, NULL);
+		    }
+		}
+	    }
+	}
+    }
+}
+
+/*
  * popup_create({text}, {options})
  */
     void
@@ -128,27 +213,21 @@ f_popup_create(typval_T *argvars, typval
 
     // Add text to the buffer.
     if (argvars[0].v_type == VAR_STRING)
+    {
 	// just a string
 	ml_append_buf(buf, 0, argvars[0].vval.v_string, (colnr_T)0, TRUE);
-    else if (argvars[0].vval.v_list->lv_first->li_tv.v_type == VAR_STRING)
-    {
-	listitem_T  *li;
-	linenr_T    lnum = 0;
-	char_u	    *p;
-
-	// list of strings
-	for (li = argvars[0].vval.v_list->lv_first; li != NULL;
-							      li = li->li_next)
-	    if (li->li_tv.v_type == VAR_STRING)
-	    {
-		p = li->li_tv.vval.v_string;
-		ml_append_buf(buf, lnum++,
-			       p == NULL ? (char_u *)"" : p, (colnr_T)0, TRUE);
-	    }
     }
     else
-	// TODO: handle a list of dictionaries
-	emsg("Not implemented yet");
+    {
+	list_T *l = argvars[0].vval.v_list;
+
+	if (l->lv_first->li_tv.v_type == VAR_STRING)
+	    // list of strings
+	    add_popup_strings(buf, l);
+	else
+	    // list of dictionaries
+	    add_popup_dicts(buf, l);
+    }
 
     // Delete the line of the empty buffer.
     curbuf = buf;
--- a/src/proto/textprop.pro
+++ b/src/proto/textprop.pro
@@ -1,5 +1,6 @@
 /* textprop.c */
 void f_prop_add(typval_T *argvars, typval_T *rettv);
+void prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T *default_buf, typval_T *dict_arg);
 int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
 proptype_T *text_prop_type_by_id(buf_T *buf, int id);
 void f_prop_clear(typval_T *argvars, typval_T *rettv);
--- a/src/screen.c
+++ b/src/screen.c
@@ -4405,7 +4405,10 @@ win_line(
 		char_attr = hl_combine_attr(line_attr, search_attr);
 # ifdef FEAT_TEXT_PROP
 	    else if (text_prop_type != NULL)
-		char_attr = hl_combine_attr(line_attr, text_prop_attr);
+	    {
+		char_attr = hl_combine_attr(
+			line_attr != 0 ? line_attr : win_attr, text_prop_attr);
+	    }
 # endif
 	    else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
 				|| vcol < fromcol || vcol_prev < fromcol_prev
@@ -4429,7 +4432,8 @@ win_line(
 			char_attr = hl_combine_attr(
 						  syntax_attr, text_prop_attr);
 		    else
-			char_attr = text_prop_attr;
+			char_attr = hl_combine_attr(
+						  win_attr, text_prop_attr);
 		}
 		else
 #endif
--- a/src/testdir/dumps/Test_popupwin_02.dump
+++ b/src/testdir/dumps/Test_popupwin_02.dump
@@ -2,9 +2,9 @@
 > +0#0000000#ffffff0@74
 |~+0#4040ff13&| @73
 |~| @6|o+0#0000001#ffd7ff255|t|h|e|r| |t|a|b| @10| +0#4040ff13#ffffff0@46
+|~| @6|a+0#0000001#ffd7ff255| |c+0#ff404010&|o|m@1|e|n|t| +0#0000001&|l|i|n|e| @5| +0#4040ff13#ffffff0@46
 |~| @73
 |~| @73
 |~| @73
 |~| @73
-|~| @73
-|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|c|r|e|a|t|e|(|'|o|t|h|e|r| |t|a|b|'|,| |{|'|l|i|n|e|'|:| |4|,| |'|c|o|l|'|:| |9|}|)| @2|0|,|0|-|1| @8|A|l@1| 
+| +0#0000000&@56|0|,|0|-|1| @8|A|l@1| 
--- a/src/testdir/dumps/Test_popupwin_03.dump
+++ b/src/testdir/dumps/Test_popupwin_03.dump
@@ -7,4 +7,4 @@
 |6| @73
 |7| @73
 |8| @73
-|:|c|a|l@1| |p|o|p|u|p|_|c|r|e|a|t|e|(|'|o|t|h|e|r| |t|a|b|'|,| |{|'|l|i|n|e|'|:| |4|,| |'|c|o| @9|1|,|1| @10|T|o|p| 
+@57|1|,|1| @10|T|o|p| 
--- a/src/testdir/dumps/Test_popupwin_04.dump
+++ b/src/testdir/dumps/Test_popupwin_04.dump
@@ -2,7 +2,7 @@
 |~+0#4040ff13&| @73
 |~| @73
 |~| @6|o+0#0000001#ffd7ff255|t|h|e|r| |t|a|b| @10| +0#4040ff13#ffffff0@46
-|~| @73
+|~| @6|a+0#0000001#ffd7ff255| |c+0#ff404010&|o|m@1|e|n|t| +0#0000001&|l|i|n|e| @5| +0#4040ff13#ffffff0@46
 |~| @73
 |~| @73
 |~| @73
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -14,6 +14,8 @@ func Test_simple_popup()
 	\ "call setline(1, range(1, 100))",
 	\ "hi PopupColor1 ctermbg=lightblue",
 	\ "hi PopupColor2 ctermbg=lightcyan",
+	\ "hi Comment ctermfg=red",
+	\ "call prop_type_add('comment', {'highlight': 'Comment'})",
 	\ "let winid = popup_create('hello there', {'line': 3, 'col': 11, 'highlight': 'PopupColor1'})",
 	\ "let winid2 = popup_create(['another one', 'another two', 'another three'], {'line': 3, 'col': 25})",
 	\ "call setwinvar(winid2, '&wincolor', 'PopupColor2')",
@@ -23,7 +25,12 @@ func Test_simple_popup()
 
   " Add a tabpage
   call term_sendkeys(buf, ":tabnew\<CR>")
-  call term_sendkeys(buf, ":call popup_create('other tab', {'line': 4, 'col': 9})\<CR>")
+  call term_sendkeys(buf, ":call popup_create(["
+	\ .. "{'text': 'other tab'},"
+	\ .. "{'text': 'a comment line', 'props': [{"
+	\ .. "'col': 3, 'length': 7, 'type': 'comment'"
+	\ .. "}]},"
+	\ .. "], {'line': 4, 'col': 9})\<CR>")
   call VerifyScreenDump(buf, 'Test_popupwin_02', {})
 
   " switch back to first tabpage
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -142,23 +142,8 @@ get_bufnr_from_arg(typval_T *arg, buf_T 
     void
 f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
 {
-    linenr_T	lnum;
     linenr_T	start_lnum;
-    linenr_T	end_lnum;
     colnr_T	start_col;
-    colnr_T	end_col;
-    dict_T	*dict;
-    char_u	*type_name;
-    proptype_T	*type;
-    buf_T	*buf = curbuf;
-    int		id = 0;
-    char_u	*newtext;
-    int		proplen;
-    size_t	textlen;
-    char_u	*props = NULL;
-    char_u	*newprops;
-    textprop_T	tmp_prop;
-    int		i;
 
     start_lnum = tv_get_number(&argvars[0]);
     start_col = tv_get_number(&argvars[1]);
@@ -172,7 +157,38 @@ f_prop_add(typval_T *argvars, typval_T *
 	emsg(_(e_dictreq));
 	return;
     }
-    dict = argvars[2].vval.v_dict;
+
+    prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict,
+							  curbuf, &argvars[2]);
+}
+
+/*
+ * Shared between prop_add() and popup_create().
+ * "dict_arg" is the function argument of a dict containing "bufnr".
+ * it is NULL for popup_create().
+ */
+    void
+prop_add_common(
+	linenr_T    start_lnum,
+	colnr_T	    start_col,
+	dict_T	    *dict,
+	buf_T	    *default_buf,
+	typval_T    *dict_arg)
+{
+    linenr_T	lnum;
+    linenr_T	end_lnum;
+    colnr_T	end_col;
+    char_u	*type_name;
+    proptype_T	*type;
+    buf_T	*buf = default_buf;
+    int		id = 0;
+    char_u	*newtext;
+    int		proplen;
+    size_t	textlen;
+    char_u	*props = NULL;
+    char_u	*newprops;
+    textprop_T	tmp_prop;
+    int		i;
 
     if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
     {
@@ -221,7 +237,7 @@ f_prop_add(typval_T *argvars, typval_T *
     if (dict_find(dict, (char_u *)"id", -1) != NULL)
 	id = dict_get_number(dict, (char_u *)"id");
 
-    if (get_bufnr_from_arg(&argvars[2], &buf) == FAIL)
+    if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
 	return;
 
     type = lookup_prop_type(type_name, buf);
@@ -278,12 +294,12 @@ f_prop_add(typval_T *argvars, typval_T *
 	mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
 
 	// Find the index where to insert the new property.
-	// Since the text properties are not aligned properly when stored with the
-	// text, we need to copy them as bytes before using it as a struct.
+	// Since the text properties are not aligned properly when stored with
+	// the text, we need to copy them as bytes before using it as a struct.
 	for (i = 0; i < proplen; ++i)
 	{
 	    mch_memmove(&tmp_prop, props + i * sizeof(textprop_T),
-							       sizeof(textprop_T));
+							   sizeof(textprop_T));
 	    if (tmp_prop.tp_col >= col)
 		break;
 	}
@@ -298,7 +314,7 @@ f_prop_add(typval_T *argvars, typval_T *
 	tmp_prop.tp_flags = (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0)
 			  | (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0);
 	mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop,
-							       sizeof(textprop_T));
+							   sizeof(textprop_T));
 
 	if (i < proplen)
 	    mch_memmove(newprops + (i + 1) * sizeof(textprop_T),
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1407,
+/**/
     1406,
 /**/
     1405,