Ich habe daran gearbeitet, einen Code in meinem Computer vimrc
in einige eigenständige und wiederverwendbare Bundles / Plugins-Plugins zu modularisieren und zu konvertieren . Ich bin auf ein Problem mit Autoloading & Scope gestoßen, das ich nur schwer verstehen kann. Ich habe gelesen , durch :h autoload
, :h <sid>
, :h script-local
, aber ich bin immer noch nicht ganz klar, wie dies funktioniert.
Ich habe mir einige gut entwickelte Plugins angesehen, um einige häufig verwendete Muster herauszufinden, und meine Plugins wie folgt strukturiert:
" ~/.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
Zu Beginn meines vimrc starte ich das Plugin mit:
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
Dies alles scheint korrekt und wie erwartet zu funktionieren - aber jedes Mal, wenn eine Funktion aufgerufen wird, wird die s:set_default(...)
Funktion für jedes Flag aufgerufen, was ineffizient ist. Deshalb habe ich versucht, sie aus den Funktionen zu entfernen:
" ~/.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() " {{{
" ...
Dies führt jedoch zu Fehlern, bei denen ich mir nicht sicher bin, wie ich sie beheben soll:
Error detected while processing /Users/nfarrar/.vim/myplugin.vim
line 40:
E117: Unknown function: <SNR>3_set_default
Ich verstehe das Scoping von vim immer noch nicht genau, aber nach dem, was ich gelesen habe, scheint es, dass vim eine Form der Namensverfälschung mit Skripten implementiert, um "Scope" bereitzustellen. Es weist jeder Datei, die zur Laufzeit geladen wird, eine eindeutige SID zu (nicht sicher, wie genau dieser Prozess funktioniert). Wenn Sie eine Funktion aufrufen, der eine Skriptbereichskennung ( s:
) vorangestellt ist , wird diese Kennung transparent durch eine zugeordnete SID ersetzt .
In einigen Fällen habe ich Skripte gesehen, die Funktionen wie diese aufrufen (aber in meinem Fall funktioniert es nicht, ich verstehe nicht warum und hoffe, dass jemand dies erklären kann):
call <SID>set_default('g:myplugin_thing_one_flag', 1)
call <SNR>set_default('g:myplugin_thing_one_flag', 1)
Folgendes funktioniert, aber ich bin mir nicht sicher, ob es ein gutes Muster ist:
" ~/.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 " }}}
In script local heißt es:
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
Es sieht so aus, als wäre dies der Ansatz, den ich wählen muss, aber ich bin mir nicht ganz sicher, warum oder wie ich ihn genau verwenden soll. Kann jemand einen Einblick geben?
echom 'this is the function call'
in der Funktion hinzufüge , die von vimrc aufgerufen wird, und eineechom 'file was sourced'
andere an einer anderen Stelle in der Datei (nicht in einer Funktion), sehe ich zuerst die letztere, dann die erstere.Ich empfehle diese Struktur:
Dies ist mit allen modernen Plugin-Managern kompatibel und hält die Dinge sauber. Von diesen:
myplugin/doc/myplugin.txt
sollte die Hilfedatei seinmyplugin/plugin/myplugin.vim
sollte beinhalten:myplugin/autoload/myplugin.vim
sollte den Hauptcode Ihres Plugins enthalten.Bereiche sind eigentlich ziemlich einfach:
s:
können überall angezeigt werden, sind jedoch lokal für die Datei, in der sie definiert sind. Sie können sie nur aus der Datei aufrufen, in der sie definiert sind.myplugin/autoload/myplugin.vim
müssen Namen habenmyplugin#function()
und sind global; Sie können sie von überall aus aufrufen (achten Sie jedoch darauf, dass beim Aufrufen die Dateimyplugin/autoload/myplugin.vim
geladen wird).Function()
und sind ebenfalls global. Sie können sie von überall anrufen.<SID>
und<Plug>
werden für Zuordnungen verwendet, und sie sind ein Thema, das Sie wahrscheinlich vermeiden sollten, bis Sie ein umfassendes Verständnis dafür haben, wie sie funktionieren und welches Problem sie lösen sollen.<SNR>
ist etwas, das Sie niemals direkt verwenden sollten.quelle
autoload/
und trennenplugin/
? Ich habe immer alles reingestecktplugin/
und das scheint gut zu funktionieren?plugin/
außer dass es nur geladen wird, wenn es benötigt wird, anstatt beim Start geladen zu werden.autoload
wenn Sie alles verschieben , z. B. können Sie nicht prüfen, ob eine Funktion vorhanden ist, wenn die Datei, in der sie sich befindet, nicht geladen wurde.