How to find enclosing block in vim? - vim

Searching backwards for { is finding sibling blocks.
The file is properly indented, possibly this can be done by moving upwards from one character before (^) until first non-whitespace character.
Is there any other way?
Eg:
if (some condition) {
for (;;) {
}
some statements;
here you're;
while (some condition) {
}
}
Is there a way to navigate from "here you're" to if?
I was thinking of placing cursor before "here you're" and call a function which will move cursor up until it finds non-whitespace character.

Press (cursor on any char of here you're line)
[{
This is exactly what you are looking for. For detailed info, :h [{, or :h motion.txt.

% is the correct way to do that.

Your example uses C code, which uses braces ({ and }) for grouping, so the following suggestion is not directly useful. For many languages that use matching patterns for grouping (such as if and fi in shell scripts, <table> and </table> in HTML, for example) my matchit.vim script, part of the standard vim distribution, extends % and defines additional motions:
g%: cycle backwards
[%: start of enclosing block (like the current question)
]%: end of enclosing block
a%: (Visual mode only) select the matching block
:help matchit-install

Related

Vim: match next/previous line in search pattern

I'm trying to practice my search patterns for ex commands and trying to do stuff I would usually do with macros using them, and I got stuck with one I'm not sure is possible.
I have some code that looks like this:
public myFunc (): any {
return {};
}
And I'm trying to yank it with this command (with the cursor after the function):
:?\vpublic\s*\w+\s*\(.*\)\s*:\s*\w+\s*\{?;/}$/y
This works as expected and matches the function that I mentioned up there.
What I would like to do but haven't found a way is to ignore the first line and the last one (I just want the contents of the function). I suspect it is possible to do it somehow (maybe +/- search offsets?), but I haven't had any luck yet.
Does anyone know how to do this? Thanks!
Yes, this is a simple matter of adding the appropriate offsets (:help search-offset). You basically define a range with two searches (one upwards from the current position, one downwards from there): ?...?;/.../. To exclude the targets, you just add / subtract 1; this is done by appending the offset to the search: ?...?+1;/.../-1. Applied to your example:
:?\vpublic\s*\w+\s*\(.*\)\s*:\s*\w+\s*\{?+1;/}$/-1y
To insert carriage return (Enter) like below use Ctrl-v Enter
:normal ?public^Mjwyiw
Explanation
:normal ............ in normal mode
?public ............. search backward for public
^M .................. Enter
j ................... move to the line below
yiw ................. yank inner word

VIM - how to delete all lines inside a php tag?

I would like to know how to delete :
all of the contents inside a php tag using vim
<?php i want to delete this ?>
If your opening & closing PHP tags (<?php ... ?>) are in the same line, you can do it this way.
Put your cursor at the first character after PHP opening tag.
Type v/ ?[enter]d in normal mode.
The 2nd point means to enters visual mode ('v') from the first character, searches ('/') for the [space]? (' ?') pattern (exactly before the PHP closing tag), and then delete it ('d').
Use di< or di> to delete all the characters inside <>. The cursor should be inside of the <>.
Use ci< or ci> to delete and be in insert mode.
Helpful but Optional Explanation:
It is better to start with text-objects. Excerpt from :h text-objects, given below, suggest two forms i and a
This is a series of commands that can only be used while in Visual mode or
after an operator. The commands that start with "a" select "a"n object
including white space, the commands starting with "i" select an "inner" object
without white space, or just the white space. Thus the "inner" commands always select less text than the "a" commands.
text-objects are useful to other character pair like (), {}, etc. For example, it is useful while changing
if ( i == true ) {
}
to
if (_) {
}
by using ci( or ci).

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

Move to the next row which has non-white space character in the same column in VIM?

As source code is usually indented, it will help navigate source code quickly if I can move to the next/previous row which has non-empty white character in the same column. Using below code snippet as example and the cursor in on the last }, is there a way to navigate the cursor to i which starts if?
if (condition) {
// some code
}
To search for the same screen column, you can use the special /\%v atom; the current column can be queried with virtcol('.'). Assert a non-whitespace (\S) at that position, and trigger a backwards search() for it:
:call search('\%' . virtcol('.') . 'v\S', 'bW')
You can easily turn this into a normal-mode mapping.
I've now implemented this motion in my JumpToVerticalOccurrence plugin; by default mapped to ]| / [|. There are other, related mappings like a ]V{char} mapping that works just like f, but vertically.
So if you don't mind installing a plugin (plus dependencies), this is more robust and functional (it supports [count] as well).
Not exactly what you're asking for, but if you start at } and hit %, the cursor moves to the matching {.
If your code has a defined indentation system, jeetsukumaran/vim-indentwise works well for relative, absolute, or block-scope movements across indented blocks.

How to delete a paragraph as quickly as possible

I want to delete the following codes in my config file:
server {
listen 80;
server_name xxx;
location / {
try_files xx;
}
}
I know I can use 7dd, but this is not handy enough- if the section is too long, counting the rows would be inconvenient.
Is there a better way to do this?
Sometimes, I have to delete a whole function, any ideas for that?
As in common in Vim, there are a bunch of ways!
Note that the first two solutions depend on an absence of blank lines within the block.
If your cursor is on the server line, try d}. It will delete everything to the next block.
Within the entry itself, dap will delete the 'paragraph'.
You can delete a curly brack block with da}. (If you like this syntax, I recommend Tim Pope's fantastic surround.vim, which adds more features with a similar feel).
You could also try using regular expressions to delete until the next far left-indented closing curly brace: d/^}Enter
]] and [[ move to the next/previous first-column curly brace (equivalent to using / and ? with that regex I mentioned above. Combine with the d motion, and you acheive the same effect.
If you're below a block, you can also make use of the handy 'offset' feature of a Vim search. d?^{?-1 will delete backwards to one line before the first occurrence of a first-column opening curly brace. This command's a bit tricky to type. Maybe you could make a <leader> shortcut out of it.
Note that much of this answer is taken from previous answer I gave on a similar topic.
If there is a blank line immediately after these lines, Vim will identify it as a paragraph, so you can simply use d} to delete it (assuming the cursor is on the first line).
Try using visual mode with %.
For example, say your cursor is at the beginning of the "server" line.
Press v to go into visual mode. Press % to highlight to the end of the block. Press d to delete it.
As David said their are many ways. Here are a few that I like:
Vf{%d This assumes you are on the line w/ server and you do a visual line selection, find the { and then find the matching } via the % command.
set relativenumber or set rnu for short. This turns on line numbering relative to your cursor. So you do not have to count the lines just look and 7dd away to deleting your block.
Use VaB to visually select a block i.e. { to }, line-wise. While still in visual mode continue doing aB until the proper block is selected then execute d. This means you can select a block from inside the block instead of at the start or end.
d} will delete a paragraph. This works in your current scenario because there is no blank line inside the block. If there is one then all bets are off. Although you can continue pressing . until the block is properly deleted.
If inside a block you can jump to the current block via [{ then continue executing [{ until you are at the correct block then V%d or d%dd to delete the block
Using the techniques above you can delete a function as well, but you can also use the [M and friends ([m, ]m, ]M) to jump to the start and endings of methods but they commonly work for functions as well.
For more information
:h %
:h 'rnu'
:h aB
:h }
:h .
:h [{
:h [m
Given matching parens, or braces, you can use % with d to delete, spanning lines.
So, assuming that you're on the server { line, you can do d%. This is generally useful for all code blocks, e.g. function blocks, loop blocks, try blocks.
Similarly, dip works, but d} is shorter. However, both will only delete to the next empty line.

Resources