module Options.Applicative.BashCompletion
( bashCompletionParser
) where
import Control.Applicative ((<$>), (<*>), many)
import Data.Foldable (asum)
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe, listToMaybe)
import Options.Applicative.Builder
import Options.Applicative.Common
import Options.Applicative.Internal
import Options.Applicative.Types
bashCompletionParser :: ParserInfo a -> ParserPrefs -> Parser CompletionResult
bashCompletionParser pinfo pprefs = complParser
where
failure opts = CompletionResult
{ execCompletion = \progn -> unlines <$> opts progn }
complParser = asum
[ failure <$>
( bashCompletionQuery pinfo pprefs
<$> (many . strOption) (long "bash-completion-word"
`mappend` internal)
<*> option (long "bash-completion-index" `mappend` internal) )
, failure <$>
(bashCompletionScript <$>
strOption (long "bash-completion-script" `mappend` internal)) ]
bashCompletionQuery :: ParserInfo a -> ParserPrefs -> [String] -> Int -> String -> IO [String]
bashCompletionQuery pinfo pprefs ws i _ = case runCompletion compl pprefs of
Just (Left (SomeParser p)) -> list_options p
Just (Right c) -> run_completer c
_ -> return []
where
list_options =
fmap concat
. sequence
. mapParser (\_ -> opt_completions)
opt_completions opt = case optMain opt of
OptReader ns _ _ -> return $ show_names ns
FlagReader ns _ -> return $ show_names ns
ArgReader rdr -> run_completer (crCompleter rdr)
CmdReader ns _ -> return $ filter_names ns
show_name :: OptName -> String
show_name (OptShort c) = '-':[c]
show_name (OptLong name) = "--" ++ name
show_names :: [OptName] -> [String]
show_names = filter_names . map show_name
filter_names :: [String] -> [String]
filter_names = filter is_completion
run_completer :: Completer -> IO [String]
run_completer c = runCompleter c (fromMaybe "" (listToMaybe ws''))
(ws', ws'') = splitAt i ws
is_completion :: String -> Bool
is_completion =
case ws'' of
w:_ -> isPrefixOf w
_ -> const True
compl = do
setParser Nothing (infoParser pinfo)
runParserInfo pinfo (drop 1 ws')
bashCompletionScript :: String -> String -> IO [String]
bashCompletionScript prog progn = return
[ "_" ++ progn ++ "()"
, "{"
, " local cmdline"
, " CMDLINE=(--bash-completion-index $COMP_CWORD)"
, ""
, " for arg in ${COMP_WORDS[@]}; do"
, " CMDLINE=(${CMDLINE[@]} --bash-completion-word $arg)"
, " done"
, ""
, " COMPREPLY=( $(" ++ prog ++ " \"${CMDLINE[@]}\") )"
, "}"
, ""
, "complete -o filenames -F _" ++ progn ++ " " ++ progn ]