He estado trabajando en modularizar y convertir un código en mi vimrc
en algunos paquetes / complementos reutilizables y autónomos. Me he encontrado con un problema con la carga automática y el alcance que tengo dificultades para comprender. He leído a través de :h autoload
, :h <sid>
, :h script-local
, pero todavía no estoy muy claro sobre cómo funciona este.
He estado buscando algunos complementos bien desarrollados para descubrir algunos patrones comúnmente utilizados, y he estructurado mis complementos de la siguiente manera:
" ~/.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
Al comienzo de mi vimrc, ejecuto el complemento con:
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
Todo esto parece funcionar correctamente y como se esperaba, pero cada vez que se llama a una función, se llama a la s:set_default(...)
función para cada indicador, lo cual es ineficaz, así que intenté moverlas fuera de las funciones:
" ~/.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() " {{{
" ...
Pero esto causa errores que no estoy seguro de cómo debería resolver:
Error detected while processing /Users/nfarrar/.vim/myplugin.vim
line 40:
E117: Unknown function: <SNR>3_set_default
Todavía no entiendo sólidamente el alcance de vim, pero por lo que he leído, parece que vim implementa una forma de manipulación de nombres con scripts para proporcionar 'alcance'. Asigna (no estoy seguro de cómo funciona exactamente este proceso) un SID único para cada archivo que se carga en tiempo de ejecución, y cuando llama a una función que tiene el prefijo con un identificador de alcance de script ( s:
), reemplaza ese identificador de forma transparente con un SID asignado .
En algunos casos, he visto scripts que llaman a funciones como esta (pero no funciona en mi caso, no entiendo por qué y espero que alguien pueda explicar esto):
call <SID>set_default('g:myplugin_thing_one_flag', 1)
call <SNR>set_default('g:myplugin_thing_one_flag', 1)
Lo siguiente funciona, pero no estoy seguro si es un buen patrón:
" ~/.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 " }}}
En script local, dice:
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
Parece que este podría ser el enfoque que debo adoptar, pero no estoy completamente seguro de por qué, o exactamente cómo usarlo. ¿Alguien puede dar alguna idea?
echom 'this is the function call'
en la función que se llama desde vimrc y otro enechom 'file was sourced'
cualquier otro lugar del archivo (no en una función), veo el último primero, luego el primero.Recomiendo esta estructura:
Esto es compatible con todos los administradores de complementos modernos y mantiene las cosas limpias. De estos:
myplugin/doc/myplugin.txt
debería ser el archivo de ayudamyplugin/plugin/myplugin.vim
debería contener:myplugin/autoload/myplugin.vim
debe contener el código principal de su complemento.Los ámbitos son realmente bastante simples:
s:
pueden aparecer en cualquier lugar, pero son locales al archivo en el que están definidas; solo puede llamarlos desde el archivo donde están definidos;myplugin/autoload/myplugin.vim
deben tener nombresmyplugin#function()
y son globales; puede llamarlos desde cualquier lugar (pero tenga en cuenta que llamarlos hacemyplugin/autoload/myplugin.vim
que se cargue el archivo );Function()
, y también son globales; puedes llamarlos desde todas partes.<SID>
y<Plug>
se usan para mapeos, y son un tema que probablemente debería evitar hasta que comprenda por completo cómo funcionan y qué problema se supone que deben resolver.<SNR>
es algo que nunca deberías usar directamente.fuente
autoload/
yplugin/
directorios? Siempre he puesto todoplugin/
y parece que funciona bien?plugin/
excepto que solo se carga una vez que se necesita en lugar de cargarse en el inicio.autoload
, si no puede probar la existencia de una función si el archivo en el que vive no se ha cargado.