1

I have this command to prune :verb map down to only my plugin mappings:

g!^\~/vimfiles/plugin/^-1d _

It also needs :$d to remove last line that has verbose comment "Last set [...]".

Can someone explain how the command to :g works? i.e. -1d. I believe it means, "delete preceding line that is not marked". I've gone through listing of maps with :verb map and mentally gone, ok this line has not been marked, so delete the preceding line, but then my mental powers fail me and I can't quite see how it works.

I've noticed that

g^\~/vimfiles/plugin/^-1,d

works in reverse manner. But notice the command -1,d. I believe this means, "delete preceding line and current marked line". I can understand how this works.

[EDIT]

It seems further explanation is required. Viz WTH am I doing? (I should also point out that this is not entirely original. If I knew I would credit the person I cribbed this from.)

I paste output from :verb map into a new buffer and run:

g/^$/d
g!^\~/vimfiles/plugin/\|\~/vimfiles/ftplugin/\|\~/vimfiles/after/
    \|\~/vimfiles/vimrc\|\~/vimfiles/autoload\(\/pathogen\)\@!^-1d _
%!sort -k1.4,1.7

It successfully turns, e.g.

x  "            @peekaboo#peek(v:count1, '"',  1)
        Last set from ~/vimfiles/bundle/vim-peekaboo-master/plugin/peekaboo.vim line 35
v  ["          *@:<C-U>exe "normal! gv"|call search('\%(^\s*".*\n\)\%(^\s*"\)\@!', "bW")<CR>
        Last set from ~/Documents/bin/apps/vim/vim91/ftplugin/vim.vim line 91
n  \cm         * :call ConvertMarkdownToHtml(input('CSS File Number (Optional): '))<CR>
        Last set from ~/vimfiles/plugin/maps.vim line 169
n  \y          * :silent w !cb<CR>:echom "Buffer copied to clipboard"<CR>
        Last set from ~/vimfiles/plugin/maps.vim line 163
v  \fp         * :call FixPath()
        Last set from ~/vimfiles/plugin/maps.vim line 159
n  \cp         * :let @+ = expand("%:p")<CR>

into

n  \cm         * :call ConvertMarkdownToHtml(input('CSS File Number (Optional): '))<CR>
n  \cp         * :let @+ = expand("%:p")<CR>
v  \fp         * :call FixPath()
n  \y          * :silent w !cb<CR>:echom "Buffer copied to clipboard"<CR>

:h :v says rather clumsily:

For ":v" and ":g!" the command is executed for each not marked line.

Which is what I meant when I said, rather clumsily, "delete preceding line that is not marked" in regards to command -1d. I could have better said, "delete preceding line on lines that are not marked".

My question is still, how am getting the result I do get with the :g command and -1d? If I manually go through the original listing saying, "this line was not marked, so delete previous line; next line, this one wasn't marked, so delete previous line" etc etc, I don't see how I can end up with the (nice!) result I do.

2
  • Do you still have something open in your question? How can we help you further? Otherwise maybe could you accept one of the answers using the v button next to the arrow voting buttons. It allow the question to rest :-) Mar 3 at 6:42
  • I see now that the :g command doesn't work as intended.
    – Tom
    Mar 4 at 1:07

2 Answers 2

0

How did you get that command? Did you read :help :g? :help :range?

Anyway, let's deconstruct that command:

:g!^\~/vimfiles/plugin/^-1d _
  • :g/<pattern>/<command> executes <command> on each line where <pattern> matches.
  • :g!/<pattern>/<command> executes <command> on each line where <pattern> doesn't match.
  • :g can use arbitrary separators instead of /, which is useful when your pattern contains multiple / and you don't want the hassle of escaping all of them. Your command uses ^ as separators.
  • \~/vimfiles/plugin/ is your <pattern>.
  • -1d _ is your <command>.
  • -1 sets the address of the command one line above the matched line, it could be shortened to -. See :range-offset.
  • d _ cuts the line to the "black hole" register. See :help :d and :help "_.

Therefore, the command removes the line immediately above each line that doesn't match \~/vimfiles/plugin/ which, frankly, doesn't seem useful at all. I tested it with the output of :verbose map and I am not sure why I would want to do that.

First few lines of :verbose map:

