J'ai travaillé sur la modularisation et la conversion d'un code dans mon vimrc
en quelques bundles / plugins autonomes et réutilisables. J'ai rencontré un problème avec le chargement automatique et la portée que j'ai du mal à comprendre. Je l' ai lu :h autoload
, :h <sid>
, :h script-local
, mais je ne suis pas encore tout à fait clair sur la façon dont cela fonctionne.
J'ai regardé des plugins bien développés pour comprendre certains modèles couramment utilisés et j'ai structuré mes plugins comme suit:
" ~/.vim/autoload/myplugin.vim
if exists('g:loaded_myplugin')
finish
endif
let g:loaded_myplugin = 1
let g:myplugin_version = 0.0.1
" Save cpoptions.
let s:cpo_save = &cpo
set cpo&vim
function! myplugin#init() " {{{
" Default 'init' function. This will run the others with default values,
" but the intent is that they can be called individually if not all are
" desired.
call myplugin#init_thing_one()
call myplugin#init_thing_two()
endfunction" }}}
function! myplugin#init_thing_one() " {{{
" init thing one
call s:set_default('g:myplugin_thing_one_flag', 1)
" do some things ...
endfunction " }}}
function! myplugin#init_thing_two() " {{{
" init thing two
call s:set_default('g:myplugin_thing_two_flag', 1)
" do some things ...
endfunction " }}}
function! s:set_default(name, default) " {{{
" Helper function for setting default values.
if !exists(a:name)
let {a:name} = a:default
endif
endfunction " }}}
" Restore cpotions.
let &cpo = s:cpo_save
unlet s:cpo_save
Au début de mon vimrc, j'exécute le plugin avec:
if has('vim_starting')
if &compatible | set nocompatible | endif
let g:myplugin_thing_one_flag = 0
let g:myplugin_thing_two_flag = 2
call myplugin#init()
endif
Tout cela semble fonctionner correctement et comme prévu - mais chaque fois qu'une fonction est appelée, la s:set_default(...)
fonction est appelée pour chaque indicateur, ce qui est inefficace - j'ai donc tenté de les déplacer hors des fonctions:
" ~/.vim/autoload/myplugin.vim
" ...
set cpo&vim
" Set all defaults once, the first time this plugin is referenced:
call s:set_default('g:myplugin_thing_one_flag', 1)
call s:set_default('g:myplugin_thing_two_flag', 1)
function! myplugin#init() " {{{
" ...
Mais cela provoque des erreurs que je ne sais pas comment résoudre:
Error detected while processing /Users/nfarrar/.vim/myplugin.vim
line 40:
E117: Unknown function: <SNR>3_set_default
Je ne comprends toujours pas bien la portée de vim, mais d'après ce que j'ai lu - il semble que vim implémente une forme de manipulation de nom avec des scripts pour fournir une «portée». Il attribue (pas sûr de savoir comment fonctionne exactement ce processus) un SID unique pour chaque fichier qui est chargé au moment de l'exécution - et lorsque vous appelez une fonction qui est préfixée avec un identificateur de portée de script ( s:
), il remplace de manière transparente cet identifiant par un SID mappé .
Dans certains cas, j'ai vu des scripts qui appellent des fonctions comme celle-ci (mais cela ne fonctionne pas dans mon cas, je ne comprends pas pourquoi, et j'espère que quelqu'un peut expliquer cela):
call <SID>set_default('g:myplugin_thing_one_flag', 1)
call <SNR>set_default('g:myplugin_thing_one_flag', 1)
Ce qui suit fonctionne, mais je ne sais pas si c'est un bon modèle:
" ~/.vim/autoload/myplugin.vim
" ...
set cpo&vim
" Set all defaults once, the first time this plugin is referenced:
call myplugin#set_default('g:myplugin_thing_one_flag', 1)
call myplugin#set_default('g:myplugin_thing_two_flag', 1)
function! myplugin#init() " {{{
" ...
function! myplugin#set_default(name, default) " {{{
" ...
endfunction " }}}
Dans le script local, il indique:
When executing an autocommand or a user command, it will run in the context of
the script it was defined in. This makes it possible that the command calls a
local function or uses a local mapping.
Otherwise, using "<SID>" outside of a script context is an error.
If you need to get the script number to use in a complicated script, you can
use this function:
function s:SID()
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfun
Il voit que cela pourrait être l'approche que je dois adopter, mais je ne sais pas vraiment pourquoi, ni exactement comment l'utiliser. Quelqu'un peut-il donner un aperçu?
echom 'this is the function call'
dans la fonction appelée depuis vimrc et une autreechom 'file was sourced'
n'importe où ailleurs dans le fichier (pas dans une fonction), je vois la dernière en premier, puis la première.Je recommande cette structure:
Ceci est compatible avec tous les gestionnaires de plugins modernes et garde les choses propres. Parmi ceux-ci:
myplugin/doc/myplugin.txt
devrait être le fichier d'aidemyplugin/plugin/myplugin.vim
Devrait contenir:myplugin/autoload/myplugin.vim
devrait contenir le code principal de votre plugin.Les portées sont en fait assez simples:
s:
peuvent apparaître n'importe où, mais sont locales au fichier dans lequel elles sont définies; vous ne pouvez les appeler qu'à partir du fichier où ils sont définis;myplugin/autoload/myplugin.vim
doivent avoir des nomsmyplugin#function()
et sont globales; vous pouvez les appeler de partout (mais attention, les appeler provoque lemyplugin/autoload/myplugin.vim
chargement du fichier );Function()
, et sont également globales; vous pouvez les appeler de partout.<SID>
et<Plug>
sont utilisés pour les mappages, et c'est un sujet que vous devriez probablement éviter jusqu'à ce que vous ayez une compréhension complète de la façon dont ils fonctionnent et du problème qu'ils sont censés résoudre.<SNR>
est quelque chose que vous ne devriez jamais utiliser directement.la source
autoload/
etplugin/
? J'ai toujours tout misplugin/
et ça semble bien marcher?plugin/
sauf qu'il n'est chargé qu'une fois qu'il est nécessaire au lieu d'être chargé au démarrage.autoload
, par exemple , vous ne pouvez pas tester l'existence d'une fonction si le fichier dans lequel elle se trouve n'a pas été chargé.