Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

picker#Register() is not available at startup #45

Closed
srstevenson opened this issue Jan 15, 2019 · 5 comments
Closed

picker#Register() is not available at startup #45

srstevenson opened this issue Jan 15, 2019 · 5 comments

Comments

@srstevenson
Copy link
Owner

The autoloaded picker#Register() function isn't known to Vim at startup. This means a line such as

call picker#Register('notes', 'file', 'edit', 'find ~/notes -name "*.md"')

in your vimrc leads to the following error:

Error detected while processing /home/srstevenson/.vim/vimrc:
line   76:
E117: Unknown function: picker#Register
Press ENTER or type command to continue

This can be worked around until fixed by defining an autocommand on the VimEnter event:

autocmd VimEnter call picker#Register('notes', 'file', 'edit', 'find ~/notes -name "*.md"')
@srstevenson srstevenson changed the title picker#Register is not available at startup picker#Register() is not available at startup Jan 15, 2019
@boxofrox
Copy link
Contributor

boxofrox commented Jan 16, 2019

This was another weird bug for me. One minute it was there, and the next it was gone.

The following two init.vim examples don't reproduce this error in either Neovim 0.3 or Vim 8.1. E.g. vim --noplugin -u [./init1.vim | ./init2.vim].

If I remove the runtime! plugin/**/*.vim, then the error appears, so maybe that's where I went wrong. I wonder if that runtime! call is triggering a premature autoload.

" Save as init1.vim
" Run as `nvim --noplugin -u ./init1.vim`
" No plugin manager.
set nocompatible " otherwise Vim 8 complains about script syntax.
set runtimepath=./repo

runtime! plugin/**/*.vim

nmap <leader>pb <Plug>PickerBuffer

call picker#Register(
	\ 'recent-notes',
	\ 'file',
	\ 'edit',
	\ 'find . -path ./git -prune -o -iname "*.md" -printf "%T@ %p\n" | sort -n | cut -d" " -f2-',
	\ )

nmap <leader>pr :call picker#Execute('recent-notes')<cr>
" Save as init2.vim
" Run as `nvim --noplugin -u ./init2.vim`
" Load plugins with vim-plug.
set nocompatible " otherwise Vim 8 complains about script syntax.
set runtimepath=~/.config/nvim

source ~/.config/nvim/autoload/plug.vim

au!

call plug#begin('~/.config/nvim/plugged')

Plug 'srstevenson/vim-picker'

call plug#end()

runtime! plugin/**/*.vim

nmap <leader>pb <Plug>PickerBuffer

call picker#Register(
	\ 'recent-notes',
	\ 'file',
	\ 'edit',
	\ 'find . -path ./git -prune -o -iname "*.md" -printf "%T@ %p\n" | sort -n | cut -d" " -f2-',
	\ )

nmap <leader>pr :call picker#Execute('recent-notes')<cr>

@boxofrox
Copy link
Contributor

boxofrox commented Jan 16, 2019

Yep, runtime! plugin/**/*.vim triggers an autoload of autoload/picker.vim, and yet, it doesn't seem that it should since autoload/ isn't a subfolder of plugin/.

The documentation regarding "autoloading" scripts suggests that vim/neovim should Just Work™. I'll continue trying to identify what we're missing that causing this bug.

Using an autoload script ~
							*autoload* *E746*
This is introduced in the user manual, section |41.15|.

Using a script in the "autoload" directory is simpler, but requires using
exactly the right file name.  A function that can be autoloaded has a name
like this: >

	:call filename#funcname()

When such a function is called, and it is not defined yet, Vim will search the
"autoload" directories in 'runtimepath' for a script file called
"filename.vim".  For example "~/.config/nvim/autoload/filename.vim".  That
file should then define the function like this: >

	function filename#funcname()
	   echo "Done!"
	endfunction

The file name and the name used before the # in the function must match
exactly, and the defined function must have the name exactly as it will be
called.

It is possible to use subdirectories.  Every # in the function name works like
a path separator.  Thus when calling a function: >

	:call foo#bar#func()

Vim will look for the file "autoload/foo/bar.vim" in 'runtimepath'.

@boxofrox
Copy link
Contributor

boxofrox commented Jan 16, 2019

I'm chasing my tail a bit, because now I can't reproduce the error. I'm not sure why, but autoloading appears to be working. Apparently, not reading the docs beforehand was my issue, cause autoloading appears to work as expected now that I reread the docs. sigh

To debug, I added the following echom's in the patch below. The init3.vim below documents the behavior I now see.

Without runtime! plugin/**/*.vim, plugin/picker.vim never loads, but triggering a picker# function will autoload autoload/picker.vim. I thought the vim docs mentioned the runtime! plugin/**/*.vim, but I can't find where I learned of it. I believe I'm using runtime! to compensate for the --noplugin CLI flag that disables loading plugins.

So far, the echom's show plugin/picker.vim loading, then autoload/picker.vim when I start Vim or Neovim as described in the comments of init3.vim.

