module UI.Butcher.Monadic.Interactive
( simpleCompletion
, shellCompletionWords
, interactiveHelpDoc
, partDescStrings
)
where
#include "prelude.inc"
import qualified Text.PrettyPrint as PP
import UI.Butcher.Monadic.Internal.Types
import UI.Butcher.Monadic.Internal.Core
import UI.Butcher.Monadic.Pretty
simpleCompletion
:: String
-> CommandDesc ()
-> String
-> String
simpleCompletion line cdesc pcRest = case reverse line of
[] -> compl
' ' : _ -> compl
_ | null pcRest -> ""
_ -> compl
where
compl = List.drop (List.length lastWord) (longestCommonPrefix choices)
longestCommonPrefix [] = ""
longestCommonPrefix (c1 : cr) =
case find (\s -> List.all (s `isPrefixOf`) cr) $ reverse $ List.inits c1 of
Nothing -> ""
Just x -> x
nameDesc = case _cmd_mParent cdesc of
Nothing -> cdesc
Just (_, parent) | null pcRest && not (null lastWord) -> parent
Just{} -> cdesc
lastWord = reverse $ takeWhile (not . Char.isSpace) $ reverse $ line
choices :: [String]
choices = join
[ [ r
| (Just r, _) <- Data.Foldable.toList (_cmd_children nameDesc)
, lastWord `isPrefixOf` r
, lastWord /= r
]
, [ s
| s <- partDescStrings =<< _cmd_parts nameDesc
, lastWord `isPrefixOf` s
, lastWord /= s
]
]
shellCompletionWords
:: String
-> CommandDesc ()
-> String
-> [CompletionItem]
shellCompletionWords line cdesc pcRest = choices
where
nameDesc = case _cmd_mParent cdesc of
Nothing -> cdesc
Just (_, parent) | null pcRest && not (null lastWord) -> parent
Just{} -> cdesc
lastWord = reverse $ takeWhile (not . Char.isSpace) $ reverse $ line
choices :: [CompletionItem]
choices = join
[ [ CompletionString r
| (Just r, _) <- Data.Foldable.toList (_cmd_children nameDesc)
, lastWord `isPrefixOf` r
, lastWord /= r
]
, [ c
| c <- partDescCompletions =<< _cmd_parts cdesc
, case c of
CompletionString s -> lastWord `isPrefixOf` s && lastWord /= s
_ -> True
]
]
interactiveHelpDoc
:: String
-> CommandDesc ()
-> String
-> Int
-> PP.Doc
interactiveHelpDoc cmdline desc pcRest maxLines = if
| null cmdline -> helpStrShort
| List.last cmdline == ' ' -> helpStrShort
| otherwise -> helpStr
where
helpStr = if List.length optionLines > maxLines
then
PP.fcat $ List.intersperse (PP.text "|") $ PP.text . fst <$> optionLines
else PP.vcat $ optionLines <&> \case
(s, "") -> PP.text s
(s, h ) -> PP.text s PP.<> PP.text h
where
nameDesc = case _cmd_mParent desc of
Nothing -> desc
Just (_, parent) | null pcRest -> parent
Just{} -> desc
lastWord = reverse $ takeWhile (not . Char.isSpace) $ reverse $ cmdline
optionLines :: [(String, String)]
optionLines =
join
[ [ (s, e)
| (Just s, c) <- Data.Foldable.toList (_cmd_children nameDesc)
, lastWord `isPrefixOf` s
, let e = join $ join
[ [ " ARGS" | not $ null $ _cmd_parts c ]
, [ " CMDS" | not $ null $ _cmd_children c ]
, [ ": " ++ show h | Just h <- [_cmd_help c] ]
]
]
, [ (s, "")
| s <- partDescStrings =<< _cmd_parts nameDesc
, lastWord `isPrefixOf` s
]
]
helpStrShort = ppUsageWithHelp desc
partDescStrings :: PartDesc -> [String]
partDescStrings = \case
PartLiteral s -> [s]
PartVariable _ -> []
PartOptional x -> partDescStrings x
PartAlts alts -> alts >>= partDescStrings
PartSeq [] -> []
PartSeq (x:_) -> partDescStrings x
PartDefault _ x -> partDescStrings x
PartSuggestion ss x -> [ s | CompletionString s <- ss ] ++ partDescStrings x
PartRedirect _ x -> partDescStrings x
PartReorder xs -> xs >>= partDescStrings
PartMany x -> partDescStrings x
PartWithHelp _h x -> partDescStrings x
PartHidden{} -> []
partDescCompletions :: PartDesc -> [CompletionItem]
partDescCompletions = \case
PartLiteral s -> [CompletionString s]
PartVariable _ -> []
PartOptional x -> partDescCompletions x
PartAlts alts -> alts >>= partDescCompletions
PartSeq [] -> []
PartSeq (x:_) -> partDescCompletions x
PartDefault _ x -> partDescCompletions x
PartSuggestion ss x -> ss ++ partDescCompletions x
PartRedirect _ x -> partDescCompletions x
PartReorder xs -> xs >>= partDescCompletions
PartMany x -> partDescCompletions x
PartWithHelp _h x -> partDescCompletions x
PartHidden{} -> []