I came to an idea that <C-a> in Vim's normal mode should not only increase numbers but toggle booleans. It makes sense if you consider true and false as integers modulo 2.
So, I downloaded an excellent script to do the hairy work and wrote a new definition for <C-a>:
fun! NewCA()
let cw = tolower(expand("<cword>"))
if cw == "true" || cw == "false"
ToggleWord
else
" run the built-in <C-a>
execute "normal \<C-a>"
endif
endfun
command! NewCA :call NewCA()
nnoremap <C-a> :NewCA<cr>
But as it happens, nnoremap doesn't go as far as to check inside functions. I get recursive behaviour if my cursor is not on words true or false.
In this point I swear a lot, why didn't Bram go pick an excellent idea from Emacs, that everything should be functions and key bindings freely setable. Then I just could check the function for <C-a> and call it in that function. But no, I can't find such a function, and the execute "normal foo" phrases seem to be the Vim idiom.
Any suggestions on how I could make <C-a> work such that
Toggle booleans when the cursor is over a word true or false
Fall back to built-in <C-a> behaviour otherwise
Help appreciated!
change
execute "normal \<C-a>" to:
normal! ^A
you can get ^A by running <C-v><C-a> in normal mode
the "!" at the end of normal say "use default mapping"
From :help :normal
:norm[al][!] {commands}
...
If the [!] is given, mappings will not be used.
....
Also defining a command is not needed, you can directly
nnoremap <C-a> :call NewCA()
Related
I've got the following vimscript function:
function! WindowCommand(cmd)
execute a:cmd
if !g:golden_ratio_enabled
normal <C-w>=
endif
endfunction
And I use it like so:
map <space>w/ :call WindowCommand(':vs')<cr>
It's supposed to equalize the windows, but only if g:golden_ratio_enabled is 0, otherwise it should do nothing.
It doesn't work, though, and I'm not sure why, because the following DOES work:
map <space>w/ :vs<cr><C-w>=
What am I doing wrong here?
There are a couple fixes. Thankfully, the fix is really simple
For whatever reason, normal <C-w>foo does not work; You must use wincmd instead. From :h wincmd
*:winc* *:wincmd*
These commands can also be executed with ":wincmd":
:[count]winc[md] {arg}
Like executing CTRL-W [count] {arg}. Example: >
:wincmd j
Moves to the window below the current one.
This command is useful when a Normal mode cannot be used (for
the |CursorHold| autocommand event). Or when a Normal mode
command is inconvenient.
The count can also be a window number. Example: >
:exe nr . "wincmd w"
This goes to window "nr".
So in this case, you should do
wincmd =
Alternatively, you could enter a literal <C-w> character, by typing <C-v><C-w>. In your vim session, this character will be displayed as ^W.
To execute actions with <notation>, use instead:
:exe "normal \<notation>"
I use it a lot to debug mappings.
But in this case, prefer indeed wincmd.
Here is the code that is a practice for writing vim plugin. I write it as per the vim docs: :help usr_41.txt section 41.11 write a plugin.
let s:save_cpo = &cpo
set cpo&vim
if exists("g:loaded_echoplugin")
finish
endif
function s:EchoWord()
echo expand('<cword>')
endfunction
if !exists(":EchoWord")
command -nargs=0 EchoWord :call s:EchoWord()
endif
if !hasmapto('<Plug>EchoWord')
map <F8> <Plug>EchoWord
endif
noremap <script> <Plug>EchoWord <SID>EchoWord
noremap <SID>EchoWord :call <SID>EchoWord()<CR>
let g:loaded_echoplugin = 1
let &cpo = s:save_cpo
unlet s:save_cpo
The code is for displaying the word under the cursor when clicking <F8>. Here is the mapping sequence: <F8> -> <Plug>EchoWord -> <SID>EchoWord -> :call <SID>Echoword() and it works.
Here, however, I have 2 questions:
1. I have used the noremap here, why it is still able to remap or recursive mapping?
2. If I change the mapping from map <F8> <Plug>EchoWord to noremap <F8> <Plug>EchoWord, it will do NOT work.
Could anybody please help to figure it out? thanks!
<Plug>Foo is a mapping. Whether it is itself recursive or not doesn't matter.
When you do a recursive mapping, Vim uses whatever is the current meaning of the commands in the right hand side:
map b B
map <key> db " works like dB
When you do a non-recursive mapping, Vim uses the original meaning of the commands in the right hand side:
map b B
noremap <key> db " works like db
<Plug>Foo doesn't mean anything by default so there's no point mapping it non-recursively.
You want recursiveness, here, so you are supposed to use map, imap, nmap, etc.
I have read the vim docs for the related command carefully, and I have found the root cause. I add it here just for anybody who may concern.
Type the command :help :map-<script> and here is the reason:
Note: ":map <script>" and ":noremap <script>" do the same thing. The
"<script>" overrules the command name. Using ":noremap <script>" is
preferred, because it's clearer that remapping is (mostly) disabled.
Gived this script (packages suggestion was simplified, original takes care of <cword>)
function! CompleteImport()
let packages = ['java.util.Vector','java.lang.String']
call complete(col('.'),packages)
return ''
endfunction
inoremap <F8> import <C-R>=CompleteImport()<CR>
while on insert mode you can add an import and choose between suggested packages pressing F8
But I want to be enable to reach that popup selection from normal mode
function! InsertImport()
exe "normal iimport \<C-R>=CompleteImport()\<CR>"
"this commented line would work too
"exe "normal i\<F8>"
endfunction
map <Leader>ji :call InsertImport()<CR>
so from normal mode ,ji (stands for java import) add an import to word under cursor if it is found
(Move to right position is not a problem so I ommit here)
By now ,ji adds first suggestion from popup and exists insert mode
I have tried :startinsert but no luck.
see on http://vimdoc.sourceforge.net/htmldoc/eval.html#:execute there is a suggested code:
:execute "normal ixxx\<Esc>"
but that final Esc doesn't matter at all (for my vim install at least) This do exactly the same for me:
:execute "normal ixxx"
I would think this is not possible if I haven't found that on docs. So, it's possible to stay on a popup calling from a function?
Other interested docs:
http://vimdoc.sourceforge.net/htmldoc/various.html#:normal
http://vimdoc.sourceforge.net/htmldoc/insert.html#:startinsert
:startinsert usually is the right approach, but it indeed gives control back to the user, so you cannot automatically trigger the completion.
Through the feedkeys() function, you can send arbitrary keys "as if typed". This allows you to start insert mode and trigger the completion:
function! InsertImport()
call feedkeys("iimport \<C-R>=CompleteImport()\<CR>", 't')
endfunction
nnoremap <Leader>ji :call InsertImport()<CR>
PS: You should use :noremap for the normal mode mapping, too; it makes the mapping immune to remapping and recursion.
I am trying to do a comment remap in Vim with an inline if to check if it's already commented or not. This is what I have already and of course it's not working ha ha:
imap <c-c> <Esc>^:if getline(".")[col(".")-1] == '/' i<Delete><Delete> else i// endif
What I want to do is check the first character if it's a / or not. If it's a / then delete the first two characters on that line, if it's not a / then add two // in front of the line.
What I had originally was this:
imap <c-c> <Esc>^i//
And that worked perfectly, but what I want is to be able to comment/uncomment at a whim.
I completely agree with #Peter Rincker's answer warning against doing this in insert mode, and pointing you to fully-featured plugins.
However, I couldn't resist writing this function to do precisely what you ask for. I find it easier to deal with this kind of mapping with functions. As an added bonus, it returns you to insert mode in the same position on the line as you started (which has been shifted by inserting or deleting the characters).
function! ToggleComment()
let pos=getpos(".")
let win=winsaveview()
if getline(".") =~ '\s*\/\/'
normal! ^2x
let pos[2]-=1
else
normal! ^i//
let pos[2]+=3
endif
call winrestview(win)
call setpos(".",pos)
startinsert
endfunction
inoremap <c-c> <Esc>:call ToggleComment()<CR>
Notice the modifications to pos to ensure the cursor is returned to the correct column. The command startinsert is useful in this type of function to return to insert mode. It is always safer to use noremap for mappings, unless there is a very good reason not to.
This seems to work well, but it is not very Vim-like, and you might find other plugins more flexible in the long run.
There are many commenting plugins for vim:
commentary.vim
tComment
EnhCommentify
NERD Commenter
and many more at www.vim.org
I would highly suggest you take a look at some these plugins first before you decide to roll your own. It will save you great effort.
As a side note you typically would want to comment/uncomment in normal mode not insert mode. This is not only the vim way, but will also provide a nicer undo history.
If you are dead set on creating your own mappings I suggest you create a function to do all the hard work and have your mapping call that function via :call. If you think you can get by with simple logic that doesn't need a function then you can use an expression mapping (see :h map-<expr>). You may want organize into a plugin as it could be large. If that is the case look at :h write-plugin to give you a feel
for writing plugins the proper way.
Example of a simple expression mapping for toggling comments:
nnoremap <expr> <leader>c getline(".") =~ '\m^\s*\/\/' ? '^"_2x' : 'I//<esc>`['
there's also this vimtip! http://vim.wikia.com/wiki/Comment/UnComment_visually_selected_text
i use the bottom one with the
...
noremap <silent> ,c :<C-B>sil <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:noh<CR>
noremap <silent> ,u :<C-B>sil <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:noh<CR>
,c comments out a region
,u uncomments a region
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