vifm / vifm.vim

Vim plugin that allows use of vifm as a file picker
325 stars 18 forks source link

Switching file with :Vifm slower than opening file from plain vifm #64

Closed AckslD closed 2 years ago

AckslD commented 2 years ago

Opening a file within vim using :Vifm is significantly slower than opening a file from vifm, I haven't timed it but it's significantly slower, maybe 3x or so. Anyone else experiencing this or know why that might be?

xaizek commented 2 years ago

Maybe you have some auto-command that is slow or waits for something? I'd try commenting out configuration and disabling other plugins. You could also try using Vim's :profile command, which might show where the slowdown happens.

AckslD commented 2 years ago

Thanks for your reply @xaizek! I'll try to do some profiling to see what's happening. What I don't understand is why it's slower than opening a file normally (:e) or opening a file using vifm from outside of vim.

xaizek commented 2 years ago

The plugin uses term buffer and switches buffers several times. Some auto-command might accidentally run where it wasn't meant to be run or maybe something is wrong with Vim's handling of jobs.

AckslD commented 2 years ago

So it seems to be due to this line:

    1   0.831576   0.001005         execute editcmd fnamemodify(file, ':.')

In the following function:

FUNCTION  <SNR>58_HandleRunResults()
    Defined: ~/.local/share/nvim/site/pack/packer/start/vifm.vim/plugin/vifm.vim:243
Called 1 time
Total time:   0.831778
 Self time:   0.001207

count  total (s)   self (s)
    1              0.000001     if a:exitcode != 0
                                    echoerr 'Got non-zero code from vifm: ' . a:exitcode
                                    call delete(a:listf)
                                    call delete(a:typef)
                                    return
    1              0.000000     endif

                                " The selected files are written and read from a file instead of using
                                " vim's clientserver so that it will work in the console without a X server
                                " running.

    1              0.000007     if !file_readable(a:listf)
                                    echoerr 'Failed to read list of files'
                                    call delete(a:listf)
                                    call delete(a:typef)
                                    return
    1              0.000000     endif

    1              0.000011     let flist = readfile(a:listf)
    1              0.000012     call delete(a:listf)

    1              0.000009     let opentype = file_readable(a:typef) ? readfile(a:typef) : []
    1              0.000004     call delete(a:typef)

                                " User exits vifm without selecting a file.
    1              0.000001     if empty(flist)
                                    echohl WarningMsg | echo 'No file selected' | echohl None
                                    return
    1              0.000000     endif

    1              0.000002     let unescaped_firstfile = flist[0]
    1              0.000004     call map(flist, 'fnameescape(v:val)')
    1              0.000001     let firstfile = flist[0]

    1              0.000002     if !empty(opentype) && !empty(opentype[0]) && opentype[0] != '"%VIFM_OPEN_TYPE%"'
                                    let editcmd = has('win32') ? opentype[0][1:-2] : opentype[0]
    1              0.000000     else
    1              0.000001         let editcmd = a:editcmd
    1              0.000000     endif

                                " Don't split if current window is empty
    1              0.000002     if empty(expand('%')) && editcmd =~ '^v\?split$'
                                    execute 'edit' fnamemodify(flist[0], ':.')
                                    let flist = flist[1:-1]
    1              0.000000     endif

                                " We emulate :args to not leave unnamed buffer around after we open our
                                " buffers.
    1              0.000002     if editcmd == 'edit' && len(flist) > 1
                                    silent! %argdelete
    1              0.000000     endif

    2              0.000003     for file in flist
    1   0.831576   0.001005         execute editcmd fnamemodify(file, ':.')
    1              0.000008         if editcmd == 'edit' && len(flist) > 1
                                        execute 'argadd' fnamemodify(file, ':.')
    1              0.000000         endif
    2              0.000001     endfor

                                " Go to the first file working around possibility that :drop command is not
                                " evailable, if possible
    1              0.000001     if editcmd == 'edit' || !s:has_drop
                                    " Linked folders must be resolved to successfully call 'buffer'
    1              0.000003         let firstfile = unescaped_firstfile
    1              0.000048         let firstfile = resolve(fnamemodify(firstfile, ':h')) .'/'.fnamemodify(firstfile, ':t')
    1              0.000002         let firstfile = fnameescape(firstfile)
    1              0.000049         execute 'buffer' fnamemodify(firstfile, ':.')
                                elseif s:has_drop
                                    " Mind that drop replaces arglist, so don't use it with :edit.
                                    execute 'drop' firstfile
    1              0.000000     endif

Here's the full profile: vim-profile.log

Any idea why that might take almost 1 second?

xaizek commented 2 years ago

fnamemodify(file, ':.') is called below without such delay, so it must be opening the file. I guess the delay will go away if you add noautocmd (self time is only 1ms):

execute 'noautocmd' editcmd fnamemodify(file, ':.')

If so, start disabling plugins.

AckslD commented 2 years ago

Found it! It was indeed one of my autocommands that was the culprit. Thanks a lot for the help with debugging :)