-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Map file locations across diffs -- -- See DiffLoc. @package diff-loc @version 0.1.0.0 -- | Interfaces of structures used to implement ADiff. module DiffLoc.Shift -- | Shift algebra. -- -- Laws: -- --
--   src <$>   shiftR r s   =     shiftBlock r (src s)
--   tgt <$>   shiftR r s   =     shiftBlock r (tgt s)
--   src <$> coshiftR r s   =   coshiftBlock r (src s)
--   tgt <$> coshiftR r s   =   coshiftBlock r (tgt s)
--   
--   shiftBlock r b = Just d   <==>   coshiftBlock r d = Just b
--   shiftR     r s = Just z   <==>   coshiftR     r z = Just s
--   
--   shiftR r s = Just z  &&  shiftR s r = Just q   ==>
--     z <> r  =  q <> s
--   
--   coshiftR r s = Just z  &&  coshiftR s r = Just q   ==>
--     r <> z  =  s <> q
--   
-- -- Duality laws: -- --
--   src = tgt . dual
--   tgt = src . dual
--   shiftBlock = coshiftBlock . dual
--   coshiftBlock = shiftBlock . dual
--   coshiftR = shiftR . dual
--   shiftR = coshiftR . dual
--   
class (Semigroup r, BlockOrder (Block r)) => Shift r where { type Block r :: Type; } src :: Shift r => r -> Block r tgt :: Shift r => r -> Block r shiftBlock :: Shift r => r -> Block r -> Maybe (Block r) coshiftBlock :: Shift r => r -> Block r -> Maybe (Block r) shiftR :: Shift r => r -> r -> Maybe r coshiftR :: Shift r => r -> r -> Maybe r dual :: Shift r => r -> r -- | Partial ordering of interval-like things. class BlockOrder b precedes :: BlockOrder b => b -> b -> Bool -- | Precedes but not adjacent, provided you have a notion of adjacence. -- Otherwise it's fine to equate this with precedes. distantlyPrecedes :: BlockOrder b => b -> b -> Bool -- | Action d'un Monoïde Ordonné. Ordered monoid actions. -- -- -- -- In addition to the Ord and Monoid laws, ordered monoids -- must have a monotone (<>): -- --
--   v <= v'   ==>    w <= w'   =>   (v <> w) <= (v' <> w')
--   
-- -- -- -- In other words, we only require the existence of "positive" -- translations (this is unlike affine spaces, where translations exist -- between any two points). This makes it possible to implement this -- class for line-column locations (DiffLoc.Colline), where -- translations are not invertible. -- -- (.-.?) is not part of a standard definition of ordered -- monoid actions. Feel free to suggest a better name for this structure -- or a way to not depend on this operation. -- -- Laws: -- --
--                 (x .+ v) .+ w  =  x .+ (v <> w)
--   x <= y  ==>  x .+ (y .-. x)  =  y
--                (x .+ v) .-. x  =  x
--   
class (Ord p, Ord (Trans p), Monoid (Trans p)) => Amor p where { -- | Type of translations between points of p. type Trans p :: Type; } -- | Translate a point. (.+) :: Amor p => p -> Trans p -> p -- | Translation between two points. j .-.? i must be defined -- (Just) if i <= j, -- -- There is an unsafe wrapper (.-.) in -- DiffLoc.Unsafe. (.-.?) :: Amor p => p -> p -> Maybe (Trans p) infixr 6 .+ -- | Extend Amor with an "origin" point from which vectors can be -- drawn to all points. To make the interface slightly more general, only -- the partial application (origin .-.) needs to be supplied. -- -- Laws: -- --
--   origin <= x
--   
class Amor p => Origin p origin :: Origin p => p -- | Find the vector from the origin to this point. -- --
--   x <= y   =   fromOrigin x <= fromOrigin y
--   
--   ofOrigin (fromOrigin x) = x
--   fromOrigin (ofOrigin v) = v
--   
--   fromOrigin (x .+ v)  =   fromOrigin x <> v
--   
fromOrigin :: Origin p => p -> Trans p -- | Translate the origin along a vector. -- --
--   x <= y   =   ofOrigin x <= ofOrigin y
--   
--   ofOrigin x .+ v             =   ofOrigin (x .+ v)
--   ofOrigin x .-. ofOrigin y   =   x .-. y
--   
ofOrigin :: Origin p => Trans p -> p -- | Indices and offsets. module DiffLoc.Index -- | One-dimensional indices. newtype Plain a Plain :: a -> Plain a -- | One-dimensional indices with an origin (an initial index). Indices -- must be greater than the origin, hence the constructor is hidden. -- -- Use indexFromM to construct indices, with -- TypeApplications to make the indexing scheme explicit, and -- fromIndex to destruct them. -- --
--   (origin :: IndexFrom n a) <= i    -- for all i
--   
data IndexFrom (n :: Nat) a -- | Constructor for IndexFrom. -- -- See also indexFrom in DiffLoc.Unsafe, a variant of -- indexFromM that throws errors instead of using Maybe. indexFromM :: forall n a. (KnownNat n, Num a, Ord a) => a -> Maybe (IndexFrom n a) -- | indexFromM specialized to 0-indexing. indexFromM0 :: forall a. (Num a, Ord a) => a -> Maybe (IndexFrom 0 a) -- | indexFromM specialized to 1-indexing. indexFromM1 :: forall a. (Num a, Ord a) => a -> Maybe (IndexFrom 1 a) -- | Destructor for IndexFrom. fromIndex :: forall n a. IndexFrom n a -> a -- | fromIndex specialized to 0-indexing. fromIndex0 :: IndexFrom 0 a -> a -- | fromIndex specialized to 1-indexing. fromIndex1 :: IndexFrom 1 a -> a -- | Convert from one-indexing to zero-indexing. zeroIndex :: Num a => IndexFrom 1 a -> IndexFrom 0 a -- | Convert from zero-indexing to one-indexing. oneIndex :: Num a => IndexFrom 0 a -> IndexFrom 1 a -- | Type of nonnegative offsets. data Offset a -- | Construct a nonnegative Offset. -- -- See also offset in DiffLoc.Unsafe, a variant of -- offsetM that throws errors instead of using Maybe. offsetM :: (Num a, Ord a) => a -> Maybe (Offset a) -- | Unwrap Offset. fromOffset :: Offset a -> a instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.Plain a) instance GHC.Classes.Ord a => GHC.Classes.Ord (DiffLoc.Index.Plain a) instance GHC.Classes.Eq a => GHC.Classes.Eq (DiffLoc.Index.Plain a) instance (GHC.Num.Num a, GHC.Classes.Ord a) => DiffLoc.Shift.Amor (DiffLoc.Index.IndexFrom n a) instance GHC.Classes.Ord a => GHC.Classes.Ord (DiffLoc.Index.IndexFrom n a) instance GHC.Classes.Eq a => GHC.Classes.Eq (DiffLoc.Index.IndexFrom n a) instance GHC.Num.Num a => GHC.Base.Monoid (DiffLoc.Index.Offset a) instance GHC.Num.Num a => GHC.Base.Semigroup (DiffLoc.Index.Offset a) instance GHC.Classes.Ord a => GHC.Classes.Ord (DiffLoc.Index.Offset a) instance GHC.Classes.Eq a => GHC.Classes.Eq (DiffLoc.Index.Offset a) instance (GHC.Num.Num a, GHC.Classes.Ord a) => DiffLoc.Shift.Amor (DiffLoc.Index.Plain a) instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.Offset a) instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.IndexFrom n a) instance (GHC.Num.Num a, GHC.Classes.Ord a, GHC.TypeNats.KnownNat n) => DiffLoc.Shift.Origin (DiffLoc.Index.IndexFrom n a) -- | Mapping intervals across diffs module DiffLoc.Diff -- | A diff represents a transformation from one file to another. -- -- Example diff between "abcdefgh" and "appcfgzzh": -- --
--   source ab cdefg  h
--        -  b  de
--        +  pp     zz
--   target appc  fgzzh
--   
-- -- It consists of three replacements: -- --
    --
  1. replace "b" with "pp" at location 1, mkReplace 1 1 -- 2;
  2. --
  3. replace "de" with "" at location 3, mkReplace 3 2 0;
  4. --
  5. replace "" with "zz" at location 7, mkReplace 7 0 2.
  6. --
