diff options
author | Alexander Foremny <aforemny@posteo.de> | 2023-12-26 03:24:31 +0100 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2023-12-26 03:24:31 +0100 |
commit | 336273d2797de14d44ec387ea7e5bd0215bf98ab (patch) | |
tree | 0567244c2d1a735096cfaaf5b855bb080c82cdf1 /app/Prompt.hs | |
parent | fdb3b6d964ea82490d5c5abe94c97144c0d0288d (diff) |
chore: add `createdAt` tag
Diffstat (limited to 'app/Prompt.hs')
-rw-r--r-- | app/Prompt.hs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/app/Prompt.hs b/app/Prompt.hs new file mode 100644 index 0000000..0548c80 --- /dev/null +++ b/app/Prompt.hs @@ -0,0 +1,85 @@ +{-# LANGUAGE GADTs #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing #-} + +module Prompt + ( Prompt, + prompt, + choice, + string, + help, + compact, + ) +where + +import Data.Char (isSpace) +import Data.List.NonEmpty qualified as N +import Data.Maybe (fromJust, isNothing) +import System.IO (hFlush, stdout) +import Text.Printf (printf) +import Text.Read (readMaybe) + +data Prompt a where + Choice :: Bool -> Maybe (a -> String) -> String -> N.NonEmpty a -> Prompt a + String :: Bool -> Maybe (String -> String) -> String -> [String] -> Prompt String + +string :: String -> [String] -> Prompt String +string = String False Nothing + +choice :: String -> N.NonEmpty a -> Prompt a +choice = Choice False Nothing + +-- TODO add `help` +help :: (a -> String) -> Prompt a -> Prompt a +help h (Choice c _ q as) = Choice c (Just h) q as +help h (String c _ q as) = String c (Just h) q as + +-- TODO add `compact` +compact :: Prompt a -> Prompt a +compact (Choice _ h' q as) = Choice True h' q as +compact (String _ h' q as) = String True h' q as + +class Promptable a where + toString :: a -> String + fromString :: String -> Maybe a + +instance Promptable String where + toString = id + fromString = Just + +prompt :: (Eq a, Promptable a) => Prompt a -> IO a +prompt p@(Choice c h' q as) = do + -- TODO add `help` + let p' = String c Nothing q (map toString (N.toList as)) + a' <- fromString <$> prompt p' + if isNothing a' || not (a' `elem` (map Just (N.toList as))) + then prompt p + else pure (fromJust a') +prompt p@(String _ _ q as) = do + if null as + then printf "%s " q + else do + printf "%s\n" q + mapM_ (\(n, a) -> printf "[%d] %s\n" n a) (zip [1 :: Int ..] as) + printf "Your choice? [default: %s] " (head as) + hFlush stdout + a <- strip <$> getLine + if null as + then pure a + else case readMaybe a of + Just n -> + case drop (n - 1) as of + [] -> prompt p + (a : _) -> pure a + Nothing -> + if null a + then pure (head as) + else pure a + +strip :: String -> String +strip = stripEnd . stripStart + +stripStart :: String -> String +stripStart = dropWhile isSpace + +stripEnd :: String -> String +stripEnd = reverse . stripStart . reverse |