How do I create a mapping that calls a script-local function in Vim without namespace collisions?
Answer
<SID>
Explanation
<SID> (Script ID) is a Vimscript token that expands to a unique, per-script prefix at runtime. It lets you safely call s: (script-local) functions from key mappings, even when multiple plugins define internal functions with the same name.
How it works
In Vimscript, the s: prefix makes a function local to the script file — it cannot be called from outside. But key mappings are executed globally, so you cannot write :call s:MyFunc() in a mapping directly. <SID> solves this:
function! s:MyHelper()
echo 'Running from: ' . expand('%')
endfunction
" <SID> expands to a unique SNR prefix at runtime
nnoremap <silent> <leader>h :<C-u>call <SID>MyHelper()<CR>
When Vim loads the script, <SID> expands to <SNR>{N}_ where N is the script's internal number. So <SID>MyHelper might become <SNR>42_MyHelper. Each script gets a different N, so there are no conflicts.
Example
" WRONG: s: prefix doesn't work in a mapping (evaluated globally)
nnoremap <leader>x :call s:Process()<CR>
" RIGHT: <SID> is translated correctly to the script's SNR prefix
nnoremap <leader>x :<C-u>call <SID>Process()<CR>
You can verify the expansion with :map <leader>x — you will see the <SNR>{N}_ prefix in the output.
Tips
<SID>only works inside the script file where thes:function is defined- Always combine with
:<C-u>beforecallto clear any visual range prefix that may be auto-inserted - Use
:scriptnamesto see each script's assigned number and correlate it with the<SNR>prefix - For functions meant to be called from outside the script, use autoload style (
myplugin#funcname) instead ofs: - In Neovim Lua, use
localfunctions and closures invim.keymap.set—<SID>is a Vimscript-only concept