I have written a function that will, given a directory and a title, display a popup with all the files contained in that folder:
function! ListFiles(dir, title)
let l:dir = a:dir
let l:title = a:title
let l:files = glob(l:dir . '/*', 0, 1)
let l:file_list = []
for l:file in l:files
call add(l:file_list, fnamemodify(l:file, ':t'))
endfor
" Define custom highlight groups
highlight PopupMenu guifg=#ffffff guibg=#333333 ctermfg=white ctermbg=darkred
highlight PopupMenuSelected guifg=#000000 guibg=#ffff00 ctermfg=black ctermbg=yellow
" Create a popup menu with the file list
let l:selected_file = popup_menu(l:file_list, {
\ 'title': ' ' . l:title . ' ',
\ 'callback': 's:HandleFileSelection',
\ 'line': &lines / 2,
\ 'col': &columns / 2,
\ 'highlight': 'PopupMenu',
\ 'border': [],
\ 'close': 'click',
\ 'padding': [1, 2, 1, 2],
\ 'mapping': 0,
\ 'filter': 'popup_filter_menu',
\ 'wrap': 0
\ })
" Define a function to handle the selection
function! s:HandleFileSelection(id, result)
let l:file_name = ""
if a:result != -1
let l:file_name = getbufline(winbufnr(a:id), a:result)[0]
endif
echom "FOO.".l:selected_file
return l:file_name
endfunction
" Return file
echom "BAR.".l:selected_file
return l:selected_file
endfunction
However, when I run it, I can see that BAR...
message is displayed (with a number) before FOO...
message appears (with the selected file) once you press enter on an item.
So it seems that the code first executes the return of the ListFiles
function and then the one at the handler.
Why is this happening? Which would be the way to just get a single return with the selected item?
Well, that's how it works. No matter if calling popup_menu
or popup_dialog
, the only difference is due to filter
function that can consume all user input while popup_menu
is still active. However, there is no modal loop there.
What to do? Just return immediately and continue execution inside the callback function.