Skip to content

Commit

Permalink
Do not sort parser groups to match command groups
Browse files Browse the repository at this point in the history
  • Loading branch information
tbidne committed May 16, 2024
1 parent 37ac35e commit 3352559
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 48 deletions.
34 changes: 27 additions & 7 deletions src/Options/Applicative/Help/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,32 @@ optionsDesc global pprefs p = vsepChunks
tabulateGroup l@((title,_):_) = (title, tabulate (prefTabulateFill pprefs) (snd <$> l))
tabulateGroup [] = mempty

-- REVIEW:
--
-- Conundrum: If we want to behave like command groups, then:
--
-- 1. Groups should not be alphabetically sorted; first come, first serve
-- 2. Duplicate groups __are__ allowed. In particular, ungrouped commands
-- are titled 'Available commands:', thus there can be multiples of
-- this section.
--
-- 1 just means we do not do any sorting when grouping (sortGroupFst).
-- 2 means that we should adorn __each__ ungrouped option with the
-- 'Available options:' title, so we need to do it here.
--
-- The question is, how do we interact with 'Global options:'? Right now
-- we treat it identically, simply swapping out the default title. But
-- we could do something different.
formatTitle :: (Maybe String, Chunk Doc) -> Chunk Doc
formatTitle (mTitle, opts) = case mTitle of
Nothing -> opts
Just title -> (pretty (title ++ ":") .$.) <$> opts
formatTitle (mTitle, opts) =
case mTitle of
Nothing -> (pretty defTitle .$.) <$> opts
Just title -> (pretty (title ++ ":") .$.) <$> opts
where
defTitle =
if global
then "Global options:"
else "Available options:"

doc :: ArgumentReachability -> Option a -> Maybe (Maybe String, (Doc, Doc))
doc info opt = do
Expand Down Expand Up @@ -257,7 +279,7 @@ footerHelp chunk = mempty { helpFooter = chunk }
parserHelp :: ParserPrefs -> Parser a -> ParserHelp
parserHelp pprefs p =
bodyHelp . vsepChunks $
with_title "Available options:" (fullDesc pprefs p)
(fullDesc pprefs p)
: (group_title <$> cs)
where
def = "Available commands:"
Expand All @@ -274,9 +296,7 @@ parserHelp pprefs p =

parserGlobals :: ParserPrefs -> Parser a -> ParserHelp
parserGlobals pprefs p =
globalsHelp $
(.$.) <$> stringChunk "Global options:"
<*> globalDesc pprefs p
globalsHelp $ globalDesc pprefs p



Expand Down
12 changes: 3 additions & 9 deletions src/Options/Applicative/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import Control.Monad.Trans.Reader
(mapReaderT, runReader, runReaderT, Reader, ReaderT, ask)
import Control.Monad.Trans.State (StateT, get, put, modify, evalStateT, runStateT)
import Data.Function (on)
import Data.List (groupBy, sortBy)
import Data.List (groupBy)
import Data.Maybe (catMaybes)

import Options.Applicative.Types
Expand Down Expand Up @@ -275,15 +275,9 @@ hoistList = foldr cons empty
where
cons x xs = pure x <|> xs

-- | Strips 'Nothing', sorts then groups on the first element of the tuple.
-- | Strips 'Nothing', then groups on the first element of the tuple.
sortGroupFst :: (Ord a) => [Maybe (a, b)] -> [[(a, b)]]
sortGroupFst =
groupFst
-- By sorting prior to grouping, we ensure all Eq a's are consecutive,
-- meaning we are guaranteed to have exactly one representative for
-- each group.
. sortBy (compare `on` fst)
. catMaybes
sortGroupFst = groupFst . catMaybes
where
groupFst = groupBy ((==) `on` fst)

Expand Down
3 changes: 3 additions & 0 deletions tests/Examples/ParserGroup/CommandGroups.hs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ sample = do

