How to jump to a search in a mapped :normal command? - vim

What do you need to properly jump to a matched search result?
To reproduce, make a macro with a search in it after you've run vim -u NONE to ensure there's no vimrc interfering. You'll need to make a file with at least 2 lines and put the cursor on the line without the text TEST_TEXT.
map x :norm gg/TEST_TEXT^MIthis
My intention is that when I press x, it goes to the top of the file, looks for TEST_TEXT and then puts this at the start of the line that matches the search. The ^M is a literal newline, achieved with the CtrlQ+Enter keypress. What's happening instead is either nothing happens, or the text gets entered on the same line as when I called the macro.
If I just run the :norm gg/TEST_TEXT^MIthis command without mapping it to a key, the command executes successfully.
I had an initially longer command involving a separate file and the tcomment plugin, but I've gotten it narrowed down to this.
What is the correct sequence of keys to pull this off once I've mapped it to a key?

The problem is that the ^M concludes the :normal Ex command, so your search command is aborted instead of executed. The Ithis is then executed outside of :normal.
In fact, you don't need :normal here at all. And, it's easier and more readable to use the special key notation with mappings:
:map x gg/TEST_TEXT<CR>Ithis
If you really wanted to use :normal, you'd have to wrap this in :execute, like this:
:map x :exe "norm gg/TEST_TEXT\<lt>CR>Ithis"<CR>
Bonus tips
You should use :noremap; it makes the mapping immune to remapping and recursion.
Better restrict the mapping to normal mode, as in its current form, it won't behave as expected in visual and operator-pending mode: :nnoremap
This clobbers the last search pattern and its highlighting. Use of lower-level functions like search() is recommended instead.

There are many ways of doing this however this is my preferred method:
nnoremap x :0/TEST_TEXT/norm! Itest<esc>
Explanation:
:{range}norm! {cmd} - execute normal commands, {cmd}, on a range of lines,{range}.
! on :normal means the commands will not be remapped.
The range 0/TEST_TEXT start before the first line and then finds the first matching line.
I have a few issues with your current mapping:
You are not specifying noremap. You usually want to use noremap
It would be best to specifiy a mode like normal mode, e.g. nnoremap
It is usually best to use <cr> notation with mappings
You are using :normal when your command is already in normal mode but not using any of the ex command features, e.g. a range.
For more help see:
:h :map
:h :norm
:h range

try this mapping:
nnoremap x gg/TEST_TEXT<cr>Ithis<esc>
note that, if you map x on this operation, you lost the original x feature.

Related

VIM: Getting register into command with macro; replace all occurences with register

I want to make a macro such that the current term searched is replaced by the last insert.
My incorrect approach:
map <C-r> :%s//"p./<CR>
How can I get the register . into my substitute command?
You can insert any register's contents in command-line mode via :help c_CTRL-R:
nnoremap <C-r> :%s//<C-r>./<CR>
Notes
You should use :noremap; it makes the mapping immune to remapping and recursion.
Limit the mapping to as few modes as possible. I don't think you need to trigger this from visual mode or operator-pending mode, so :nnoremap fits best.
Your mapping only replaces the first occurrence in each line unless you add the /g flag. /e flag may also make sense to suppress the error when there are no matches.
<C-R> in normal mode is redo; remapping such a crucial command is not recommended, losing it completely is even worse.
You're looking for #. or getreg('.'). But as they are expressions, you'd need :exe. This would be convoluted.
Another way consists in using :h c_CTRL-R:
nnoremap <c-r> :%s//<c-r>./<cr>
PS: I usually avoid to trigger mappings on keysequences that already do things. In particular when they do important and critical stuff. Here CTRL-R is redo. I'm quite certain you don't want to loose that.

Creating new mappings in Vim

I am trying to create a mapping the allows me to execute my current node.js file when I press comma + n. I am trying to use the following:
:map <cn> :!node .
When I type this in it simply jumps my cursor to a random line in my current file. How do I create this mapping?
You've specified the mapping keys in the wrong format, see :help key-notation. To trigger the mapping via , followed by N, use this:
:nnoremap ,n :!node %<CR>
Additional notes:
You should use :noremap; it makes the mapping immune to remapping and recursion.
Likewise, you should be as specific in the modes, so :nmap instead of :map for normal mode only.
A mapping works as typed. As you invoke an Ex command from normal mode, you need to conclude command-line mode via <CR>, just as you would press Enter when typing this interactively.
You probably want to pass the current file to node; that's done by the special % identifier, not by .. See :help cmdline-special

What is the meaning of a <CR> at the end of some vim mappings?

