module Data.Loc
  (
    -- * Concepts
    -- $concepts

    -- * Imports
    -- $imports

    -- * Core types
    Line, Column, Loc, Span, SpanOrLoc, Area,

    -- * Constructing
    -- ** Loc
    loc, origin,
    -- ** Span
    spanFromTo, spanFromToMay,
    -- ** SpanOrLoc
    spanOrLocFromTo,
    -- ** Area
    areaFromTo, spanArea,

    -- * Deconstructing
    -- ** Loc
    locLine, locColumn,
    -- ** Span
    spanStart, spanEnd,
    -- ** SpanOrLoc
    spanOrLocStart, spanOrLocEnd,
    -- ** Area
    areaStart, areaEnd, areaSpansAsc,

    -- * Combining
    -- ** Span
    spanUnion, spanDifference,
    -- ** Area
    areaUnion, areaDifference,

    -- * Miscellaneous
    Pos, OneToTwo, ZeroToTwo, ToNat (..), LocException (..),
  )
  where

import Data.Loc.Internal.Prelude

import Data.Loc.Area (Area)
import Data.Loc.Exception (LocException (..))
import Data.Loc.List.OneToTwo (OneToTwo)
import Data.Loc.List.ZeroToTwo (ZeroToTwo)
import Data.Loc.Loc (Loc)
import Data.Loc.Pos (Column, Line, Pos, ToNat (..))
import Data.Loc.Span (Span)
import Data.Loc.SpanOrLoc (SpanOrLoc)

import qualified Data.Loc.Area as Area
import qualified Data.Loc.Loc as Loc
import qualified Data.Loc.Span as Span
import qualified Data.Loc.SpanOrLoc as SpanOrLoc

{- |
The smallest location: @'loc' 1 1@.

/This is an alias for 'Loc.origin'./
-}
origin :: Loc
origin :: Loc
origin = Loc
Loc.origin

{- |
Create a 'Loc' from a line number and column number.

/This is an alias for 'Loc.loc'./
-}
loc :: Line -> Column -> Loc
loc :: Line -> Column -> Loc
loc = Line -> Column -> Loc
Loc.loc

-- | /This is an alias for 'Loc.line'./
locLine :: Loc -> Line
locLine :: Loc -> Line
locLine = Loc -> Line
Loc.line

-- | /This is an alias for 'Loc.column'./
locColumn :: Loc -> Column
locColumn :: Loc -> Column
locColumn = Loc -> Column
Loc.column

{- |
Attempt to construct a 'Span' from two 'Loc's. The lesser loc will be the
start, and the greater loc will be the end. The two locs must not be equal,
or else this throws 'EmptySpan'.

/The safe version of this function is 'spanFromToMay'./

/This is an alias for 'Span.fromTo'./
-}
spanFromTo :: Loc -> Loc -> Span
spanFromTo :: Loc -> Loc -> Span
spanFromTo = Loc -> Loc -> Span
Span.fromTo

{- |
Attempt to construct a 'Span' from two 'Loc's. The lesser loc will be the
start, and the greater loc will be the end. If the two locs are equal,
the result is 'Nothing', because a span cannot be empty.

/This is the safe version of 'spanFromTo', which throws an exception instead./

/This is an alias for 'Span.fromToMay'./
-}
spanFromToMay :: Loc -> Loc -> Maybe Span
spanFromToMay :: Loc -> Loc -> Maybe Span
spanFromToMay = Loc -> Loc -> Maybe Span
Span.fromToMay

{- |

Construct a 'SpanOrLoc' from two 'Loc's. If the two locs are not equal,
the lesser loc will be the start, and the greater loc will be the end.

/This is an alias for 'SpanOrLoc.fromTo'./

-}
spanOrLocFromTo :: Loc -> Loc -> SpanOrLoc
spanOrLocFromTo :: Loc -> Loc -> SpanOrLoc
spanOrLocFromTo = Loc -> Loc -> SpanOrLoc
SpanOrLoc.fromTo

-- | /This is an alias for 'SpanOrLoc.start'./
spanOrLocStart :: SpanOrLoc -> Loc
spanOrLocStart :: SpanOrLoc -> Loc
spanOrLocStart = SpanOrLoc -> Loc
SpanOrLoc.start

-- | /This is an alias for 'SpanOrLoc.end'./
spanOrLocEnd :: SpanOrLoc -> Loc
spanOrLocEnd :: SpanOrLoc -> Loc
spanOrLocEnd = SpanOrLoc -> Loc
SpanOrLoc.end