parseCommand =
hsubparser
( command "list 2" (info (pure List) $ progDesc "Lists elements")
)
<|> hsubparser
( command "list" (info (pure List) $ progDesc "Lists elements")
<> command "print" (info (pure Print) $ progDesc "Prints table")
<> commandGroup "Info commands"
Expand Down
1 change: 0 additions & 1 deletion tests/parser_group_all_grouped.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Usage: parser_group_all_grouped [--file-log-path PATH]

Every option is grouped

Available options:
Logging:
--file-log-path PATH Log file path
--file-log-verbosity INT File log verbosity
Expand Down
10 changes: 7 additions & 3 deletions tests/parser_group_basic.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ Usage: parser_group_basic --hello TARGET [--file-log-path PATH]

Available options:
--hello TARGET Target for the greeting
-q,--quiet Whether to be quiet
-v,--verbosity ARG Console verbosity
-h,--help Show this help text

Logging:
--file-log-path PATH Log file path
--file-log-verbosity INT File log verbosity

Available options:
-q,--quiet Whether to be quiet

System Options:
--poll Whether to poll
--timeout INT Whether to time out

Available options:
-v,--verbosity ARG Console verbosity
-h,--help Show this help text
15 changes: 11 additions & 4 deletions tests/parser_group_command_groups.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ parser_group.command_groups - a test for optparse-applicative
Usage: parser_group_command_groups --hello TARGET [--file-log-path PATH]
[--file-log-verbosity INT] [-q|--quiet]
[--poll] --timeout INT (-v|--verbosity ARG)
(COMMAND | COMMAND | COMMAND)
(COMMAND | COMMAND | COMMAND | COMMAND)

Option and command groups

Available options:
--hello TARGET Target for the greeting
-q,--quiet Whether to be quiet
-v,--verbosity ARG Console verbosity
-h,--help Show this help text

Logging:
--file-log-path PATH Log file path
--file-log-verbosity INT File log verbosity

Available options:
-q,--quiet Whether to be quiet

System Options:
--poll Whether to poll
--timeout INT Whether to time out

Available options:
-v,--verbosity ARG Console verbosity
-h,--help Show this help text

Available commands:
list 2 Lists elements

Info commands
list Lists elements
print Prints table
Expand Down
12 changes: 9 additions & 3 deletions tests/parser_group_duplicates.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ Usage: parser_group_duplicates --hello TARGET [--file-log-path PATH]

Available options:
--hello TARGET Target for the greeting
-q,--quiet Whether to be quiet
-v,--verbosity ARG Console verbosity
-h,--help Show this help text

Logging:
--file-log-path PATH Log file path
--file-log-verbosity INT File log verbosity

Available options:
-q,--quiet Whether to be quiet

Logging:
--poll Whether to poll
--timeout INT Whether to time out

Available options:
-v,--verbosity ARG Console verbosity
-h,--help Show this help text
8 changes: 5 additions & 3 deletions tests/parser_group_nested.err.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ Usage: parser_group_nested --hello TARGET [--file-log-path PATH] [--poll]

Available options:
--hello TARGET Target for the greeting
-q,--quiet Whether to be quiet
-v,--verbosity ARG Console verbosity
-h,--help Show this help text

Logging:
--file-log-path PATH Log file path
--poll Whether to poll
--timeout INT Whether to time out
--file-log-verbosity INT File log verbosity

Available options:
-q,--quiet Whether to be quiet
-v,--verbosity ARG Console verbosity
-h,--help Show this help text
18 changes: 0 additions & 18 deletions tests/test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,24 +1006,6 @@ prop_stringChunk_2 s = isEmpty (stringChunk s) === null s
prop_paragraph :: String -> Property
prop_paragraph s = isEmpty (paragraph s) === null (words s)

prop_sortGroupFst :: [Maybe (Maybe String, Int)] -> Property
prop_sortGroupFst xs =
conjoin
[ isSorted result
, noDuplicates result
]
where
result :: [[(Maybe String, Int)]]
result = Internal.sortGroupFst xs

isSorted :: Ord a => [a] -> Bool
isSorted [] = True
isSorted [_] = True
isSorted (y1 : y2 : ys) = y1 <= y2 && isSorted (y2 : ys)

noDuplicates :: [[(Maybe String, Int)]] -> Bool
noDuplicates ys = ys == nubBy ((==) `on` fst . unsafeHead) ys

---

--
Expand Down

0 comments on commit 3352559

Please sign in to comment.