diffchar.vim
Highlight the exact differences, based on characters and words
____ _ ____ ____ _____ _ _ _____ ____
| | | || || || || | | || _ || _ |
| _ || || __|| __|| || | | || | | || | ||
| | | || || |__ | |__ | __|| |_| || |_| || |_||_
| |_| || || __|| __|| | | || || __ |
| || || | | | | |__ | _ || _ || | | |
|____| |_||_| |_| |_____||_| |_||_| |_||_| |_|
This plugin has been developed in order to make diff mode more useful. Vim highlights all the text in between the first and last different characters on a changed line. But this plugin will find the exact differences between them, character by character - so called DiffChar.
This plugin will exactly show the changed and added units:
Sync with diff mode
This plugin will synchronously show/reset the highlights of the exact differences as soon as the diff mode begins/ends. And the exact differences will be kept updated while editing.
Diff unit
This plugin shows the diffs based on a g:DiffUnit
. Its default is 'Word1'
and it handles a \w\+
word and a \W
character as a diff unit. There are other
types of word provided and you can also set 'Char' to compare character by
character. In addition, you can specify one or more diff unit delimiters, such
as comma (','), colon (':'), tab ("\t"), and HTML tag symbols ('<' and '>'),
and also specify a custom pattern in the g:DiffUnit
.
Diff matching colors
In diff mode, the corresponding hl-DiffChange
lines are compared between two
windows. As a default, all the changed units are highlighted with
hl-DiffText
. You can set g:DiffColors
to use more than one matching color
to make it easy to find the corresponding units between two windows. The
number of colors depends on the color scheme. In addition, hl-DiffAdd
is
always used for the added units and both the previous and next character of
the deleted units are shown in bold/underline.
Diff pair visible
While showing the exact differences, when the cursor is moved on a diff unit,
you can see its corresponding unit highlighted with hl-Cursor
,
hl-TermCursor
, or similar one in another window, based on a
g:DiffPairVisible
. If you change its default, the corresponding unit is
echoed in the command line or displayed in a popup/floating window just below
the cursor position or at the mouse position. Those options take effect on
:diffupdate
command as well.
Jump to next/prev diff unit
You can use ]b
or ]e
to jump cursor to start or end position of the next
diff unit, and [b
or [e
to the start or end position of the previous unit.
Get/put a diff unit
Like line-based :diffget
/:diffput
and do
/dp
vim commands, you can use
<Leader>g
and <Leader>p
commands in normal mode to get and put each diff
unit, where the cursor is on, between 2 buffers and undo its difference. Those
keymaps are configurable in your vimrc and so on.
Find diff lines incrementally
When the diff mode begins, this plugin locally finds the hl-DiffChange
lines
in the limited range of the current visible and its upper/lower lines of a
window. And each time a cursor is moved on to other ranges upon scrolling or
searching, the new hl-DiffChange
lines will be incrementally found in that
range. Which means, independently of the file size, the number of lines to be
found and then the time consumed are always constant.
Tab page individual
This plugin works on each tab page individually. You can use a tab page variable (t:), instead of a global one (g:), to specify different options on each tab page. Note that this plugin can not handle more than two diff mode windows in a tab page. If it would happen, to prevent any trouble, all the highlighted units are to be reset in the tab page.
Follow 'diffopt' option
This plugin supports icase
, iwhite
, iwhiteall
, and iwhiteeol
in the
diffopt
option. In addition, when indent-heuristic
is specified,
positioning of the added/deleted diff units is adjusted to make them easier
to read.
Comparison algorithm
To find the exact differences, this plugin uses "An O(NP) Sequence Comparison
Algorithm" developed by S.Wu, et al., which always finds an optimum sequence.
But it takes time to check a long and dissimilar line. To improve the
performance, the algorithm is also implemented in Vim9 script. In addition,
if available in nvim, this plugin uses a builtin Lua vim.diff()
function and
makes it much faster.
See also
For a range and area selectable partial comparison, see spotdiff.vim plugin.
Options
-
g:DiffUnit
,t:DiffUnit
: A type of difference unitValue Description 'Char' any single character 'Word1' \w\+
word and any\W
single character (default)'Word2' non-space and space words 'Word3' \<
or\>
character class boundaries (set byiskeyword
option)'word' see word
'WORD' see WORD
'[{del}]' one or more diff unit delimiters (e.g. "[,:\t<>]") '/{pat}/' a pattern to split into diff units (e.g. '/.{4}\zs/') -
g:DiffColors
,t:DiffColors
: Matching colors for changed unitsValue Description 0 hl-DiffText
(default)1 hl-DiffText
+ a few (3, 4, ...) highlight groups2 hl-DiffText
+ several (7, 8, ...) highlight groups3 hl-DiffText
+ many (11, 12, ...) highlight groups100 all available highlight groups in random order [{hlg}] a list of your favorite highlight groups -
g:DiffPairVisible
,t:DiffPairVisible
: Visibility of corresponding diff unitsValue Description 0 disable 1 highlight with hl-Cursor
(default)2 highlight with hl-Cursor
+ echo in the command line3 highlight with hl-Cursor
+ popup/floating window at cursor position4 highlight with hl-Cursor
+ popup/floating window at mouse position
Keymaps
Mapping | Default Key | Description |
---|---|---|
<Plug>JumpDiffCharPrevStart |
[b |
Jump cursor to the start position of the previous diff unit |
<Plug>JumpDiffCharNextStart |
]b |
Jump cursor to the start position of the next diff unit |
<Plug>JumpDiffCharPrevEnd |
[e |
Jump cursor to the end position of the previous diff unit |
<Plug>JumpDiffCharNextEnd |
]e |
Jump cursor to the end position of the next diff unit |
<Plug>GetDiffCharPair |
<Leader>g |
Get a corresponding diff unit from another buffer to undo difference |
<Plug>PutDiffCharPair |
<Leader>p |
Put a corresponding diff unit to another buffer to undo difference |
Demo
License
MIT