mdoc-0.1.1.0: src/Mdoc/Gen/Described.hs
-- |
--
-- Module : Mdoc.Gen.Described
-- Copyright : (c) 2026 Patrick Brisbin
-- License : AGPL-3
-- Maintainer : pbrisbin@gmail.com
-- Stability : experimental
-- Portability : POSIX
module Mdoc.Gen.Described
( Described (..)
, required
, redescribe
, setHelpLines
, setHelpText
, partitionDescribed
, renderDescribedItems
, renderDescribedItem
) where
import Mdoc.Prelude
import Data.List (intersperse)
import Mdoc.Gen.Optionality
import Mdoc.MacroArg
import Mdoc.MacroName
import Mdoc.MdocLine
import Mdoc.Optics
data Described a = Described
{ item :: a
, optionality :: Optionality
, multiple :: Bool
, helpLines :: Maybe (NonEmpty String)
}
deriving stock (Eq, Functor, Generic, Show)
-- | Describe an item as 'Required', singular, without help
required :: a -> Described a
required item =
Described
{ item
, optionality = Required
, multiple = False
, helpLines = Nothing
}
-- | Concat a described list into a single item
--
-- NB. The element descriptions are discarded and 'required' is used. We could
-- get clever (e.g. any required -> required, concatenat help, etc) but it's
-- just not useful in the project to do so.
redescribe :: ([a] -> b) -> [Described a] -> Described b
redescribe f = required . f . map (.item)
setHelpLines :: NonEmpty String -> Described a -> Described a
setHelpLines x = field @"helpLines" ?~ x
-- | Set a 'Described's 'helpLines' from a 'Text'
setHelpText :: Text -> Described a -> Described a
setHelpText = maybe id setHelpLines . nonEmpty . lines . unpack
partitionDescribed :: [Described (Either a b)] -> ([Described a], [Described b])
partitionDescribed = go ([], [])
where
go acc [] = acc
go (as, bs) (d : ds) = case d.item of
Left a -> go (as <> [a <$ d], bs) ds
Right b -> go (as, bs <> [b <$ d]) ds
renderDescribedItems
:: Foldable t
=> (a -> [MacroArg])
-> t (Described a)
-> [MdocLine]
renderDescribedItems f = concatMap (renderDescribedItem f) . toList
-- TODO: add "Default:" line
-- TODO: add "This option may be specified multiple times" line
renderDescribedItem :: (a -> [MacroArg]) -> Described a -> [MdocLine]
renderDescribedItem f d = MacroLine It (f d.item) : descriptionLines
where
descriptionLines =
intersperse (MacroLine Pp [])
$ map (TextLine . esc . pack)
$ maybe [] toList d.helpLines