What is gained by the extra <SID> level of map indirection recommended in help?

46 views
Skip to first unread message

Brett Stahlman

unread,
Nov 29, 2016, 2:19:06 PM11/29/16
to vim...@googlegroups.com
The 'write-plugin' section of the help recommends the following
3-level map approach:

map ,c <Plug>TypecorrAdd
noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>

I understand how it works, but it wasn't immediately clear to me what
was being gained by the middle level of indirection: specifically the
map to <SID>Add. What is the advantage of this strategy over the
following 2-level approach?

map ,c <Plug>TypecorrAdd
noremap <unique> <script> <Plug>TypecorrAdd
\ :call <SID>Add(expand("<cword>"), 1)<CR>

The help says...
"If another script would also map <SID>Add, it would get another
script ID and thus define another mapping."

While this is true, isn't this sort of script-uniqueness already
guaranteed by the use of <SID> in the rhs of the 3rd mapping? I.e.,
:call <SID>Add(...)<CR>

Thanks,
Brett S.

Andy Wokula

unread,
Dec 10, 2016, 12:32:33 PM12/10/16
to vim...@googlegroups.com
Am 29.11.2016 um 20:18 schrieb Brett Stahlman:
> The 'write-plugin' section of the help recommends the following
> 3-level map approach:
>
> map ,c <Plug>TypecorrAdd
> noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
> noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
>
> I understand how it works, but it wasn't immediately clear to me what
> was being gained by the middle level of indirection: specifically the
> map to <SID>Add. What is the advantage of this strategy over the
> following 2-level approach?
>
> map ,c <Plug>TypecorrAdd
> noremap <unique> <script> <Plug>TypecorrAdd
> \ :call <SID>Add(expand("<cword>"), 1)<CR>

Your "2-level approach" contains a mistake: `<script>' should be
removed.

> The help says...
> "If another script would also map <SID>Add, it would get another
> script ID and thus define another mapping."
>
> While this is true, isn't this sort of script-uniqueness already
> guaranteed by the use of <SID> in the rhs of the 3rd mapping? I.e.,
> :call <SID>Add(...)<CR>

It is.

`<script>' controls "remapping", not "script-uniqueness".

There is ":map" (remapping on) and ":noremap" (remapping off) and then
there is ":noremap <script>" (remapping on for <SID> maps, remapping off
otherwise). ":map <script>" can be used also, it's the same.

--
Andy

Brett Stahlman

unread,
Dec 13, 2016, 4:07:49 PM12/13/16
to vim_use, anw...@yahoo.de
On Saturday, December 10, 2016 at 11:32:33 AM UTC-6, Andy Wokula wrote:
> Am 29.11.2016 um 20:18 schrieb Brett Stahlman:
> > The 'write-plugin' section of the help recommends the following
> > 3-level map approach:
> >
> > map ,c <Plug>TypecorrAdd
> > noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
> > noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
> >
> > I understand how it works, but it wasn't immediately clear to me what
> > was being gained by the middle level of indirection: specifically the
> > map to <SID>Add. What is the advantage of this strategy over the
> > following 2-level approach?
> >
> > map ,c <Plug>TypecorrAdd
> > noremap <unique> <script> <Plug>TypecorrAdd
> > \ :call <SID>Add(expand("<cword>"), 1)<CR>
>
> Your "2-level approach" contains a mistake: `<script>' should be
> removed.

I see that it's not needed (given that there are no <SID> maps in the rhs), but how is it an error? IIUC, it simply inhibits remapping, which is already inhibited by the "noremap".

>
> > The help says...
> > "If another script would also map <SID>Add, it would get another
> > script ID and thus define another mapping."
> >
> > While this is true, isn't this sort of script-uniqueness already
> > guaranteed by the use of <SID> in the rhs of the 3rd mapping? I.e.,
> > :call <SID>Add(...)<CR>
>
> It is.
>
> `<script>' controls "remapping", not "script-uniqueness".
>
> There is ":map" (remapping on) and ":noremap" (remapping off) and then
> there is ":noremap <script>" (remapping on for <SID> maps, remapping off
> otherwise). ":map <script>" can be used also, it's the same.