I see <cr>s a lot in vim mappings, but what does it do?
:help key-notation
says:
notation meaning equivalent decimal value(s)
-----------------------------------------------------------------------
<CR> carriage return CTRL-M 13 *carriage-return*
<Return> same as <CR> *<Return>*
<Enter> same as <CR> *<Enter>*
Mappings often involve Ex commands and you must press <CR> to execute them so it's included in the mapping.
Why <special keys>?
While you can use literal keys in mapping definitions (the Enter key would appear as ^M, or even just as an additional new line, depending on the settings), Vim provides a special key notation for key (combinations), so that it is easier to define (you don't have to use i_CTRL-V to literally insert the special character) and understand (<A-a> better expresses the intention than the equivalent รก) the mappings.
See :help key-notation for a list and explanation.
Why <CR>?
As many mappings invoke Ex commands (e.g. :w) and therefore have to switch from normal to command-line mode, they have to conclude the command with <Enter> (or <CR>), just as you would when manually typing the command.
The <CR> in vim mappings is the carriage return usually the Enter on your keyboard.
<CR> in a mapping corresponds to the Enter key just like a in a mapping corresponds to the A key. Ley's say you have this mapping
:map <f8> :wq<cr>
This will map F8 to the key sequence :WQEnter (which would save the current buffer and quit).
It's basically a means to say "this is the end", see map:
When you have a mapping that contains an Ex command, you need to put a line
terminator after it to have it executed. The use of is recommended for
this. Example:
:map _ls :!ls -l %<CR>:echo "the end"<CR>
also,
<CR> [count] lines downward, on the first non-blank character |linewise|.

Why isn't this Vim mapping working?

noremap :hsp :botright new
noremap :vsp :botright vnew
"Not an editor command: hsp"
I'm probably googling the wrong thing, but I can't find many results on aliasing vim commands. I can find tons of info about mapping keys to commands like my one for tabs:
noremap <C-t> :tabnew<CR>
But can't find commands mapped to other commands.
What you're doing is simulating a command with a mapping. You're saying that when you press the 4 keys :hsv in normal mode, it should type out the keys :botright new (which would need a <CR> to run, as others have said), but it's not actually making the command hsv. You could make an actual command with a user command (:h user-commands). These must start with a capital letter, though.
:command Hsp botright new
:command Vsp botright vnew
Now you can type :Hsp and hit enter to run the command botright new.
Did you try command abbreviation?
ca hsp botright new
ca vsp botright vnew
You will have to initialize the expansion of the abbreviation by hitting the space key afterwards. Depending on the global vim configuration, expansion also happens automatically just when enter is pressed.
with your same mapping, I cannot get the Not an editor command: hsp error message with my vim (v7.4).
Your mapping works fine, but you don't have <cr> at the end, so when you press :hsp in normal mode, your mapping will switch to commandline mode, and put the mapped command there, without executing it. You have to manually press Enter.
#XZS's answer works, but keep in mind that it is an abbreviation(ab), not a mapping. ab is not command aliases, it is not exactly same as mapping. For example, you have to press another key (like space) after hsp to trigger the ab. also, you cannot ab some special keys, this would be another limitation of ab.
There is c(nore)map for command mapping.
e.g. you could have:
cnoremap hsp botright new
with above line, as same as your original one, you have to manually press Enter, if you want it to be executed, you need add <CR> at the end of the line.
I think if I do this, I would create mapping.
Creating command alias can be tricky:
Using a simple cabbrev and/or cmap will cause expansions and mappings to fire in unexpected places like during searches with / and in the middle of filenames.
cmap's will have a visible delay in outputting to the screen which is why cabbrev is often used.
However there are a few ways to create a proper alias:
Create a command via :command.
e.g. command W w
command's first letter must be a uppercase letter
must supply -nargs, -bar, -complete, and -range options according to the needs of your alias
Expression :cabbrev to guard the abbreviation from expanding in in proper places.
expression mapping use the <expr> option
verify getcmdtype() is equal to :
verify the abbreviation is at the beginning of command line via getcmdline() or getcmdpos()
e.g. cnoreabbrev <expr> W getcmdtype() == ':' && getcmdline() ==# 'W' ? 'w' : 'W'
Use :Alias via the cmdalias.vim plugin by Hari Krishna Dara
e.g. Alias W w
uses an expression cabbrev under the covers similar to the technique above

Map :w (save) and a call for a .sh file to F2 in VIM

I'd like to map F2 in VIM so that it first saves the file with :w and then calls a script /home/user/proj/script.sh that will upload the changed files to the server.
I already tried
:map F2 :w<cr>|:! /home/user/proj/script.sh
but that doesn't work.
Please tell my why this isn't working and help me to get this working.
Try :noremap <F2> :<c-u>update <bar> !/home/user/proj/script.sh<cr>.
noremap vs. map
This creates a non-recursive mapping. See Wikia - Mappings keys in Vim
I just assumed this, because it's what people want most of the time. :-)
update vs. write
Only save the file if there were actual changes. See: :help :update.
<bar> vs. |
:help map_bar
<c-u>?
You used a generic mapping, instead of one for a certain mode, like nmap for normal mode mappings. Thus the mapping could also be triggered in visual mode. If you select something in visual mode and hit :, you'll see the commandline is prefixed with a range. But you don't want that in your case and <c-u> clears the commandline.
<cr> at the end?
Your mapping drops into the commandline mode and inserts 2 things separated by <bar>. Afterwards it has to execute what it has written, thus you need to append a <cr>.

Resources