Add line completion and history

This commit is contained in:
rnhmjoj 2015-09-19 05:55:18 +02:00
parent 839b87a3b2
commit 58bc738d79

View File

@ -1,25 +1,42 @@
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns, LambdaCase #-}
import Data.List import Control.Monad (foldM)
import Data.Maybe import Data.List (isPrefixOf)
import Text.Read import Text.Read (readMaybe)
import Text.Printf import Text.Printf (printf)
import Control.Monad import System.Directory (createDirectoryIfMissing)
import System.FilePath (takeDirectory)
import System.Environment.XDG.BaseDir (getUserDataFile)
import System.Console.Haskeline import System.Console.Haskeline
import System.Console.Haskeline.Completion
-- | Run calculator
main :: IO () main :: IO ()
main = runInputT defaultSettings repl main = settings >>= flip runInputT repl
-- | Program main loop
repl :: InputT IO () repl :: InputT IO ()
repl = do repl = getInputLine "" >>= \case
line <- getInputLine "" Nothing -> return ()
case fromMaybe "" line of Just "" -> repl
"q" -> return () Just exp -> outputStrLn (result (rpn exp) ++ "\n") >> repl
"" -> outputStrLn "" >> repl
exp -> outputStrLn (result (rpn exp) ++ "\n") >> repl
-- Pretty print RPN result/errors -- | Program settings
-- add function name completion and history
settings :: IO (Settings IO)
settings = do
path <- getUserDataFile "hsilop" "history"
createDirectoryIfMissing True (takeDirectory path)
return $ Settings (completeWord Nothing "\t " complete) (Just path) True
where
names = map fst monad ++ map fst nilad
complete x = return $ map simpleCompletion (filter (isPrefixOf x) names)
-- | Pretty print RPN result/errors
result :: Either String Double -> String result :: Either String Double -> String
result (Left err) = "Ꞥ∘ " ++ err result (Left err) = "Ꞥ∘ " ++ err
result (Right x) = printf format x where result (Right x) = printf format x where
@ -27,9 +44,9 @@ result (Right x) = printf format x where
| otherwise = "∘ %.10f" | otherwise = "∘ %.10f"
-- Solve a RPN expression -- | Solve a RPN expression
rpn :: String -> Either String Double rpn :: String -> Either String Double
rpn = foldM parse [] . words >=> return . head where rpn = fmap head . foldM parse [] . words where
parse (y:x:xs) (flip lookup dyad -> Just f) = Right (f x y : xs) parse (y:x:xs) (flip lookup dyad -> Just f) = Right (f x y : xs)
parse (x:xs) (flip lookup monad -> Just f) = Right (f x : xs) parse (x:xs) (flip lookup monad -> Just f) = Right (f x : xs)
parse xs (flip lookup nilad -> Just k) = Right (k : xs) parse xs (flip lookup nilad -> Just k) = Right (k : xs)
@ -37,14 +54,20 @@ rpn = foldM parse [] . words >=> return . head where
parse _ _ = Left "syntax error" parse _ _ = Left "syntax error"
-- dyadic functions -- Functions --
-- | Dyadic
-- i.e. operators
dyad :: [(String, Double -> Double -> Double)]
dyad = [ ("+", (+)) dyad = [ ("+", (+))
, ("-", (-)) , ("-", (-))
, ("*", (*)) , ("*", (*))
, ("/", (/)) , ("/", (/))
, ("^", (**)) ] , ("^", (**)) ]
-- monadic functions -- | Monadic
-- i.e. single argument functions
monad :: [(String, Double -> Double)]
monad = [ ("sin" , sin ) monad = [ ("sin" , sin )
, ("asin" , asin) , ("asin" , asin)
, ("cos" , cos ) , ("cos" , cos )
@ -53,12 +76,14 @@ monad = [ ("sin" , sin )
, ("atan" , atan) , ("atan" , atan)
, ("ln" , log ) , ("ln" , log )
, ("sqrt" , sqrt) , ("sqrt" , sqrt)
, ("abs" , abs )
, ("sgn" , signum) , ("sgn" , signum)
, ("abs" , abs)
, ("floor", fromIntegral . floor) , ("floor", fromIntegral . floor)
, ("ceil" , fromIntegral . ceiling) ] , ("ceil" , fromIntegral . ceiling) ]
-- niladic functions -- | Niladic
-- i.e. constants
nilad :: [(String, Double)]
nilad = [ ("pi" , pi) nilad = [ ("pi" , pi)
, ("e" , exp 1) , ("e" , exp 1)
, ("phi", (1 + sqrt 5)/2) ] , ("phi", (1 + sqrt 5)/2) ]