Vim: copy a word any number of words away - vim

Just supposing the cursor is at the underscore '_':
line one function Abracadabrabrabra() = {
line two stuff _
line three more longWordIdoNotWantToType
}
And I want to insert Abracadabrabrabra, or maybe longWordIdoNotWantToType, or both, is there some way I can do it like this: execute a magic key command, and then press forward or backwards to cycle through the words that are nearby until I get the word I'm interested in, then press enter to insert that word.
Any other techniques that may be just as fast and flexible would also be appreciated.

Yes, of course, type the two or three first characters and press <C-x><C-n> (completion from the current buffer) or <C-n> (completion from many sources).
See :help ins-completion.

Related

Best Vim alternative to VSCode's Ctrl+D

Lets say we are editing this totally made up JSON file:
[{
"id_4f7xg4egb": "<some_random_guid",
// ... other fields
}, {
"id_h34k3": "<another_id>",
// ... different fields than prev object potentially
"nested": {
"id_j3h": "<nested_obj_id>",
// ... nested obj fields
}
},
// ...
]
It contains N objects (including the nested ones), and we'd like to replace the id value with the string coming appended to the field key itself. The result would be something like:
[{
"id": "4f7xg4egb",
// ... other fields
}, {
"id": "h34k3",
// ... different fields than prev object potentially
"nested": {
"id": "j3h",
// ... nested obj fields
}
},
// ...
]
Now, here is what I would do in VSCode using multiple cursors:
With VSCode Ctrl+d
Select first occurrence of "id_ with Shift+→x4
Select (and create a cursor on) every occurrence of the remaining N-1 "id_ with Ctrl+dx(N-1)
Select the id string(s) following "id_ with →,← (to deselect), Ctrl+Shift+→
Cut them with Ctrl+x (yes, each cursor gets its own "clipboard")
Delete the _ with Backspace
Select the portion we want to replace ("<every_diff_id>") with →x4,Shift+End, ←x2
Replace the value with Ctrl+v and Esc to get rid of the extra cursors
So we are talking about 5+N+5+2+1+8+3=N+24=o(N) keystrokes (taking into account the fact that, for example, the Ctrl key is counted only once and then held down for the rest of the N-1 Ctrl+d commands).
With the Power of Vim
And... my question is: How to accomplish the same result using Vim (in =< # of operations, ofc)?! I'm a noob, one week old vimmer, and I'm loving it so far! I've been using . and basic macros for similar tasks, but I'm not sure what would be the most efficient way to tackle this one :(. I'd also prefer a solution NOT using plugins or involving adding some complicated mappings/functions to my .vimrc. After all, the VSCode solution is vanilla VSCode ;).
Thanks!
I would do it in two intuitive passes and not worry about counting keystrokes or beating the wall clock.
First pass:
:g/id/norm f_s": "
Use :global to execute a command on every line matching a pattern.
The pattern is id.
The command is :normal followed by a normal mode macro.
The macro…
moves the cursor to the first _ on the line with f_,
and substitutes it with ": ".
See :help :global, :help :normal, :help f, and :help s.
Second pass:
:g//norm f:;C,
Use :global to execute a command on every line matching a pattern.
The pattern is the same so it can be omitted.
The command is :normal followed by a normal mode macro.
The macro…
moves the cursor to the first : on the line with f:,
then repeats the move to get to the second : with ;,
replaces the rest of the line with a ,.
See :help ; and :help C.
By recording a macro and replaying it N times.
For example:
qa/"id_/e<CR>s": "<Esc>f:dt,q2#a
That's a total of 25 keystrokes.
Breaking it down:
qa: Start recording macro #a.
/"id_/e: Search for pattern id_ and place cursor at the end of the pattern. The <CR> executes the search.
s: Replace the character under the cursor (the _), starting insert mode. Then use ": " as the replacement text (produces "id": "... and the <Esc> leaves insert mode.
f: Move forward to the : after the field. dt,: Delete until the comma (preserving it.)
q: Stop recording the macro.
2#a: Execute macro #a two times. (If there were more id's to replace, execute it more times. Use 999#a to execute up to 999 times, or until there's an error, whatever comes first.)
I agree that multiple cursors are pretty visual and might be easier to grasp... Vim macros can be somewhat abstract and require you to think of what these operations would do to the other positions you apply the macro to...
For this particular situation, perhaps using a :s command would be easier. But that's a good thing of Vim, there are often multiple ways to solve a problem and you can choose the one you prefer.
I would probably just do something like this:
:% s/"id_\([^"]*\)": .*,/"id": "\1"/
That's a global search-and-replace, matching the "id_<something>": <stuff>, and replacing it with "id": "<something>". I think of that as a single "operation", but not sure if that's what you were looking for.
Using global command becomes:
:g/"id/exe 'norm! f_xdt"f<vi"p'
where we find "id
normal mode
f_ .................... jump to underscore
x ...................... cut
dt" .................... deletes until " (goes to unnamed register)
f< .................... jumps to <
vi" .................... visual select inner "
p ...................... paste default register
I have posted this solution but I think filbranden's is better.

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: pass a char or word to your function

