Using variable in vim key mappings - vim

How can I use a variable when mapping keys in vim? The specific problem that I am trying to solve is the following. I need these key mappings:
nnoremap <C-1> 1gt
nnoremap <C-2> 2gt
nnoremap <C-3> 3gt
... and so on.
Can I specify one mapping; something like
nnoremap <C-x> xgt
where x takes the value of the key pressed (which can be from 1..9)
Thank you.
Edit 1: Towards the solution (not yet complete) thanks to Peter Rincker
I can use the function
function gotoTab(num)
execute "normal" a:num."gt"
endfunction
If I :call goToTab(3), it goes to tab 3.
How do I map Command-x (D-x) to goToTab(x) where x is between 1..9. How do I read the number from a Command-x press?

I got bad news. You can not map <c-1>, etc. You can only bind <c-6> which I wouldn't do as it is very handy.
It also seems like you are doing a heavily tab centric workflow. I know it might sound weird but maybe use less tab panes and more buffers. Here are some nice posts about it:
Why do Vim experts prefer buffers over tabs?
Use buffers effectively!
... Ok, but I really want to do this variable mapping thing. You have options:
Use a for loop and use :execute to create mappings
The more Vim Way is to use a count so 7gt. The 7 is the count.
Example of using :for and :execute:
for i in range(1, 9)
execute "nnoremap \<d-" . i . "> " . i . "gt"
endfor
Note: this uses <d-...> syntax for Command which is only available on MacVim and no terminal support (See :h <D-). You can use <a-...> for Alt. However I must warn you using Alt on the terminal can be tricky.
For more help see:
:h keycodes
:h map-which-keys
:h :for
:h :exe
:h count
:h v:count
:h range(

Related

Mapping Ctrl+[ and Ctrl+] to move between buffers in Vim

I'm trying to map Ctrl+[ and Ctrl+] to move between buffers.
I have this in my .vimrc:
nnoremap <c-[> :bprevious<CR>
nnoremap <c-]> :bnext<CR>
nnoremap <Esc> :noh<CR>
The Ctrl+] works. The Ctrl+[ trigger an :noh and I don't know why.
I would like to Ctrl+] and Ctrl+[ simply move between buffers and Esc to trigger an :nho.
ctrl+], ctrl+ [ and ESC are already being used by vim. Mapping keys which are already being used by vim is not recommended.
More at :help map-which-keys.
So, instead of mapping those keys, I would like to suggest, for example, to use F2 and F3
nnoremap <F2> :bprevious<CR>
nnoremap <F3> :bnext<CR>
#dlmeetei and #Lucas Beier are correct. These are poor keys for Vim.
Map safe keys like function keys, leader mappings, or unused mappings. Example (same as unimpaired.vim):
nnoremap [b :bprevious<c>r
nnoremap ]b :bnext<cr>
nnoremap ]B :blast<cr>
nnoremap [B :bfirst<cr>
For more help see:
:h map-which-keys
:h key-notation
:h :bfirst
:h :blast
We can do better! or The problem with cycling buffers
Cycling buffers is kind slow. I believe :bprevious and :bnext are only useful in a narrow set of conditions:
These commands become useful after you use more than 2 buffers (probably due to <c-6>/<c-^>).
Once you hit a certain buffer number threshold, there is sort of an upper limit on the usefulness of cycling with these commands. Is it faster to cycle forward? Backwards? Does it matter because it simply takes too long either way?
Instead of cycling with :bp and :bn you can jump directly to a buffer via :b command. Simply use :b {partial_name}<tab>.
Behold the power of :b:
Uses <tab> completion
Use <c-d> to list out completion
Use partial file name. e.g. :b foo. Works great with <tab>.
Globbing. e.g. :b foo*bar or :b foo/**/bar
Split variant of :b is :sb.
Also accepts a buffer number
A common mapping: nnoremap <leader>b :ls<cr>:b<space>
For more help see:
:h :b
:h :ls
:h cmdline-completion
:h file-searching
Can we do better than :b?
Skip the buffer management completely and use tags, cscope, and/or GNU Global. These will help you go directly to where you want to go not just the right buffer with where ever you last left the cursor.
For beginners to tags I suggest Gutentags and :h tags.
You can also use :find with tab completion and set your 'path' to .,,** for a basic less fuzzy finder.
For more help see:
:h CTRL-]
:h tags
:h cscope
:h :find
:h 'path'
Plugins?
A fuzzy finder like CtrlP or fzf allows for general file navigation. For more specific project navigation you can use something like Projectionist.vim.
Conclusion
I would suggest slowly learning more buffer and general navigation commands. These commands will serve you well and help you navigation quicker without resorting to buffer cycling.
Personally, I use a combination of :b, tags, cscope/GNU Global, and projectionist.vim for most of my navigation needs. I often have over 50+ buffers open and get to my desired file without ever resorting to buffer cycling.

Vim: Issue with visual mode commands

I'm simply trying perform some commands on text that is selected in visual mode.
If I select some text & then press y (for yank) or d (for delete), it yanks or deletes the selected text
However I need to be able to do this from the command line (because I'm writing a function that I'm going to remap to one of my keys).
However when I enter the command line from visual mode '<,'> is there by default, so I just try to append y or d to the end of it leaving me with :'<,'>d
The problem with this however is that it deletes the whole line that the visual selection is in. I only want to delete the selection I made within the line.
I've tried looking at http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection but nothing I try seems to work.
I'm sure it must be something simple but I just don't know what. Any help would be greatly appreciated.
All Vim native ex commands work on lines. I guess you can buck this trend. However you seem to be wanting to create a command simply so you can map it some key(s). You probably just want to call the function directly or creating a <Plug> or <SID> mapping instead.
Calling a function directly
xnoremap * :<c-u>call YourFunctionGoesHere<cr>
The secret sauce using :<c-u>call here. You probably want to use :normal! gv inside your function.
Using <Plug>
Here is a quick-n-dirty visual start example showing:
function! s:vstar()
let reg = ##
normal! gvy
let #/ = '\V' . substitute(escape(##, '\'))
let ## = reg
endfunction
xnoremap <Plug>(vstar) :<c-u>call <SID>vstar()<cr>/<c-r>/<cr><cr>
This show how to create the <Plug> map which shows how to call a function which is the same as calling the function directly example. The use of <SID>/s: makes sure the function is "namespace'd" to the current script.
Now you can just map * to your <Plug> mapping like in your ~/.vimrc file:
xmap * <Plug>(vstar)
This is how Vim Plugin's create their mappings. A good starting place for learning Vim plugins is :h write-plugin and looking at some very popular vim plugins. I suggest you look at Tim Pope's or Ingo Karkat's plugins as both are very prolific authors.
For more help see:
:h <Plug>
:h <SID>
:h using-<Plug>
:h write-plugin
:h c_ctrl-u
:h :norm

Two key maps conflict in vim, need to know why

from cscope i got this nmap:
nmap <C-\>s :cs find s <C-R>=expand("<cword>")<CR><CR>
and i had these maps originally:
nmap <tab> v>
nmap <s-tab> v<
vmap <tab> >gv
vmap <s-tab> <gv
Now if i type s, then it will jump to the definition with one side effect:
it will tab the target line or target function/class content.
I can't find out where is this conflict. It seems that these two maps have no relationship.
I have tried out your mappings w/o any issue, so I assume there might be some kind of trailing charter issue like #glts suggested in his comment. Use :set list to show invisible characters.
However there are somethings you may want to consider:
Unless you are mapping to a plugin or a very special need you should almost always use nnoremap over nmap to prevent recursive mappings.
The vim way to indent/unindent is to use >> / << (or > / < in visual mode). If you want to repeat the command then use .. The dot command will redo the last change. You can use u to undo if you have gone to far. Although I understand the want for mappings such as these, learning and making a habit to use . will help you in your journey to vim nirvana.
Example of nice usage of the . command by showing off quick and dirty substitution.
Search for a common pattern in you file /pat
Change text to something else via c. e.g. cgnfoo<esc>
The gn motion will select the current pattern
repeat with . command.
For more help see:
:h mapping
:h .
:h u
:h >>

How could I bind the vim navigational keys to the same as in emacs?

I'd like to bind these:
CTRLF one character forward
CTRLB one character backward
CTRLN go to the line below the current one ( not in insert mode )
CTRLP go to the line above the current one ( not in insert mode )
Which functions should I bind? How could I find them?
On vim.org you can find a script called Vimacs : Vim-Improved eMACS: Emacs emulation for Vim
The short description says:
Vimacs (Vim-Improved eMACS) brings Emacs's extensive key bindings and modeless editing features to the Vim world, while completely retaining Vim's powerful moded editing style.
So I guess this is all you need.
If you just want those four mappings and not the full Vimacs, you can do this:
nmap <c-f> l
nmap <c-b> h
nmap <c-n> j
nmap <c-p> k
To get ctrl-f and ctrl-b to work in insert mode add these:
imap <c-f> <right>
imap <c-b> <left>
Check out the map command.
:h :map
You might want to consider learning the vim mappings. (h/l and j/k are shorter than ctrl-f/ctrl-b and ctrl-n/ctrl-p).
Also, check out..
:h index
.. for a list of the mappings.

In vim, how can I map a key to toggle folding over the whole buffer?

I'd like to map a key to toggle between foldmethod=indent and no folding. How can I do that?
I'd say zi (toggle foldenable) does the job.
No mapping required. (see also :he folding)
(You could also look at zM and zR)
Since you want to map it to a single key, proceed as follows:
:nnoremap <F10> zi
To force the foldmode to indent each time (not really recommended for me), you'd need a function:
Add the function to your vimrc[2]:
function ForceFoldmethodIndent()
if &foldenable
se foldmethod=indent
endif
endfunction
nnoremap <F10> :normal zi^M|call ForceFoldmethodIndent()^M
inoremap <F10> ^O:normal zi^M|call ForceFoldmethodIndent()^M
Let me know if that works for you. I appreciate if you accept this answer if it does :)
Cheers
[1] with behave mswin
[2] To enter the special keys (e.g. ^O) in commandline or insertmode use e.g.
Ctrl-VCtrl-O or
on windows[1] Ctrl-QCtrl-O

Resources