-- --
--   >>> :{
--     let 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.
--   :}
--   
-- -- ADiff is an abstract representation to be instantiated with a -- concrete representation of atomic replacements. -- --

Internal details

-- -- Internally, a diff is a sequence of disjoint and -- nonempty replacements, ordered by their source -- locations. The monoid annotation in the fingertree gives the endpoints -- of the replacements. data ADiff r -- | The empty diff. emptyDiff :: Semigroup r => ADiff r -- | Add a replacement to a diff. The replacement is performed after -- the diff. -- --

Properties

-- --
--   not (isZeroLength x) ==> mapDiff (addDiff r d) x == (shiftBlock r <=< mapDiff (d :: Diff N)) x
--   
-- --
--   not (isZeroLength x) ==> comapDiff (addDiff r d) x == (comapDiff d <=< coshiftBlock (r :: Replace N)) x
--   
addDiff :: forall r. Shift r => r -> ADiff r -> ADiff r -- | Translate a span in the source of a diff to a span in its target. -- Nothing if the span overlaps with a replacement. -- -- For exaple, given the following ADiff (or Replace) from -- "aAacCc" to "aAabbbcCc": -- --
--   source aAa   cCc
--        - 
--        +    bbb
--   target aAabbbcCc
--   
-- --
--   >>> r0 = Replace 3 (offset 0) (offset 3) :: Replace N
--   
--   >>> d0 = addDiff r0 emptyDiff
--   
-- -- The span of "A" remains unchanged. -- --
--   >>> mapDiff d0 (1 :.. offset 1)
--   Just (1 :.. offset 1)
--   
--   >>> shiftBlock r0 (1 :.. offset 1)
--   Just (1 :.. offset 1)
--   
--   >>> comapDiff d0 (1 :.. offset 1)
--   Just (1 :.. offset 1)
--   
--   >>> coshiftBlock r0 (1 :.. offset 1)
--   Just (1 :.. offset 1)
--   
-- -- The span of "C" is shifted by 3 characters. -- --
--   >>> mapDiff d0 (4 :.. offset 1)
--   Just (7 :.. offset 1)
--   
--   >>> shiftBlock r0 (4 :.. offset 1)
--   Just (7 :.. offset 1)
--   
--   >>> comapDiff d0 (7 :.. offset 1)
--   Just (4 :.. offset 1)
--   
--   >>> coshiftBlock r0 (7 :.. offset 1)
--   Just (4 :.. offset 1)
--   
-- -- The span of "ac" overlaps with the replacement, so the mapping is -- undefined. -- --
--   >>> mapDiff d0 (2 :.. offset 2)
--   Nothing
--   
--   >>> shiftBlock r0 (2 :.. offset 2)
--   Nothing
--   
--   >>> comapDiff d0 (2 :.. offset 5)
--   Nothing
--   
--   >>> coshiftBlock r0 (2 :.. offset 5)
--   Nothing
--   
-- --

