fzy icon indicating copy to clipboard operation
fzy copied to clipboard

Visual defects in neovim

Open dtcyganok opened this issue 6 years ago • 17 comments

I tried the example from the README.md with neovim and found visual flaws. Lines are displayed indented as a ladder. If you enter a few characters, then nothing on the screen can be understood.

dtcyganok avatar Dec 06 '17 17:12 dtcyganok

Happens to me too. Screenshot:

fzy

On the right there's the input for fzy. On the top left, you can see the Vim integration in .vimrc On the bottom left, there's the ladder (the bug).

Versions: NVIM v0.2.2 fzy 0.9 (c) 2014 John Hawthorn (installed from the fzy_0.9-1_amd64.deb release here on GitHub)

Janiczek avatar Dec 08 '17 07:12 Janiczek

Same! What program do you use with fzy? ripgrep/find/silversearcher? I thought it was some issue with ripgrep + fzy.

mo3rfan avatar Dec 13 '17 07:12 mo3rfan

There is no issue in neovim 0.2.0 but starting from 0.2.1 up to nightly (0.2.3-dev), this issue occurs.

To reproduce just :exec system('ls | fzy')

kimat avatar Dec 21 '17 10:12 kimat

Related? https://github.com/neovim/neovim/wiki/FAQ#-and-system-do-weird-things-with-interactive-processes

mo3rfan avatar Dec 21 '17 12:12 mo3rfan

@PowerInside thank you for attention!

It seems that so. I consider that it is necessary to add the correct instruction in README.md for neovim. Do you have a working example of integration with neovim?

dtcyganok avatar Dec 21 '17 14:12 dtcyganok

I have tried something with termopen() instead of system(), but I don't know enough VimScript to figure it out (right now) and it errors out.

let s:Fzy = {}

function s:Fzy.new(bufid)
  let this = copy(self)
  let this._chunks = ['']
  let this._bufid = a:bufid
  return this
endfunction

function s:Fzy.on_exit(job_id, code)
  redraw!
  if !empty(string(fzy._chunks))
    exec ':e ' . string(fzy._chunks)
  endif
  call feedkeys('\<c-\\><c-n>:bd! ' . self._bufid . '<cr>', 'n')
endfunction

function s:Fzy.on_stdout(job_id, data) "dict
  let self._chunks[-1] .= a:data[0]
  call extend(self._chunks, a:data[1:])
endfunction

function FzyCommand()
  let bufid = bufnr('%')
  let fzy = s:Fzy.new(bufid)
  let cmd = "rg . -l -g '' | fzy"
  sp | enew | call termopen(cmd, fzy) | startinsert
endfunction

nnoremap <leader>e :call FzyCommand()<cr>

Maybe somebody knows more than me and can make this work :)

Janiczek avatar Dec 21 '17 14:12 Janiczek

This problem seems to have been solved in the fzf for a long time. But I can not quickly understand ~800 lines of vimscript :)

dtcyganok avatar Dec 21 '17 14:12 dtcyganok

Picker by Scott Stevenson might be a good place to look for this. I have copied what I think might be the relevant bit below:

function! s:PickerTermopen(list_command, vim_command, callback) abort
    " Open a terminal emulator buffer in a new window, execute
    " list_command piping its output to the fuzzy selector, and call
    " callback.on_select with the item selected by the user as the first
    " argument.
    "
    " Parameters
    " ----------
    " list_command : String
    "     Shell command to generate list user will choose from.
    " vim_command : String
    "     Readable representation of the Vim command which will be
    "     invoked against the user's selection, for display in the
    "     statusline.
    " callback.on_select : String -> Void
    "     Function executed with the item selected by the user as the
    "     first argument.
    let l:callback = {
                \ 'window_id': win_getid(),
                \ 'filename': tempname(),
                \ 'callback': a:callback
                \ }

    function! l:callback.on_exit(job_id, data, event) abort
        bdelete!
        call win_gotoid(self.window_id)
        if filereadable(self.filename)
            try
                call self.callback.on_select(readfile(self.filename)[0])
            catch /E684/
            endtry
            call delete(self.filename)
        endif
    endfunction

    execute g:picker_split g:picker_height . 'new'
    let l:term_command = a:list_command . '|' . g:picker_selector . '>' .
                \ l:callback.filename
    let s:picker_job_id = termopen(l:term_command, l:callback)
    let b:picker_statusline = 'Picker [command: ' . a:vim_command .
                \ ', directory: ' . getcwd() . ']'
    setlocal nonumber norelativenumber statusline=%{b:picker_statusline}
    setfiletype picker
    startinsert
