-- |
-- = 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
  ( -- * API

    -- ** Overview

    -- |
    -- @
    --                                       "DiffLoc.Diff"
    -- +------------------------------------------------+
    -- |  data 'Diff' r                                   |
    -- |       'addDiff' :: r -> Diff r -> Diff r         |
    -- |       'mapDiff' :: Diff r -> Block r -> Block r  |
    -- +------------------------------------------------+
    --         | requires
    --         v                                                "DiffLoc.Shift"
    -- **********************************************************************
    -- *  class 'Shift' r                                                     *
    -- *  type  'Block' r                                                     *
    -- *        'src', 'tgt' :: r -> Block r                                    *
    -- *        'shiftBlock', 'coshiftBlock' :: r -> Block r -> Maybe (Block r) *
    -- *        'shiftR', 'coshiftR' :: r -> r -> Maybe r                       *
    -- **********************************************************************
    --         ^
    --         | implements with
    --         |          r = 'Replace' p
    --         |    'Block' r = 'Interval' p
    --         |
    --         |
    --         |  "DiffLoc.Interval"
    -- +-------------------+
    -- |  data 'Interval' p  |
    -- |  data 'Replace' p   |
    -- +-------------------+
    --         | requires
    --         v                           "DiffLoc.Shift"
    -- *************************************************
    -- *  class 'Amor' p                                 *
    -- *  type  'Trans' p                                *
    -- *  class Ord p                                  *
    -- *  class Ord ('Trans' p)                          *
    -- *  class Monoid ('Trans' p)                       *<---+
    -- *        ('.+') :: p -> Trans p -> p              *    |
    -- *        ('.-.?') :: p -> p -> Maybe (Trans p)    *    |
    -- *************************************************    |
    --         ^                               ^            |
    --         | implements with               |            | requires from
    --         |          p = 'Plain' a          |            |        l as p
    --         |    or    p = 'IndexFrom' n a    |            |    and c as p
    --         |    'Trans' p = 'Offset' a         |            |
    --         |                               |            |
    --         |                               |            |  "DiffLoc.Colline"
    --         |      "DiffLoc.Index"            |       +---------------------+
    -- +--------------------------+            |       |  data 'Colline' l c   |
    -- |  newtype 'Plain' a         |            |_______|  data 'Vallee' l' c'  |
    -- |  newtype 'IndexFrom' n a   |                    +---------------------+
    -- |  newtype 'Offset' a        |     implements with
    -- +--------------------------+                p = 'Colline' l c
    --         | requires                    'Trans' p = 'Vallee' ('Trans' l) ('Trans' c)
    --         v
    -- *****************
    -- *  class Num a  *
    -- *  class Ord a  *
    -- *****************
    -- @

    -- ** Diffs
    module DiffLoc.Diff

    -- ** Interfaces
    --
    -- - 'Shift', 'BlockOrder'
    -- - 'Amor', 'Origin'
  , module DiffLoc.Shift

    -- ** Intervals and replacements
  , module DiffLoc.Interval

    -- ** Plain indices
  , module DiffLoc.Index

    -- ** Lines and columns
  , module DiffLoc.Colline

    -- ** Basic configurations to get started
  , module DiffLoc.Starter

    -- $unsafe
  ) where

import DiffLoc.Colline
import DiffLoc.Diff
import DiffLoc.Index
import DiffLoc.Interval
import DiffLoc.Shift
import DiffLoc.Starter

-- $unsafe
-- The module "DiffLoc.Unsafe" is not reexported here.
-- You can import it separately.

-- $setup
-- >>> import DiffLoc.Unsafe