effectful-cli 0.2.4.2 → 0.2.5.0
raw patch · 4 files changed
+74/−2 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.CLI.Impl: commandTree :: Parser a -> Doc
+ Data.CLI.Impl: usageTreeWith :: HelpStyle -> String -> String -> String -> Parser a -> ParserInfo a
Files
- CHANGELOG.md +6/−0
- effectful-cli.cabal +1/−1
- src/Data/CLI/Impl.hs +50/−0
- test/Spec.hs +17/−1
CHANGELOG.md view
@@ -1,3 +1,9 @@+## [2.5.0](https://github.com/haskell-github-trust/effectful-cli/compare/2.4.2...2.5.0) (2026-11-05)++### Features++* show whole command tree on help ([db5ad51](https://github.com/haskell-github-trust/effectful-cli/commit/db5ad51e5352c765bc73b292e8b2f004ebf44c9b))+ ## [2.4.2](https://github.com/haskell-github-trust/effectful-cli/compare/2.4.1...2.4.2) (2026-11-05) ### Bug Fixes
effectful-cli.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: effectful-cli-version: 0.2.4.2+version: 0.2.5.0 synopsis: CLI helpers for the effectful ecosystem description: Please see the README at https://github.com/haskell-github-trust/effectful-cli category: CLI
src/Data/CLI/Impl.hs view
@@ -14,6 +14,8 @@ mkCommands, usage, usageWith,+ usageTreeWith,+ commandTree, HelpStyle (..), defaultHelpStyle, plainHelpStyle,@@ -26,22 +28,31 @@ import Data.CLI.Class (Command (..)) import Data.Char (toUpper) import Data.List (sortOn)+import Data.Maybe (fromMaybe) import Data.UUID (UUID) import Data.UUID qualified as UUID import Data.Void (Void) import Options.Applicative+import Options.Applicative.Common (mapParser)+import Options.Applicative.Help.Chunk (unChunk) import Options.Applicative.Help.Pretty ( AnsiStyle, Color (..), Doc,+ align, annotate, bold, color,+ fill,+ indent,+ line, pretty, unAnnotate, underlined,+ vsep, (<+>), )+import Options.Applicative.Types (OptReader (..), Option (..)) import System.Environment (getArgs, lookupEnv) import System.IO (hIsTerminalDevice, stderr, stdout) import Text.Megaparsec (Parsec, eof, errorBundlePretty, runParser)@@ -273,3 +284,42 @@ ) ) )++-- | 'usageWith' with the full 'commandTree' as footer.+--+-- @since 0.2.5.0+usageTreeWith+ :: HelpStyle+ -- ^ help style+ -> String+ -- ^ program name+ -> String+ -- ^ version+ -> String+ -- ^ description+ -> Parser a+ -- ^ arguments parser+ -> ParserInfo a+usageTreeWith s name version hdr p =+ (usageWith s name version hdr p)+ { infoFooter = pure (vsep ["Command tree:", indent 2 (commandTree p)])+ }++-- | Every command of a parser, hidden ones included, with nested subcommands indented under their+-- parent.+--+-- @since 0.2.5.0+commandTree :: Parser a -> Doc+commandTree = vsep . commands+ where+ commands :: Parser x -> [Doc]+ commands = concat . mapParser (const entries)+ entries :: Option x -> [Doc]+ entries o = case optMain o of+ CmdReader _ cs -> uncurry entry <$> cs+ _ -> []+ entry :: String -> ParserInfo x -> Doc+ entry n i =+ fill 12 (pretty n) <+> align (fromMaybe mempty (unChunk (infoProgDesc i))) <> case commands (infoParser i) of+ [] -> mempty+ sub -> line <> indent 2 (vsep sub)
test/Spec.hs view
@@ -1,7 +1,14 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} -import Data.CLI.Impl (fromParsec, plainHelpStyle, reversibleSwitch, usage, usageWith)+import Data.CLI.Impl (+ commandTree,+ fromParsec,+ plainHelpStyle,+ reversibleSwitch,+ usage,+ usageWith,+ ) import Data.Error.CLI (CLIError (..), displayCLIError) import Data.List (isInfixOf) import Effectful (Eff, IOE, liftIO, runEff)@@ -97,3 +104,12 @@ , "prog - desc - version 1.0" `isInfixOf` render (usageWith plainHelpStyle) ) `shouldBe` (True, False, True)++ describe "commandTree"+ $ it "renders nested and hidden commands"+ $ let leaf n = command n (info (pure ()) (progDesc (n <> " desc")))+ p =+ subparser (leaf "a")+ <|> subparser (hidden <> command "b" (info (subparser (leaf "c")) (progDesc "b desc")))+ in show (commandTree p)+ `shouldBe` "a a desc\nb b desc\n c c desc"