vim-fz icon indicating copy to clipboard operation
vim-fz copied to clipboard

allow vim-fz to be extended

Open prabirshrestha opened this issue 6 years ago • 2 comments

Would it be possible to support an api so that we can use vim-fz for other things rather than just files something similar to fzf https://github.com/junegunn/fzf/wiki/Examples-(vim). I would like to replace Ctrl+P and fzf features with it.

Here is what I'm thinking.

  • Make vim-fz only expose the core api and allow other plugin author to use it for something else.
  • Create another repo that is specific to vim. Might be name something like basic-vim-fz? This would then support commands like :FzColors, :FzFiletypes, :FzLines, :FzTags, :FzQuickFix, :FzBookmarks and so on. You could also move :FzFiles and :FzDirs in this repo.
  • Create another repo that is specific to source controls. For example, git-vim-fz which contains :FzGitFiles, :FzGitBranch, :FzGitStashedFiles. If someone uses mercurial, svn the can go ahead and create hg-vim-fzf or svn-vim-fzf.

Here is what the core api could look like. This is a very simplified version of the api.

fz#run({
    \ 'type': 'cmd',
    \ 'cmd': ['git', 'ls-files'],
    \ 'accept': {files-> exec 'edit files[0]'},
\ })

fz#run({
    \ 'type': 'list',
    \ 'list': ['Item1', 'Item2'],
    \ 'accept': {items -> .. do something with items ...},
\ })

fz#run({
    \ 'type': 'file',
    \ 'file': expand('~/somefile'),
    \ 'accept': {result-> ... do something with the result },
})

It would be also good to have first class async support. This is a place where most of the plugins doesn't support it.

" if type is not specified it could default to manual, then user can use fz#append(id, list) and fz#clear(id)
let l:id= fz#run({
    \ 'accept': {result-> ... do something with the result },
\ })

let s:counter = 0
function! s:some_async_function(t) abort
    let s:counter = s:counter + 1
    call fz#append(l:id, [s:counter])
    if s:counter == 100
        call fz#clean(l:id)
        let s:counter = 0
    endif
endfunction

call timer_start(2000, function('s:some_async_function'), { 'repeat': -1 })

If I wanted to create a command I can easily use command! FzGitFiles call fz#run(....)

This is useful when I'm searching for vim-lsp case where I could be opening multiple language servers and would like to append to the same list. Also useful when streaming support for language server protocol is implemented.

There is also another async feature that would make sense but this might be difficult until gof or fzf supports it first. Basically as I type the search text I would also like to be notified about the search text. There are cases where the results is too large. For example when implementing a UI for npm install I would like to search the npmjs.org repository. This means I would most likely want to make a new http request every time the user presses a key.

let l:id= fz#run({
    \ 'type': 'manual',
    \ 'accept': {result-> ... do something with the result },
    \ 'search_changed': function('s:on_search_text_changed'),
\ })

function! s:on_search_text_changed(id, search_text) abort
    let l:result = http#get('http://npmjs.org/search?q=' . a:search_text)
    call fz#clear(a:id)
    call fz#append(a:id, l:result)
endfunction

There are cases when list can be just string. For example: for files, filetypes, colorschemes. But there are cases when list needs to be a bit more complicated might be something like how omnifunc works ie. list of completeitem, it would be good to support ['item1', 'item2'] as well as [ { 'text': 'class HelloWorld', 'data': { 'file': 'hello.js', 'line': 1, 'col: 1 } } ]. This way when I implement get current document symbols, I can show HelloWorld in results, but when I click enter in the accept method I can look at the data and edit the file and navigate to that particular line and col.

accept function might want to return a dictionary instead of just the selected items so that it can be future proof. For example, the user might type Ctrl+t, Ctrl+v and Ctrl+s instead of enter. This would allow the plugin author to know that the user pressed Ctrl+v so it will open the file in vertical split but if the user pressed Ctrl+t it can open in new tab.

function! s:on_accept(option) abort
     a:option.id " id of the fz#run
     a:options.items " list of items, since sometimes it is ok to select multiple items
     a:options.selection_type " Ctrl+t, Ctrl+v and so on
endfunction

Also would be good if the same api could be ported to CtrlP so supporting both UI would be easy.

Thoughts?

prabirshrestha avatar Aug 13 '17 20:08 prabirshrestha

Thanks for implementing some of these requests. There is one minor problem I encountered that I think we should improve.

call fz#run({ 'type': 'cmd', 'cmd': 'git ls-files | gof' })
call fz#run({ 'type': 'cmd', 'cmd': 'git ls-files | fzf' })

Here I need to specify explicitly gof or fzf. Would it make sense to do this instead?

" for gof
let g:fz_command = 'gof'
let g:fz_command_files = 'files -A'

" for fzf
let g:fz_command = 'fzf'
let g:fz_command_files = ''

So now I could just do this and don't have to worry about whether it is using gof or fzf.

call fz#run({ 'type': 'cmd', 'cmd': 'git ls-files' })

If someone want to override it per fz#run they could use this. But I think almost no one would use this.

call fz#run({ 'type': 'cmd', 'cmd': 'git ls-files', 'fz_command': 'gof' })
call fz#run({ 'type': 'cmd', 'cmd': 'git ls-files | gof', 'fz_command': '' })

prabirshrestha avatar Aug 14 '17 16:08 prabirshrestha

@mattn I have decided to implement a picker ui in pure vim script with a good extension points. It is very much work in progress and supports on_change handler. Plugin is called quickpick.vim and you can find the roadmap at https://github.com/prabirshrestha/quickpick.vim/issues/1. The goal is for me to replace CtrlP, vim-fz and fzf so I only have one plugin to do fuzzy search.

prabirshrestha avatar Dec 23 '18 21:12 prabirshrestha