8

I'm using a really clever plugin that changes the line number style (relative/normal) contextually. Basically when you enter insert mode you have normal line numbers and when you leave insert mode it switches to relative numbers. A missing feature is to have normal line numbers when your in command-line mode.

Looking at how it is implemented it uses Vim's events system to trigger the change. I've looked but Vim's documentation seems to only offer events on insert enter/leave. (Funny aside: UserGettingBored).

At first I thought of adding nnoremap : :call MyFunc()<CR>: which works on enter but not on exit. Also relying on a map seems flaky.

How do I trigger a function when the user enters command-line mode (presses :)? And how do I trigger a function when the user leaves this mode (presses enter, ctrlc or esc)?

7
  • 1
    Why do you want to trigger a function when entering / leaving command mode, rather than entering / leaving insert mode?
    – lcd047
    Commented Jun 4, 2015 at 12:59
  • If relativenumbers are on in normal mode and I hit : then my range (.,+3) is more complicated then actual line numbers which I would see if norelativenumbers was set. and so the request that when switching into command mode to swap the relative numbers setting and put it back when leaving. This is how the plugin works for insert/normal mode switching but vim doesn't provide a normal/command event.
    – Sukima
    Commented Jun 4, 2015 at 15:38
  • Note that the 'command-mode' term, while not widely used, actually means 'normal mode'. What you want is 'command-line mode' (since you add the : to explain, the idea gets through, though).
    – VanLaser
    Commented Jun 5, 2015 at 8:13
  • I edited it. To be fair in my 20 some years reading the Vim docs I don't recall a reference to command-line mode. I have seen normal, insert, command (from cmap or command mapping style), and ex modes. The last (ex) is usually over loaded to mean either the command line from : or the batch mode from Q.
    – Sukima
    Commented Jun 5, 2015 at 12:29
  • Well, just run these commands in vim: :h command-mode :h command-line-mode
    – VanLaser
    Commented Jun 5, 2015 at 12:31

3 Answers 3

6

You can use mappings to override :, /, and ? to do some action first:

nnoremap : :set number<CR>:
nnoremap / :set number<CR>/
nnoremap ? :set number<CR>?

Because we use non-recursive mappings, the : at the end will call the original built-in :.

To hide the numbers again, you can use command-line mappings to override <CR>, <Esc>, and <C-c>:

cnoremap <silent> <CR> <CR>:set nonumber<CR>
cnoremap <silent> <Esc> <Esc>:set nonumber<CR>
cnoremap <silent> <C-c> <C-c>:set nonumber<CR>

This same trick should also work with the commands from your plugin.

3
  • Does this misfire when using the expression register in Command-line mode?
    – tommcdo
    Commented Jun 4, 2015 at 13:14
  • Unfortunately this is not perfect. It will now trigger the <Esc> map when you press the up arrow (since they use terminal ESC sequences).
    – Sukima
    Commented Jun 5, 2015 at 1:25
  • @Sukima Confirmed ... I need to meditate on a solution... Commented Jun 5, 2015 at 8:51
13

As of version 8.0.1206, Vim supports this with CmdlineEnter and CmdlineLeave.

2
  • This is one of those StackExchange posts where the correct answer is not being flagged as such. Admittedly, the answer that is flagged as correct was submitted before Vim 8 was released--so that could account for it. Commented Jun 28, 2020 at 15:05
  • 1
    CmdlineEnter is triggered also for non-interactive mode, possibly causing non-intuitive behaviours. In netwrc tree mode, for example, it triggers when toggling a folder.
    – ndvo
    Commented Apr 4, 2021 at 11:27
1

I haven't tried it for your situation, but likely you're looking for 'doautocmd'. Here's the relevant info from :h doauto

                    *:do* *:doau* *:doautocmd* *E217*
:do[autocmd] [group] {event} [fname]
            Apply the autocommands matching [fname] (default:
            current file name) for {event} to the current buffer.
            You can use this when the current file name does not
            match the right pattern, after changing settings, or
            to execute autocommands for a certain event.
            It's possible to use this inside an autocommand too,
            so you can base the autocommands for one extension on
            another extension.  Example:
                :au Bufenter *.cpp so ~/.vimrc_cpp
                :au Bufenter *.cpp doau BufEnter x.c
            Be careful to avoid endless loops.  See
            |autocmd-nested|.

            When the [group] argument is not given, Vim executes
            the autocommands for all groups.  When the [group]
            argument is included, Vim executes only the matching
            autocommands for that group.  Note: if you use an
            undefined group name, Vim gives you an error message.

            After applying the autocommands the modelines are
            processed, so that their settings overrule the
            settings from autocommands, like what happens when
            editing a file.

Your Answer

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

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