vital.vim icon indicating copy to clipboard operation
vital.vim copied to clipboard

[WIP] add popup support

Open prabirshrestha opened this issue 5 years ago • 5 comments

PR for https://github.com/vim-jp/vital.vim/issues/747. This PR is at a very early stage so will need lot of revisions but starting a thread so folks can start contributing and looking at it and provide feedback.

Goal is to have a consistent api that works on both vim and neovim. It is also meant to be very dumb api where other powerful popup manager can be built on top. It is also meant to easily work with lua apis hence it uses id

  • [ ] documentation
  • [ ] tests
  • [x] new({}) to create popup
  • [x] close(id)
  • [x] pos: 'topleft|topright|bottomleft|bottomright|topcenter|bottomcenter'
  • [x] hide(id)
  • [x] show(id)
  • [x] contents(['line1', 'line2']) to update popup text
  • [ ] border support
  • [ ] custom border chars support
  • [x] add options() to move, resize popup.
  • [ ] scrollbars??
  • [ ] title
  • [x] fixed width/height
  • [ ] max/min width/height
  • [ ] auto width/height
  • [ ] custom buffer settings such as linenumbers/syntax onoff/wrap onoff
  • [ ] terminals are special ... and many more... feel free to suggest

Events

  • [x] create event
  • [x] close event
  • [x] hide event
  • [x] show event
  • [x] options event
  • [ ] add before and after events. either beforeshow aftershow or preshow postshow.
let s:V = vital#vital#new()
let s:Popup = s:V.import('Experimental.UI.Popup')

let s:id = s:Popup.create({
    \ 'contents': ['This', 'is', 'a', 'line'],
    \ 'w': 5,
    \ 'h': 5,
    \ 'x': 1,
    \ 'y': 1,
    \ 'pos': 'topleft',
    \ })

call timer_start(2000, {->s:Popup.close(s:id)})

prabirshrestha avatar Jun 28 '20 06:06 prabirshrestha

Since neovim and vim using different position. I'm now using x, y instead. Also added support for pos: 'topleft|topright|bottomleft|bottomright|topcenter|bottomcenter'.

Simple way to check the position is using this file.

A0123456789
B0123456789
C0123456789
D0123456789
E0123456789
F0123456789
G0123456789
H0123456789
I0123456789
J0123456789

Then run this code

let s:V = vital#vital#new()
let s:Popup = s:V.import('Experimental.UI.Popup')

call s:Popup.create({
    \ 'contents': ['XXXX', 'XXXX', 'XXXX', 'XXXX'],
    \ 'w': 4,
    \ 'h': 4,
    \ 'x': 5,
    \ 'y': 5,
    \ 'pos': 'topcenter',
    \ })

call cursor(5, 5)

Here is how topcenter looks like. Cursor is at E3 and X is the popup contents.

image

prabirshrestha avatar Jun 30 '20 20:06 prabirshrestha

Added support for events. One can use either generic on_event where all events are fired if it exists or register to specific events by explicitly prefixing with on_* where * is the event name.

function! s:on_event(id, data, event) abort
    echom a:event
endfunction

let s:pid = s:Popup.create({
    \ 'contents': ['XXXX', 'XXXX', 'XXXX', 'XXXX'],
    \ 'w': 4,
    \ 'h': 4,
    \ 'x': 5,
    \ 'y': 5,
    \ 'pos': 'topcenter',
    \ 'on_create': {id, data, event->timer_start(2000, {->s:Popup.close(id)})},
    \ 'on_event': function('s:on_event'),
    \ })

Feel free to review the code.

prabirshrestha avatar Sep 19 '20 20:09 prabirshrestha

added contents() api to change the contents of the popup and options() api to move and resize the popup. https://asciinema.org/a/360796 popup resize and move

let s:V = vital#vital#new()
let s:Popup = s:V.import('Experimental.UI.Popup')

function! s:update(id) abort
    call s:Popup.contents(a:id, ['hello', 'world'])
    call s:Popup.options(a:id, { 'w': 10, 'h': 10, 'x': 2, 'y': 2 })
    call timer_start(2000, {->s:Popup.hide(a:id)})
endfunction

function! s:on_event(id, data, event) abort
    if a:event ==# 'show'
        call timer_start(1000, {->s:update(a:id)})
    endif
endfunction

let s:pid = s:Popup.create({
    \ 'contents': ['XXXX', 'XXXX', 'XXXX', 'XXXX'],
    \ 'w': 4,
    \ 'h': 4,
    \ 'x': 5,
    \ 'y': 5,
    \ 'pos': 'topcenter',
    \ 'on_event': function('s:on_event'),
    \ })

prabirshrestha avatar Sep 20 '20 19:09 prabirshrestha

I'm now using x, y instead

x and y with respect to? Starts from 0 or 1 or something else?

E.g. in neovim, the indexing for window placement starts from (0, 0) (which is how I represent ('width', 'height') ) and that represents the top-left corner of the screen.

In the same way, which corner of the screen do you start your co-ordinates from, and what value it starts from? Also, just being sure, by x you mean the width, right? And y for height?

Just for clarity

subnut avatar Oct 23 '20 18:10 subnut

Currently I use _user_to_editor_xy to normalize with different editors. I personally do not have strong opinion on if we want to use vim or neovim position. We should stick with one. I have been trying to make the api either complelty like vim or neovim so I can tell someone to just go and read one of those docs and should be simple. for example xy starts with 1 in vim so I chose pos as topleft. I will document this in code so it is easy to follow.

x is width and y is height. If you have better suggestions let me know. vim uses line and col. this was one exception I did with the above rule I mentioned since line and col sounds as if we can't have a popup above status line and only applies to inside a buffer..

prabirshrestha avatar Oct 24 '20 02:10 prabirshrestha