Insert character without entering insert mode? - vim

Sometimes I want to insert a # to comment out a line and test it quickly. Currently I do:
i#ESC:w
Is there something shorter I can do?

Although I agree with others that there are better ways to comment and uncomment code, it seems that people have gotten distracted and forgotten to actually answer the question.
This is my approach to inserting a single character:
:noremap <key> i <Esc>r
I tend to find that I need to replace, remove, or add single characters very often if I'm correcting typos, so (resp.) r, x, and whatever is chosen for <key> in the above become very handy.
Note that . is also particularly handy for this sort of task. It repeats the previous action.
Personally though, I only map this function to a valuable key when I'm doing a task where I use it frequently enough to justify occupying a prime spot on the keyboard (such as correcting typos), because really, it only saves one keystroke per use and that's only when <key> is not a combination, which of course limits availability.

I map a couple of things to my <leader> key (\ by default):
" # comment the current line
nnoremap <leader>d I#<ESC>
" block comment in visual mode
vnoremap <leader>c <ESC>'<O/*<ESC>'>o*/<ESC>V'<k
If you want to add a # to the start of a group of lines, then do this:
<ctl-v>
j (as many times as necessary
I#
<esc>

You could use a recording. From normal mode, type:
qlml0i#<press escape>`lq
Then to comment out a line, just press #l

Mapping in vim is so easy that I might do something like
:nmap CC I#<Esc>:w<CR>
on the fly. If I get used to it, then I will add it to my vimrc file.
:help key-mapping
:help usr_40.txt

Actually there is a plugin you might wanna take a look at:
http://www.vim.org/scripts/script.php?script_id=1218
It is specifically designed for that purpose.

I'm particularly fond of the tComment plugin. gcc to comment a line, repeat to uncomment, multiple lines, motions, etc.

Related

Is it possible to easily insert a single word in vim

I often want to insert a single word with vim. Is there a way to insert as many Chars as you want until you type a <Space> which then acts as an <esc>?
I know that a normal i with an <esc> doesn't take too long, but I would like to have such a command and the <esc> is quiet hard to reach.
You should consider the following
remap caps lock to esc or;
remap caps lock to control, and then use
the alias for esc which is control-[.
Otherwise, though this isn't quite what you're looking for, see this post for a possible approach, but also read Ingo Karkat's answer there for why it may not be such a great idea to make such mappings.
Please mention the most underrated <C-c>

Swap two characters atomically, so that it can be repeated with "."

The idiom for swapping two characters in Vim is xp.
See the help at :h 04.5, final paragraph, and Vim: how do I swap two characters?.
But very occasionally I need to do two or more swap operations in a row. I'm often surprised that what feels like a single operation to me, xp, is actually two operations to Vim. This makes it impossible to repeat xp with .. (Or atomic undo with u.)
Is there a way to swap two characters in a single operation that I can quickly repeat with .?
This isn't ideal, but if you store xp as a macro, it will be repeatable after you've executed the macro. So instead of xp, you're using, say #s (for swap). Then ## will repeat it. Not as nice as ., but it does work.
Edit: You know, I'm sure there's a way to accomplish this with some vimscript and tpope's repeat.vim. Sadly, my vimscript is not up to snuff. I got this far - maybe someone can correct where I'm going wrong?
fun! DoSwap()
:normal xp
silent! call repeat#set("\<Plug>Swap",1)
endfun
nnoremap <silent> <Plug>Swap :call DoSwap()<CR>
nmap <Leader>s <Plug>Swap
The problem with this is that once you enter \s, it does indeed swap the characters you're on, and it DOES repeat when you hit ., but it jumps to the beginning of the line first, which is not what you want. But I do think this can be done, I'm just not all the way there.
Here's an idea. Suppose the cursor is on the "y" of the word "oyxgen".
In normal mode, type
2sxy<Esc>
Now the word reads "oxygen". Find the next instance of the typo (fy) and repeat the change (.).
Too bad this works only for the specific swap "yx" to "xy", so this isn't the definitive solution.
Vimcasts.org has published an episode that addresses this very problem.
As #Jeremy guessed the solution is to use the repeat.vim plugin. Then simply add the following <Plug> mapping and key mapping to your vimrc.
nnoremap <silent> <Plug>Transpose xp:call repeat#set("\<Plug>Transpose")<CR>
nmap cp <Plug>Transpose
The mapping shown here uses cp. cp is the new xp, repeatable with . but otherwise exactly the same.
Now all that remains is getting used to it.

Advanced Usage of Ranges with Vim Keymappings

I have a mapping in my vimrc that downwardly comments out regions of c code:
nmap comc :normal! I//<ESC>
Since the 'normal' ex command implicitly converts input such as "Ncomc" to ".,.+N-1 comc", I can range comments downwardly without many keystrokes and without leaving normal mode. This is, however, a very limited subset of what vim ranges can do. If I'm willing to be verbose, I can achieve upward ranging comments like so:
.,.-5 normal comc
While editing text, I would much prefer to type something like "-6comc" or make a mapping of "Comc" that uses upward ranges. I'm haven't been able to do so successfully.
Similarly, range operations support commenting until a search pattern is reached, e.g :
.,/int main/ comc
I would, however, like to do so without all that typing.
The behavior you requested is normally done with :h map-operator mapping. With this commenting 3 lines down will turn into comc2j though, but 3 lines up is now just as easy: comc2k.
You can also use visual mode without changing your mapping at all: V2kcomc. You will have to add xnoremap with the identical lhs and rhs because nnoremap works only for normal mode. (And do not use nmap.)
Third option is mapping - to something that moves {count} lines up and puts count back:
nnoremap <expr> - (v:count ? ":\<C-u>\n" . (v:count-1) . 'k' . v:count : '')
. This assumes you are writing 6-comc, not -6comc.
// By the way, I would suggest The NERD Commenter if it comes to the plugin.
While it's commendable to go as far as possible without any plugins, sometimes they're just the best option. What will you do when you start working in a language that has comments with # or (*...*)? Add new mappings for these comment characters?
I recommend commentary.vim which does filetype-aware commenting.
The default commenting operator in commentary.vim is gc. You can combine it with motions, and use it in Visual mode too.
Your use cases:
Comment downwards N lines (say, 3): :.,.+3normal gcc, or gc3j or 4gcc.
Comment upwards 5 lines: :.,.-5normal gcc, or simply gc5k.
Comment until int main: :.,/int main/-1normal gcc, or simply gc/int main followed by Enter.

mapping # in vim

In my .vimrc I have mapped the #-key to a macro for commenting out/in lines of code.
Unfortunately # in vim already has a function - it searches backwards for the word beneath the cursor.
What I would now like to have is a way to map this functionality to another key-sequence (ideally I would like to have Control-* for that as * alone searches forward).
Does anyone know how to achieve this?
Many thanks!
Unfortunately, Ctrl + * cannot be used; I would propose \*; it's longer to type, but backwards searches are probably not that common.
:nnoremap <Leader>* #
Like Ingo Karkat said, mapping Ctrl+certain keys is impossible in vim. However, you can map Alt+8 instead:
noremap <A-8> #
I suggest Alt+8 instead of Alt+* because if you wanted to bend your hand in unnatural ways to press more than one modifier keys to perform a command, you would probably be using Emacs instead of Vim.
I use \+c for commenting and \+d for removing comments. The mappings are following :
:map \c <ESC>:s,^\(\s*\)[^/ \t]\#=,\1// <ESC>,e<CR>j$a
:map \d <ESC>:s,^\(\s*\)// \s\#!,\1<ESC>,e<CR>j$a
Above mappings are used in command mode. Taken from one answer on SO, which I am currently unable to find.

Making inserting a single character in Vim an atomic operation

I've long used this very useful shortcut in vim:
nmap <space> i <esc>r
this means that if I press spacef, for example, it will insert a single character f at the given position.
unfortunately, however, this is not atomic, ie, if I press spacef and then navigate somewhere else, then press ., I get the equivalent of rf, not spacef.
all this makes sense, but here's the question: is there a way of making this atomic, so that . will repeat the 'insert character' operation, and so that undo etc all treat it as one operation, too?
Awesome! Michael's answer pointed me to the plugin I needed to finish my plugin, which can now do what you want - I had been trying to figure out how to do this for ages!
1) Install Tim Pope's plugin
2) Install my plugin
3) Add a mapping to your .vimrc:
nnoremap <space> :<C-U>call InsertChar#insert(v:count1)<CR>
Does this work for you?
noremap <silent> <space> :exe "normal i".nr2char(getchar())<CR>
You might want to have a look at this plugin script. It may be possible to configure your map so it can be supported. Read the supporting docs
http://www.vim.org/scripts/script.php?script_id=2136
Sorry I can't provide a specific answer to your problem but I will note that I tend to use the . key when I have to reproduce quite a lot of commands (e.g. I want to insert f 5 or more times).
If that is the case here, I don't think the saving of using your macro is worth it. You save one keystroke by using your macro rather than ifesc and that operation is atomic so you could then . to your heart's content.
I would just use the non-macro version if I know I want to repeat it a lot.
P.S. You know I'm starting to like the <kbd> tag quite a bit :-)

Resources