Error when loading .vimrc containing substitution - vim

How do I map a substitution to a key in my .vimrc without getting an error when I source it?
I'm trying to add
nnoremap <leader>re :'<,'>s/<%=*\s//g | '<,'>s/\s-*%>//g
to my .vimrc but when I do so and reload the file I get the following error:

The problem is that you're combining two :s commands, but the command separator | concludes the :map command, so that the second substitution is executed immediately, causing the error. You need to escape the |, or better use the special <Bar> notation inside mappings:
nnoremap <leader>re :'<,'>s/<%=*\s//g <Bar> '<,'>s/\s-*%>//g
PS: Wouldn't it be more natural to define the mapping in visual mode (as it works on the last selection, anyway)? With a :vmap, the first '<,'> range will be inserted automatically:
xnoremap <leader>re :s/<%=*\s//g <Bar> '<,'>s/\s-*%>//g

Related

Mapping a working substitute command to a shortcut via vimrc

The following substitute command works fine on the command line:
:s/\vlabel\{(\w|:)+}/nonumber
It searches for label{eq:xyz123} and replaces its occurence on the current line line with nonumber.
I would like to map this to a command via vimrc. I tried:
nnoremap <leader>nn :s/\vlabel\{(\w|:)+}/nonumber<CR>
but this gives the error:
E492: Not an editor command: :)+}/nonumber<CR>
What is the right way to effect this mapping?
You can use:
nnoremap <leader>nn :s/\vlabel\{(\w<bar>:)+}/nonumber<CR>
Note the use of <bar> instead of |. The error occurs because | is interpreted as a delimiter of commands; i.e., Vim is interpreting your command as if there were two separate lines:
nnoremap <leader>nn :s/\vlabel\{(\w
:)+}/nonumber<CR>
For more, you can read :help map-bar.

vim: conflict between mapping quote

I remapped single and double quotes to the following:
nnoremap " ci"
nnoremap ' ci'
This makes editing strings easier. However, before I had defined this alias to reopen the last modified vim file. But this no more works
alias vil='vim -c "normal '\''0"'
How can I resolve this or any other mapping that works without conflicts
Use normal! to avoid mappings. See :h :normal

Why does the <C-n> syntax for using control key work with :command command but not with :normal command?

I am trying to execute a normal mode command Ctrl-n or j from Ex mode. Normally, one would do this using the :normal command. For example, the following command moves the cursor one line down.
:normal j
So does the following command. Note: ^N is typed by pressing Ctrl-v Ctrl-n.
:normal ^N
But the following command does not work. This command seems to have no effect on the buffer.
:normal <C-n>
However, when I create a new Ex command for Ctrl-n using the following command, it works!
:command Down <C-n>
Even this works, although normal is redundant here.
:command Down normal <C-n>
Now, I can use the Ex command :Down to move the cursor one line down.
My question is why does the <C-n> syntax not work with the :normal command but works with the :command command?
use :exec and escape the <c-x>:
for example:
:exec "normal \<c-n>"
in fact the instruction you can find in :h :normal help doc:
to use |:execute|, which uses an
expression as argument. This allows the use of
printable characters to represent special characters.
Example: >
:exe "normal \<c-w>\<c-w>"
Your question is probably academic (or you are trying to solve another problem) but, for what it's worth, you can already do :+ and :join.

I want to update the file (if necessary) and run the system command on current file

I realize that I can :nmap <leader>rc :!cat %<CR> to provide an easy set of triggers, but I would like to do this instead.
nmap <leader>rc :up :!cat %<CR> but it complains about needing only one filename. How do I get vim to recognize both commands, in series?
You are missing a <CR> after :up. <CR> tells vim you want a carriage return here.
nmap <leader>rc :up<CR> :!cat %<CR>
The reason up is complaining about multiple file names is that it sees :!cat and %<CR> as two arguments to up.
So the new macro executes
:up
:!cat %
instead of
:up :!cat %
(Side Note: you should probably use nnoremap instead of nmap)
ZyX recommends using the following mapping instead.
nnoremap ,rc :up\|execute "!cat" shellescape(#%, 1)<CR>
This uses | to separate commands and escapes the %. Escaping the % leads to a more robust mapping just incase the filename contains special characters.
Help for :h execute and :h shellescape

vim: map command with confirmation to key

I've written a few macros in my .vimrc for the version control system I'm using (Perforce) (please don't suggest the perforce plugin for vim, I tried it and I don't like it). They all work fine except the revert macro, which breaks due to a confirmation prompt (which I need so I don't accidentally fat-finger my changes away). It currently looks like this:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
This causes bash to complain when vim tries to load the file:
bin/bash: -c: line 0: syntax error near unexpected token `('
Looking at the buffer bash sees, it looks like the error is that vim sends it everything after the first pipe, not just the part meant for bash. I tried a few alternatives but I can't seem to make it work. I've got it to show confirm dialog correctly when I removed the pipes and endif (using shorthand if), but then vim complains after the user gives a response.
I think you want something along these lines:
:map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.
Building it up a piece at time, from the inside out:
There's a shell command you sometimes want to run.
That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
If that works, put the mapping in your .vimrc.
Use of the pipe to string multiple vim commands together is not particularly well-defined, and there are numerous eccentricities. Critically, (see :help :bar) it can't be used after a command like the shell command :! which sees a | character as its argument.
You might find it easier to use the system() function.
E.G.
:echo system("p4 revert " . shellescape(expand("%:p")))
The shellescape() wrapper is useful in case you have characters like spaces or quotes in the filename (or have cleverly named it ; rm -rf ~ (Don't try this at home!)).
In the interest of creating more readable/maintainable code, you may want to move your code into a function:
function Revert()
if confirm('Revert to original?', "&Yes\n&No", 1)==1
return system("p4 revert " . shellescape(expand("%:p")))
endif
endfunction
which you would access by using the :call or :echo command in your macro.

Resources