{-# LANGUAGE CPP #-}
module Options.Applicative.Builder.Completer
( Completer
, mkCompleter
, listIOCompleter
, listCompleter
, bashCompleter
, requote
) where
import Control.Applicative
import Prelude
import Control.Exception (IOException, try)
import Data.List (isPrefixOf)
#ifdef MIN_VERSION_process
import System.Process (readProcess)
#endif
import Options.Applicative.Types
listIOCompleter :: IO [String] -> Completer
listIOCompleter :: IO [String] -> Completer
listIOCompleter IO [String]
ss = (String -> IO [String]) -> Completer
Completer forall a b. (a -> b) -> a -> b
$ \String
s ->
forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
s) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [String]
ss
listCompleter :: [String] -> Completer
listCompleter :: [String] -> Completer
listCompleter = IO [String] -> Completer
listIOCompleter forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure
bashCompleter :: String -> Completer
#ifdef MIN_VERSION_process
bashCompleter :: String -> Completer
bashCompleter String
action = (String -> IO [String]) -> Completer
Completer forall a b. (a -> b) -> a -> b
$ \String
word -> do
let cmd :: String
cmd = [String] -> String
unwords [String
"compgen", String
"-A", String
action, String
"--", String -> String
requote String
word]
Either IOException String
result <- forall a. IO a -> IO (Either IOException a)
tryIO forall a b. (a -> b) -> a -> b
$ String -> [String] -> String -> IO String
readProcess String
"bash" [String
"-c", String
cmd] String
""
forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> b -> a
const []) forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ Either IOException String
result
#else
bashCompleter = const $ Completer $ const $ return []
#endif
tryIO :: IO a -> IO (Either IOException a)
tryIO :: forall a. IO a -> IO (Either IOException a)
tryIO = forall e a. Exception e => IO a -> IO (Either e a)
try
requote :: String -> String
requote :: String -> String
requote String
s =
let
unescaped :: String
unescaped =
case String
s of
(Char
'\'': String
rs) -> String -> String
unescapeN String
rs
(Char
'"': String
rs) -> String -> String
unescapeD String
rs
String
elsewise -> String -> String
unescapeU String
elsewise
in
forall {t :: * -> *}. Foldable t => t Char -> String
strong String
unescaped
where
strong :: t Char -> String
strong t Char
ss = Char
'\'' forall a. a -> [a] -> [a]
: forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Char -> String -> String
go String
"'" t Char
ss
where
go :: Char -> String -> String
go Char
'\'' String
t = String
"'\\''" forall a. [a] -> [a] -> [a]
++ String
t
go Char
h String
t = Char
h forall a. a -> [a] -> [a]
: String
t
unescapeN :: String -> String
unescapeN = String -> String
goX
where
goX :: String -> String
goX (Char
'\'' : String
xs) = String -> String
goN String
xs
goX (Char
x : String
xs) = Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
goX [] = []
goN :: String -> String
goN (Char
'\\' : Char
'\'' : String
xs) = Char
'\'' forall a. a -> [a] -> [a]
: String -> String
goN String
xs
goN (Char
'\'' : String
xs) = String -> String
goX String
xs
goN (Char
x : String
xs) = Char
x forall a. a -> [a] -> [a]
: String -> String
goN String
xs
goN [] = []
unescapeU :: String -> String
unescapeU = String -> String
goX
where
goX :: String -> String
goX [] = []
goX (Char
'\\' : Char
x : String
xs) = Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
goX (Char
x : String
xs) = Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
unescapeD :: String -> String
unescapeD = String -> String
goX
where
goX :: String -> String
goX (Char
'\\' : Char
x : String
xs)
| Char
x forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"$`\"\\\n" = Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
| Bool
otherwise = Char
'\\' forall a. a -> [a] -> [a]
: Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
goX (Char
'"' : String
xs)
= String
xs
goX (Char
x : String
xs)
= Char
x forall a. a -> [a] -> [a]
: String -> String
goX String
xs
goX []
= []