packages feed

ronn-opt-env-conf-1.0.1.1: src/Ronn/OptEnvConf/Opt.hs

-- |
--
-- Module      : Ronn.OptEnvConf.Opt
-- Copyright   : (c) 2024 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Ronn.OptEnvConf.Opt
  ( optSynopsis
  , optDefinitions
  ) where

import Prelude

import Data.Foldable (toList)
import Data.List (intersperse)
import Data.String (IsString (..))
import Data.Text (pack)
import Data.Text qualified as T
import OptEnvConf (Parser)
import OptEnvConf.Args (Dashed (..))
import OptEnvConf.Doc (AnyDocs (..), OptDoc (..), parserOptDocs)
import Ronn.AST

optSynopsis :: Parser a -> [Part]
optSynopsis = go False . parserOptDocs
 where
  go :: Bool -> AnyDocs (Maybe OptDoc) -> [Part]
  go nested = \case
    AnyDocsCommands {} -> [] -- TODO
    AnyDocsAnd ds -> concatMap (go True) ds
    AnyDocsOr [AnyDocsSingle (Just d)] -> [Brackets $ optDocPart d] -- optional d
    AnyDocsOr ds ->
      [ (if nested then Parens else id)
          $ Concat
          $ intersperse " \\| "
          $ concatMap (go True) ds
      ]
    AnyDocsSingle Nothing -> []
    AnyDocsSingle (Just d) -> [optDocPart d]

optDocPart :: OptDoc -> Part
optDocPart doc = bracketize go
 where
  go
    | null (optDocDasheds doc)
    , Just mv <- optDocMetavar doc =
        case optDocDefault doc of
          Nothing -> Variable $ fromString mv
          Just {} -> Brackets $ fromString mv
    | otherwise =
        Concat
          $ intersperse "\\|"
          $ optDashedParts doc

  bracketize = case optDocDefault doc of
    Nothing -> id
    Just {} -> Brackets

optDefinitions :: Parser a -> [Definition]
optDefinitions = go . parserOptDocs
 where
  go :: AnyDocs (Maybe OptDoc) -> [Definition]
  go = \case
    AnyDocsCommands {} -> [] -- TODO
    AnyDocsAnd ds -> concatMap go ds
    AnyDocsOr ds -> concatMap go ds
    AnyDocsSingle Nothing -> []
    AnyDocsSingle (Just d) -> [optDocDefinition d]

optDocDefinition :: OptDoc -> Definition
optDocDefinition doc =
  Definition
    { name
    , description =
        concat
          [ maybe [] (pure . fromString) $ optDocHelp doc
          , maybe [] (\d -> pure $ Parens $ "default " <> fromString d) $ optDocDefault doc
          ]
    , content = Nothing
    }
 where
  name
    | null (optDocDasheds doc)
    , Just mv <- optDocMetavar doc =
        Code $ fromString mv
    | otherwise = Concat $ intersperse ", " $ optDashedParts doc

optDashedParts :: OptDoc -> [Part]
optDashedParts doc =
  map (\c -> Concat [Code $ "-" <> Raw (T.singleton c)]) shorts
    <> map
      (\n -> Concat $ addArgument (optDocMetavar doc) [Code $ "--" <> Raw (pack n)])
      longs
 where
  (shorts, longs) = partitionDasheds $ optDocDasheds doc

addArgument :: Maybe String -> [Part] -> [Part]
addArgument = \case
  Nothing -> id
  Just arg -> (<> ["=", Variable $ fromString arg])

partitionDasheds :: [Dashed] -> ([Char], [String])
partitionDasheds = go ([], [])
 where
  go acc@(shorts, longs) = \case
    [] -> acc
    (DashedShort c : ds) -> go (shorts <> [c], longs) ds
    (DashedLong cs : ds) -> go (shorts, longs <> [toList cs]) ds