26

The latest version of Vim, 8.2, has a new feature called "popups" or "popup windows". They sound interesting but I'm not quite sure what they're good for. Can you enlighten me...preferably with some examples?

  • @MartinTournoij I just noticed the large bounty you've attached. My understanding of bounties was pretty one-dimensional (i.e. it's about attracting additional and/or better answers) but now that I've done some research I think I understand your actual intent (as indicated by your chosen reason and the chosen waiting period) to which I say, "Thanks! That's very generous of you." :) – B Layer Apr 10 at 0:09
  • Ya, I just wanted to add it to your answer. For some reason you still have to wait 24 hours when you fill in "reward existing answer" 🤷‍♂️ I got way too much reputation anyway just because I was active in the early days; I figured I might as well attach them to some exceptional answers as I come across them. – Martin Tournoij Apr 10 at 12:02
  • In the various meta threads I read a lot of people questioned the 24h requirement despite Jeff Atwood's (IMO not very convincing) insistence in one thread that it is necessary. But there were also a number of people who said they like it and, in fact, some choose the full week deferral because it's an added reward for the poster to whom they intend to give the bounty. How? The extra visibility bountied questions/answers get, they reason, can lead to additional votes for the poster that they'd not otherwise receive. Anyways, thanks again! – B Layer Apr 10 at 18:51
34
+500

Background: I was playing around with Vim 8.2's popups recently (I have a small plugin that allows navigation of sections in a markup document and I was looking at showing section hierarchies in popups). I figured the info I collected would make a decent introduction...

Overview

Vim 8.2's popup windows allow Vimscript authors and plugin developers to create one or more floating, modal windows that, among other things, can be used for tool tips, notifications/alerts, dialog boxes and transient menus.

Window and Buffer

Each popup is a Vim window and an associated buffer. The window and buffer have a number of unique characteristics including:

  • Popups cover some or all of vim's regular windows/buffers. They contain no cursor but the cursor in the regular buffer underneath it is visible through the popup window. (For the sake of not losing track of your place, I assume.)
  • Popups can be stacked on top of each other with stacking order determined by value of each windows' zindex attribute.
  • The buffer is not 'buflisted', is 'bufhidden' and has a 'buftype' of "popup".
  • A buffer's initial contents can be specified several ways including by putting the contents in a string or a list of strings. You can also use an existing buffer created with bufadd() (and having a couple other required characteristics).
  • The buffer has no swapfile or undo capability and is not editable by normal means but the content can be modified post-creation with popup_settext().
  • The window/buffer look and feel is highly customizable.

Creation

There are six different functions for creating a popup. That's a lot but only one of them is required, popup_create() and the others are "pre-packaged" configurations with particular purposes. Here they are with brief descriptions (from :h popup-functions):

  • popup_create() - centered in the screen
  • popup_atcursor() - just above the cursor position, closes on mouse move
  • popup_beval() - at pos indicated by v:beval_ variables, closes on mouse move
  • popup_notification() - show a notification for three seconds
  • popup_dialog() - centered with padding and border
  • popup_menu() - prompt for selecting an item from a list

Customization

Text appearance can be controlled with syntax highlighting or using text properties (another major new feature in Vim 8.2...like syntax highlighting except it sticks to associated text as it moves in the buffer). There are also a number of attributes or "options" that control certain other look-and-feel characteristics. This is a sampling of those options.

  • Placement/Size: line, col, pos (e.g. "botright"), maxheight, resize (by mouse), drag (with mouse), minwidth (Note: window height/width is ordinarily based on the width and height of the contained text.)
  • Appearance: padding, border, borderchars, highlight (a la :hi), title, mask (see example below)
  • Behavior: time (until close), callback (function), filter (input processing)

Option values can be defined on creation of a popup window or afterwards through the popup_setoptions() function.

Interaction

A popup's lifetime can be controlled several ways including by timer, upon mouse movement or user input or programmatically with popup_close(). In a pinch, there is the nuclear option popup_clear() that will dismiss any and all existing popups.

How a popup processes user input can be controlled with so-called "filters". There are a couple of builtin filters including the "yesno" filter demonstrated in the examples below.

Each popup can have an assigned callback function. When the popup is closed this function is called with the "result". This is most applicable for popups acting as menus. The result, in that case, is usually just the number of the row that the user selected. We'll see this in action, too, in the examples.

Examples

Let's look at examples of some of the features mentioned above.

Notification

For a time-limited notification popup:

call popup_notification("Get the hell out of Dodge!", #{ line: 5, col: 10, highlight: 'WildMenu', } )

enter image description here

As noted above this will show for three seconds then close.

Menu

Now for a simple menu:

func! MenuCB(id, result)
  echo "You chose item #".a:result
endfunc

call popup_menu(['The quick fox...', '...jumped over...', '...the lazy dogs!'], 
  #{ title: "Well? Pick one", callback: 'MenuCB', line: 25, col: 40, highlight: 'Question', border: [], close: 'click',  padding: [1,1,0,1]} )

enter image description here

Note the added title and padding option to put a little space between the title and side borders and the menu items. Choosing the last row results in...

enter image description here

Yes/No Dialog

In this example we'll use the builtin filter popup_filter_yesno. This will wait until the user has clicked a close key (x or <Esc>) or one of Y, y, N, or n. Yes replies cause the callback to be called with result 1. No sends result 0.

func! YayOrNay(id, result)
  if a:result | echo "You said 'yay'" | endif
endfunc

call popup_dialog('[y]ay or [n]ay?', #{ filter: 'popup_filter_yesno', callback: 'YayOrNay'})

enter image description here

If I choose Y or y the message ("You said 'yay'") will show on the status line.

If you specify your own filter function then you can intercept a subset of key presses, handling them in whatever way you choose and pass the rest on to the generic filter, popup_filter_menu(). There's an example at :h popup-examples.

The Base Case

Let's try the base function, popup_create().

call popup_create(poplist, #{ close: 'click' })

Where poplist begins with: [' 1 Vim Launch and App Startup', ' 2 General Use (Editing)', ' 3 Auto Commands', ' 4 Scripting', ' 5 Syntax and Basics', ' 6 Variables', ' 7 Windows', ...etc...]. The idea here was to see what a hierarchical menu (i.e. having depth > 1) would look like.

enter image description here

This is what a popup with all default options looks like (not counting the close: 'click' option so I had an easy way to dismiss it): positioned in the middle of the window, no borders, dimensions dictated by the contained text.

The Z-Index and Masking

Finally, let's see the z-index functionality and, for amusement mostly, demonstrate the mask attribute. With 'mask' you can specify popup coordinates and those sections of the popup will be rendered as transparent. I've not thought of a totally practical use for this yet so here I just cut off a couple corners and poked a couple big holes in the thing.

call popup_create(poplist, #{ zindex: 20, line: 5, col: 20, close: 'click',
  mask: [[1, 10, 1, 3], [-10, -4, 3, 5], [10, 23, -5, -2], [-10, -1, -3, -1]] })

enter image description here

Normally one would expect additional popups to be placed over existing ones. But by specifying a lower value for the zindex attribute....

call popup_create(poplist, #{ zindex: 10, line: 7, col: 25, close: 'click', highlight: 'CursorLine' })

...we can make it a pop-under:

enter image description here

(The garish pink? That's the default color for popups in many color schemes. :p A lot of auto-completion users probably recognize it.)

Other Features

Okay, hopefully that gives everyone a good feeling for what popups are capable of. There are certainly some features I haven't covered or only mentioned briefly including:

  • Asynchronous content fill-in
  • Popup manipulation functions (e.g. popup_move(), popup_setoptions())
  • User-defined filters
  • Key mappings
  • Running a terminal in a popup window

To learn more about those and everything else popup related visit the dedicated 1000+ line chapter in the Vim help docs with :h popups.

| improve this answer | |
  • 1
    That markdown outline jumping thing sounds useful... i’d love to stay posted on its development – D. Ben Knoble Apr 5 at 14:21
  • 3
    @D.BenKnoble I created it for myself but I can share it if it reaches an appropriate level of stability/usability. Note, though, that I said markUP. Specifically, I use asciidoc(tor) which is similar to but much more powerful than markdown. – B Layer Apr 5 at 22:37
  • 1
    Awesome answer! Good to see so many examples – mowwwalker Apr 6 at 17:45
  • 1
    @MaximKim Looks like we're working on similar things. Add scrollbar: 1 to the option map when you call popup_create and a scrollbar will be there if the text doesn't fit. I haven't tried them yet because even my largest asciidoctor doc, which would probably render out to 150 printed pages (I should write a book) has "only" 19 top-level sections. I do have a huge monitor and use tall windows, to be fair. – B Layer Apr 8 at 20:02
  • 1
    @D.BenKnoble The markup section navigator thingy works nicely with popups. I had to add custom key handler so numbers can be used to select sections (by default you get nothing more than Up/Down or j/k which sucks with 40 or more sections) I'm digging it and use it every day. Probably a while yet until I share it...todo list is still long...but I almost certainly will. – B Layer May 10 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.