Skip to content
Browse files

patch 8.1.1928: popup windows don't move with the text when making ch…


Problem:    Popup windows don't move with the text when making changes.
Solution:   Add the 'textprop" property to the popup window options, position
            the popup relative to a text property. (closes #4560)
            No tests yet.
  • Loading branch information...
brammool committed Aug 25, 2019
1 parent 307c5a5 commit 12034e22dd80cf533ac1c681be521ab299383f63
Showing with 418 additions and 96 deletions.
  1. +82 −0 runtime/doc/popup.txt
  2. +6 −4 src/move.c
  3. +261 −90 src/popupwin.c
  4. +1 −0 src/proto/
  5. +1 −0 src/proto/
  6. +2 −0 src/proto/
  7. +11 −2 src/structs.h
  8. +48 −0 src/textprop.c
  9. +2 −0 src/version.c
  10. +4 −0 src/window.c
@@ -16,6 +16,7 @@ Displaying text in a floating window. *popup* *popup-window*
3. Usage |popup-usage|
popup_create() arguments |popup_create-arguments|
Popup text properties |popup-props|
Position popup with textprop |popup-textprop-pos|
Popup filter |popup-filter|
Popup callback |popup-callback|
Popup scrollbar |popup-scrollbar|
@@ -325,6 +326,9 @@ popup_getoptions({id}) *popup_getoptions()*
the current tabpage and a positive number for a popup on
another tabpage.

"textprop", "textpropid" and "textpropwin" are only present
when "textprop" was set.

If popup window {id} is not found an empty Dict is returned.

@@ -507,17 +511,29 @@ The second argument of |popup_create()| is a dictionary with options:
the line of the cursor and add or subtract a number of
lines. If omitted the popup is vertically centered.
The first line is 1.
When using "textprop" the number is relative to the
text property and can be negative.
col Screen column where to position the popup. Can use a
number or "cursor" to use the column of the cursor,
"cursor+9" or "cursor-9" to add or subtract a number
of columns. If omitted the popup is horizontally
centered. The first column is 1.
When using "textprop" the number is relative to the
text property and can be negative.
pos "topleft", "topright", "botleft" or "botright":
defines what corner of the popup "line" and "col" are
used for. When not set "topleft" is used.
Alternatively "center" can be used to position the
popup in the center of the Vim window, in which case
"line" and "col" are ignored.
textprop When present the popup is positioned next to a text
property with this name and will move when the text
property moves. Use an empty string to remove. See
textpropwin What window to search for the text property. When
omitted or invalid the current window is used.
textpropid Used to identify the text property when "textprop" is
present. Use zero to reset.
fixed When FALSE (the default), and:
- "pos" is "botleft" or "topleft", and
- "wrap" is off, and
@@ -670,6 +686,72 @@ So we get:


Positioning a popup next to a text property causes the popup to move when text
is inserted or deleted. The popup functions like a tooltip.

These steps are needed to make this work:

- Define a text property type, it defines the name. >
call prop_type_add('popupMarker', {})

- Place a text property at the desired text: >
let lnum = {line of the text}
let col = {start column of the text}
let len = {length of the text}
let propId = {arbitrary but unique number}
call prop_add(lnum, col, #{
\ length: len,
\ type: 'popupMarker',
\ id: propId,
\ })

- Create a popup: >
let winid = popup_create('the text', #{
\ pos: 'botleft',
\ textprop: 'popupMarker',
\ textpropid: propId,
\ border: [],
\ padding: [0,1,0,1],
\ close: 'click',
\ })

By default the popup is positioned at the corner of the text, opposite of the
"pos" specified for the popup. Thus when the popup uses "botleft", the
bottom-left corner of the popup is positioned next to the top-right corner of
the text property:
| the text |
just some PROPERTY as an example

Here the text property is on "PROPERTY". Move the popup to the left by
passing a negative "col" value to popup_create(). With "col: -5" you get:

| the text |
just some PROPERTY as an example

If the text property moves out of view then the popup will be hidden.
If the window for which the popup was defined is closed, the popup is closed.

If the popup cannot fit in the desired position, it may show at a nearby

Some hints:
- To avoid collision with other plugins the text property type name has to be
unique. You can also use the "bufnr" item to make it local to a buffer.
- You can leave out the text property ID if there is only ever one text
property visible.
- The popup may be in the way of what the user is doing, making it close with
a click, as in the example above, helps for that.
- If the text property is removed the popup is closed. Use something like
this: >
call prop_remove(#{type: 'popupMarker', id: propId})

POPUP FILTER *popup-filter*

A callback that gets any typed keys while a popup is displayed. The filter is
@@ -1179,12 +1179,12 @@ curs_columns(

#if defined(FEAT_EVAL) || defined(PROTO)
#if (defined(FEAT_EVAL) || defined(FEAT_TEXT_PROP)) || defined(PROTO)
* Compute the screen position of text character at "pos" in window "wp"
* The resulting values are one-based, zero when character is not visible.
static void
win_T *wp,
pos_T *pos,
@@ -1213,12 +1213,12 @@ textpos2screenpos(
col += off;
width = wp->w_width - off + win_col_off2(wp);

/* long line wrapping, adjust row */
// long line wrapping, adjust row
if (wp->w_p_wrap
&& col >= (colnr_T)wp->w_width
&& width > 0)
/* use same formula as what is used in curs_columns() */
// use same formula as what is used in curs_columns()
rowoff = ((col - wp->w_width) / width + 1);
col -= rowoff * width;
@@ -1236,7 +1236,9 @@ textpos2screenpos(
*ccolp = ccol + coloff;
*ecolp = ecol + coloff;

#if defined(FEAT_EVAL) || defined(PROTO)
* "screenpos({winid}, {lnum}, {col})" function

0 comments on commit 12034e2

Please sign in to comment.
You can’t perform that action at this time.