mdoc-0.2.0.0: src/Mdoc/Data/List.hs
-- |
--
-- Module : Mdoc.Data.List
-- Copyright : (c) 2026 Patrick Brisbin
-- License : AGPL-3
-- Maintainer : pbrisbin@gmail.com
-- Stability : experimental
-- Portability : POSIX
module Mdoc.Data.List
( List
, fromNonEmpty
, singleton
-- * Width
, Width (..)
, Indent
, ByItem
) where
import Mdoc.Prelude
import Data.Aeson (object, (.=))
import Data.Kind (Constraint, Type)
import Data.List.NonEmpty qualified as NE
import Data.Text qualified as T
import Mdoc.Data.Described
import Mdoc.Pretty
import Mdoc.Syntax
type List :: forall {k}. k -> Type -> Type
newtype List t a = List
{ items :: NonEmpty (Described a)
}
deriving stock (Eq, Generic, Show)
deriving (Semigroup) via Generically (List t a)
instance (Ord a, ToJSON a, Width t a) => ToJSON (List t a) where
toJSON l =
object
[ "width" .= renderedWidth (Proxy @t) items
, "items" .= items
]
where
items :: NonEmpty (Described a)
items = NE.sort $ NE.nub l.items
fromNonEmpty :: NonEmpty (Described a) -> List t a
fromNonEmpty = foldMap1 singleton
singleton :: Described a -> List t a
singleton described = List {items = pure described}
data Indent
data ByItem
type Width :: forall {k}. k -> Type -> Constraint
class Width t a where
renderedWidth :: Proxy t -> NonEmpty (Described a) -> MacroArg
instance Width Indent a where
renderedWidth _ _ = "indent"
instance Pretty a => Width ByItem a where
renderedWidth _ =
Quoted
. esc
. maximumBy (comparing T.length)
. fmap headWidth
headWidth :: Pretty a => Described a -> Text
headWidth = go . T.words . renderPlain . pretty . (.item)
where
go :: [Text] -> Text
go = \case
[] -> ""
("Ev" : rest) -> go rest
("Ns" : rest) -> go rest
("Ar" : rest) -> go rest
("Op" : rest) -> "[" <> go rest <> "]"
("Fl" : rest) -> "-" <> go rest
("|" : rest) -> "|" <> go rest -- assume Ns-wrapped
("," : rest) -> " , " <> go rest -- assume not Ns-wrapped
(x : rest) -> x <> go rest