I know that when you define a function in vim, you can use the range keyword so that users can say:
:-5,+5call MyFunction()
And then your function gets a:firstline and a:lastline.
What I want is something similar, but more like the traditional vi way of combining a command with a movement, so that 'd ' deletes a space, 'dw' deletes a word, 'd2w' deletes two words, 'd2j' deletes three lines, etc. Assuming my function gets mapped to some input-mode character sequence, is there any way to make it accept similar variable-length inputs, and then modify that text?
Just to be a little more clear, suppose I want to define a function to wrap <b> tags around existing text. We'll say that function is mapped to ;b. I want users to be able to say ';bw' to bold one word, or ';bf.' to bold everything to the end of the sentence, or whatever, with all the flexibility that vim provides to built-in commands.
If I understand what you're asking, then all you do is include the char argument in your mapping. For example:
map d :call MyFunction('d')<cr>
map dw :call MyFunction('dw')<cr>
map d2w :call MyFunction('d2w')<cr>
" Of course these would be terrible mappings because they
" are already mapped to important Vim functions
The way mappings work is that if you "overspecify" a char like 'd' above so that it is usable either by itself or as a prefix for longer command, Vim will wait briefly (for timeoutlen)after you press 'd' to see if you're going to press another character. (This depends on thetimeout option being set to true, which is the default.) If you don't press another character, Vim will execute the 'd' mapping. If you do it will call the more complex mapping. See :h map-commands generally and :h map-typing for more.
Note: After your clarification I think what you want is to create a custom 'operator' function that you can use to operate on buffer areas defined by Vim motions. See :h map-operator for info on how to do this.

Is there some pattern behind the many VIM commands?

