Как запросить у пользователя несколько записей в списке?

Я работаю над плагином vim. Существует множество допустимых опций для параметра конфигурации. Я бы хотел, чтобы пользователь мог выбирать нужные параметры из списка.

Это похоже на inputlist, но inputlist возвращает только индекс одного выбранного элемента. Я бы предпочел, чтобы он возвращал индексы всех выбранных элементов.

Как бы я создал мутлиселект в vim?

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,

В lh-vim-lib я предоставляю lh#ui#check() функция, которая делает именно это. Его поведение похоже на confirm() в текстовом режиме. т.е. я полагаюсь на старый трюк, который взламывает статусную строку. (Это нужно играть с "\r", :redraw и так далее)

Вы можете увидеть это в прямом эфире на экране, который я сделал для lh-тегов. Ждите "Какие виды вы хотите отобразить?" вопрос. (В скриншоте вы должны увидеть старый код с CHECK, CONFIRM а также CHOOSE)

Кстати, диалог, используемый в lh-тэгах для выбора одной записи, также может быть использован (с tagged параметр установлен на один), чтобы выбрать несколько записей одновременно.

Другие вопросы по тегам