1 -- This file is part of Diohsc
2 -- Copyright (C) 2020 Martin Bays <mbays@sdf.org>
4 -- This program is free software: you can redistribute it and/or modify
5 -- it under the terms of version 3 of the GNU General Public License as
6 -- published by the Free Software Foundation, or any later version.
8 -- You should have received a copy of the GNU General Public License
9 -- along with this program. If not, see http://www.gnu.org/licenses/.
17 , promptLineWithCompletions
18 , promptLineWithHistoryFile
22 import Control
.Exception
.Base
(bracket)
23 import Control
.Monad
(void
)
24 import Control
.Monad
.Catch
(MonadMask
)
25 import Control
.Monad
.IO.Class
(MonadIO
)
26 import Control
.Monad
.Trans
(lift
)
27 import Data
.Bits
(xor
)
28 import Data
.List
(isPrefixOf)
31 import qualified System
.Console
.Haskeline
as HL
36 defaultInputSettings
:: HL
.Settings
IO
37 defaultInputSettings
= (HL
.defaultSettings
:: HL
.Settings
IO) {HL
.complete
= HL
.noCompletion
}
39 runInputTDefWithAbortValue
:: a
-> HL
.InputT
IO a
-> IO a
40 runInputTDefWithAbortValue
= runInputTWithAbortValue defaultInputSettings
42 runInputTWithAbortValue
:: HL
.Settings
IO -> a
-> HL
.InputT
IO a
-> IO a
43 runInputTWithAbortValue settings abortValue
=
44 HL
.handleInterrupt
(return abortValue
) . HL
.runInputT settings
. HL
.withInterrupt
47 waitKey
:: String -> IO Bool
48 waitKey prompt
= runInputTDefWithAbortValue
False $
49 (HL
.haveTerminalUI
>>? void
. HL
.waitForAnyKey
$ escapePromptCSI prompt
) >> return True
51 promptChar
:: String -> IO (Maybe Char)
52 promptChar prompt
= bracketSet
(hGetEcho
stdin) (hSetEcho
stdin) False .
53 bracketSet
(hGetBuffering stdin) (hSetBuffering stdin) NoBuffering
$ do
56 runInputTDefWithAbortValue Nothing
. lift
$ Just
<$> getChar
57 where bracketSet get set v f
= bracket get set
$ \_
-> set v
>> f
59 promptYN
:: Bool -> Bool -> String -> IO Bool
60 promptYN
False def _
= return def
61 promptYN
True def prompt
= do
62 answer
<- xor def
. (`
elem`
map Just
(if def
then "nN" else "yY"))
63 <$> promptChar
(prompt
++ if def
then " [Y/n] " else " [y/N] ")
64 putStrLn $ if answer
then "y" else "n"
67 promptPassword
:: String -> IO (Maybe String)
68 promptPassword
= runInputTDefWithAbortValue Nothing
. HL
.getPassword
(Just
'*') . escapePromptCSI
70 -- Possible return values:
71 -- Nothing: interrupted
74 promptLineInputT
:: (MonadIO m
, MonadMask m
) => String -> HL
.InputT m
(Maybe (Maybe String))
75 promptLineInputT
= HL
.handleInterrupt
(return Nothing
) . HL
.withInterrupt
. (Just
<$>) . HL
.getInputLine
. escapePromptCSI
77 promptLine
:: String -> IO (Maybe (Maybe String))
78 promptLine
= HL
.runInputT defaultInputSettings
. promptLineInputT
80 promptLineWithCompletions
:: String -> [String] -> IO (Maybe (Maybe String))
81 promptLineWithCompletions prompt completions
=
82 HL
.runInputT settings
$ promptLineInputT prompt
83 where settings
= defaultInputSettings
84 { HL
.complete
= HL
.completeWord Nothing
" " $ \w
->
85 return . map HL
.simpleCompletion
$ filter (isPrefixOf w
) completions
}
87 promptLineWithHistoryFile
:: FilePath -> String -> IO (Maybe (Maybe String))
88 promptLineWithHistoryFile path
=
89 HL
.runInputT settings
. promptLineInputT
90 where settings
= defaultInputSettings
{ HL
.historyFile
= Just path
}