Special comment snippet for VIM - vim

I want to add comments dependant on the column i'm writing for example if i'm adding a comment over a code which is indented 4 spaces the comment should look like
/* Comment -------------*/
as many dashes as needed to fill up the line till column 100. It should recognize where the position is and how long the comment is.
I can't figure it out with vimscript myself.

You can solve this with an expression mapping; see :help :map-expr:
:inoreabbrev <expr> comsep '/* Comment ' . repeat('-', 17 - indent('.')) . '*/'
This determines the width by subtracting the current indent (via indent()) from a constant. You could use &textwidth here, too.
Whenever you type comsep, it'll be expanded. Alternatively, you could also use an :inoremap <expr> <C-g> ... instead.
To insert the comment text, you could either use input(), or first just insert dashes and re-position the cursor by appending a number of "\<Left> keycodes.
If you use a snippet plugin like snipMate or Ultisnips, those may have functionality to dynamically modify the snippet, but the built-in methods should suffice.

Related

vimscript: How to substitute in current selection?

Inside a function I can use:
s/foo/bar/ge
but it only substitutes the current line.
I'd like to substitute in the current selection. I tried
'<,'>s/foo/bar/ge
with no success.
Any help is appreciated.
This is perfectly fine:
fun! Foo()
'<,'>s/foo/bar/ge
endfun
You may get E20: Mark not set when no visual selection has yet been established, though. For the '<,'> marks to be defined, visual mode must have been left already; but this is also accomplished by the : command that is used to invoke the function, so it shouldn't be a problem (except for special cases like :help :map-<expr>). If you establish the visual selection only within the function, you need to leave it. Instead of
:normal! Vjj
append a <Esc> to leave visual mode (and set the marks):
:execute normal! "Vjj\<Esc>"
Note that hard-coding the selection often is bad style; you usually want a mapping to work either on the selection, or [count] lines, or the current line / entire buffer. For that, it's advisable to define the function with the range attribute; see :help function-range-example for details.

Delete specific lines above current line in vim normal mode? [duplicate]

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.

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.

How to select a rectangular area in visual block mode (Ctrl+v) in empty file (vim)?

I can easily select a rectangular area in a file provided this area contains text or spaces (or anything). I do it with visual block mode and motion keys.
But when I try to create such area in a new file (or any file without text) I can't.
Is there a way to 'expand' this area by automatically filling it with spaces for example? Or am I going in wrong direction?
The reason I want this:
I create a new file with vim and then would like to create a comment block similar to this:
##############################################
# #
# My comment goes here #
# #
##############################################
I can do it over existing text using Ctrl+v+motion keys, then r# to create an area filled with pounds. Then similarly to cut out inner rectangle with spaces.
How do I use this technique on a new file?
Thanks.
Apart from the (very good) answer from Brian Rasmussen, the only way I know of to do almost exactly what you're asking is to use virtualedit mode. This won't let you edit on non-existent lines, but it will let you edit beyond the end of existing lines. Therefore, to turn the current line into a load of # symbols, you could do this:
:set virtualedit=all
v50lr#
To make a 50x5 block, you could create 4 new blank lines and then do the same:
:set virtualedit=all
4o<ESC>
<C-V>4k50lr#
(where <C-V> means press Ctrl+V and <ESC> means press Esc).
I believe there are some plugins for various file types that make it much easier to create comment blocks like this, but I'm not sure which is best.
You could just do something like:
50i#<ESC>yyo#<ESC>48a<SPACE><ESC>a#<ENTER>#<SPACE><SPACE>My comment goes here<ESC>:exe<SPACE>'normal'<SPACE>(49-getpos('.')[2]).'a<SPACE>'<ENTER>a#<ENTER>#<ESC>48a<SPACE><ESC>a#<ESC>p
But maybe that's just me being silly! I'll leave it as an exercise for the reader to figure out what's going on there if you're interested (:help is your friend).
How about this as a slightly more serious alternative: bung the following in your vimrc or in a file in the plugins directory of the vim runtime folder (e.g. ~/.vim/plugins on Unix)
nmap <F4> :InsertCommentBlock<CR>
command! InsertCommentBlock call InsertCommentBlock()
function! InsertCommentBlock()
let linelength = 50
let linelist = []
call add(linelist, repeat('#', linelength))
call add(linelist, '#' . repeat(' ', linelength-2) . '#')
let comment = input('Please enter a comment: ')
call add(linelist, '# ' . comment . repeat(' ', linelength - (4+len(comment))) . '#')
call add(linelist, '#' . repeat(' ', linelength-2) . '#')
call add(linelist, repeat('#', linelength))
call append(line('.'), linelist)
endfunction
See:
:help function
:help 'virtualedit'
:help command
:help nmap
:help repeat()
:help append()
:help add()
:help getpos()
:help :exe
etc...
If you want to create a block like that in a new file, you could do something like 50i#EscY5P
So it's 50 times insert # followed by yank current line and put it 5 times. This will give you a 50x5 block of #.
Of course you still have to do, whatever you do to get from the block of #s to the comment in your post.
The accepted answer mentions using
:set virtualedit=all
However, then you enable virtualedit in all modes, which might not what you want. There is actually also an option to enable it in just block editing mode:
:set virtualedit=block
This is what I put in my vimrc
I don't think there's any to select text that isn't there, but the easy solution would be to "seed" it with something like 76a yy4p ... so draw 76 spaces, then copy the line 4 extra times.

Insert comments automatically in Vim

My SAS code requires this style of comment:
/*
* This is the comment
*/
I've been able to type this command (From the Vim Comment Howto):
:set comments=sl:/*,mb:*,elx:*/
The problem is that once I type this set command I don't know how to actually get those comments to add to the code. The instructions say to type /\*<enter> but in insert mode this just acts normally, and in command mode this does a find on *.
How do I get this to work, and are there better ways than this to automatically insert comment marks?
By default, Vim doesn't automatically insert the newlines or end markers for you. Instead, it makes it easy to insert those as you type, as long as 'formatoptions' contains r:
:set formatoptions+=r
After this, start typing your comment as normal: "/*<Enter>" (in insert mode). After you hit the Enter key, the comment leader (an asterisk and a space) should appear automatically on the next line, ready for you to start typing. When your comment is complete, end it with "<Enter>/"; the <Enter> moves to the next line, and the slash becomes the second character of the end marker. Yes, it will remove the space for you, but only right after you hit enter.
To make editing this type of comment easier, you wish to add the c and/or o characters to formatoptions, as well. The former allows comments to auto-wrap, and the latter inserts the comment leader when you create a new line inside the comment using normal-mode commands.
Which language?
In C Vim autoloads this setting for comments:
" Set 'comments' to format dashed lists in comments.
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
Which works as you'd expect. Maybe you need to add that to the ftplugin for the language/extension you're using?
I have this abbreviation in my .vimrc:
" /// -> insert javadoc comment
iab <buffer> /// /**^M *^M*/^[0A
where ^[0A is ctrl-v + up.
Type /// in insert mode to get a comment like
/**
*
*/
Also remember to check your comments style (:set comments?) if you are using multiple file types. PHP, for example will sometimes use HTML style comments <!-- ... --> if there is embedded HTML, hence typing /* and then pressing Enter will appear to have no effect.
I have the following in my .vimrc file to make sure PHP comments are used by default
au Bufenter *.php set comments=sl:/*,mb:*,elx:*/
HTML code will still be properly commented, however, spaces within HTML code might use the PHP commenting convention (if you use plugins like tComment) and you won't have multi line HTML comments, which I don't think are possible anyways.
this Vim script might solve your problem - just put it into "vimXY/syntax" folder

Resources