Properties

-- --
--   \(FSN d s) -> not (isZeroLength s) ==> partialSemiInverse (mapDiff d) (comapDiff d) s
--   
-- --
--   \(FSN d s) -> not (isZeroLength s) ==> partialSemiInverse (comapDiff d) (mapDiff d) s
--   
-- -- where partialSemiInverse f g x is the property -- --
--   if   f x == Just y   -- for some y
--   then g y == Just x
--   
mapDiff :: Shift r => ADiff r -> Block r -> Maybe (Block r) -- | Translate a span in the target of a diff to a span in its source. -- Nothing if the span overlaps with a replacement. -- -- See also mapDiff. comapDiff :: Shift r => ADiff r -> Block r -> Maybe (Block r) -- |
--   listToDiff = foldr addDiff emptyDiff
--   
listToDiff :: Shift r => [r] -> ADiff r instance GHC.Show.Show r => GHC.Show.Show (DiffLoc.Diff.R r) instance GHC.Classes.Eq r => GHC.Classes.Eq (DiffLoc.Diff.R r) instance GHC.Classes.Eq r => GHC.Classes.Eq (DiffLoc.Diff.ADiff r) instance GHC.Show.Show r => GHC.Show.Show (DiffLoc.Diff.ADiff r) instance GHC.Base.Semigroup r => Data.FingerTree.Measured (GHC.Maybe.Maybe r) (DiffLoc.Diff.R r) -- | Line-column locations and its offset monoid. module DiffLoc.Colline -- | Line and column coordinates. -- -- The generalization over types of line and column numbers frees us from -- any specific indexing scheme, notably whether columns are zero- or -- one-indexed. -- --

Example

