🥽

Vim scriptでNeovimのvim.ui.selectっぽいセレクトを作る

2022/08/09に公開

Neovimの標準のvim.ui.select()っぽいセレクトメニューを出力するVim scriptをかきました。

utils.vim
function! utils#select(items, opts, on_choice) abort
  let prompt = get(a:opts, 'prompt', 'Select one of:')
  let s:format_item = get(a:opts, 'format_item', {item->item})
  let items = map(a:items[:], {idx,item-> (idx + 1) .. ': ' .. s:format_item(item)})

  let choice = inputlist(insert(items, prompt))

  if choice > 0 && choice <= len(a:items)
    call a:on_choice(a:items[choice-1], choice)
  else
    call a:on_choice(v:null, v:null)
  endif
endfunction

function! utils#handler(item, idx) abort
  # process item and idx
  echo a:item a:idx
endfunction

以下の2つが同じような結果になります。

lua vim.ui.select({'Fire', 'Air', 'Water', 'Earth'}, {}, vim.fn['utils#handler'])
call utils#select(['Fire', 'Air', 'Water', 'Earth'], {}, function('utils#handler'))

即時関数を使うならこんな感じ。

lua vim.ui.select({'Fire', 'Air', 'Water', 'Earth'}, {}, function(item,idx) if idx then vim.api.nvim_echo({{item}}, nil, {}) end end)
call utils#select(['Fire', 'Air', 'Water', 'Earth'], {}, {item,idx->idx != v:null ? execute('echo "' .. item .. '"', '') : ''})

オプションを使うならこんな感じです。

lua vim.ui.select({'Fire', 'Air', 'Water', 'Earth'}, { prompt = 'Select Element:', format_item = function(item) return 'The ' .. item end }, vim.fn['utils#handler'])
call utils#select(['Fire', 'Air', 'Water', 'Earth'], { 'prompt': 'Select Element:', 'format_item': {item->'The ' .. item} }, function('utils#handler'))

vim.ui.selectdressing.nvimなど外部プラグインで拡張できるのが強みなので、Vim scriptで模倣しても同じものができるわけではないのですが、何かの参考になれば。

Discussion