I have to add a VIM personality to an IDE. I never used VIM for more than the most basic edits and i'm now overwhelmed by the complexity of the command structure.
Is there any overall structure for the combination of counts moves and insert/delete commands?
I just can't see the wood for the trees.
Well, there is obviously a finger position pattern behind h, j, k, l.
The fact that ^ goes to the beginning of a line and $ goes to the end is patterned on common regular expression syntax.
Ctrl-F and Ctrl-B page forward and back, and that's fairly intuitive.
i inserts (before) and a appends (after the cursor). Similarly,
I inserts at the beginning of the line, and A appends at the very end.
> and < indent and outdent, respectively. That's also kind of intuitive.
But on the whole, many of the other commands are on whatever keys were left – it's hard to find an intuitive mapping between the letters of the alphabet and an editor's commands.
Repeat counts are always entered before a command, and mostly repeat the command that many times, but in some cases do something clever but analogous.
I think the secret to not going crazy over vi is to start out with only a small handful of commands. I have a lot of colleagues who don't know to do anything other than
move the cursor around using the arrow keys (you don't have to use h, j, k, l);
insert with i, delete with Del (you don't have to use x);
delete a line with dd
get out of input mode with Esc
get out of vi with :x (exit) or q! (quit, and throw away my changes!)
Because I'm much smarter, the additional commands I know and use are:
go to the top of the file with gg, the bottom with G.
I can go to a specified line number with (line-number)G.
copy a line with y (yank), paste it with p
change a word with cw, the rest of the line with C
delete a word with dw, the rest of the line with D
I sometimes use . to repeat the last command, or u (undo) if I messed up.
When you have occasion to use other commands, you can teach them to yourself one by one as needed.
This is a good article for explaining the VIM philosophy.
I think the characteristic that better defines VIM in respect to other editors is its wide array of motion commands. The first thing to learn to fully use VIM is hitting the arrow keys as little as possible, and think at the text in terms of "blocks" like "a sentence" "a tag" "a word" "a group of brackets".
Say you have function foo($bar, $fooz) you can change the parameters by simply positioning your cursor anywhere inside the brackets and pressing ci) (mnemonic: change inner bracket). The same pattern applies to other commands: yank (y), delete (d) and so on.
I know this doesn't explain the whole "VIM philosophy" but combining normal mode commands with the vast amount of motion modifiers is what really made me see the light.
There are plenty of nice and interesting tutorials. One example is
http://blog.interlinked.org/tutorials/vim_tutorial.html
But the broad structure that most of them would give you is
There are two main modes for editing - Command mode and insert mode. You can move from insert mode to command mode using the key.
You can execute commands in the command mode by typing a single key or a sequence of keys.
Commands can help you achieve a wide variety of things
deletion of lines - dd
yanking (copying of lines ) - yy
pasting lines below the current line - p
pasting lines above the current line - P ( and so on)
Most commands in the command mode can be pre-fixed by a "count" to indicate the number of times the command has to be executed. For example, 3dd would delete three lines.
One set of commands in the command mode lets you move to the insert mode. That is explained below.
There are different ways of entering the insert mode from the command mode. Prominent among them are (i-insert at cursor, I-insert at beginning of line, o-insert a line below, O-insert a line above, a-append, A-append at end of line.
The quick reference at
http://www.andy-roberts.net/misc/vim/vim.pdf
Will help you understand the relevance of "count"

Vim: Split Words Into Lines?

I frequently use Shift+J in visual mode to join several selected lines into a single line with the original lines separated by spaces. But I am wondering if there is an opposite shortcut such that it will split selected words into separate lines (one word per line).
Of course I can do:
:'<,'>s/ /^M/g
But something more succinct in terms of keystrokes would be very useful. Has anyone else found a way to do this?
Thanks in advance,
-aj
Map it if you are using it often in your ~/.vimrc file or similar
vnoremap \ll :'<,'>s/ /^M/g<cr>
nnoremap \ll :s/ /^M/g<cr>
if you are only wanting to to it multiple times now you can use & command to repeat last search also
Theres also gqq but thats for textwidth eg 80 chars
Recently I stumbled across the same problem. My solution is the following vim function (put in my .vimrc):
function SplitToLines() range
for lnum in range(a:lastline, a:firstline, -1)
let words = split(getline(lnum))
execute lnum . "delete"
call append(lnum-1, words)
endfor
endfunction
This can be used with line ranges, e.g., as follows
:26call SplitToLines()
which would split line number 26. But the code also handles ranges of lines gracefully (that's why the range in the for loop is built in reverse order).
1,10call SplitToLines()
will split lines 1 to 10 into several lines. However, I mostly use this in visual mode, like
'<,'>call SplitToLines()
which splits all lines that are visually marked. Of course you may define some single letter abbreviation for this function call (with auto completion by Tab I do not find it necessary). Also note that by adding an additional argument which would also be used by 'split' you can have a function that does split lines at specific patterns (instead of just white space).
I use this in my config to Un-Join/split the last word on current line:
nnoremap <C-J> g_F<Space><Space>i<CR><Esc>k
It maps CTRL-j to do the opposite of Join, I think of it as Counter-Join :) I mostly use it to convert between K&R style vs ...the other kind of curly brace placement.
g_ : search for the last non-whitespace on current line
F<Space> : reverse-find first space
<Space> : go one character forward
i : enter insert mode
<CR> : insert a line break
<Esc> : return to normal mode
k : go up one line to where we begun

Resources