diff --git a/autoload/picker.vim b/autoload/picker.vim
index 2d83e8d..0a06758 100644
--- a/autoload/picker.vim
+++ b/autoload/picker.vim
@@ -2,6 +2,8 @@
 " Maintainer: Scott Stevenson <scott@stevenson.io>
 " Source:     https://github.com/srstevenson/vim-picker
 
+echom 'Loading autoload/picker.vim'
+
 if !exists('s:command_registry')
     let s:picker_command_registry = {}
 endif

diff --git a/plugin/picker.vim b/plugin/picker.vim
index 4ddc19e..0cffbaa 100644
--- a/plugin/picker.vim
+++ b/plugin/picker.vim
@@ -2,49 +2,21 @@
 " Maintainer: Scott Stevenson <scott@stevenson.io>
 " Source:     https://github.com/srstevenson/vim-picker
 
+echom 'Loading plugin/picker.vim'
+
 if exists('g:loaded_picker')
     finish
 endif
" Save as ./init3.vim
" Run as `nvim --noplugin -u ./init3.vim
set nocompatible " otherwise Vim 8 complains about script syntax.
set runtimepath^=./repo

" Without runtime!, plugin/picker.vim does not load.  Autoloading won't load plugin/picker.vim later.
runtime! plugin/**/*.vim

" nmap definitions don't trigger autoloading.
"nmap <leader>pb <Plug>PickerBuffer

let g:picker_find_executable = 'fd'
let g:picker_find_flags = '--color=never'

" Uncomment and picker#Register will trigger loading of autoload/picker.vim as expected.
"call picker#Register(
"	\ 'recent-notes',
"	\ 'file',
"	\ 'edit',
"	\ 'find . -path ./git -prune -o -iname "*.md" -printf "%T@ %p\n" | sort -n | cut -d" " -f2-',
"	\ )
"

" nmap does not trigger autoload, but executing the keybinding <leader>pr does
" trigger loading of autoload/picker.vim.
"nmap <leader>pr :call picker#Execute('recent-notes')<cr>

@boxofrox
Copy link
Contributor

@srstevenson before the error occurs at line 76, could you echom &runtimepath and verify the path to vim-picker is in the list?

So long as I have vim-picker in runtimepath before I use picker#blah, I don't run into this error in my vimrc/init.vim. Vim-plug usually handles that for me, day to day. init3.vim explicitly updates the runtimepath during my minimal environment tests.

Apologies for all the noise. My inadequate understanding and interpretation of observations has led me on a merry chase.

@srstevenson srstevenson removed the bug label Jan 20, 2019
@srstevenson
Copy link
Owner Author

I think this is due to the way the native packages support works, which is what I'm using, with vim-picker cloned to /home/srstevenson/.config/nvim/pack/plugins/start/vim-picker. After adding the echom calls to autoload/picker.vim and plugin/picker.vim, and a similar one to init.vim, I can see that vim-picker isn't loaded until after init.vim:

$ nvim
Loading init.vim
Loading plugin/picker.vim
Press ENTER or type command to continue

Which is actually what the documentation says, now I've read it again (emphasis mine):

When Vim starts up, after processing your .vimrc, it scans all directories in 'packpath' for plugins under the "pack/*/start" directory. First all those directories are added to 'runtimepath'. Then all the plugins are loaded.

Printing &runtimepath from init.vim confirms vim-picker isn't there when init.vim is loaded:

/home/srstevenson/.config/nvim,/etc/xdg/nvim,/home/srstevenson/.local/share/nvim/site,/usr/local/share/nvim/site,/usr/share/nvim/site,/usr/share/nvim/runtime,/usr/share/nvim/site/after,/usr/local/share/nvim/site/after,/home/srstevenson/.local/share/nvim/site/after,/etc/xdg/nvim/after,/home/srstevenson/.config/nvim/after,/usr/share/vim/vimfiles

However, after Vim has started:

/home/srstevenson/.config/nvim,/home/srstevenson/.config/nvim/pack/plugins/start/vim-picker,/etc/xdg/nvim,/home/srstevenson/.local/share/nvim/site,/usr/local/share/nvim/site,/usr/share/nvim/site,/usr/share/nvim/runtime,/usr/share/nvim/site/after,/usr/local/share/nvim/site/after,/home/srstevenson/.local/share/nvim/site/after,/etc/xdg/nvim/after,/home/srstevenson/.config/nvim/after,/usr/share/vim/vimfiles

The documentation also says:

To load packages earlier, so that 'runtimepath' gets updated: :packloadall

After adding :packloadall in init.vim before calling picker#Register, things work as expected:

$ nvim
Loading plugin/picker.vim
Loading init.vim
Loading autoload/picker.vim
Loading plugin/picker.vim
Press ENTER or type command to continue

Therefore I don't think this is a bug in vim-picker (or Vim), but is just me not initially being aware of the difference in how this is handled with the native packages support versus the established third party tools like vim-plug and Vundle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants