@@ -198,29 +198,93 @@ optionsDesc global pprefs p = vsepChunks
198198 . fmap formatTitle
199199 . fmap tabulateGroup
200200 . groupByTitle
201- $ mapParser doc p
201+ $ docs
202202 where
203+ docs :: [Maybe (OptGroup , (Doc , Doc ))]
204+ docs = mapParser doc p
205+
203206 groupByTitle :: [Maybe (OptGroup , (Doc , Doc ))] -> [[(OptGroup , (Doc , Doc ))]]
204- groupByTitle = groupFstAll . catMaybes
207+ groupByTitle xs = groupFstAll . catMaybes $ xs
208+
209+ -- NOTE: [Nested group alignment]
210+ --
211+ -- For nested groups, we want to produce output like:
212+ --
213+ -- Group 1
214+ -- --opt-1 INT Option 1
215+ --
216+ -- - Group 2
217+ -- --opt-2 INT Option 2
218+ --
219+ -- - Group 3
220+ -- - opt-3 INT Option 3
221+ --
222+ -- That is, we have the following constraints:
223+ --
224+ -- 1. Nested groups are prefixed with a hyphen '- ', where the hyphen
225+ -- starts on the same column as the parent group.
226+ --
227+ -- 2. We still want the listed options to be indented twice under the
228+ -- group name, so this means nested options need to be indented
229+ -- again by the standard amount (2), due to the hyphen.
230+ --
231+ -- 3. Help text should be __globally__ aligned.
205232
206233 tabulateGroup :: [(OptGroup , (Doc , Doc ))] -> (OptGroup , Chunk Doc )
207- tabulateGroup l@ ((title,_): _) = (title, tabulate (prefTabulateFill pprefs) (snd <$> l))
208- tabulateGroup [] = mempty
234+ tabulateGroup l@ ((title,_): _) =
235+ (title, tabulate (prefTabulateFill pprefs) (getGroup <$> l))
236+ where
237+ -- Handle NOTE: [Nested group alignment] 3. here i.e. indent the
238+ -- right Doc (help text) according to its indention level and
239+ -- global maxGroupLevel. Notice there is an inverse relationship here,
240+ -- as the further the entire group is indented, the less we need to
241+ -- indent the help text.
242+ getGroup :: (OptGroup , (Doc , Doc )) -> (Doc , Doc )
243+ getGroup o@ (_, (x, y)) =
244+ let helpIndent = calcOptHelpIndent o
245+ in (x, indent helpIndent y)
246+
247+ -- Indents the option help text, taking the option's group level and
248+ -- maximum group level into account.
249+ calcOptHelpIndent :: (OptGroup , a ) -> Int
250+ calcOptHelpIndent g =
251+ let groupLvl = optGroupToLevel g
252+ in lvlIndent * (maxGroupLevel - groupLvl)
253+
254+ tabulateGroup [] = (OptGroup 0 Nothing , mempty )
209255
210- -- Note that we treat Global/Available options identically, when it comes
211- -- to titles.
212256 formatTitle :: (OptGroup , Chunk Doc ) -> Chunk Doc
213- formatTitle (OptGroup groups, opts) =
214- case groups of
215- [] -> (pretty defTitle .$. ) <$> opts
216- gs@ (_: _) -> (renderGroupStr gs .$. ) <$> opts
257+ formatTitle (OptGroup idx mTitle, opts) =
258+ -- Two cases to handle w.r.t group level (i.e. nested groups).
259+ case idx of
260+ -- Group not nested: no indention.
261+ 0 -> (\ d -> pretty title .$. d) <$> opts
262+ -- Handle NOTE: [Nested group alignment] 1 and 2 here.
263+ n ->
264+ let -- indent entire group based on its level.
265+ indentGroup = indent (lvlIndent * (n - 1 ))
266+ -- indent opts an extra lvlIndent to account for hyphen
267+ indentOpts = indent lvlIndent
268+ in (\ d -> indentGroup $ (pretty $ " - " <> title) .$. indentOpts d)
269+ <$> opts
217270 where
271+ title = case mTitle of
272+ Nothing -> defTitle
273+ Just t -> t
218274 defTitle =
219275 if global
220276 then " Global options:"
221277 else " Available options:"
222278
223- renderGroupStr = pretty . intercalate " ."
279+ maxGroupLevel :: Int
280+ maxGroupLevel = findMaxGroupLevel docs
281+
282+ -- Finds the maxium OptGroup level.
283+ findMaxGroupLevel :: [Maybe (OptGroup , (Doc , Doc ))] -> Int
284+ findMaxGroupLevel = foldl' (\ acc -> max acc . optGroupToLevel) 0 . catMaybes
285+
286+ optGroupToLevel :: (OptGroup , a ) -> Int
287+ optGroupToLevel ((OptGroup i _), _) = i
224288
225289 doc :: ArgumentReachability -> Option a -> Maybe (OptGroup , (Doc , Doc ))
226290 doc info opt = do
@@ -238,6 +302,9 @@ optionsDesc global pprefs p = vsepChunks
238302 descGlobal = global
239303 }
240304
305+ lvlIndent :: Int
306+ lvlIndent = 2
307+
241308errorHelp :: Chunk Doc -> ParserHelp
242309errorHelp chunk = mempty { helpError = chunk }
243310
0 commit comments