packages feed

mdoc-0.1.0.0: src/Mdoc/Gen/Description.hs

-- |
--
-- Module      : Mdoc.Gen.Description
-- Copyright   : (c) 2026 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Mdoc.Gen.Description
  ( man1Description
  , man5Description

    -- * Exported for testing
  , switchLines
  , optionLines
  , configLines
  ) where

import Mdoc.Prelude

import Data.List (nubBy, sortOn)
import Mdoc.Gen.Argument
import Mdoc.Gen.Config
import Mdoc.Gen.Described
import Mdoc.Gen.Flag
import Mdoc.Gen.Man1 (Man1 (..))
import Mdoc.Gen.Man5 (Man5 (..))
import Mdoc.Gen.Option
import Mdoc.MacroName
import Mdoc.MdocLine

man1Description :: Man1 -> NonEmpty MdocLine
man1Description m = case nonEmpty items of
  Nothing -> pure $ TextLine "This program accepts no options"
  Just neItems ->
    sconcat
      $ pure (TextLine "The options are as follows:")
      :| [ pure $ MacroLine Bl ["-tag", "-width", "indent"]
         , neItems
         , pure $ MacroLine El []
         ]
 where
  items = optionsLines m.switches m.options <> argumentsLines m.arguments

man5Description :: Man5 -> NonEmpty MdocLine
man5Description m =
  case nonEmpty $ configsLines m.configs of
    Nothing -> TextLine "Config file for" :| [MacroLine Nm []]
    Just neItems ->
      sconcat
        $ pure (MacroLine Bl ["-tag", "-width", "indent"])
        :| [neItems, pure $ MacroLine El []]

optionsLines :: [Described Flag] -> [Described Option] -> [MdocLine]
optionsLines switches options =
  concatMap snd
    $ sortOn fst
    $ map switchLines switches
    <> map optionLines options

switchLines :: Described Flag -> (FlagOrder, [MdocLine])
switchLines d =
  ( flagOrder d.item
  , renderDescribedItem (`renderFlag` Nothing) d
  )

optionLines :: Described Option -> (FlagOrder, [MdocLine])
optionLines d =
  ( flagOrder d.item.flag
  , renderDescribedItem ((`renderFlag` (Just d.item.argument)) . (.flag)) d
  )

argumentsLines :: [Described Argument] -> [MdocLine]
argumentsLines = renderDescribedItems renderArgument . nubBy sameArg
 where
  -- For usage like: PATH [PATH ...], avoid rendering PATH twice in DESCRIPTION
  sameArg a b =
    and
      [ a.item.schema == b.item.schema
      , a.helpLines == b.helpLines
      ]

configsLines :: [Described Config] -> [MdocLine]
configsLines = concatMap configLines . sortOn (.item.name)

configLines :: Described Config -> [MdocLine]
configLines d = renderDescribedItem renderConfig d <> exampleLines
 where
  exampleLines :: [MdocLine]
  exampleLines = case d.item.exampleLines of
    Nothing -> []
    Just ls ->
      concat
        [ [MacroLine Pp []]
        , [TextLine "Example:"]
        , [MacroLine Bd ["-literal", "-offset", "indent"]]
        , map (TextLine . esc . pack) $ toList ls
        , [MacroLine Ed []]
        ]