@@ -201,29 +201,93 @@ optionsDesc global pprefs p = vsepChunks
201201 . fmap formatTitle
202202 . fmap tabulateGroup
203203 . groupByTitle
204- $ mapParser doc p
204+ $ docs
205205 where
206+ docs :: [Maybe (OptGroup , (Doc , Doc ))]
207+ docs = mapParser doc p
208+
206209 groupByTitle :: [Maybe (OptGroup , (Doc , Doc ))] -> [[(OptGroup , (Doc , Doc ))]]
207- groupByTitle = groupFstAll . catMaybes
210+ groupByTitle xs = groupFstAll . catMaybes $ xs
211+
212+ -- NOTE: [Nested group alignment]
213+ --
214+ -- For nested groups, we want to produce output like:
215+ --
216+ -- Group 1
217+ -- --opt-1 INT Option 1
218+ --
219+ -- - Group 2
220+ -- --opt-2 INT Option 2
221+ --
222+ -- - Group 3
223+ -- - opt-3 INT Option 3
224+ --
225+ -- That is, we have the following constraints:
226+ --
227+ -- 1. Nested groups are prefixed with a hyphen '- ', where the hyphen
228+ -- starts on the same column as the parent group.
229+ --
230+ -- 2. We still want the listed options to be indented twice under the
231+ -- group name, so this means nested options need to be indented
232+ -- again by the standard amount (2), due to the hyphen.
233+ --
234+ -- 3. Help text should be __globally__ aligned.
208235
209236 tabulateGroup :: [(OptGroup , (Doc , Doc ))] -> (OptGroup , Chunk Doc )
210- tabulateGroup l@ ((title,_): _) = (title, tabulate (prefTabulateFill pprefs) (snd <$> l))
211- tabulateGroup [] = mempty
237+ tabulateGroup l@ ((title,_): _) =
238+ (title, tabulate (prefTabulateFill pprefs) (getGroup <$> l))
239+ where
240+ -- Handle NOTE: [Nested group alignment] 3. here i.e. indent the
241+ -- right Doc (help text) according to its indention level and
242+ -- global maxGroupLevel. Notice there is an inverse relationship here,
243+ -- as the further the entire group is indented, the less we need to
244+ -- indent the help text.
245+ getGroup :: (OptGroup , (Doc , Doc )) -> (Doc , Doc )
246+ getGroup o@ (_, (x, y)) =
247+ let helpIndent = calcOptHelpIndent o
248+ in (x, indent helpIndent y)
249+
250+ -- Indents the option help text, taking the option's group level and
251+ -- maximum group level into account.
252+ calcOptHelpIndent :: (OptGroup , a ) -> Int
253+ calcOptHelpIndent g =
254+ let groupLvl = optGroupToLevel g
255+ in lvlIndent * (maxGroupLevel - groupLvl)
256+
257+ tabulateGroup [] = (OptGroup 0 Nothing , mempty )
212258
213- -- Note that we treat Global/Available options identically, when it comes
214- -- to titles.
215259 formatTitle :: (OptGroup , Chunk Doc ) -> Chunk Doc
216- formatTitle (OptGroup groups, opts) =
217- case groups of
218- [] -> (pretty defTitle .$. ) <$> opts
219- gs@ (_: _) -> (renderGroupStr gs .$. ) <$> opts
260+ formatTitle (OptGroup idx mTitle, opts) =
261+ -- Two cases to handle w.r.t group level (i.e. nested groups).
262+ case idx of
263+ -- Group not nested: no indention.
264+ 0 -> (\ d -> pretty title .$. d) <$> opts
265+ -- Handle NOTE: [Nested group alignment] 1 and 2 here.
266+ n ->
267+ let -- indent entire group based on its level.
268+ indentGroup = indent (lvlIndent * (n - 1 ))
269+ -- indent opts an extra lvlIndent to account for hyphen
270+ indentOpts = indent lvlIndent
271+ in (\ d -> indentGroup $ (pretty $ " - " <> title) .$. indentOpts d)
272+ <$> opts
220273 where
274+ title = case mTitle of
275+ Nothing -> defTitle
276+ Just t -> t
221277 defTitle =
222278 if global
223279 then " Global options:"
224280 else " Available options:"
225281
226- renderGroupStr = pretty . intercalate " ."
282+ maxGroupLevel :: Int
283+ maxGroupLevel = findMaxGroupLevel docs
284+
285+ -- Finds the maxium OptGroup level.
286+ findMaxGroupLevel :: [Maybe (OptGroup , (Doc , Doc ))] -> Int
287+ findMaxGroupLevel = foldl' (\ acc -> max acc . optGroupToLevel) 0 . catMaybes
288+
289+ optGroupToLevel :: (OptGroup , a ) -> Int
290+ optGroupToLevel ((OptGroup i _), _) = i
227291
228292 doc :: ArgumentReachability -> Option a -> Maybe (OptGroup , (Doc , Doc ))
229293 doc info opt = do
@@ -241,6 +305,9 @@ optionsDesc global pprefs p = vsepChunks
241305 descGlobal = global
242306 }
243307
308+ lvlIndent :: Int
309+ lvlIndent = 2
310+
244311errorHelp :: Chunk Doc -> ParserHelp
245312errorHelp chunk = mempty { helpError = chunk }
246313
0 commit comments