summaryrefslogtreecommitdiff
path: root/Pancake/Command.hs
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2017-11-05 07:28:36 +0300
committerdefanor <defanor@uberspace.net>2017-11-05 07:28:36 +0300
commit7488196f36824184e2e9088ed9984a189a87cffa (patch)
tree7b87fed3eb5fb5e3d599e9e1c617f7d075615554 /Pancake/Command.hs
parent6740a349caa6c20513191bbf213570448352093f (diff)
Use Parsec for command parsing
Diffstat (limited to 'Pancake/Command.hs')
-rw-r--r--Pancake/Command.hs86
1 files changed, 86 insertions, 0 deletions
diff --git a/Pancake/Command.hs b/Pancake/Command.hs
new file mode 100644
index 0000000..46a3e66
--- /dev/null
+++ b/Pancake/Command.hs
@@ -0,0 +1,86 @@
+{- |
+Module : Pancake.Command
+Maintainer : defanor <defanor@uberspace.net>
+Stability : unstable
+Portability : portable
+
+User command parsing.
+-}
+
+module Pancake.Command ( Command(..)
+ , parseCommand
+ ) where
+
+import Network.URI
+import Text.Parsec
+import Text.Parsec.String
+import qualified Data.Map as M
+
+import Pancake.Configuration
+
+
+-- | Interactive user command.
+data Command = Quit
+ | Follow Int
+ | More
+ | GoTo URI
+ | Reload
+ | Back
+ | Forward
+ | Help
+ | Show Int
+ | ShowCurrent
+ | Shortcut String String
+ | ReloadConfig
+ deriving (Show, Eq)
+
+-- | Parses a user command.
+parseCommand :: Config -> String -> Command
+parseCommand c = either (const Help) id . parse (command c) "user input"
+
+-- | Basic (constant) command parser.
+basicCommand :: Parser Command
+basicCommand = choice . map (\(s, c) -> try (string s <* eof) *> pure c) $
+ [ ("q", Quit)
+ , ("b", Back)
+ , ("f", Forward)
+ , ("r", Reload)
+ , ("re", ReloadConfig)
+ , ("h", Help)
+ , ("?", ShowCurrent)
+ , ("", More)]
+
+-- | 'Follow' command parser.
+followRef :: Parser Command
+followRef = Follow . read <$> many1 digit <* eof
+
+-- | 'Show' command parser.
+showRef :: Parser Command
+showRef = char '?' *> (Show . read <$> many1 digit) <* eof
+
+-- | 'GoTo' command parser.
+goTo :: Parser Command
+goTo = do
+ s <- manyTill anyChar eof
+ maybe (fail "Failed to parse URI") (pure . GoTo) $ parseURIReference s
+
+-- | 'Shortcut' command parser.
+shortcut :: M.Map String String -> Parser Command
+shortcut m = do
+ s <- choice $ map (try . string) $ M.keys m
+ _ <- space
+ case M.lookup s m of
+ Nothing -> fail $ "No such shortcut: " ++ s
+ Just u -> do
+ q <- manyTill anyChar eof
+ pure $ Shortcut u q
+
+-- | Command parser.
+command :: Config -> Parser Command
+command c =
+ choice (map try
+ [ basicCommand <?> "basic command"
+ , followRef <?> "follow ref"
+ , showRef <?> "show ref"
+ , goTo <?> "go to"
+ , shortcut (shortcuts c) <?> "shortcut"])