-- --
--   abc
--   de
--   fgh
--   
-- -- Assuming the lines and columns are both 1-indexed, "b" is at -- location (Colline 1 2) and "h" is at location -- (Colline 3 3). data Colline l c Colline :: !l -> !c -> Colline l c -- | The space between two Collines. -- -- This type represents offsets between text locations x <= y -- as the number of newlines inbetween and the number of characters from -- the last new line to y, if there is at least one newline, or -- the number of characters from x to y. -- --

Example

-- --
--   abc
--   de
--   fgh
--   
-- -- -- -- The offset from "b" to "h" is actually the same as -- from "a" to "h" and from "c" to -- "h". Line-column offsets are thus not invertible. This was -- one of the main constraints in the design of the Amor class. data Vallee dl dc Vallee :: !dl -> !dc -> Vallee dl dc -- | Sans commentaire. type Vallée = Vallee instance (GHC.Show.Show l, GHC.Show.Show c) => GHC.Show.Show (DiffLoc.Colline.Colline l c) instance (GHC.Classes.Ord l, GHC.Classes.Ord c) => GHC.Classes.Ord (DiffLoc.Colline.Colline l c) instance (GHC.Classes.Eq l, GHC.Classes.Eq c) => GHC.Classes.Eq (DiffLoc.Colline.Colline l c) instance (GHC.Show.Show dl, GHC.Show.Show dc) => GHC.Show.Show (DiffLoc.Colline.Vallee dl dc) instance (GHC.Classes.Ord dl, GHC.Classes.Ord dc) => GHC.Classes.Ord (DiffLoc.Colline.Vallee dl dc) instance (GHC.Classes.Eq dl, GHC.Classes.Eq dc) => GHC.Classes.Eq (DiffLoc.Colline.Vallee dl dc) instance (GHC.Base.Monoid l, GHC.Classes.Eq l, GHC.Base.Semigroup c) => GHC.Base.Semigroup (DiffLoc.Colline.Vallee l c) instance (GHC.Base.Monoid l, GHC.Classes.Eq l, GHC.Base.Monoid c) => GHC.Base.Monoid (DiffLoc.Colline.Vallee l c) instance (DiffLoc.Shift.Amor l, DiffLoc.Shift.Origin c) => DiffLoc.Shift.Amor (DiffLoc.Colline.Colline l c) instance (DiffLoc.Shift.Origin l, DiffLoc.Shift.Origin c) => DiffLoc.Shift.Origin (DiffLoc.Colline.Colline l c) -- | Unsafe functions that will throw errors if misused. module DiffLoc.Unsafe -- | An unsafe variant of (.-.?) which throws an exception -- on Nothing. This operator may appear in class laws, imposing -- an implicit requirement that its operands must be ordered. (.-.) :: HasCallStack => Amor p => p -> p -> Trans p infixl 6 .-. -- | Constructor for IndexFrom. The index must be greater than the -- origin, otherwise an error is raised. -- --
--   origin <= indexFrom i
--   
indexFrom :: forall n a. (HasCallStack, KnownNat n, Num a, Ord a) => a -> IndexFrom n a -- | indexFrom specialized to 0-indexing. indexFrom0 :: (HasCallStack, Num a, Ord a) => a -> IndexFrom 0 a -- | indexFrom specialized to 1-indexing. indexFrom1 :: (HasCallStack, Num a, Ord a) => a -> IndexFrom 1 a -- | Construct an Offset. The offset must be nonnegative, otherwise -- an error is raised. offset :: (HasCallStack, Num a, Ord a) => a -> Offset a -- | Interval implements Shift. module DiffLoc.Interval -- | (i :.. n) represents a span of text between index -- i and index i+n. -- -- The type of indices p is expected to be an instance of -- Amor. -- -- The length n in an interval (i :.. n) may be zero. -- -- The elements of the interval can be thought of as indexing the -- interstices between characters. A span of length zero is a -- single interstice between two characters, where some chunk of text may -- be inserted. -- -- Example: drawing of 1 :.. 2 in "abcde". -- --
--    a b c d e
--   0 1 2 3 4 5
--     ^b+c+ length = 2
--     ^
--     ^ start = 1
--   
data Interval p (:..) :: !p -> !Trans p -> Interval p infixl 3 :.. -- | Does the interval have length zero? isZeroLength :: (Eq (Trans p), Monoid (Trans p)) => Interval p -> Bool -- | A minimalistic representation of text replacements. -- -- A replacement Replace i n m is given by a start -- location i, the length n of the interval to replace -- (source) and the length m of its replacement (target). This -- representation does not keep track of the actual data being inserted. -- -- This may overapproximate the underlying text replacement, with -- intervals being wider than necessary. For example, the transformation -- from "abc" to "ac" could be represented by mkReplace 1 1 0 -- (replace "b" with "" at location 1), and also by mkReplace 0 2 -- 1 (replace "ab" with "a" at location 0). -- --
--   source   abc   abc
--        -    b    ab
--        +         a
--   target   a c   a c
--   
-- -- Insertions are replacements with source intervals of length zero. -- Deletions are replacements with target intervals of length zero. data Replace p Replace :: !p -> !Trans p -> !Trans p -> Replace p instance (GHC.Classes.Eq p, GHC.Classes.Eq (DiffLoc.Shift.Trans p)) => GHC.Classes.Eq (DiffLoc.Interval.Interval p) instance (GHC.Show.Show p, GHC.Show.Show (DiffLoc.Shift.Trans p)) => GHC.Show.Show (DiffLoc.Interval.Interval p) instance (GHC.Classes.Eq p, GHC.Classes.Eq (DiffLoc.Shift.Trans p)) => GHC.Classes.Eq (DiffLoc.Interval.Replace p) instance (GHC.Show.Show p, GHC.Show.Show (DiffLoc.Shift.Trans p)) => GHC.Show.Show (DiffLoc.Interval.Replace p) instance DiffLoc.Shift.Amor p => GHC.Base.Semigroup (DiffLoc.Interval.Replace p) instance DiffLoc.Shift.Amor p => DiffLoc.Shift.Shift (DiffLoc.Interval.Replace p) instance DiffLoc.Shift.Amor p => DiffLoc.Shift.BlockOrder (DiffLoc.Interval.Interval p) -- | Basic configurations to get started. module DiffLoc.Starter -- | A shorthand for the common use case of Diff. type Diff p = ADiff (Replace p) -- | Integers. type Z = Plain :$: Int -- | Natural numbers. type N = IndexFrom 0 :$: Int -- | Positive numbers. type N' = IndexFrom 1 :$: Int -- | A trick to reduce noise by hiding newtype wrapper constructors. This -- makes the documentation more palatable. -- --
--   >>> show (NoShow (Plain 3) :: Plain :$: Int)
--   "3"
--   
--   >>> show (Colline 4 2 :.. Vallee (offset 3) (offset 3) :: Interval (Colline N N))
--   "Colline 4 2 :.. Vallee (offset 3) (offset 3)"
--   
newtype f :$: x NoShow :: f x -> (:$:) f x instance DiffLoc.Shift.Origin (f x) => DiffLoc.Shift.Origin (f DiffLoc.Starter.:$: x) instance DiffLoc.Shift.Amor (f x) => DiffLoc.Shift.Amor (f DiffLoc.Starter.:$: x) instance GHC.Base.Monoid (f x) => GHC.Base.Monoid (f DiffLoc.Starter.:$: x) instance GHC.Base.Semigroup (f x) => GHC.Base.Semigroup (f DiffLoc.Starter.:$: x) instance GHC.Classes.Ord (f x) => GHC.Classes.Ord (f DiffLoc.Starter.:$: x) instance GHC.Classes.Eq (f x) => GHC.Classes.Eq (f DiffLoc.Starter.:$: x) instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.Plain DiffLoc.Starter.:$: a) instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.IndexFrom n DiffLoc.Starter.:$: a) instance GHC.Show.Show a => GHC.Show.Show (DiffLoc.Index.Offset DiffLoc.Starter.:$: a) instance GHC.Num.Num a => GHC.Num.Num (DiffLoc.Index.Plain DiffLoc.Starter.:$: a) instance (GHC.Num.Num a, GHC.Classes.Ord a, GHC.TypeNats.KnownNat n) => GHC.Num.Num (DiffLoc.Index.IndexFrom n DiffLoc.Starter.:$: a) instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (DiffLoc.Index.Offset DiffLoc.Starter.:$: a) -- |

Example

-- -- You have a diff between two versions of a file. Given a source -- location in one version, find the corresponding location 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. -- --
--   >>> :{
--     let 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 starts at location 5 -- and has length 2. -- --
--   >>> let s = 5 :.. offset 2 :: Interval N
--   
-- --
--    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 resulting 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
--   
module DiffLoc