-- 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. -- --
-- v <= v' ==> w <= w' => (v <> w) <= (v' <> w') ---- --
-- (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: -- --
-- >>> :{
-- 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.
--
-- -- 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 ---- --
-- \(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. -- --
-- 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. -- --
-- abc -- de -- fgh ---- --
-- 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) -- |
-- 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