How can you reformat C source code '{' placements in VIM? - vim

I want to change the following code:
if (test)
{
statements;
}
else
{
statements;
}
To the following:
if (test) {
statements;
} else {
statements;
}
Using '=' doesn't do this function (as far as I can tell).
Is there any clever VIM command to do this?

You can play with regexes. Here, it will be:
:%s/\_s*{/ {/g
:%s/}\zs\_s*\ze\(else\|while\)/ /g
The secret is in /\_s which is like /\s (which matches spaces), but which also matches newlines.
If you also want to transform things like { return foo; }, you'll have to insert newlines as well, and then reindent everything.
:%s/\_s*{\_s*/ {\r/g
gg=G
You can also have a look at vim plugins that integrates tools like AStyle or clang-format which should give better results.
PS: lh-cpp and mu-template snippets have an option (through :AddStyle) that lets the end-user specify whether a newline shall be inserted or not. Sometimes, the better approach is to produce code that conforms to project style.

Related

Highlight C/C++ function declarations and function calls differently in Vim

I am used to the way Sublime Text highlights function declarations vs function calls and am trying to emulate something similar with Vim. There are posts addressing something like this, but they seem to highlight declarations and calls the same way.
int function1() {
function3();
}
int function2()
{
...
}
Here, function1 and function2 should be of one color and function3 should be of another color. I am trying to write regular expressions to match each of these cases and then going from there.
So far, I came up with
syn match cFunDecl "\zs\w\+\ze(.*){"
syn match cFunCall "\zs\w\+\ze(.*);"
These don't really seem to work. Following this approach, I also expect to run into issues with header files where declarations are highlighted as calls but will probably deal with that later.
This is possible with Neovim and nvim-treesitter. I will note, it's probably also possible with LSP plugins such as vim-lsp-cxx-highlight, but I've found those to be a nightmare to work with.
First of all, you want to create a fork of nvim-treesitter. The reason is that, currently, function calls and declarations are highlighted the same in the c module. That's really easy to change, though. In your fork, go to queries/c/highlights.scm. Lower in the file you should see something like this:
(function_declarator
declarator: (identifier) #function)
That #function bit specifies the colour to use. If you replace it with something else, you can get different highlighting. You can find the list of available captures in CONTRIBUTING.md. For example, I just used #number, so I changed the above code to look like this:
(function_declarator
declarator: (identifier) #number)
Then, you can just install nvim-treesitter from your fork as normal. For me, that meant:
Adding this to my ~/.vimrc:
Plug 'vladh/nvim-treesitter', {'do': ':TSUpdate'}
lua <<EOF
require'nvim-treesitter.configs'.setup {
highlight = { enable = true },
}
EOF
:PlugInstall
:TSInstall c cpp
If everything worked correctly, your function declarations should now be highlighted differently! I also really wanted this feature, and fortunately nvim-treesitter now seems to be stable enough to do this easily.

VIM - Reformatting indentation and braces

When working with blocks of code in VIM, I'm able to easily re-indent blocks of code via selecting a region in visual mode (SHIFT+v), then just hit =. This re-tabs lines of code, uses the correct indentation depths, hard-tabs vs spaces, etc.
I have a large set of functions I need to re-factor, and I have several blocks of code with braces on the same line as if/else keywords, ie:
if(something) {
doFunction(something);
} else if(somethingElse) {
doFunction(somethingElse);
} else {
// default stuff to do
}
And I would like to change the brace and spacing style to:
if ( something ) {
doFunction( something);
}
else if ( somethingElse )
{
doFunction( somethingElse );
}
else
{
// default stuff to do
}
The differences include:
Having the opening/closing braces on their own dedicated line
The argument to if, else if, and functions has a space separating the beginning and end of the argument list from the surrounding round brackets.
There is a space between if/else if and the argument brackets, but not for function names and the argument brackets.
Is there a way to set this style as the default in VIM, and to also have re-indentation commands change the style to match the latter of the two I've provided? I've found tools to enforce things like line endings, tabs-vs-spaces, etc, but not style details like those shown above.
Thank you.
The indentation scripts in vim are not constructed for so complex tasks. I would advise you to use the indent command, in particular the following arguments:
-prs, --space-after-parentheses
Put a space after every '(' and before every ')'.
See STATEMENTS.
-sai, --space-after-if
Put a space after each if.
See STATEMENTS.
You should read the command's man page for more details.
Obviously, this command can be used to filter the buffer's content using:
:%!indent

Apply a set of lines to a template

I want to process a set of lines and apply a template to each line. Let's say I have the following block of lines:
CASE
ESAC
IF
FI
And I would like to get the following output:
<YYINITIAL> {CASE} {
return new Symbol(sym.CASE);
}
...
<YYINITIAL> {FI} {
return new Symbol(sym.FI);
}
So, I thought of having a template with the body to apply for each line, something like this:
<YYINITIAL> {###PLACE_HOLDER###} {
return new Symbol(sym.###PLACE_HOLDER###);
}
And apply it to each line.
What I thought was of selecting the lines, putting then in a register ("a, for instance), then selecting the template putting it in a register ("b) and call an external script that generates the output. However no luck (don't know how to pass the contents of a register to an external script).
Any other approach is welcome.
this command will do that job:
:%s/.*/<YYINITIAL> {&} {\r\treturn new Symbol(sym.&);\r}/
you could remove the %, if you visual selected lines. Also you could create a mapping or user command for it, if it is used often.
Your suggested approach seems overly complex, especially because you still have to implement the template expansion logic as the external script.
Why don't you simply define your templates as :substitute commands?! You can pattern-match your PLACEHOLDER via /\({pattern}\)/ and insert it in the replacement text as \1, \2, etc. (I hope you know about the power of Vim's :substitute command; otherwise, read :help :s.
You can keep and persist your templates in several ways, depending on how often / long you need them:
Just in the command-line history (:s<Up>)
Save in named registers (:let #a = #:), execute with :#a
Save in a Vim script and :source it
Write a custom plugin with :commands

How to insert boilerplate everytime a key is invoked in vim?

When I'm coding in C/C++, when I type '{' I generally want the next couple characters to be a newline, tab, newline, ended by '}'. This is especially convenient with top-down programming so that you can make the format of your function and continue on, only to come back later and it has already been prototyped for you.
So, to clarify, I want '{' to be replaced by
{\n\t\n}
Is that possible in vim, and if so, how?
is this ok for you?
inoremap { {<cr>}<esc>O<tab>
with this mapping, if you type foo{ in INSERT mode, it will change to:
foo {
I
}
I is cursor position.
You may be interested to try out some of the many "auto closing" plugins available. I use DelimitMate but you could try AutoClose or AutoPair.
You have a bunch of yank registers. Perhaps the simplest solution would be to yank that to a designated register and then put from that register each time you need it.
For that kind of "top down" coding with "auto prototyping", snippet plugins are excellent.
With a snippet plugin you can do much more extensive "top down" coding than just expanding brackets.
Ultisnips is a great snippet plugin. If you don't have python support in your vim, then SnipMate, the predecessor of Ultisnips, is quite capable also, but not as advanced.
With Ultisnips, you could use any of the three snippets below:
1) Create the brackets and place cursor following them
snippet {
{
}
$1
endsnippet
2) Create the brackets and place the cursor within them
snippet {
{
$1
}
endsnippet
3) Create the brackets and place the cursor within them, then Ctrl-j to place the cursor following the brackets
snippet {
{
$1
}
$2
endsnippet
But in addition to simple snippets like these three, you could get much more sophisticated, defining whole function/class/etc templates in snippets that can be quickly expanded and jumped through.

Is it possible to modify the cindent rules for one case in vim?

I am currently using vim as my editor for programming in D. The indent rules are pretty much identical to C, but I've run into a case that vim doesn't handle by default. In D, case statements can take strings which are not properly handled by cindent.
For instance, this works:
switch(blah)
{
case 1:
// something
case some_variable:
// ...
}
But not this:
switch(blah)
{
case "yark":
case "flurb":
// something
case "...":
// ...
}
Is there some way to override that single rule in a custom indent file, or would the entire cindent ruleset have to be reimplemented?
Try Vim 7.3. The indentation rules introduced in this version mainly for JavaScript also fix this particular situation.
With Vim 7.3 the code is correctly indented as:
switch(blah)
{
case "yark":
case "flurb":
// something
case "...":
// ...
}

Resources