diff-mode editing. It is unfortunately missing in most editors (or IDEs) that I am aware of. But where there is imagination, there is a way. With some hacking, I managed to have this feature in Vim. 1
Vim has already offered
diff-mode editing. It can be started either by running
vimdiff file1 file2from the shell or by calling
:diffsplit file2while editing
file1inside Vim. This will display the contents of
file2in two windows (the former way vertically, the latter horizontally). However, neither way shows live differences. One has to always run the command
:diffupdateto see the updated differences after any editing. Even worse, both cannot show differences of the same file, that is, when
file2are the same.
The second problem can be easily worked around by making a temprorary copy of the file and then start
diff-mode editing on them. I have the following shell script called
diffvimto do this automatically.
It starts with making a temporary copy of the file (the filename passed as an argument to
#!/bin/sh # diffvim - Differentially Viming TMPDIR=/tmp/diffvim FILENM=$1 FILEBN=$(basename $FILENM) if [ ! -d "$TMPDIR" ]; then mkdir $TMPDIR fi cp $FILENM $TMPDIR/$FILEBN && vimdiff $FILENM $TMPDIR/$FILEBN
diffvimin the shell) in the directory
/tmp/diffvim(hence all temporary copies created this way will be cleared out in between a shutdown and next reboot of the system), only if it succeeds, then it calls
vimdiffon the original file and the temporary copy.
The first problem that Vim in
diff-mode does not update instantly the differences of the files under editing is trickier. Actually, Vim can already update one kind of differences instantly. When inserting new lines or deleting old lines, the differences are shown immediately without delay. But inline editing could not trigger the update of differences. Unaware of Vim's event model, my first attempt was to configure Vim with my limited knowledge to approximate the needed behavior. The best approximation I could imagine was when leaving INSERT mode and entering NORMAL mode, trigger the update of differences. The command to leave the INSERT mode and enter NORMAL mode in Vim is associated with the Esc key. So I remapped it as follows:
This line tells Vim that, in INSERT mode, remap the command associated with the Esc key to
imap <Esc> <Esc>:diffupdate<CR>
<Esc>:diffupdate<CR>. So when the Esc key is pressed in INSERT mode after any editing, it will first leave INSERT mode and enter NORMAL mode as usual, but this time it will also update the differences of the files under eiditing. This sounds a reasonable solution. Indeed the effect is not bad. Although the updated differences could still not be shown instantly during the editing, it can be shown immediately after the editing is done. However, it only solves a half or less of the problem. Because I soon noticed that if I modify the text directly in NORMAL mode, that is, without a detour of first entering and then leaving INSERT mode, the differences would still not be updated. That is sad since a central philosophy of Vim is to manipulate text as much as possible in NORMAL mode. So I added another remap of the command associated with the Esc key, but this time for NORMAL mode:
The expected effect was, in NORMAL mode I could trigger the update of the differences by simply pressing the Esc key after any direct manipulation of the text. In a sense, it worked. But it also brought in some unexpected effects: if after running
nmap <Esc> :diffupdate<CR>
diffvim filefrom the shell (thus starting my approximate live
diff-mode editing), the first thing I do was not pressing the Esc key but issuing some other NORMAL mode commands, like pressing the key j or l to move the cursor around, I was put into INSERT mode. I tried hard to fix this problem but all my attempts failed. Eventually, I turned to the Unix StackExchange for help. There I learned that overloading the Esc is a bad idea and that the proper way to achieve what I want is to let Vim execute the
:diffupdatecommand automatically in an event-driven way. The event names suggested there,
InsertLeave, only covers respectively the events of Entering and Leaving INSERT mode. So associating
:diffupdateto them would only update the differences when entering or leaving the INSERT mode, which my ad-hoc solution could do as well. However, it did suggest the right way to a thorough solution. After checking the supported events in Vim's help, I found the right event names to capture any text change in both INSERT and NORMAL mode. The events
CursorMovedIare triggered whenever the cursor is moved in NORMAL or INSERT mode. The following command associates the command
:diffupdateto these two events:
It tells Vim to update the differences of whatever file (since its name always matches the wildcard filename pattern
autocmd CursorMoved,CursorMovedI * :diffupdate
*) under editing whenever the events
CursorMovedIis triggered. To see why these events do the job perfectly, one only needs to notice that any inline editing, whether in INSERT or NORMAL mode, will involve moving the cursor either forward or backward.
Later, I also learned that it is better to restrict specific settings for Vim in
diffmode local by collecting them into the following conditional structure:
I could not find an explanation of
if &diff autocmd CursorMoved,CursorMovedI * :diffupdate endif
&diffin the Vim help. But clearly it is a boolean variable set when Vim is in
The only drawback I can see of this solution is that, in NORMAL mode, just moving around without changing the text will also trigger the update of the differences even though there is no difference to udpate. But I view this as a trade-off.
That is all to have this interesting feature. Enjoy live
diff-mode editing in Vim!