Understood. Thanks. The confusion stemmed from my mistaken assumption that the purpose of the <SID>Add map went beyond simple code reuse - that it was required for mapping "hygiene". (It would have been more obvious if I'd noticed that in the Vim example, <SID>Add appeared in 2 distinct right hand sides: both <Plug>TypecorrAdd and menu item 'Plugin.Add Correction'...)

Thanks,
Brett Stahlman

>
> --
> Andy

Nikolay Aleksandrovich Pavlov

unread,
Dec 13, 2016, 5:37:57 PM12/13/16
to vim...@googlegroups.com
2016-11-29 22:18 GMT+03:00 Brett Stahlman <bretts...@gmail.com>:
> The 'write-plugin' section of the help recommends the following
> 3-level map approach:
>
> map ,c <Plug>TypecorrAdd
> noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
> noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
>
> I understand how it works, but it wasn't immediately clear to me what
> was being gained by the middle level of indirection: specifically the
> map to <SID>Add. What is the advantage of this strategy over the
> following 2-level approach?
>
> map ,c <Plug>TypecorrAdd
> noremap <unique> <script> <Plug>TypecorrAdd
> \ :call <SID>Add(expand("<cword>"), 1)<CR>

I would really suggest using single-level approach, where {lhs} is
defined based on global variables. The 2-level as well as 3-level
approach encourage (actually, leave no other choice) user to use :*map
and using :*map is most of time considered a bad practice: actually,
the only valid way to use :*map from my point of view is using :*map
when the whole {rhs} is mapped to something else and you know to what
(i.e. `:nmap ,c <Plug>foo` is fine, `:nmap ,c
<Plug>foo:nohlsearch<CR>` is bad).

Additionally, if you have a plugin with many mappings it may be
convenient for user to have two sets of global variables: one contains
a single variable which defines a common prefix (defaulting to e.g.
`<leader>c`), second defines per-mapping trailing part of {lhs}. This
way I e.g. could assign NERDCommenter to have `,c` as a leader in one
:let in place of writing

```VimL
for [s:rhs, s:lhs] in [['<plug>NERDCommenterComment', ',cc' ],
\ ['<plug>NERDCommenterToggle', ',c<space>'],
\ ['<plug>NERDCommenterMinimal', ',cm' ],
\ ['<plug>NERDCommenterSexy', ',cs' ],
\ ['<plug>NERDCommenterInvert', ',ci' ],
\ ['<plug>NERDCommenterYank', ',cy' ],
\ ['<plug>NERDCommenterAlignLeft', ',cl' ],
\ ['<plug>NERDCommenterAlignBoth', ',cb' ],
\ ['<plug>NERDCommenterNest', ',cn' ],
\ ['<plug>NERDCommenterUncomment', ',cu' ],
\ ['<plug>NERDCommenterToEOL', ',c$' ],
\ ['<plug>NERDCommenterAppend', ',cA' ],]
execute 'nmap <special>' s:lhs s:rhs
execute 'vmap <special>' s:lhs s:rhs
endfor
unlet s:lhs s:rhs
```

(and, no, I am not setting `mapleader` to comma, ever. I have plugins
whose mappings I do not want to see and it is much easier to stash
them away by letting them prefix their mappings by a backslash then
actively fight the mappings or determine how they can be disabled…
each time I happen to add a new plugin).

>
> The help says...
> "If another script would also map <SID>Add, it would get another
> script ID and thus define another mapping."
>
> While this is true, isn't this sort of script-uniqueness already
> guaranteed by the use of <SID> in the rhs of the 3rd mapping? I.e.,
> :call <SID>Add(...)<CR>
>
> Thanks,
> Brett S.
>
> --
> --
> You received this message from the "vim_use" maillist.
> Do not top-post! Type your reply below the text you are replying to.
> For more information, visit http://www.vim.org/maillist.php
>
> ---
> You received this message because you are subscribed to the Google Groups "vim_use" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages