I'm tinkering with popups and trying to open one, select a line (namely set the cursor line by pressing mapped keys (Ctrln / Ctrlp)), then close it. The problem is that I cannot select a line, despite the setpos function's doc says that one can use it to set the cursor line in another buffer and that the setpos function returns 0 if the cursor line can be set (I checked it with echo setpos(…), it returned 0):

Returns 0 when the position could be set, -1 otherwise. An error message is given if {expr} is invalid.

When I press Ctrln to set the line, it is set in the current buffer, not in the popup one and the cursorline highlighting is not changed in the popup window.

This is the screen shot and below is the script:

screen shot of the popup

let s:popup_content = ['line one',
  \'line one',
  \'line three']
let s:popup_win_id = v:none
let s:popup_buf_id = v:none
let s:cur_line = 1

function! Omni_create()
  let s:popup_win_id = popup_create(s:popup_content,
      \pos: 'botleft',
      \line: 'cursor-1',
      \col: 'cursor',
      \title: 'some ttl:',
      \cursorline: 1,
  let s:popup_buf_id = winbufnr(s:popup_win_id)
  noremap <Esc> :call Omni_delete()<CR>
  noremap <C-N> :call Omni_cursor_next()<CR>
  "noremap <C-P :call Omni_cursor_prev()<CR>

function! Omni_delete()
  call popup_close(s:popup_win_id)
  unmap <Esc>
  unmap <C-N>
  "unmap <C-P>
  normal gi

function! Omni_cursor_next()
  let s:cur_line += 1
  "everything is echoed correctly
  echo 'here'
  echo s:cur_line
  echo s:popup_buf_id
  call setpos('.', [s:popup_buf_id, s:cur_line, 1, 0])

inoremap <C-X><C-O> <Esc>:call Omni_create()<CR>

So could anyone please suggest how can I approach this? Either what's being wrong with the setpos function or should I use something different?

  • 1
    If you want to scroll in a popup use win_execute() + :norm!. You may also need to reset the firstline key.
    – user938271
    Jun 1, 2020 at 13:08
  • I think popup_menu does what you want.
    – Ralf
    Jun 1, 2020 at 14:01

1 Answer 1


Your example is trying to mimic popup menu by popup window, it's complicate, I changed it to use arrow keys to scroll popup window in normal mode, it's only purpose is to show you how to change cursor in popup window:

noremap <buffer> <down> :call Omni_cursor(1)<CR>
noremap <buffer> <up> :call Omni_cursor(0)<CR>
noremap <buffer> <C-x><c-o> :call Omni_create()<CR>

function Omni_create()
  let d = #{ pos: 'botleft', line: 'cursor-1', col: 'cursor',
        \    title: 'some ttl:', cursorline: 1, maxheight: 3, }
  let s:popup_win_id = popup_create(map(range(10), {i,v->string(v)}), d)

" scroll popup window, change current line
function Omni_cursor(down)
  call win_execute(s:popup_win_id, a:down ? '+' : '-')
  call popup_setoptions(s:popup_win_id, #{cursorline: 1})
  call win_execute(s:popup_win_id, 'let l:line = getline(".")')
  call setline('.', line)

" for debug purpose
call popup_clear()

All map is in created in normal mode.

Popup window won't change your current buffer, so setpos won't work, you need to use win_execute.

Another thing about popup window is you might need to change a property to trigger redraw, above program reset 'cursorline' option to trigger redraw everytime you scroll.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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