spectacle-1.0.0: src/Language/Spectacle/Interaction/Point.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
--
-- @since 1.0.0
module Language.Spectacle.Interaction.Point
( -- * Points
Point (Point),
pointLabel,
pointFields,
pointPos,
pointPar,
pointLen,
-- ** Construction
fromWorld,
-- ** Lenses
label,
parent,
fields,
column,
row,
extent,
)
where
import Data.Function (on)
import Lens.Micro (Lens', SimpleGetter, lens, to, (^.))
import Prettyprinter (Doc, pretty, viaShow, (<+>))
import Prettyprinter.Render.Terminal (AnsiStyle)
import Data.Fingerprint (Fingerprint)
import Data.Type.Rec (HasDict, Rec, evident, pattern ConE, pattern NilE)
import Data.World (World (World))
import Language.Spectacle.Interaction.Pos (Pos, pcol, prow, pattern Pos)
-- ---------------------------------------------------------------------------------------------------------------------
data Point = Point
{ pointLabel :: {-# UNPACK #-} !Fingerprint
, pointFields :: [Doc AnsiStyle]
, pointPar :: !(Maybe Fingerprint)
, pointLen :: {-# UNPACK #-} !Int
, pointPos :: {-# UNPACK #-} !Pos
}
deriving (Show)
fromWorld :: HasDict Show ctx => World ctx -> Point
fromWorld (World hash fs0) = Point hash (docFields fs0) Nothing 0 (Pos 0 0)
where
docFields :: HasDict Show ctx => Rec ctx -> [Doc AnsiStyle]
docFields rs =
case evident @Show rs of
ConE n x xs -> pretty n <+> "=" <+> viaShow x : docFields xs
NilE -> []
-- | @since 1.0.0
instance Eq Point where
pt0 == pt1 =
let lblEq = pt0 ^. label == pt1 ^. label
posEq = pt0 ^. position == pt1 ^. position
in lblEq && posEq
{-# INLINE (==) #-}
-- | @since 1.0.0
instance Ord Point where
compare x y = case (compare `on` pointPos) x y of
EQ -> (compare `on` pointLabel) x y
ordering -> ordering
{-# INLINE compare #-}
-- ---------------------------------------------------------------------------------------------------------------------
label :: SimpleGetter Point Fingerprint
label = to pointLabel
{-# INLINE label #-}
fields :: SimpleGetter Point [Doc AnsiStyle]
fields = to pointFields
{-# INLINE fields #-}
parent :: Lens' Point (Maybe Fingerprint)
parent = lens pointPar \pt par -> pt {pointPar = par}
{-# INLINE parent #-}
position :: Lens' Point Pos
position = lens pointPos \pt p -> pt {pointPos = p}
{-# INLINE position #-}
column :: Lens' Point Int
column = position . pcol
{-# INLINE column #-}
row :: Lens' Point Int
row = position . prow
{-# INLINE row #-}
extent :: Lens' Point Int
extent = lens pointLen \pt i -> pt {pointLen = i}
{-# INLINE extent #-}