endfunction

casr avatar Dec 22 '17 09:12 casr

@casr I hacked on it a bit and this works!

function! FzyCommand(list_command) abort
    let l:callback = {
                \ 'window_id': win_getid(),
                \ 'filename': tempname()
                \ }
    let l:fzy_command = 'fzy'

    function! l:callback.on_exit(job_id, data, event) abort
        bdelete!
        call win_gotoid(self.window_id)
        if filereadable(self.filename)
            try
                let l:selected_filename = readfile(self.filename)[0]
                exec ':e ' . l:selected_filename
            catch /E684/
            endtry
            call delete(self.filename)
        endif
    endfunction

    execute 'botright 10 new'
    let l:term_command = a:list_command . '|' . l:fzy_command . '>' .
                \ l:callback.filename
    let l:term_job_id = termopen(l:term_command, l:callback)
    setlocal nonumber norelativenumber
    startinsert
endfunction

nnoremap <leader>e :call FzyCommand("rg . -l -g ''")<cr>

Janiczek avatar Dec 22 '17 09:12 Janiczek

Adapted FzyCommand's signature be closer to the one in the README + hid the statusbar & co so it's visually closer to what we had (still one blank line).

function! FzyCommand(choice_command, vim_command) abort
    let l:callback = {
                \ 'window_id': win_getid(),
                \ 'filename': tempname(),
                \  'vim_command':  a:vim_command
                \ }

    function! l:callback.on_exit(job_id, data, event) abort
        bdelete!
        call win_gotoid(self.window_id)
        if filereadable(self.filename)
            try
                let l:selected_filename = readfile(self.filename)[0]
                exec self.vim_command . l:selected_filename
            catch /E684/
            endtry
        endif
        call delete(self.filename)
    endfunction

    botright 10 new
    let l:term_command = a:choice_command . ' | fzy > ' .  l:callback.filename
    silent call termopen(l:term_command, l:callback)
    setlocal nonumber norelativenumber
    startinsert
endfunction

nnoremap <silent> <c-o> :call FzyCommand('rg --files .', ':e ')<cr>

kimat avatar Dec 22 '17 16:12 kimat

Is the above a drop in replacement for the README version?

HaleTom avatar Jul 02 '18 16:07 HaleTom

Yes!

Janiczek avatar Jul 02 '18 21:07 Janiczek

Should be added to the readme imo.

ruifm avatar Jun 16 '19 03:06 ruifm

@ruifm Open a PR with the changes to the README and your wish might come true :)

casr avatar Jun 16 '19 09:06 casr

Is it possible to use fzy+ripgrep to search inside files?

concatime avatar Jul 05 '19 22:07 concatime

Is it possible to use fzy+ripgrep to search inside files?

I use it fine using:

nnoremap <silent><leader>t :call FzyCommand("rg --files --hidden -g '!.git/*' .", ":tabedit")<cr>

ruifm avatar Jul 05 '19 22:07 ruifm

One hack would be to rely on --color=always.

rg --column --no-heading --color=always --smart-case -- ""
+
let l:real_filename = matchstr(l:selected_filename, '\f\+\ze\e', 9)
exec self.vim_command . l:real_filename

The issue that I have is fzy does not highlight selection when colors are forced, so impossible to know which one is selected.

screenshot screenshot0

concatime avatar Jul 06 '19 15:07 concatime