2

There is a function within a plug-in which I would like to have some of my own code run afterwards.

If it were a general fix/improvement I'd submit the change, however its just a personal preference which must run after the plug-in's function.

Is there a way to have my own code run after a plug-ins vimscript function! ?


In case it helps, this is the function (indent_guides#enable) to give some context.

1
  • 1
    The best you can do is override the mappings and/or commands that call this function. But you can't overwrite functions like you can in Ruby or Python. Dec 17, 2016 at 1:49

1 Answer 1

8

I don't know whether the author of the plugin will agree, but instead of asking them to add your own code, you could ask them to add the ability for the user to run any code after their function.

To do so, you would create a pull request in which you add a small patch at the end of the function:

function! indent_guides#enable()
    ...

    " beginning of the patch
    if exists('#User#IndentGuidesEnablePost')
        doautocmd <nomodeline> User IndentGuidesEnablePost
    endif
    " end of the patch

endfunction

Now, any user of the plugin, including you, should be able to run arbitrary code after the plugin's function has been processed. As a user, you would write in your vimrc:

augroup IndentGuidesPlugin
    autocmd!
    autocmd User IndentGuidesEnablePost call YourFunction()
augroup END

Whenever the plugin's function indent_guides#enable() will be executed, YourFunction() will also be executed at the end of it.

I don't use this particular plugin, so you should probably test the patch locally to make sure it's working as intended.


If you want to better understand how this small patch work, here's an explanation.

The :doautocmd command allows you to run any autocmd, at any time you want, not just when its event occurs. Its syntax is described in :h :do:

:do[autocmd] [<nomodeline>] [group] {event} [fname]

The optional arguments allow you to fine-tune which autocmds you want to execute.

In the patch, you pass to :doautocmd the argument User, as well as the pattern IndentGuidesEnablePost. The latter is an ad-hoc event name. As for User, it's a special kind of event, because it only occurs when you execute:

doautocmd User {MadeUpEvent}

When you add the previous line in a function or a script, it's as if you were creating and triggering a new event whose name is {MadeUpEvent}.

But there's a problem, because if the user doesn't install any autocmd in their vimrc which uses this new event, they will have the following message:

No matching autocommands

To get around this issue, the plugin author could prefix :doautocmd with :silent:

silent doautocmd User MadeUpEvent

But then, the user's autocmd will run silently, which can be a problem if it wants to echo a message:

autocmd User MadeUpEvent echo 'your message'

It won't work. The user will have to use :unsilent:

autocmd User MadeUpEvent unsilent echo 'your message'

Which can be annoying. So, to make things work properly without unsilent, before running :doautocmd, the plugin author could check whether the user installed an autocmd watching the MadeUpEvent event:

if exists('#User#MadeUpEvent')
    doautocmd User MadeUpEvent
endif

Finally, the <nomodeline> argument is recommended in this case. From :h :do:

        After applying the autocommands the modelines are
        processed, so that their settings overrule the
        settings from autocommands, like what happens when
        editing a file. This is skipped when the <nomodeline>
        argument is present. You probably want to use
        <nomodeline> for events that are not used when loading
        a buffer, such as |User|.
        Processing modelines is also skipped when no
        matching autocommands were executed.

For an example where <nomodeline> can be useful, see this issue on the bug tracker of the vim-commentary plugin.

1
  • Cool idea. I'm not clear on why you're using an intermediary autocommand instead of calling the function directly (or via a Funcref), though. Could you clarify?
    – Rich
    Jan 30, 2018 at 10:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.