New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[discuss] Popup Window API design. #4063
Comments
Few more things I would like to add.
|
@skywind3000: you may correct this statement:
See r/vim/comments/discuss_vim_popup_window_api_design#comment. |
Possible implementation for GVim and Vim: For Windows, create a layered child window on the top of For terminal, ncurses has overlapping windows and panels. I don't know if they can be used because I have never used ncurses. |
Currently, nvim support floating window! |
webview is crazy great |
@iamcco @prabirshrestha Webview is too big for vim, GVim needs to include at least 20MB dynamic libraries to support webview. You can check the binary size of CEF or Electron. The webview can be implemented in a separated process, and attach to GVim's main window. |
By webview I mean the OS default browser that is for Mac it would be safari and windows IE. Not sure about Linux. But if it isn’t portable then not worth it. Or if one could make a markdown renderer that would also be great. |
I think it is very important that the implementation is super simple (KISS) and NOT super feature rich. We need only the basic overlay with just the proposed controls and new highlight groups and then the users are free to use it for various stuff. There will be many new ideas, you'll see. |
Prefer text ui, not webview. |
For the plugin writers' sanity sake, we should really try to make our implementation's API as close to neovim's as possible. Though, that's a little hard at the moment, considering that neovim's documentation isn't available just yet. |
@bstaletic I'm working on it here neovim/neovim#9669, though I need adjust the script to show the indented text in nvim_open_win() correctly, so currently that part can be read here. Edit: initial documentation is on master, see |
Found another RFC by @puremourning: |
That RFC has been updated in my vim fork: https://github.com/bstaletic/vim/tree/current_argument_update |
As part of https://github.com/myitcv/govim I'd like to see development in this area. One of the key use cases is signature help. That is, when the user is in the middle of typing an expression that represents a function/method call, signature help reminds them of the function/method's signature, which parameter they are currently providing etc. Some users will prefer this sort of detail in the status line. Others, particularly those perhaps more used to things like VSCode, will appreciate the option of a balloon-like presentation of the signature help immediately above/below the relevant position. Highlighting support would be a bonus, not least because it can be used to show the current parameter. (Highlighting support in balloons would also be useful too) @brammool - what are your thoughts on this space in general? |
@myitcv reminder that you have all that available in neovim master/nightly, with coc.nvim making use of it for quite a while already. I find the govim's approach regarding adopting Vim8-only late remote API instead of NeoVim's one (and producing/using a wrapper over it for Vim8) kinda... strange. Is it worth it? I see even @Shougo preferring the latest approach with his plugins, even despite he being the original author of Vim's remote API implementation, if I recall correctly. I think the remote API feature is one hard-to-borrow idea if you simply dismiss implementing it in a compatible way, and since NeoVim took the lead, I've seen many authors leveraging its remote API before Vim came with its own, unrelated one, that's of no use for the already existing remote plugins in NeoVim-land. Reason why I hardly see any Vim8-only remote plugin around. |
@oblitum - I'd be happy to continue the conversation about |
I have added a detailed design in patch 8.1.1329. Feel free to comment. |
Regarding the API, i'm a strong believer in "write the usage code first", i.e. you can't really know if the API works without some practical code which uses it. Bram, if you have a toy or POC implementation of the proposed API, i am more than willing to rewrite our my RFC demo to use it and let you know how it goes ? But on the face of it, your proposed API does seem to be a superset of what i proposed in that RFC. In my original proposal i said this(;
For some reason i recall that i wanted to set the text, then display it separately. Maybe this was just implementation convenience, but perhaps it would make sense to allow |
I guess that was your idea at some point, but you also scrapped it and didn't end up using it in the actual code for the RFC mentioned, because you also had:
Your branch didn't use |
OK then, carry on... :) |
Your paperclip design is awesome! |
I was wondering about mouse clicks. We can probably do this: A mouse click arrives as . The coordinates are in |
See a discussion about using a buffer instead of a List of lines: https://groups.google.com/forum/#!topic/vim_dev/6RXkRnhpMNM |
I think, it's better to merge floating window feature from neovim. |
@brammool Thank you for the quick response.
Yes, the whole section of the screen is drawn by fzf. It's a generic text filter with |
What about a new which will execute command in a dedicated popup window and returns after command exit. Not flexible I know, but enough for tools like fzf. |
What about a new `!` command ? for example `!!`, which will execute
command in a dedicated popup window and returns after command exit.
Not flexible I know, but enough for tools like fzf.
That starts looking like something you should do with a new terminal,
not inside Vim:
:!xterm -c "your command"&
I was only thinking of the use case of a dialog to select a file, where
the dialog can have keyboard focus until it's closed. Popup windows are
intended for that, but so far excluding using a terminal window.
…--
This is an airconditioned room, do not open Windows.
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
This would be great to have! |
If we have this topmost terminal popup window, maybe we can get |
Hi @brammool thanks for Vim! Just to +1 @junegunn comment above, I need some way to use a I absolutely love the API you've designed with Happy new year! |
@brammool , I am trying to simulate this, by calling function! PopupBuffer(bid)
let opts = {'mapping':0, 'close':'button'}
let opts.filter = 'PopupFilter'
let opts.title = ' POPUP '
let opts.border = [1,1,1,1,1,1,1,1,1]
let winid = popup_create(a:bid, opts)
let opts = {"minwidth":20, "minheight":5, "maxwidth":20, "maxheight":5}
call popup_move(winid, opts)
call popup_show(winid)
endfunc
function! PopupFilter(winid, key)
let bid = winbufnr(a:winid)
if a:key == "\<c-x>"
call popup_close(a:winid, 0)
return 1
endif
echo "key: ".a:key
call term_sendkeys(bid, a:key)
return 1
endfunc
term
let bid = bufnr('')
wincmd p
call PopupBuffer(bid) But it displays:
Can we just remove this restriction ? and I can send keys to a hidden terminal from my popup filter. |
It is now possible to run a terminal in a popup window. First create the terminal buffer hidden, then create a popup for that buffer. |
@brammool , I tried it but the popup can not be closed when terminal job finished: let w = 80
let h = 24
let opts = {'hidden': 1, 'term_rows':h, 'term_cols':w}
let opts.term_kill = 'term'
let opts.norestore = 1
let bid = term_start(['bash'], opts)
let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h}
let opts.wrap = 0
let opts.mapping = 0
let opts.title = 'popup-terminal'
let opts.close = 'button'
let opts.border = [1,1,1,1,1,1,1,1,1]
let opts.drag = 1
let opts.resize = 0
let winid = popup_create(bid, opts) save this to the terminal popup should be closed, but it remains there and in the terminal-normal mode. I tried to add a
Also, I can use |
@brammool use |
When I create a terminal in a popup window, |
FWIW, I inspect the output of I consider the current window as a popup window if and only if it's not empty. But I like your suggestion of setting |
diff --git a/src/popupwin.c b/src/popupwin.c
index 714f457fe..32adb7935 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -1826,6 +1826,11 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
win_init_popup_win(wp, buf);
set_local_options_default(wp, FALSE);
buffer_ensure_loaded(buf);
+#ifdef FEAT_TERMINAL
+ if (buf->b_term != NULL)
+ set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1,
+ (char_u *)"popup-terminal", OPT_FREE|OPT_LOCAL, 0);
+#endif
}
else
{ |
I've noticed that
But I had some issues because of it; some of my terminal-specific configurations were applied to regular buffers, because I didn't think it was necessary to inspect |
Don't use What you need to detect is I have implemented a I am editing |
@brammool , I tried it but the popup can not be closed when terminal job finished:
```VimL
let w = 80
let h = 24
let opts = {'hidden': 1, 'term_rows':h, 'term_cols':w}
let opts.term_kill = 'term'
let opts.norestore = 1
Add term_finish "close" here.
let bid = term_start(['bash'], opts)
let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h}
let opts.wrap = 0
let opts.mapping = 0
let opts.title = 'popup-terminal'
let opts.close = 'button'
let opts.border = [1,1,1,1,1,1,1,1,1]
let opts.drag = 1
let opts.resize = 0
let winid = popup_create(bid, opts)
```
save this to `test.vim` and `so test.vim` in vim 8.2.0200, than type `exit` in the popup terminal.
the terminal popup should be closed, but it remains there.
Typing ":quit" works, right?
…--
How To Keep A Healthy Level Of Insanity:
8. Don't use any punctuation marks.
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
Okay, got it. So what's the correct way to detect a popup window after all? I think I just want to expose |
Can't you simply use a |
@brammool , yes, using a let w = 80
let h = 24
let opts = {'hidden': 1, 'term_rows':h, 'term_cols':w}
let opts.term_kill = 'term'
let opts.norestore = 1
let opts.exit_cb = 'OnTermExit'
let bid = term_start(['bash'], opts)
function! OnTermExit(job, message)
close
" TODO: add some code to confirm that current window is a popup.
" TODO: prevent close other window by accident.
endfunction
let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h}
let opts.wrap = 0
let opts.mapping = 0
let opts.title = 'popup-terminal'
let opts.close = 'button'
let opts.border = [1,1,1,1,1,1,1,1,1]
let opts.drag = 1
let opts.resize = 0
let winid = popup_create(bid, opts) It works as expected now. |
This also works:
But I cannot get the exit code. using a |
FWIW, I would go with |
When I create a terminal in a popup window, `&buftype` is set to
`terminal` (consider `autocmd WinEnter * echom 'WinEnter: ' .
&buftype`). Should it be `popup-terminal` or something)? How can we
detect popup windows (including a terminal in popup) since there're
many limitations in the popup window.
Adding a 'wintype' option would pair with 'buftype', but since it's not
an option you can set, would give the wrong idea.
Adding win_ispopup() would work, but perhaps it's better to use
win_type() and return "popup". We can then use it for other types as
well. But we don't need to duplicate what is already in 'buftype.
One that comes to mind is the command line window, which is another
specialy one.
So if 'buftype' is "terminal" and win_type() returns "popup" you have a
terminal running in a popup window. Makes sense?
…--
How To Keep A Healthy Level Of Insanity:
16. Have your coworkers address you by your wrestling name, Rock Hard Kim.
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
@brammool, the The popup terminal can be more useful if it can be temporary hidden or shown. (or the relative popup window can be closed and recreated). An efficient workflow will be possible if so:
It can make me really productive if the terminal popup can be toggled on/off swiftly by But sadly, I found both |
This issue was closed, please create a new issue for new items to discuss. |
This is not an issue, but I have no idea how to attach images in
vim_dev
group. So forgive me create this post in the issues and it can be closed immediately.The human readable page is here:
https://github.com/skywind3000/vim-proposal/blob/master/popup_window.md
Popup Window API Proposal
Problem
Vim has already got some builtin popup-widgets for certain usage, like completion menu or balloon. But users and plugin authors are still asking for more:
In Vim conf 2018, Bram claimed that he has plan for this already:
Summary, there are two types of popup window: interactive and non-interactive.
For non-interactive popup windows, people want to use them to:
For interactive popup windows, people want to use them to:
There are too many popup-related widgets for certain usage, designing one by one is nearly impossible.
Implementing a neovim's floating window will take too much time (it is working in progress for almost 2-years and still not merge to master).
Can we implement the popup window in a simple and adaptive way ? Is this possible to unify all their needs and simplify API design ?
The following parts of this article will introduce an
overlay
mechanism similar to Emacs's text overlay which is the backend of various popup windows in Emacs.API Scope
Popup windows will draw into an overlay layer, A popup will remain after creation until an
erase
function is called. Everything in the overlay will not interfere vim's states, people can continue editing or using vim commands no matter there is a popup window or not.So, the APIs are only designed for drawing a popup window and has nothing to do with user input. Dialogs like
yes/no
box and confirm box require user input, can be simulated with following steps:Popup window APIs is not responsible for any interactive functionalities. Instead of implementing a complex widget/event system (which is too complex), it is sane to let user to handle the input by
getchar()
.There can be a
popup.vim
script contains some predefined popup windows/dialogs and will be shipped with vim itself. User can use the primitive APIs andgetchar()
to implement other complex dialogs like a popup fuzzy finder or a command line history completion box.Overlay Buffer
The overlay buffer is a character matrix with the same size of the screen:
Similar to Video Buffer (0xb8000) in x86's text mode, the overlay buffer is a 2D array of characters and attributes. Change the content of the 2D array will change the text in the screen.
The overlay buffer is invisible by default and can be enabled by:
Every existent text rendering code in both Vim & GVim needs to be updated to support this overlay buffer, once it finished, we can use it to build powerful popup windows.
There are also some basic APIs for overlay buffer:
redrawoverlay
to update the overlay (it uses double buffer to prevent flicker).With these primitive APIs, user can draw what ever they like on the overlay buffer.
Overlay Panes
Overlay panes is an abstraction of the popup windows, it consists of:
There can be multiple panes at the same time, the panes can be manipulated by:
(PS: they are provided as both C-apis and vim functions).
The life cycle of a pane is between
pane_create
andpane_destroy
.The (row, col) is using screen coordinate system, and there can be some functions to convert window based coordinate system to screen coordinate system. If you want to display a popup balloon right above your cursor, you can use them to calculate the position.
Finally, there is a function to render the pane list into the overlay buffer:
pane_flush();
If you create some panes, the
overlay buffer
will not change untilpane_flush()
.Popup Windows
All the common popup windows are implemented in
popup.vim
script, they will usepanes
to display a popup window andgetchar()
to provide interactive functionalities.There are some predefined popup windows:
<cword>
.getchar()
to receive user input) and quit after user select an item.yes/no
box and return the result after user made a selection.User or plugin authors can use the high level APIs provided by
popup.vim
or design their own popup window by utilizing lower level pane APIs or overlay APIs.Summary
It is complex to design an event system or NeoVim's floating window, and nearly impossible to implement every type of popup window for certain usage.
To unify and simplify the interface, this proposal suggests to provide an overlay mechanism with some primitive APIs to:
And let user handle input themself by
getchar()
. At last, makes it possible to enable users to create various popup windows with different styles and functionalities.--
2019/3/2 edit: floating window got merged to master.
The text was updated successfully, but these errors were encountered: