I am not trying to play golf with my editor. I am just trying to improve my editing skills with vim.
Let's consider this piece of assembly that I would like to convert to C. In order to do it methodically, I want to make small changes iteratively line after line.
dm(__abcd_bar_id + axis) = f4;
f1 = dm(_abcd_foo_id + axis);
f5 = f4 - f1;
The job with this example is:
Simplify the first line with abcd_bar_id[axis] = f4
Simplify the second line with f1 = abcd_foo_id[axis]
Replace f1 in the third line with the second line
Remove the second line
These steps are not negotiable. I know I can easily get rid of all my dm(__variable + index) with a regex like the one below but this is off topic.
:%s/dm\s*(\s*_\+\(\w\+\)\s\++\s\+\(\w\+\)\s*)/\1[\2]/g
So, to achieve these changes I traditionally do this:
▶▶▶▶DelDelDelDelDel▶▶▶▶▶▶▶▶▶▶▶▶[DelDelDel▶▶▶▶Right]
▼DeleteDelDel[▶▶▶▶]Del
Home▶▶▶▶RightDelDelDelDel
Shift+End Shift+◀ Ctrl+c
▼End◀◀BackspaceBackspace Ctrl+v
And the result should be this:
abcd_bar_id[axis] = f4;
f5 = f4 - abcd_foo_id[axis];
What saves me is I am quite fast hitting the same key multiple times. However I am sure I can be more productive if I use vi features
vfahd
wh3lxi[wr]
j:%s/dm(_//Enter
f+hv2lxi[Escwr]
$hvF2ay
jf1hhplxxx
Well, this seems to me much more complicated for my brain because a pre-processing bain-time is needed before each keystrokes.
For instance if I want to move to f1 I need to parse with my eyes if there is no other 1 on the way to f1.
I really feel I need years of training to be 'fluent' with vim.
So the questions are:
How a vim guru will treat this example?
Does a vim guru exist?
I definitely don't consider myself vim guru, although I use it on the daily basis. Answering your second question first, probably there's somebody who can be treated as a guru, there are simply so many options and possibilities in vim, that everybody can have their own way of doing things. Moreover, because you can tailor vim to your needs, it's easy to simplify regular tasks, and those configurations may differ a lot. Also people who are considered gurus by me (like, for instance, Derek Wyatt) claim that have still much to learn about vim, so it can definitely take years to become one.
But don't be discouraged, it takes only some practise to start thinking vim-way, and your editing tasks will become much easier :)
Back to your example. First of all, I'd edit the first line with slightly less keystrokes:
dta
f)r]
bdTd
i[
The difference isn't huge in terms of number of keystrokes, but it illustrates different approach. It allows, in my opinion, much less pre-processing, which is the problem you highlighted. I divided those keystrokes into sections to show you my thought process:
delete till a
find ) and replace it with ]
back one word and delete Till (backwards) d
insert [
I don't have to think much, when I apply those changes. You might think that this is counter-intuitive, that I jumped to ) character first, but it was much easier for me to spot closing bracket than count words or
hit h or l multiple times. Of course you might know the keystrokes but when you edit something you don't always remember all of them. This comes with practise and forcing yourself to use some of them (like t/T)
to put them firmly under your fingers. Also, print a cheat-sheet trying to make use of every key, until you'll learn it by heart. It won't take long ;)
As William already suggested in the comment, I'd also think about macro here. It's a powerful and easy-to-use tool, which can really automate your changes.
I already know how to edit first line. In your example, I know that in the second step I'll be doing the same thing, but in slightly different location, so instead of editing first line, I instantly record a macro, but I have to make it universal
for easier application. So I think about putting my cursor in proper location first, before making any changes. My macro would look like this:
qq
0fd dta f)r] bdTd i[
q
Notice, that I added 3 keystrokes at the beginning (not counting qq, which starts recording macro to q register). That might look redundant in the first line, but it ensures proper location of the cursor before making any changes.
That way I can easily apply this macro in the second line with #q
Now, you have to replace this f1 in the third line. You're still in the second line with your cursor, so you just yank with:
0fay$
and then paste it to the third line:
j$bPlD
Using macros mith look like a redundant thing when you edit just 3 lines, but when you get used to making changes in a vim way, you'll really feel you're taking advantage of it's power.
When it comes to remembering recorded macros it's not that hard, you have to have the proper attitude. First of all, you record your macros to registers, so typing :registers will show you also your macros. Secondly, you can edit them,
by pasting specific register, altering it and then saving to the same register. And then you can play it with #[register_letter]. And finally, don't get attached to specific macros. Save one or two, use them to make multiple changes at
once and forget about them. And then record another one under the same letter. For example, if you realize that you have to make some repetitive change across the file, use qq, because it's fast and intuitive. After making changes you rarely
need to play the same macro over again, because whole buffer is already in the right state. But if you know, that you'll need it, record next macro under another letter. If you'll get comfortable making changes intuitively vim way, so that
they can easily be repeted, you'll find that's much easier to record another macro than trying to remember under which letter you recorded previous one.
I hope that this answer will convince you, that you don't need years of training to get fluent, but of course it won't happen overnight ;)
Related
Edit: I moved this over to the Vi and Vim site: https://vi.stackexchange.com/questions/13689/how-to-find-and-replace-in-vim-without-having-to-type-the-original-word
I'd like to optimize my "find and replace" workflow in Vim. It's something I do often, as I'm sure most of you do too. Usually something along the lines of -- copy a block and change the name of a variable in a few places. I know, I know, that probably triggers your "why are you copying and pasting code" reflex, but let's not go down that road... There are plenty of valid use cases :)
I'm well aware of the search and replace commands: :s or :%s but I don't like them. It forces me to type out both the full variable name I'm searching for and what I'm changing it to. Maybe there is a better way fix the the amount of typing with :%s? I often use long descriptive variable names, so that is really a deal breaker for me. I also don't like how typing out a variable name from scratch is typo prone and can consume time and brainpower hunting down typos. I much prefer typing it once, and then copying and pasting to just avoid this entirely if possible.
My current workflow uses some combination of movement/yank/select/search/put to move around the file and replace one by one. It is not great but has the benefit of avoiding typing out full variable names. I might just need to type the first few letters with / or use another movement command (i.e. fx) depending on what's around and then hit ve to select the whole word. I also don't mind that I have to repeat for every instance. I never do a full find replace without confirming each change. But it would be much preferable if I could repeat the replacement action with a single keystroke (which I can't do with this method). each replacement is usually something like n then ve then p (or even worse "0p)
Is there a faster way?
My own workflow is similar to yours:
To start, get the cursor on one instance, possibly with / or by navigation.
Hit * to find the next instance of that word.
Change one instance with cw and then the new variable name.
Then it's fast: n/N to get to the next/previous instance, and . to repeat the last edit.
This workflow gives me the same advantage as yours, in that I can review each case before applying the change, but it's just two keystrokes for each additional change.
Hope this helps.
I like the "visual highlight then edit" approach.
shift + v to highlight the region that you want to modify.
then :s/old/new/r where old is what word you want to replace with new.
r changes the first instance of that word old.
Note* There are options other than r which modify its behavior how you want to replace the word.
I am using vim for quite some time now, but several times per day I accidentally encounter an inconvenience by hitting ESC too early.
Assume I am editing the following file:
I want to change 'house' in this line.
'house' should stay like this.
This 'house' should become 'home'
The other 'house' should also change.
I want to change house to home in all lines except the second one. (In this simple example it would easy to write a :s command and perform the task, but usually the task is more specific and manual replacements are quicker and less error prone.) I navigate to the first occurrence of house, press cw, type hone, and hit ESC. After hitting ESC I realize that by accident I typed the letter n instead of m.
I could navigate to the next occurrence of house and hit . to repeat the faulty replacement. In this case I have to fix all hones and replace the n by m afterwards.
I could fix the mistake immediately, but then I can not repeat the same house->home replacement, since . would repeat the n->m replacement.
All of this would be no problem, if I had spotted the mistake before hitting ESC. My question is, if there is a way to undo leaving the insert mode, such that . will repeat both actions? Or similarly, is there a way to tell . to repeat the last to operations?
(Of course this sounds like recording a macro, but since I end up in this situation by mistake, I have not started a macro recording.)
As far as I am concerned, there's no command history of vim in that you could repeat the last two operations.
However, there's a plugin that could help you accomplish that. It's called the RepeatLast.vim plugin to address this exact requirement. It provides a 2\. key binding. The cost for using that plugin and how the plugin actually works is that... it actually enables macro recording all the time. But if you could live with that, it should deal with this sort of situation pretty fine.
I'm trying to make a transition to emacs (using evil mode/vim keybindings) and I'm having a hard time feeling more efficient/productive than if I just used the mouse. Here is an example of a situation where I find myself really slow:
for i in range(self.allData.shape[0]):
self.correctSequence = self.displayNumbers(i, self.allData)
self.userSequence = self.numberEntry()
self.allData.set_value(i, 'userSequence', ''.join(self.userSequence))
if len(self.correctSequence) != len(self.userSequence):
self.allData.set_value(i, 'correct', 0)
else:
if list(reversed(self.correctSequence)) == self.userSequence:
self.allData.set_value(i, 'correct', 1)
else:
self.allData.set_value(i, 'correct', 0)
It would be very common for me to have to change the first 4 instances of self.allData to something else (self.testData, for example), leaving the last 2 untouched.
Normally this wouldnt be too bad with a mouse. For example, I could replace the first allData with testData, copy it, use the mouse to the next 3 occurences and just hit CTRL-V for each one. Or better yet, just use multiple cursors in sublime/atom and replace all 4 in one go
I use spacesmacs in emacs with vim keybindings. So, in emacs I find myself having to do something like the following:
SPC-SPC a (avy jump to words beginning with a)
cw testData
Repeat those 2 steps once for each word I want to replace
This seems really inefficient and I'm wondering: am I just using an inefficient method? Is there a faster way to do what I want?
It seems that even if I managed to complete those steps really fast (4 times), theres still A LOT more typing one would have to do, and I fail to see how this would be faster than just reaching for the mouse. Yes, one could make the argument that I'm losing time by constantly reaching for the mouse, but in my mind I'm saving typing time by reaching for the mouse because I can just hit CTRL-V a few times to achieve what I want. Where exactly are the vim speed gains in a situation like this?
If you just want to replace, you can use query-replace, and replace the word one by one.
You can use replace-string too, but remember to limit replacement to part of the buffer, activate the region around that part.
Anyway, these commands could prevent you from finding the word by your eyes, moving cursor by mouse and moving your hand back to keybaord. And they could avoid probable overlook too. At least I don't want to leave my hands from the keyboard when typing. :)
I'm not sure how "vim-like" Spacemacs is, but you could do it like this in Vim:
/all<CR>
cgntest<Esc>
.
.
.
or:
/all<CR>
cetestData<Esc>
n.
n.
n.
or:
:,$s/allD/testD/gc<CR>
Maybe one of these methods works in Spacemacs too?
In addition to the usual (and generally the best) answer, query-replace (see #songyuanyao's answer), you can use the secondary selection to advantage to selectively paste the same thing at various places. Unlike the region, the secondary selection is unrelated to the cursor position (aka point), so it is always available regardless of where the cursor is.
And unlike query-replacing, you can paste it on demand, instead of having to answer for each matching occurrence. If you use delete-selection mode then just select some text to replace and paste the secondary selection to replace it.
You can set and paste the secondary selection using the mouse - see Secondary Selection on the Emacs Wiki, and see the Emacs manual, node Secondary Selection.
If you use library second-sel.el then you can use the secondary selection from the keyboard as well, and get a lot more use out of it.
I really like the behavior of YankRing, which lets me access the last several things I've yanked or deleted or changed without thinking.
However a complementary feature like this is completely missing for the . repeat command, most often when I type something I really want to repeat, then accidentally overwriting that edit by pressing x to clean something up.
Often it's possible to get back some time still by visual-mode yanking what I just typed, but this is not ideal.
It should be really easy to remember the past few commands.
The question is how possible is it to extract from Vim the representation of the last command contained in whatever stores what . will do before it gets blown away?
If it is as I fear, the only way is to get a plugin to bind to every single command that could edit something, and instrument it in such a way as to store our own repeat-buffer. This is really not practical because I can already imagine how many other plugins that will break. But, I would still really really want this feature if it is possible in any way.
Unfortunately, there's no way to get and replay the command behind the . command. The only workaround is to be perpetually in macro recording mode, and use the macro register as a replacement for the . command.
This tactic is employed by the RepeatLast plugin, which might offer what you want.
Keyword completion and/or ctrl-a in insert mode should cover your needs.
A more yankring-like solution should be possible but, as you say, probably a little too intrusive. Did you look on vim.org by yourself before asking others to do it for you?
I don't often reformat text, apart from the plain gq so this is probably something simple, but just don't seem to have the luck of finding it in the help.
Anyways, I have the text that looks like this
Funnily enough, that was exciting.
"I've just about had enough of this," said a voice beside him.
He looked up. A girl had come down the other path. Her face was red with exertion under the pale make-up, her hair hung over her eyes in ridiculous ringlets, and she wore a dress which, while clearly made for her size, was designed for someone who was ten years younger and keen on lace edging.
She was quite attractive, although this fact was not immediately apparent.
"And you know what they say when you complain?" she demanded. This was not really addressed to Victor. He was just a convenient pair of ears.
And that's a pain to read in Vim. So I tried to reformat it with gq and that gives me this
Funnily enough, that was exciting. "I've just about had enough of this,"
said a voice beside him. He looked up. A girl had come down the other path.
Her face was red with exertion under the pale make-up, her hair hung over
her eyes in ridiculous ringlets, and she wore a dress which, while clearly
made for her size, was designed for someone who was ten years younger and
keen on lace edging. She was quite attractive, although this fact was not
immediately apparent. "And you know what they say when you complain?" she
demanded. This was not really addressed to Victor. He was just a convenient
pair of ears.
which is rather useless, since the original line endings have special meaning in this case. What I'm trying to accomplish is this
Funnily enough, that was exciting.
"I've just about had enough of this," said a voice beside him.
He looked up. A girl had come down the other path. Her face was red with
exertion under the pale make-up, her hair hung over her eyes in ridiculous
ringlets, and she wore a dress which, while clearly made for her size, was
designed for someone who was ten years younger and keen on lace edging.
She was quite attractive, although this fact was not immediately apparent.
"And you know what they say when you complain?" she demanded. This was not
really addressed to Victor. He was just a convenient pair of ears.
i.e. to keep the original line endings, but to "break" every line longer than textwidth into several lines. So it fits the predefined column width limits.
Anyone have any ideas on how to do that? It is a rather large-ish document, and I need some way of handling it in one piece.
Select visually all lines then execute in ex mode:
:norm gqq
gqq reformats a single line. :norm with a range applies a normal code to each in individually in the range. That means you apply gqq on each single line individually. And because your textwidth is set to a certain length (for example 80) that means shorter lines will not be joined/wrapped.
I've tested this on your example text and it just gives what you want.
Btw, you can use vim's :formatprg to modify it with an external prg. That gives more control of what you want modify with an external application. For more info read :h formatprg
Do you just want to do this for reading purposes? If so, you should consider just turning on line wrapping at word breaks. In command mode:
:set wrap
:set linebreak
Assuming this is on Linux, there are a number of utilities to do what you're wanting - fmt, roff/nroff/troff and variants, etc. fmt is one I use often, but it would require that you have a blank line between each paragraph - that's easy to accomplish in vim, though. So you could add blank lines, save the file, then run it by fmt -76 for example to limit each line to 76 characters.
A primitive way, but in general managed to do it with
tw=80
qa (recording a macro)
Vgq
q (stop recording)
nmap <C-p> :execute "normal! #a"<cr>
and by holding <C-p> for quite a while. Not the most elegant of solutions but worked.
You can make gq think that a series of lines belongs to one paragraph if every line of the series except the last one ends with a space:
set formatoptions+=w
. After this setting gq won’t join lines in your example (unless you have trailing spaces there) and you will still be able to join them back using :%s/ \n/ /. Alternative is to add empty lines between each current line.
I also suggest doing
set list listchars+=trail:-
in order not to only make vim see where the paragraph ends, but to be able to see this by yourself (this setting will show you trailing whitespaces).