如何提示用户输入列表中的多个条目?
How to prompt a user for multiple entries in a list?
我正在开发 vim 插件。配置参数有一组有效选项。我希望用户能够 select 从列表中选择他们想要的选项。
这类似于inputlist
,但是inputlist
只是return单个选择元素的索引。我更喜欢 return 所有选定元素的索引。
如何在 vim 中创建 mutliselect?
我不知道您具体想要哪种接口,但既然您提到了 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
到 select 或取消 select 当前行。当一个选项被 selected 时,它的行用高亮组 IncSearch
.
着色
完成后,您可以关闭 window 点击 q
,您选择的所有选项都应该在 g:selected_options
.
内
在 lh-vim-lib 中,我提供了一个 lh#ui#check()
函数来执行此操作。它的行为类似于文本模式下的 confirm()
。也就是说,我依赖于破解状态线的老把戏。 (这个需要玩"\r"
,:redraw
等等)
您可以在 screencast I've made for lh-tags 中实时看到它。等待"Which kinds to you wish to display?"问题。 (在截屏视频中,您应该看到带有 CHECK
、CONFIRM
和 CHOOSE
的旧代码)
顺便说一句,lh-tags 中用于选择一个条目的对话框也可以用于(将 tagged
参数设置为一个)一次 select 多个条目。
我正在开发 vim 插件。配置参数有一组有效选项。我希望用户能够 select 从列表中选择他们想要的选项。
这类似于inputlist
,但是inputlist
只是return单个选择元素的索引。我更喜欢 return 所有选定元素的索引。
如何在 vim 中创建 mutliselect?
我不知道您具体想要哪种接口,但既然您提到了 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
到 select 或取消 select 当前行。当一个选项被 selected 时,它的行用高亮组 IncSearch
.
完成后,您可以关闭 window 点击 q
,您选择的所有选项都应该在 g:selected_options
.
在 lh-vim-lib 中,我提供了一个 lh#ui#check()
函数来执行此操作。它的行为类似于文本模式下的 confirm()
。也就是说,我依赖于破解状态线的老把戏。 (这个需要玩"\r"
,:redraw
等等)
您可以在 screencast I've made for lh-tags 中实时看到它。等待"Which kinds to you wish to display?"问题。 (在截屏视频中,您应该看到带有 CHECK
、CONFIRM
和 CHOOSE
的旧代码)
顺便说一句,lh-tags 中用于选择一个条目的对话框也可以用于(将 tagged
参数设置为一个)一次 select 多个条目。