# HG changeset patch # User Bram Moolenaar # Date 1558907105 -7200 # Node ID 0457d49eb2d9c5a74bb3010f6e1216699ddba69d # Parent 53b2302072d251fa9e4be1296b3aa26b6081864b patch 8.1.1407: popup_create() does not support text properties commit https://github.com/vim/vim/commit/7a8d0278bd6bd57e04f61183cb8e2969cf148e3f Author: Bram Moolenaar 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. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt --- 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* diff --git a/src/popupwin.c b/src/popupwin.c --- 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; diff --git a/src/proto/textprop.pro b/src/proto/textprop.pro --- 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); diff --git a/src/screen.c b/src/screen.c --- 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 diff --git a/src/testdir/dumps/Test_popupwin_02.dump b/src/testdir/dumps/Test_popupwin_02.dump --- 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| diff --git a/src/testdir/dumps/Test_popupwin_03.dump b/src/testdir/dumps/Test_popupwin_03.dump --- 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| diff --git a/src/testdir/dumps/Test_popupwin_04.dump b/src/testdir/dumps/Test_popupwin_04.dump --- 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 diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- 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\") - call term_sendkeys(buf, ":call popup_create('other tab', {'line': 4, 'col': 9})\") + 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})\") call VerifyScreenDump(buf, 'Test_popupwin_02', {}) " switch back to first tabpage diff --git a/src/textprop.c b/src/textprop.c --- 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), diff --git a/src/version.c b/src/version.c --- 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,