Create VIM Keybinding executing two commands and ranges (count) - vim

I am using Slimux and often use range modifiers to send code to a REPL. The keyboard shortcut ",s" sends a new line to the REPL, executes the commands () and advances one line (j),
map <Leader>s :SlimuxREPLSendLine<CR>j
If I use ranges, e.g. "5,s", this sends 5 lines of code to the REPL, but only advances one line (j) instead of 5j. I tried playing around with :exe and v.count1 to achieve this, but was not very successful.
Can anyone provide a code example (and explanation how this works)?

This should do the trick:
noremap <Leader>s :SlimuxREPLSendLine<Bar>execute 'normal!' v:count1 . 'j'<CR>
It depends on the :SlimuxREPLSendLine command having been defined with -bar to be able to append another command to it.
PS: You should use :noremap; it makes the mapping immune to remapping and recursion.

Related

Prevent map from breaking on motion command error

The idea is to have a map that allows me to fold blocks of code enclosed in curly braces.
nnoremap zff 0f{zf%
This works as expected but only on the opening brace.
The following version seems to work as long as { and } are on the same line. Should they be on different lines though the cursor only jumps to the opening { and no fold is created.
nnoremap zff 0f{f}zf%
edit:
The problem appears to be that once there is an error in one of the motion commands the map breaks.
:silent! prevents ex commands from breaking a map in case of an error. Is there an equivalent for motion commands?
Your first mapping should work, unless you have a filetype detection or syntax problem that prevents proper pair-matching.
Your second mapping can't work because f (and FtT) only works on the current line. Alternatives:
f{v/}<CR>zf
f{zf/}<CR>
But you can use zf with text-objects:
zfi{
zfat
zfip
so… why bother with a mapping?
You're right that an error in a command sequence breaks the sequence, and this is usually right. If you want to continue even in case of errors, just execute the commands separately through :normal!. This can be chained in a single command-line via :execute:
nnoremap zff :exe 'normal! 0f{' | exe 'normal! f}' | exe 'normal! zf%'

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

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.

Function arguments not evaluating

I'm trying to set up a couple of maps to quickly go through merge conflicts. Here's my code:
func! DiffAccept(w)
diffget a:w
diffupdate
normal ]c
endfunc
noremap dh :exec DiffAccept("//2")<CR>
noremap dl :exec DiffAccept("//3")<CR>
Every time I try to use this I get "No matching buffer for a:w". I'm clearly using this variable wrong, but it acts as expected when I change the line to "echo a:w".
Vim's evaluation rules are different than most programming languages. You need to use :execute in order to evaluate the (function argument) variable; otherwise, it's taken literally (as a buffer name):
execute 'diffget' a:w
PS: Prefer using :normal! (with !); this avoids interference from mappings.

map execute command vim

I found the following execute command to be useful in vim:
:execute "normal! mqA;\<esc>`q"
it goes to normal mode, then it makes a mark "q" at cursor position,
goes to end of the line and adds a semicolon ";", then it goes to
normal mode again and returns to the original cursor position.
How could I map all this command to a key called "scc"?
I have tried:
imap scc <Esc>:execute "normal! mqA;\<esc>`q"<CR>
however it didn't work. Thanks.
You don't need :execute - normal, you can simply do (and use the "noremap" form):
inoremap scc <Esc>mqA;<Esc>`q
But your map keys are not very good chosen(?), try e.g. <F3> for function key 3.
Others have dealt with the core problem but I should had that, instead of creating an alphabetical mark, you could use a "context mark":
inoremap <something> <Esc>m`A;<Esc>``
Using an alphabetical mark is not wrong, mind you, but I think they are more useful elsewhere.

Vim - how to store and execute commonly used commands?

If I wanted to process a batch of text files with the same set of commands for example:
:set tw=50
gggqG
Can I save the above and run it with a shortcut command?
If you want to use it only once, use a macro as specified in some of the other answers. If you want to do it more often, you can include the following line in your .vimrc file:
:map \r :set tw=50<CR>gggqG
This will map \r to cause your two lines to be executed whenever you press \r. Of course you can also choose a different shortcut, like <C-R> (Ctrl+R) or <F12> or something.
The following in .vimrc will define a new command Wrap that does what you want.
command! Wrap :set tw=50 | :normal gggqG
Call it with :Wrap
As a very quick start, put this in your .vimrc:
" define the function
" '!' means override function if already defined
" always use uppercase names for your functions
function! DoSomething()
:set tw=50
gggqG
endfunction
" map a keystroke (e.g. F12) in normal mode to call your function
nmap <F12> :call DoSomething()<CR>
note: the formatted code above looks rather horrible, but lines starting with " are comments.
Other than macros, you can use argdo. This command will perform the same operation on all open files. Here is how you format all open files using :argdo and :normal:
shell> vim *.txt
:argdo exe "normal gggqG"|up
Before you go for writing a thousands-lines .vimrc (which is a good thing, but you can postpone it for a while), I think you might want to look at the plain recording, in particular you may consider using the qx (where x is any key) for recording, q to finish recording and #x to execute recorded macro.
Yes, the important word is macro
But it seems like a 'command' such as :set tw=50 would be better included in the .vimrc file so vim uses it every time you start it up.

Resources