module FortyTwo.Utils where
import System.Console.ANSI (cursorUpLine, clearFromCursorToScreenEnd)
import System.IO (hSetBuffering, hFlush, hSetEcho, hReady, stdin, stdout, BufferMode(..))
import Data.List (findIndex, findIndices, elemIndex, intercalate)
import Control.Applicative ((<$>))
import Data.Maybe (fromJust)
import FortyTwo.Types(Option(..), Options)
import FortyTwo.Constants (emptyString)
noBuffering :: IO()
noBuffering = do
hSetBuffering stdin NoBuffering
hSetBuffering stdout NoBuffering
restoreBuffering :: IO()
restoreBuffering = do
hSetBuffering stdin LineBuffering
hSetBuffering stdout LineBuffering
noEcho :: IO ()
noEcho = hSetEcho stdin False
restoreEcho :: IO ()
restoreEcho = hSetEcho stdin True
clearLines :: Int -> IO()
clearLines l = do
cursorUpLine l
clearFromCursorToScreenEnd
map' :: (Int -> a -> b) -> [a] -> [b]
map' f = zipWith f [0..]
filter' :: Eq a => (Int -> a -> Bool) -> [a] -> [a]
filter' f xs = [x | x <- xs, f (fromJust (elemIndex x xs)) x]
getKey :: IO String
getKey = reverse <$> getKey' emptyString
where
getKey' chars = do
char <- getChar
more <- hReady stdin
(if more then getKey' else return) (char:chars)
flush :: IO()
flush = hFlush stdout
getOptionsMeta :: Options -> (Int, Int, Maybe Int)
getOptionsMeta options = (0, length options 1, getFocusedOptionIndex options)
getOptionsLines :: Options -> Int
getOptionsLines = sum . map (length . lines . getOptionValue)
stringsToOptions :: [String] -> Options
stringsToOptions options = [
Option { value = o, isFocused = False, isSelected = False } | o <- options
]
focusOption :: Int -> Options -> Options
focusOption focusedIndex = map' $ \ i o ->
Option {
value = getOptionValue o,
isSelected = getOptionIsSelected o,
isFocused = focusedIndex == i
}
addBreakingLinesSpacing :: String -> String -> String
addBreakingLinesSpacing separator value =
if null multiLines then
value
else
firstLine ++ "\n" ++ unlines (take (length normalisedLines 1) normalisedLines) ++ last normalisedLines
where
values = lines value
firstLine = head values
multiLines = tail values
normalisedLines = map (\text -> separator ++ text) multiLines
toggleFocusedOption :: Int -> Options -> Options
toggleFocusedOption focusedIndex = map' $ \ i o ->
Option {
value = getOptionValue o,
isFocused = focusedIndex == i,
isSelected = if focusedIndex == i then
not $ getOptionIsSelected o
else getOptionIsSelected o
}
toCommaSeparatedString :: [String] -> String
toCommaSeparatedString = intercalate ", "
getOptionValue :: Option -> String
getOptionValue Option { value } = value
getOptionIsFocused :: Option -> Bool
getOptionIsFocused Option { isFocused } = isFocused
getOptionIsSelected :: Option -> Bool
getOptionIsSelected Option { isSelected } = isSelected
getFocusedOptionIndex :: Options -> Maybe Int
getFocusedOptionIndex = findIndex getOptionIsFocused
getSelecteOptionsIndexes :: Options -> [Int]
getSelecteOptionsIndexes = findIndices getOptionIsSelected