diff-loc: Map file locations across diffs
Example
You have a diff between two versions of a file. Given a source span
in one version, find the corresponding span in the other version.
For example, here is a diff d
between a source string "abcdefgh"
and a target
string "appcfgzzh"
, with deletions and insertions in the middle:
ab cdefg h
- b de
+ pp zz
appc fgzzh
Diffs are represented by the type Diff
.
Only locations and lengths are recorded, not the actual characters.
import DiffLoc
import DiffLoc.Unsafe (offset)
d :: Diff N
d = addDiff (Replace 1 (offset 1) (offset 2)) -- at location 1, replace "b" (length 1) with "pp" (length 2)
$ addDiff (Replace 3 (offset 2) (offset 0)) -- at location 3, replace "de" with ""
$ addDiff (Replace 7 (offset 0) (offset 2)) -- at location 7, replace "" with "zz"
$ emptyDiff
-- N.B.: replacements should be inserted right to left, starting from 'emptyDiff'.
The span s
of "fg"
in the first string is an interval that starts at
location 5 and has length 2.
s :: Interval N
s = 5 :.. offset 2
Illustration of the span:
a b c d e f g h
0 1 2 3 4 5 6 7 8
^f+g+ length 2
^
start 5
After applying the diff, the span has been shifted to location 4.
>>> mapDiff d (5 :.. offset 2)
Just (4 :.. offset 2)
a p p c f g q q h
0 1 2 3 4 5 6 7 8 9
^f+g+ length 2
^
start 4
Conversely, we can map spans from the target string to the source string of the diff:
>>> comapDiff d (4 :.. offset 2)
Just (5 :.. offset 2)
If part of the input span is modified by the diff, there is no
corresponding output span.
>>> mapDiff d (1 :.. offset 2) -- "bc" contains "b" which is edited by the diff
Nothing
See the API documentation in DiffLoc
.