I like to have comments like this in my C code:
/********************************************************
* Blah
********************************************************/
But I get tired of typing all those asterisks, and copy/pasting can also get annoying. I was wondering if I could possibly create a macro with Vim so that if I press (for example) CTRL+L, it'll automatically insert that structure in my code and align the cursor in the middle (where the actual comment is written).
Any advice would be appreciated. Thanks!
If you are planning to go on snipmate (which IMHO is a good choice!), you should consider using the version maintained by Garbas on github (pay attention to the required plugins in the readme file).
The version from msanders is no longer maintained.
Since I am new I can't add a comment to the answer above... Sorry
Take a look at snipmate, a vim plugin for TextMate-like snippets.
https://github.com/garbas/vim-snipmate
1min screencast: http://vimeo.com/3535418
snipMate.vim implements some of TextMate's snippets features in Vim. A
snippet is a piece of often-typed text that you can insert into your
document using a trigger word followed by a <tab>.
You can use cvim, and edit ~/.vim/c-support/templates/c.comments.template to your liking.
Heh, just today I was beefing up my own support for this (as these headers are mandated by company coding standard).
iabbrev //== // (96 equal characters)<Enter>//<Enter>// (96 equal characters)<C-O>k
iabbrev //-- // (96 dashes)<Enter>//<Enter>// (96 dashes)<C-O>k
These allow me to type //== and when I press space the whole thing is entered and I'm left with the cursor "in the middle" where I want it.
So- for the OP, if you want to use Ctrl-L, do something like this:
inoremap <C-L> /*****<Enter> * <Enter>*****<C-O>k
(I like abbreviations myself, though...)
Since there are other points in our coding standard where we need to extend dashes and equals out to column 100, I whipped this up today:
iabbrev <expr> === InsertTo99Width('===')
iabbrev <expr> --- InsertTo99Width('---')
function! InsertTo99Width(insertion)
let l:line = getline('.')
let l:linelen = strlen(l:line)
let l:col = col('.')
let l:numchars = (99 - col)
let l:inserted = a:insertion
if (l:linelen <= l:col) && (l:numchars > 0)
let l:numchars += len(l:inserted)
while len(l:inserted) < l:numchars
let l:inserted = l:inserted . l:inserted
endwhile
return l:inserted[0 : l:numchars]
else
return l:inserted
endif
endfunction
(I'm sort of a vim scripting newb so there may be an easier way to make a string of N characters long, but this allows arbitrary strings of arbitrary length to be repeated so if you like dash-space-equal-space or something, it'll still look "nice".)
Anyway finally- you can use <expr> in the inoremap too if you want, so you can make your asterisks go to a set width based on the output of a function. There's a lot of power in there, but it may take some fiddling to get it just the way you want...
Related
The m normal command accepts a letter just after it to set a "letter" mark.
I would like to create a similar command that works across tabs... But my problem is with the binding : Is there a simple way to bind for example M<letter> to a function or a command or should I manually repeat all the possibilities ?
As romainl has already said, no.
Covering this for good measure (and in case someone else comes along later), you can only practically map upper-case letters. As is outlined in the documentation, lower-case marks are only valid within a single file. Upper-case ones, that the Vim docs calls "file marks", are valid from anywhere. Unless you have some dark magic function to resolve ambiguous file marks, you probably only need a single for loop mapping the upper-case letters, if you're going with the brute-force option.
That said, there are a couple alternatives here as well.
As far as I know, the only "dynamic" bit of a command is a count (or a range, but unless you want to map characters to a number (and handle ranges and other fun stuff:tm:), I don't recommend this approach:
" The <C-U> is required for all uses. If you want a function,
" you'd need :<C-U>call YourFunction()<cr>
nnoremap M :<C-U>echom v:count<cr>
See also :h v:count, which states:
Note: the <C-U> is required to remove the line range that you get when typing ':' after a count.
You can then run 26M, decode v:count as Z, and then do whatever fancy lookup from there.
The second alternative, and the one proposed by romainl and by far the most used one in cases like this (source: experience and lots of code browsing), is using a for loop to brute-force map letters:
for i in range(char2nr('A'), char2nr('Z'))
exec 'nnoremap M' . nr2char(i) ':echo "This is where the appropriate function call goes"<cr>'
endfor
Which produces all 26 mappings.
And the final approach is abusing getchar(). This means a single mapping, but at the expense of doing additional processing:
func! Func()
let c = getchar()
echo c
" Character processing (the `echo` isn't required) here
endfunc
nnoremap M :call Func()<cr>
You can decide which works for you, but I strongly suggest preferring option 2, as this gives you map timeouts and clear definitions, and more obvious conflict detection.
I’m trying to set up an abbreviation in my .vimrc that will insert a comment template for heading-level comments in my CSS files.
The comment I want to insert is:
/* ==========================================================================
#
========================================================================== */
I will then jump back to the # and add my title there (e.g. BUTTONS).
The abbreviation I have attempted to set up looks like this:
iab comsec·
\/* ==========================================================================
\<Cr>#
\<Cr>========================================================================== */
(Where · represents a trailing space.)
Right away this feels pretty crude, but the specific problem is that if try and drop a comsec in my CSS, it starts wrapping it in more comments. The output looks like this:
/* ==========================================================================
* #
* ========================================================================== */
Notice the two * at the beginnings of lines 2 and 3?
Is there a way to tell vim not to try and be clever and to just drop in exactly what I’ve told it? A way to prevent vim from trying to wrap comments around the comment?
I’m not a particularly hardcore vim user, so there’s every chance I’m overcomplicating things, or missing something obvious, or using the wrong tool for the job.
Thanks!
If you are the type of person who can keep track of your personal utilities, this isn't so fancy but works. You can import the output of an external command into your buffer, so I put a mapping like this in my .vimrc file:
"bc = block comment
map ,bc :read! python ~/my_personal_utils/insert_css_comment.py
So, I just have to type ",bc" to add the comment. On my Mac at least, this leaves me hanging in command mode, so that my cursor is after '.py' and I can quickly type an argument like BUTTONS (i.e. the python script takes an optional argument).
Here is a function to do that.
:function! Comment()
:normal! i/*
:normal! 80a=
:normal! o#
:normal! o
:normal! 80i=
:normal! a*/
:endfunction
You can put this in vimrc file and create a command or map for this.
Command
:cmap comsec call Comment()
You can keep the cursor on a line and then call this command.
Or an in insert mode mapping
:imap comsec <ESC>:comsec<CR>
As alternatives I'd suggest nerdcommenter for commenting/uncommenting with a few key strokes.
Or, even better, ultisnips. In which you can easily make your own template for those headings:
open a .css file
exec command : UltiSnipsEdit
create your own snip:
snippet heading "heading comments"
/* ===================================
* ${1}
* =================================== */
endsnippet
Here is a better and simple way to to insert your comment which check everytime if the line is surrounded by the comment template.
All you have to do is to write your comment on new line and then press ; during the insert mode. (you can change the character ; by
any combination you want.)
The comment template is set by the variable l:start, l:begin, l:end
so you can change the number of spaces or = as you like.
If you would like to change the template completely keep in mind that you need to change also the regular expressions for the variables l:matchprev, l:matchhier, l:matchnext .
inoremap <silent> ; <Esc>mx:call Comment()<cr>i<Right>
function! Comment()
let l:start= "/* ====="
let l:begin=" # "
let l:end= " ==== */"
let l:next=getline(line(".")+1)
let l:hier=getline(line("."))
let l:prev=getline(line(".")-1)
let l:matchnext= matchstr( l:next , '^\s*=\+\s*\*/\s*$')
let l:matchhier= matchstr( l:hier , '^\s*#\s*.*$')
let l:matchprev= matchstr( l:prev , '^\s*/\*\s*=\+\s*$')
if l:matchnext != '' && l:matchprev != '' && l:matchhier != ''
return 0
else
execute ":s:^.*$:".l:start."\r".l:begin."&\r".l:end."\r:"
"the number 3 is the length of the variable l:begin
normal! `xj3l
endif
endfunction
write this code in another file scriptname and then you can use the mapping in any css file by typing in the command mode first :so scriptname
Another alternative is to put all that simply in your .vimrc file
The best practice mentioned in the title is the one suggested by Uri:
When writing paragraphs, start each
sentence at the beginning of a line,
and if it spills over, each subsequent
line is tabbed.
I use gVim with Vim-LaTeX, which comes with an indent/tex.vim file, to edit LaTeX files. The way I currently implement the practice mentioned above is as follows:
I :set textwidth=79 to automatically break lines before they become too long.
I manually hit Enter after I finish inserting each sentence.
If I'm done with revising and editing a sentence, I manually shift any spillovers using >>, prefixing it with a count if necessary.
Occasionally, that last step will make one or more spillovers go over the maximum line width. In this case, I
gqq the faulty line.
J my way through to the end of the sentence.
repeat steps 1 and 2 as necessary.
As you can imagine, this can become tedious. Isn't there a more efficient way to achieve the same result? Ultimately, I want to be able to write the sentences without worrying about their format, and then use gqap, or gqip, to automatically produce the result that I currently produce manually.
To do that, I suspect that I will need to write a formatexpr of my own, but I'm not sure how to proceed. I have found a number of plugins, Latex Text Formatter and Text (Especially LaTeX) Formatter, and a tip, but none of them seem to suit my needs, and I'm not sure how to modify them to do so.
I may well be oversimplifying the problem, but does this mapping do what you want?
nnoremap \z (j>>gq)
So pressing \z in normal mode will do the following: From the cursor position, jump to the start of the sentence. Then go to the next line and indent it. Then reformat from this line to the end of the sentence. Reformatting sentence-wise is the way to go, rather than reformatting each line individually, as your method seems to do.
Of course you can use an insert-mode mapping if you prefer, or even try redefining the behaviour of the Enter key to do this automatically (although I don't know if this will have unintended consequences...).
One way to do this is not by actually breaking the lines in the file but instead doing the following:
set wrap linebreak
let &showbreak='===> '
The wrap option makes long lines wrap instead of extending off the screen and linebreak makes the line breaks happen only at characters specified in the breakat option.
You can set showbreak to anything that is pleasing to your eye. My favorite when I'm using vim where unicode characters work right is:
let &showbreak="\u21aa "
This puts a ↪ symbol at the beginning of each wrapped line.
I also like to turn on line numbers (set number) to give another indicator of what the actual lines in the file are.
To make navigating the file easier you might want to use
noremap j gj
noremap k gk
noremap gj j
noremap gk k
This makes k and j move up and down by displayed lines not file lines. To affect the cursor keys as well replace k with <Up> and j with <Down>.
One option that takes different tack than tabbing subsequent lines would be to set the w flag in formatoptions. When you do that it changes the way Vim identifies new paragraphs, and lines ending in a space are understood to continue on a new line as part of same paragraph. See :h fo-table.
If you set the w flag and enter your text so that continued sentence lines are the only ones ending in a space (and abandon completely practice of entering tabs at beginning of any text lines) then I think you should be able to use gqap to format text paragraphs as you want. To get visual cues to logical structure you can then set listchars to display the eol (i.e., <cr>) character and set different highlightings for <space><cr> and for <non-space><cr> so that sentence/paragraph ends are easily spotted.
Another benefit of this method is that you can just type your text naturally and let line breaks be entered automatically by textwidth setting. (Just make sure that LaTeX formatting lines don't break automatically in textwidth area; you want them to have non-space char as last char in line.)
That tip also caught my eye. Here's how I solved the problem (a diff of the changed lines in tex.vim):
*** tex.vim.old 2011-08-16 08:26:56.845046457 +0200
--- tex.vim 2011-08-16 08:59:14.736306930 +0200
***************
*** 90,95 ****
--- 90,96 ----
" LH modification : \begin does not always start a line
if line =~ '\\begin{\(.*\)}' && line !~ 'verbatim'
\ && line !~ 'document'
+ \ || line =~ '^\s*[A-Z].*[a-zA-Z0-9,]\s*$\C'
let ind = ind + &sw
***************
*** 105,110 ****
--- 106,112 ----
" Subtract a 'shiftwidth' when an environment ends
if cline =~ '^\s*\\end' && cline !~ 'verbatim'
\&& cline !~ 'document'
+ \|| line =~ '\.\s*$'
if g:tex_indent_items == 1
" Remove another sw for item-environments
Basically it indents new lines when the previous line starts with a capital letter and ends with a letter, digit, or comma, and "unindents" new lines with the previous line ends with a period.
There is definitely room for improvement (better criteria) but for me it works all right so far.
I find the suggestion from #kev (and the people commented) at this post to be the most satisfying.
There, it is explained that by setting
:set fo+=n
followed by either
:let &flp='^\s*\\(item\|end\|begin)*\s*'
or
:let &l:flp='^\s*\\\(item\|end\|begin\)\s*'
lets you type gggqG to reformat the entire file.
I use the vim-textobj-usr plugin to define a "LaTeXPar" text-object. Then I can use gwal to format.
There is already a vim-textobj-latex plugin, but the biggest text-object it defines is "environment". This is not what I (and OP) want.
A "LaTeXPar" is delimited by
an empty line
a line begin with \[, \], \begin, \end, }
a line end with {
this is adapted to my writing habit: I always have an empty line after \section, always use \[ \] on a single line, and so on. You can easily write one for yourself.
Here is the relative part in my ~/.vim/ftplugin/tex.vim.
call textobj#user#plugin('latexpar', {
\ 'par': {
\ 'select-a-function': 'LaTeXPar',
\ 'select-a': 'al',
\ },
\ })
function! LaTeXPar()
let pattern='\v^$|^\s*(\\\[|\\\]|\\begin|\\end|\})|\{$'
if search(pattern,"bW")
normal! j
else
normal! gg
endif
let head_pos = getpos('.')
if search(pattern,"W")
normal! k
else
normal! G
endif
let tail_pos = getpos('.')
" echo head_pos[2]
" echo tail_pos[2]
return ["V", head_pos, tail_pos]
endfunction
I’m switching from Notepad++ to Vim as my main text editor.
In Notepad++, you can have multiple cursors by holding down Ctrl and clicking anywhere in the text, so that if you type, the text appears in multiple locations.
Is it possible in Vim? Something like insert after selecting multiple rows in Visual mode, but with the possibility to have cursors anywhere in the text.
It’s a feature I rarely use, and it’s also quite easily avoidable; I’m just curious, since it’s the only one I could’t find a replacement for in Vim yet.
There is not a built-in feature of that kind.
Let me suggest a function that repeats command (for example . repeating last
change command) at the positions of given marks. Both marks and command are
specified as string arguments. Marks specified in the way ranges in regular
expressions or scanf-format specifier are defined. For example, za-dx
means marks z, a, b, c, d, x.
function! MarksRepeat(marks, command)
let pos = 0
let len = strlen(a:marks)
let alpha = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
let beta = '1234567899bcdefghijklmnopqrstuvwxyzzBCDEFGHIJKLMNOPQRSTUVWXYZZ'
while pos < len
if a:marks[pos + 1] != '-'
exe 'norm `' . a:marks[pos] . a:command
let pos += 1
elseif a:marks[pos] <= a:marks[pos+2]
let mark = a:marks[pos]
let stop = a:marks[pos+2]
if mark =~ '[0-9a-zA-Z]' && stop =~ '[0-9a-zA-Z]'
while 1
exe 'norm `' . mark . a:command
if mark == stop
break
endif
let mark = tr(mark, alpha, beta)
endwhile
endif
let pos += 3
endif
endwhile
endfunction
In your case, the function could be used as follows.
Mark all places for simultaneous insertions (except one) using Vim
marks (by means of m command).
Actually insert text in the one place that has not been marked.
Run the function:
:call MarksRepeat(‹marks›, '.')
You could insert the text in one place, in a single operation, then use . to repeat that insertion at each other place you want the text.
It's the converse of what you asked for, because you wanted to mark the locations before entering the text, but it gives you the same result in the same number of keystrokes :).
Check multi select vim plugin: http://www.vim.org/scripts/script.php?script_id=953
ib's response and the multi select vim plugin are interesting, but the following is a suggestion that does not require a special function or plugin.
Temporarily set foldmethod=manual, then mark the blocks you want to operate on with zf.
Finally, use the ex command :folddoclosed to do ex commands on the folded blocks.
For example: :folddoclosed norm Iinsert some text at the front
Note, you can use :folddoclosed on any folded groups of lines, so you could use other foldmethods... but usually it makes sense to manually create the folds.
You can also use visual markers, followed by :norm which gives you :'<,'>norm... But visual markers only let you select a continuous range of lines. Using folds and :folddoclosed you can operate on multiple ranges of lines at once.
Another tip... to save time having to type out :folddoclosed, I will type :fo<shifttab><shifttab><shifttab>
As title, if I'm in the middle of function body and the function body is very long, how can I jump back to the beginning of the function body .
[m
Go to [count] previous start of a method
Works for Java or similar structured languages, and for Python as well.
C language [[
If your C code is in the non-Egyptian style:
[[
[m only works if you have an enclosing {} around the function, e.g. class { method(){} } for Java / C++.
And this is a good bet that works for both Egyptian and non-Egyptian braces:
?^[^ \t#]
Examples:
void egypt() {
#define DONTCARE 1
int indented code = 1;
}
void tpyge()
{
#define DONTCARE 1
int indented code = 1
}
For functions contained in a pair of curly-braces {}:
Jump to beginning: [{
Jump to end: ]}
Replace the curly-blackets by parens or square-brackets for functions that use those.
I spent hours to make this pattern: /^\s*\(\i\+\_[ \t\*]\+\)\+\i\+\_s*(\_[^)]*)\_s*{, it works good for me.
EDIT: a better pattern(version 2): /\(\(if\|for\|while\|switch\|catch\)\_s*\)\#64<!(\_[^)]*)\_[^;{}()]*\zs{
see the effect here:
you can map some convenient bindings in your .vimrc, such as:
" jump to the previous function
nnoremap <silent> [f :call search('^\s*\(\i\+\_[ \t\*]\+\)\+\i\+\_s*(\_[^)]*)\_s*{', "bw")<CR>
" jump to the next function
nnoremap <silent> ]f :call search('^\s*\(\i\+\_[ \t\*]\+\)\+\i\+\_s*(\_[^)]*)\_s*{', "w")<CR>
EDIT: a better pattern(version 2):
" jump to the previous function
nnoremap <silent> [f :call
\ search('\(\(if\\|for\\|while\\|switch\\|catch\)\_s*\)\#64<!(\_[^)]*)\_[^;{}()]*\zs{', "bw")<CR>
" jump to the next function
nnoremap <silent> ]f :call
\ search('\(\(if\\|for\\|while\\|switch\\|catch\)\_s*\)\#64<!(\_[^)]*)\_[^;{}()]*\zs{', "w")<CR>
In 2022, treesitter deserves your attention.
The built-in [m uses lexical rules and always jumps to the previous { position or the outermost { position.
In contrast, treesitter takes advantage of syntactic information, so it can jump to a more precise position, and there are no limitations as described below:
The above two commands assume that the file contains a class with methods.
The class definition is surrounded in '{' and '}'. Each method in the class
Each method in the class is also surrounded with '{' and '}'. This applies to the Java language.
file looks like this: >
If you want to learn more, check https://github.com/nvim-treesitter/nvim-treesitter-textobjects
BTW, the only relatively sure way to be able to do this is to modify vim, see this post
[edit]
and this only works with languages supported by exuberant ctags. Since we've not been deigned fit to know which language you wish to do this in, it's possible that this answer will not be correct either.
[/edit]
Once you've got moving around blocks and paragraphs in code sorted you might like to look at what you can do when you're in the middle of those blocks by looking at this part of the vim doc's.
Things like delete the block, insert before the block, append after the block, etc.
HTH
Searching (backwards) for ?^{ should normally get you there.