n  <SwipeRight>  @:ta<CR>
    Last set from ~/Applications/MacVim.app/Contents/Resources/vim/runtime/ftplugin/help.vim line 24
n  <SwipeLeft>  @:po<CR>
    Last set from ~/Applications/MacVim.app/Contents/Resources/vim/runtime/ftplugin/help.vim line 23
s  <Tab>       * <Esc>i<Right><C-R>=TriggerSnippet()<CR>
    Last set from ~/.vim/pack/bundle/start/snipmate/after/plugin/snipMate.vim line 14
n  <Space>d    * [<C-D>
    Last set from ~/.vim/vimrc line 339
n  <Space>i    * [<Tab>
    Last set from ~/.vim/vimrc line 338

After your command (adjusted to my context, so I used \~/\.vim/pack as <pattern>) I get the following, which seems pretty useless and incorrect:

    Last set from ~/.vim/vimrc line 338

If I wanted to only see the mappings defined in my ~/.vim/pack/, I would probably not try to do everything in one command. Instead, I would start by joining all lines containing Last set with the line above:

:g/Last set/-j

which would give me this:

n  <SwipeRight>  @:ta<CR> Last set from ~/Applications/MacVim.app/Contents/Resources/vim/runtime/ftplugin/help.vim line 24
n  <SwipeLeft>  @:po<CR> Last set from ~/Applications/MacVim.app/Contents/Resources/vim/runtime/ftplugin/help.vim line 23
s  <Tab>       * <Esc>i<Right><C-R>=TriggerSnippet()<CR> Last set from ~/.vim/pack/bundle/start/snipmate/after/plugin/snipMate.vim line 14
n  <Space>d    * [<C-D> Last set from ~/.vim/vimrc line 339
n  <Space>i    * [<Tab> Last set from ~/.vim/vimrc line 338

and then proceed to remove the lines that I am not interested in:

:g!^\~/\.vim/pack^d

which would give me this, which seems more useful to me:

s  <Tab>       * <Esc>i<Right><C-R>=TriggerSnippet()<CR> Last set from ~/.vim/pack/bundle/start/snipmate/after/plugin/snipMate.vim line 14

FWIW, if you often feel the need to peruse :map to remember your mappings, then it is a pretty good sign a) that you may have too many of them, and/or b) that they may be too random. Both problems can be solved with a bit of work.

Dealing with too many mappings is basically a matter of going through all of them and getting rid of those you never use. Some of them can probably be turned into custom Ex commands that start with the same stub to make them more discoverable: :MyFoo, :MyBarBaz, etc., which would free up some memory.

Dealing with mappings that are too random means thinking long and hard about what they do and reorganising/renaming them according to functionality or whatever. Having several leaders helps in this case, as well as using mnemonic mappings. Etc.

1
  • Thanks for the tips. In this case it was more proof of concept kind of thing.
    – Tom
    Mar 1 at 12:07
0

The Theory

The g command is a loop over the lines of the buffer.

For each line of the buffer from the first to the last:

  • If the regular expression match a part of the line the corresponding command (:-1,d in your case) is executed
  • Otherwise continue (to the next line if any)

The g! or v command use a similar logic but negate the regular expression

For each line of the buffer from the first to the last:

  • If the regular expression doesn't match a part of the line the corresponding command (:-1d _ in your case) is executed
  • Otherwise continue (to the next line if any)

There is nothing like "previous line not marked" unfortunately.

In particular the command: :g/bar/-1d

Transforms:

foo1
foo2
foo3
bar1
bar2

Into:

foo1
foo2
bar2

The bar1 match induces the deletion of foo3 (the previous line at the time) .

The bar2 match induces the deletion of the bar1 (the previous line at the time).

To comeback to your example:

The Example

The command used is the g! command or the v (they are synonymous of each other).

It loop against all the line of the buffer.

Each time the regular expression do not match the command is triggered.

There are two type of lines in your file that alternate:

  • The mapping lines
  • The location lines (that starts with: Last set from)

The mapping lines never match the pattern. Which means that all the location line that precede a mapping or an empty line are deleted.

Remark: The trick doesn't work if you have more than one empty line at the end of your buffer.

The location match only for the location of the mapping you want to keep.

If the location line do not match the corresponding mapping line (the line right above) is deleted.

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.