Vimscript: ayuda con la carga automática, el alcance y<SID>

Pregunta:

He estado trabajando en modularizar y convertir un código en mi vimrc en algunos paquetes / complementos autónomos y reutilizables. Me he encontrado con un problema con la carga automática y el alcance que tengo dificultades para entender. He leído :h autoload :h <sid> :h script-local , pero todavía no tengo muy claro cómo funciona.

He estado buscando algunos complementos bien desarrollados para descubrir algunos patrones de uso común 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 función s:set_default(...) para cada bandera, 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 debo 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 alteració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 como prefijo un identificador ( s: 🙂 de alcance de secuencia de comandos, reemplaza de manera transparente ese identificador con un SID mapeado.

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 de 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

Ve que este podría ser el enfoque que debo tomar, pero no estoy completamente seguro de por qué, o exactamente cómo usarlo. ¿Alguien puede proporcionar alguna información?

Respuesta:

En el primer caso, el error que está obteniendo es que está intentando llamar a una función antes de que exista. Es decir, Vim está progresando a través de su guión. Cuando ve la línea de call , aún no ha procesado la línea de function que crea lo que desea llamar, lo que resulta en el error de unknown function .

Si mueve su llamada para configurar los valores predeterminados al final de su script (antes de restaurar cpo pero después de todas sus function , no habrá un error, porque Vim habrá procesado el script para crear las funciones primero, así que una vez llega a las líneas de call , las funciones existen. ej.

"....

function! s:set_default(name, default) " {{{
  " Helper function for setting default values.
  if !exists(a:name)
    let {a:name} = a:default
  endif
endfunction " }}}

" 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)

" Restore cpotions.
let &cpo = s:cpo_save
unlet s:cpo_save

No sé por qué la sintaxis alternativa de llamar a su set_default como una función de carga automática desde dentro del script de carga automática funciona cuando la función aún no se ha definido. Supongo que este es un efecto secundario de la implementación (donde un script ya leído no se vuelve a leer, o tendría una recursividad infinita). No contaría con que siempre funcione de esa manera.

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım