How to automatically insert braces after starting a code block in vim? - vim

It's really easy to insert a closing brace after typing the opening one:
inoremap { {<CR>}<Esc>ko
This way
if (true) {
converts to
if (true) {
|
}
But I'd like to save time and to type 1 character less:
if (true)<CR>
So I'd like to create the following rule: if return is pressed and the line starts with if/for/while, execute {<CR>}<Esc>ko
Is this doable?
Thanks

Building on your previous mapping, this should do what you want:
inoremap )<CR> ) {<CR>}<Esc>ko
However, you should try a snippet expansion plugin like SnipMate or Ultisnips. Both plugins allow you to define snippets with placeholders and miroring (lots of them are included by default) that are expanded when a <Tab> is pressed after a trigger.
For example, you have a snippet associated with the trigger if that expands into:
if ([condition]) {
}
condition is selected, ready for you to type, and, once you are done, you can hit <Tab> again to jump the cursor between the curly braces, ready to type:
if (myVar == 5) {
|
}
This is incredibly handy.

Related

Selecting a Javascript arrow function in Vim

It's been a challenge for me to select a whole arrow function via Vim without using relative line numbers. Any thoughts on how I can accomplish that?
Here is an example:
const myFunction = () => {
console.log('hello')
}
As always in Vim, there are lots of ways to do that but the right way is very context-dependent. For example, this problem:
const myFunction = () => {
console.log('hello')
}
is different from this problem:
console.log('---')
const myFunction = () => {
console.log('hello')
}
console.log('---')
or this one:
console.log('---')
const myFunction = () => {
console.log('hello')
}
console.log('---')
and the location of the cursor might be important as well.
Assuming your cursor is somewhere on the first or last line of the snippet, the following command should do what you want:
$V% " move cursor to end of line,
" enter visual-line mode,
" extend the selection to the matching pair
If the cursor is somewhere in the body, you could simply do Vip to visually select the current paragraph but that won't work if there are empty lines in the body or if you have other lines above and below. This is why context matters.
With the cursor somewhere in the body, you could do:
[mV% " jump to previous start of method,
" enter visual-line mode,
" extend the selection to the matching pair
But there are various ways in which it might not work, like when you are in a conditional or a switch.
FWIW, I have used (and updated) the following snippet for many years because the built-in ways have always felt limited to me:
" in after/ftplugin/javascript.vim
function! SelectFunction() abort
call search('\(function\|=>\)', "bWc")
call search("{", "Wc")
normal v%V
endfunction
xnoremap <buffer> af :<C-u>call SelectFunction()<CR>
onoremap <buffer> af :normal vaf<CR>
SelectFunction() searches for a typical JS function declaration at or before the cursor, then it searches for the opening brace at or after the cursor, then it visually selects until the matched pair.
The two mappings essentially define a custom pseudo-text object af that uses SelectFunction() under the hood. It is not a real text object in the sense that it doesn't support count or nesting, but it is nevertheless pretty damn useful:
vaf " visually select current function
daf " cut current function
yaf " yank current function
" etc.
vaf with the cursor somewhere in the body, then daf with the cursor on the closing brace:
Note that the function above probably has shortcomings. From previous interactions with the community, it seems that "select the current function" is not exactly a solved problem.

Is there extension or function to know bracket declaration when focued close bracket

I want to know declaration of open bracket when focused close bracket.(ex. if (...) ).
I know emacs, vscode, vim are has goto declaration function. But, they needs 1 action(type M-.(emacs),F12(vscode),%(vim)). I don't want to type some key each time. So, I want to know declaration of bracket with 0-action.
I don't care how displays in declaration(pop-up, mini buffer, status bar)
Background:
I'm in fixing legacy code. The code is too much nested with ifs and fors and whiles.
By much nested, end of code are many continus close bracket(}) like below.
for (var item in list){
if (cond1) {
...
while( cond2 ) {
...
if (cond3) {
...
} else {
...
}
}
}
list.append(item)
}
}
I usually mistake cond2 and cond3, created bugs, don't show log messages, and spent much time.
This question was translated by google translator. so, if you couldn't recognise this, please comment.
When your cursor is on a bracket, the other one is highlighted automatically if you have :help matchparen enabled.
When your cursor is on a bracket, you can jump to the opening one with :help %.
To quote Mass:
Yes- the plugin match-up has this feature:
https://github.com/andymass/vim-matchup
Using the option
let g:matchup_matchparen_offscreen = { 'method': 'popup' }
There is also the ability to show the match in the statusline (the
default):
let g:matchup_matchparen_offscreen = { 'method': 'status' }`

Vim delete parent parenthesis and reindent child

I'm trying to go from here:
const f = function() {
if (exists) { // delete this
const a = 'apple'
}
}
to:
const f = function() {
const a = 'apple'
}
What's the fastest way to delete and reindent everything in between?
Assuming that cursor is inside the braces; any number of lines and nested operators; "else"-branch is not supported:
[{"_dd<]}']"_dd
Explanation:
[{ go to previous unmatched brace
"_dd delete the "{"-line (now the cursor is in the first line of the block)
<]} decrease identation until the next unmatched "}"
'] go to the last changed line (i.e. "}"-line)
"_dd and delete it
If the cursor is initially set on the "{"-line and you don't care for 1-9 registers, the command can be simplified to dd<]}']dd
Assuming your cursor is somewhere on the line containing const a
?{^M%dd^Odd== (where ^M is you hitting the Enter key and ^O is you hitting Ctrl+O).
Broken down this is:
?{^M - search backwards/upwards for the opening brace
% - jump to the corresponding brace (closing brace)
dd - delete the current line
^O - jump to previous location (the opening brace)
dd - delete the line
== - indent current line
You don't need a special macro or function or anything to do this since vim gives you all the powerful text manipulation tools to do the task. If you find yourself doing this an awful lot then you could always map it to a key combination if you want.
The above only works for single lines inside curly braces, but the one below will work for multiple lines (again assuming you are on some line inside the curly braces)
<i{0f{%dd^Odd I'll leave you to figure out how this one works. Type the command slowly and see what happens.
Great answers all around, and, as pointed out, you can always map these keys to a shortcut. If you'd like to try a slightly more generic solution, you could check my "deleft" plugin: https://github.com/AndrewRadev/deleft.vim

Best way to create substitution macros in vim

I'd like to set up some custom auto-complete macros in vim. I'm thinking something like this (| represents the cursor position):
it<TAB>|
immediately becomes:
it("|", function () {
});
Is this possible using straight vim, or would I need a plugin? If so, is there a preferred plugin out there?
Using an abbreviation you could write something like this:
inorea it it("", function () {<cr>});<c-o>k<c-o>f"
The purpose of <c-o>k<c-o>f" at the end is to reposition your cursor inside the double quotes, but it may not work all the time.
Using a mapping, you could try this:
ino <expr> <tab> <sid>expand_last_word()
let s:your_expansions = {
\ 'it': '\<c-w>it(\"\", function () {\<cr>});\<c-o>k\<right>',
\ }
fu! s:expand_last_word() abort
let last_word = matchstr(getline('.'), '\v<\k+%'.col('.').'c')
return has_key(s:your_expansions, last_word)
\ ? eval('"'.s:your_expansions[last_word].'"')
\ : "\<tab>"
endfu
You would have to add your abbreviations and their expansions inside the dictionary s:your_expansions.
Using the :read command, you could define larger snippets of code, and split them across several files:
ino <expr> <tab> <sid>expand_last_word()
fu! s:expand_last_word() abort
let last_word = matchstr(getline('.'), '\v<\k+%'.col('.').'c')
if last_word ==# 'it'
return "\<c-w>\<c-o>:r /path/to/some_file\<cr>\<c-o>f\"\<right>"
endif
return "\<tab>"
endfu
Here /path/to/some_file should contain your snippet:
it("", function () {
});
They are very simple solutions, if you want something more robust, you probably need a snippets plugin. One of them is UltiSnips, which requires that your Vim version has been compiled with Python support (:echo has('python') or :echo has('python3') returns 1).
With UltiSnips, you would write your snippet like this:
snippet it "your description" b
it("$0", function () {
});
endsnippet
Here the definition is included between the keywords snippet and endsnippet. On the 1st line, you can describe the purpose of your snippet, inside the string in double quotes. It will be displayed by UltiSnips inside a list, if you've defined several snippets with the same tab trigger, and there's an ambiguity.
The ending b is an option to prevent the tab trigger it from being expanded anywhere else than the beginning of a line.
$0 is a tabstop, it stands for the position in which you want the cursor to be, once the snippet has been fully expanded.
The readme page on github gives a quick start, and some links to videos.
If you want to have a look at the snippets written by other people, you can install vim-snippets.
There are other snippet managers but I don't know them well enough to describe the syntax of their snippets. If you want a comparison, here's one, and here are links for some of them:
snipmate
mu-template
neosnippet
xptemplate
Here is a abbreviation that you can use for your particular example
:inoreabbrev it it("", function () {<cr>});<esc>kf"a
Typing it followed by ctrl + ] in insert mode will render
it("|", function () {
});
and keep you in insert mode.
But I would definitely go for ultisnips and there is a screencast for creating snippets on the same page. That's why I am omitting the snippet here as you can do it yourself.

vim: strange behavior with search-replace

Here's my code:
public function setFileAvatar($fileAvatar)
{
$this->fileAvatar=$fileAvatar;
}
I select the whole code with "V" (note the upcase) then I type: ":'<,'>s/ileAvatar/ileNameAvatar" which is supposed to replace ALL "ileAvatar" by "ileNameAvatar"
But here's the result:
public function setFileNameAvatar($fileAvatar)
{
$this->fileNameAvatar=$fileAvatar;
}
The $fileAvatar are not replaced! How comes?
Your substitution is missing the /g flag; only the first occurrence in each line is replaced.
If you make this mistake frequently, you can consider changing the default via :set gdefault.

Resources