{- |
Construct a contiguous 'Area' consisting of a single 'Span' specified by two
'Loc's. The lesser loc will be the start, and the greater loc will be the end.
If the two locs are equal, the area will be empty.

/This is an alias for 'Area.fromTo'./
-}
areaFromTo :: Loc -> Loc -> Area
areaFromTo :: Loc -> Loc -> Area
areaFromTo = Loc -> Loc -> Area
Area.fromTo

{- |
The union of two 'Area's. Spans that overlap or abut will be merged in the
result.

/This is an alias for 'Area.+'./
-}
areaUnion :: Area -> Area -> Area
areaUnion :: Area -> Area -> Area
areaUnion = Area -> Area -> Area
(Area.+)

{- |
The difference between two 'Area's. @a `'areaDifference'` b@ contains what is
covered by @a@ and not covered by @b@.

/This is an alias for 'Area.-'./
-}
areaDifference :: Area -> Area -> Area
areaDifference :: Area -> Area -> Area
areaDifference = Area -> Area -> Area
(Area.-)

{- |
A list of the 'Span's that constitute an 'Area', sorted in ascending order.

/This is an alias for 'Area.spansAsc'./
-}
areaSpansAsc :: Area -> [Span]
areaSpansAsc :: Area -> [Span]
areaSpansAsc = Area -> [Span]
Area.spansAsc

{- |
Construct an 'Area' consisting of a single 'Span'.

/This is an alias for 'Area.spanArea'./
-}
spanArea :: Span -> Area
spanArea :: Span -> Area
spanArea = Span -> Area
Area.spanArea

{- |
Combine two 'Span's, merging them if they abut or overlap.

/This is an alias for 'Span.+'./
-}
spanUnion :: Span -> Span -> OneToTwo Span
spanUnion :: Span -> Span -> OneToTwo Span
spanUnion = Span -> Span -> OneToTwo Span
(Span.+)

{- |
The difference between two 'Spans's. @a '-' b@ contains what is covered by
@a@ and not covered by @b@.

/This is an alias for 'Span.-'./
-}
spanDifference :: Span -> Span -> ZeroToTwo Span
spanDifference :: Span -> Span -> ZeroToTwo Span
spanDifference = Span -> Span -> ZeroToTwo Span
(Span.-)

{- |
/This is an alias for 'Span.start'./
-}
spanStart :: Span -> Loc
spanStart :: Span -> Loc
spanStart = Span -> Loc
Span.start

{- |
/This is an alias for 'Span.end'./
-}
spanEnd :: Span -> Loc
spanEnd :: Span -> Loc
spanEnd = Span -> Loc
Span.end

{- |
/This is an alias for 'Area.start'./
-}
areaStart :: Area -> Maybe Loc
areaStart :: Area -> Maybe Loc
areaStart = Area -> Maybe Loc
Area.start

{- |
/This is an alias for 'Area.end'./
-}
areaEnd :: Area -> Maybe Loc
areaEnd :: Area -> Maybe Loc
areaEnd = Area -> Maybe Loc
Area.end

{- $concepts

'Line' and 'Column' are positive integers representing line and column numbers.

The product of 'Line' and 'Column' is a 'Loc', which represents a position
between characters in multiline text. The smallest loc is 'origin': line 1,
column 1.

Here's a small piece of text for illustration:

>              1         2
>     12345678901234567890123456789
>   ┌───────────────────────────────┐
> 1 │ I have my reasons, you        │
> 2 │ have yours. What's obvious    │
> 3 │ to me isn't to everyone else, │
> 4 │ and vice versa.               │
>   └───────────────────────────────┘

In this example, the word “obvious” starts at line 2, column 20, and it ends at
line 2, column 27. The 'Show' instance uses a shorthand notation denoting
these locs as @2:20@ and @2:27@.

A 'Span' is a nonempty contiguous region of text between two locs; think of it
like a highlighted area in a simple text editor. In the above example, a span
that covers the word “obvious” starts at @2:20@ and ends at @2:27@. The 'Show'
instance describes this tersely as @2:20-2:27@.

Multiple non-overlapping regions form an 'Area'. You may also think of an
area like a span that can be empty or have “gaps”. In the example above, the
first three words “I have my”, and not the spaces between them, are covered by
the area @[1:1-1:2,1:3-1:7,1:8-1:10]@.

-}

{- $imports

Recommended import:

> import Data.Loc.Types
> import qualified Data.Loc as Loc

-}