如何提示用户列表中的多个条目?

时间:2017-07-10 17:48:59

标签: vim neovim

我正在开发一个vim插件。配置参数有一组有效选项。我希望用户能够从列表中选择他们想要的选项。

这与inputlist类似,但inputlist仅返回单个所选元素的索引。我更喜欢它返回所有选定元素的索引。

我如何在vim中创建mutliselect?

2 个答案:

答案 0 :(得分:2)

我不确切地知道你想要哪种界面,但是既然你提到了inputlist(),我认为你可以简单地编写一个循环,它的主体会调用它。

也许是这样的:

let options_chosen = []
let options_valid  = [
                     \ 'foo',
                     \ 'bar',
                     \ 'baz',
                     \ 'qux',
                     \ 'norf'
                     \ ]

for i in range(1,len(options_valid))
    let choice = inputlist([ 'Select your options:' ]
                          \ + map(copy(options_valid), '(v:key+1).". ".v:val'))

    if choice >= 1 && choice <= len(copy(options_valid))
        let options_chosen += [copy(options_valid)[choice - 1]]
        let options_valid = filter(options_valid, 'v:val !=# options_chosen[-1]')
    else
        break
    endif

    redraw
endfor

如果您执行此代码,则应该允许您从列表options_valid中选择一个选项。在每次迭代之后,它应该在列表options_chosen中添加所选项,并将其从列表options_valid中删除。循环最初迭代的次数与options_valid中的项目一样多。完成后,您可以点击Escape

来停止循环

它可能不是你想要的,因为我不知道你想向用户呈现什么接口:命令,映射,交互式缓冲......但它可能是一个开始,你可以建立别的东西。

以交互式缓冲区作为界面,我提出了这个:

let s:options_valid = ['foo', 'bar', 'baz', 'qux', 'norf']

com! MultipleOptions call s:multiple_options()

fu! s:multiple_options() abort
    vnew | exe 'vert resize '.(&columns/3)
    setl bh=wipe bt=nofile nobl noswf nowrap
    if !bufexists('Multiple Options') | sil file Multiple\ Options | endif

    sil! 0put =s:options_valid
    sil! $d_
    setl noma ro

    nno <silent> <buffer> <nowait> q     :<c-u>close<cr>
    nno <silent> <buffer> <nowait> <cr>  :<c-u>call <sid>toggle_option()<cr>

    augroup multi_op_close
        au!
        au WinLeave <buffer> call s:close()
    augroup END
endfu

fu! s:close() abort
    let g:selected_options = exists('w:options_chosen')
                           \   ? map(w:options_chosen.lines, 's:options_valid[v:val-1]')
                           \   : []
    au! multi_op_close | aug! multi_op_close
    close
endfu

fu! s:toggle_option() abort
    if !exists('w:options_chosen')
        let w:options_chosen = { 'lines' : [], 'pattern' : '', 'id' : 0 }
    else
        if w:options_chosen.id
            call matchdelete(w:options_chosen.id)
            let w:options_chosen.pattern .= '|'
        endif
    endif

    if !empty(w:options_chosen.lines) && count(w:options_chosen.lines, line('.'))
        call filter(w:options_chosen.lines, "v:val != line('.')")
    else
        let w:options_chosen.lines += [ line('.') ]
    endif

    let w:options_chosen.pattern = '\v'.join(map(
                                 \               copy(w:options_chosen.lines),
                                 \               "'%'.v:val.'l'"
                                 \              ), '|')

    let w:options_chosen.id = !empty(w:options_chosen.lines)
                            \   ? matchadd('IncSearch', w:options_chosen.pattern)
                            \   : 0
endfu

如果执行命令:MultipleOptions,它应该打开一个临时垂直视口,其中应显示存储在列表s:options_valid中的选项。

从那里,您可以点击Enter来选择或取消选择当前行。选择某个选项后,其行将使用突出显示组IncSearch进行着色。

完成后,您可以关闭窗口q,所有选择的选项都应在g:selected_options内。

答案 1 :(得分:2)

lh-vim-lib中,我提供了一个lh#ui#check()功能。其行为类似于文本模式中的confirm()。即我依靠一个破坏状态线的旧技巧。 (这需要使用"\r":redraw等等)

您可以在screencast I've made for lh-tags中看到它。等待“你想要显示哪种?”题。 (在截屏视频中,您应该看到包含CHECKCONFIRMCHOOSE的旧代码

BTW,也可以使用lh-tags中用于选择一个条目的对话框(将tagged参数设置为1)一次选择多个条目。