In Vim there are basically two types of commands that can make it go into insert mode:
Commands that just add something, such as: i, I, a, A (apart from using backspace).
Or, that also remove a piece of text, such as: c[motion], C, s, v[motions]s.
I would like to hook the InsertLeave event, but in my code I need to know which type of change it was (an insert like i, or a change like cw). Is there any way to find that out?
Would i<BS><BS><BS>bar count as insertion or change? If the latter, you could :undo the change on InsertLeave, store the lines affected by it (i.e. '[,']), :redo, then compare both sets. If there's "just more text", it's an insertion, else a change.
There is one difference that you may be able to exploit: The change commands all modify a register (unless the black-hole register was explicitly specified by prepending "_), whereas insertions do not (well, except for ".).
If you take a "snapshot" of the default register before (e.g. with a CursorMoved,CursorHold combo) and compare the contents on InsertLeave, you can find out.
Related
In Vim 8.x, is there a way to specify a same-line action when using g# and :set opfunc to define a custom command? In other words, I know how to use map to:
noremap <silent> <a-z> :set opfunc=MyFuncOp<cr>g#
Let's say MyFuncOp does some custom type of yank or delete. It works perfectly to press alt-z then j and do that on two lines. But what if you need it on just one line... just like you would with repeated operators like dd or yy? Mapping g#g# doesn't work. How do you convey a single linewise (i.e., the current line) to a g# custom command?
It may depend on how your MyFuncOp() is implemented but, in general, you should only need to do <A-z>l, <A-z>h, or basically use any motion that stays on the current line: 0, $, etc. Just like with a real operator.
Showing us your MyFuncOp() would help.
No, it's not to be implemented by custom g# only. Basically, you have two options.
Either, (1) create also a custom motion (mapmode-o) that includes the whole current line. So, say, you have Y to perform custom "yank" and al to select current line in operator pending mode. Then typing Yal will do. There are many existing implementations of such "custom motion" out there. And it's also pretty easy to devise another one yourself.
Or (2), define special version of your mapping. That is, both Y to invoke g-at, and YY to perform custom operation on the current line without entering the operator pending mode. Proper use of functions and commands should help to avoid code duplication in this case.
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 want to see complete list of editing positions, not just a last one like '.
Jumps (<c-o> & <c-i>) are not it, since you can edit few times without any jump.
Is something like that possible or plugin should be implemented ?
EDIT
Enter in the blank line some text<esc> then do 0i1<esc> after that $a2<esc> then o<esc>. I want to have a key to return first to 2 then 1. g;/g, do not do that, they see those 2 edits as single one.
SOLUTION
It appears that this works
set fo=
au InsertEnter * set tw=1
au InsertLeave * set tw=78
After that you can use g; / g,
So basically, you want the functionality of the built-in g; / g, commands without the special treatment described at their :help:
When two undo-able changes are in the same line and at a column position less
than 'textwidth' apart only the last one is remembered. This avoids that a
sequence of small changes in a line, for example "xxxxx", adds many positions
to the change list. When 'textwidth' is zero 'wrapmargin' is used. When that
also isn't set a fixed number of 79 is used. Detail: For the computations
bytes are used, not characters, to avoid a speed penalty (this only matters
for multi-byte encodings).
Unfortunately, you only have two options:
Write your own plugin that records the insert positions (e.g. via an :autocmd InsertLeave, but capturing changes from other modes will be harder), and provides mappings to jump to them.
Modify Vim's source code to adapt the mentioned special treatment to what you have in mind.
Edit: try http://lifehacker.com/202093/go-back-in-text-file-time-with-vim-70
it could be what you were looking for
You may want to try:
:ju (show all the "jumps", ie places where you went in the file. Not always places where you edited, though)
If you want to jump directly to the "position n-3" : 3 <c-o> will do that
Another way: g ; to go back and g , to go forward
Another way: You can "mark" positions, and refer to them later
ma mark the current position and labels it "a"
mb mark another position, and labels it "b"
then
'a goes back to position a, 'b goes to position b.
it also works in commands :
:.,'as/^/# / : add "# " in front of the lines from the current one (.) to the one where mark a is ('a)
(etc)
Another way: to quickly jump to the SAME word you are currently over (usefull to jump from function definition to function usage(s): * (until you reach the one you want)
I think what you want is g-. See also :help :undolist. For full details, read
:help undo-tree
:help usr_32.txt
Edit: As the comment pointed out, this is not what the question asked for. I was really thinking of g; and g,, as mentioned by #Olivier Dulac.
I'm aware of the possibility to edit multiple lines on the same column by doing:
CTRL+V down...down..down... SHIFT+I type_string_wanted
But I'd like to edit multiple specific locals addin new strings (maybe using cursor (h j k l) or mouse (with :set mouse=a)).
Like on this example, where I want to add the string 'XX' to specific locations. I.e.,
from this:
Hi.
My name is Mario!
to this:
XXHi.
My XXname is XXMario!
Any ideas?
Edit the first location and then use . to repeat the action at each additional location.
I'd reverse the order of your steps.
Instead of marking each location, then performing the change on all at once, just edit the first location, then use . to do the same to each of the others.
This doesn't add any keystrokes to your use case; instead of hitting some key to mark a spot beforehand, you hit . afterward.
If you suspect you might accidentally do some other things in between usages, you could record a macro using q<register> the first time, and play it back with #<register> each of the others.
I'm getting more and more comfortable with Vim after a few months.
BUT, there is only one simple feature I can't get any answer from the web. That is "Search and replace the results". The problem is that I know:
:/keyword to search, and hit enter "keyword" will be highlighted (of course with set hlsearch)
n, or N to navigate
:% s/keyword/new_keyword/g to replace all occurences of keyword with new_keyword.
BUT, I would think that there must be a way to search, and replace the matched keyword (highlighted) with any new_keyword WITHOUT doing ":% s/keyword/new_keyword/g", which is a lot of typing considering search & replace is such a day-to-day feature.
Any answers/comments will be greatly appreciated!
If you've already done a search you can do a substitution for the same pattern by simply leaving out the pattern in the substitute command. eg:
/keyword
searchs for "keyword", and then:
:%s//new_keyword/g
will replace all occurrences of "keyword" with "new_keyword".
Searching and using the dot command (you didn't meantion you are using the dot command, that's why I highlight it) to repeat the last input action is my best bet here.
I use s///g for search and replace.
Well, since #keyword# and #new_keyword# account for most of the characters, and you need some way to differentiate between them (i.e., a character in vim, or tab between entry fields in dialog in a different editor), you're left with maybe four or five keystrokes beyond that.
So I think you're probably overestimating number of keystrokes and also forgetting that (1) it becomes very natural, and (2) working this way allows you also to naturally modify the action performed by specifying a different range or option flag.
But you can cut down on keystrokes. If you want you can map a key to automatically bring up the command line with '%s/' already in place. e.g.:
nmap s :%s/
The command above would remap 's' (I'm not recommending remapping to that key, but it gives the idea) and set you up to insert the keyword.
Also, you can set the 'gdefault' option to default to substituting multiple times per line. This lets you skip the ending '/g' in your keystrokes:
set gdefault
See ':h gdefault' for help section on that option.
In the end I would say just get used to the default way it works, because using it that way allows you to keep same basic operation when you want to specify different ranges or option flags, and creating a new special map is just another thing to remember. gdefault may be worth setting if you think you're going to want it majority of time, adding /g flag at end when gdefault is set has effect of turning /g off. . .
Move to the first highlighted word then record a macro for replacing the word and moving to the next one, e.g:
gg
n
qq
caw new_word^[
n
q
#q
##
##
...