Subversion

Galculator

?curdirlinks? - Rev 8

?prevdifflink? - Blame



{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}

-------------------------------------------------------------------------------

{- |
Module      :  Galculator.Interpreter
Description :  Command line interpreter of Galculator.
Copyright   :  (c) Paulo Silva
License     :  LGPL

Maintainer  :  paufil@di.uminho.pt
Stability   :  experimental
Portability :  portable

-}


-------------------------------------------------------------------------------

module Galculator.Interpreter (
 interactiveUI
 ) where

import Control.GalcError
import Control.Monad.Error
import Control.Monad.Fresh
import Control.Monad.Trans
import Data.Char( isSpace )
import Data.IORef
import Data.List
import Galculator.RunCommand
import Galculator.State
import Language.Command.Parser
import Language.Command.Syntax
import System.Console.Readline


-------------------------------------------------------------------------------

-- | Sets the interactive environment: initializes the readline library, puts
--   the welcome banner and lanches the interactive loop with the initial state.
--   At exit resets the readline library.
interactiveUI :: IO ()
interactiveUI = do
  initialize
  setAttemptedCompletionFunction $ Just completeCommand
  putStrLn galculatorBanner
  startGalculator interactiveLoop emptyState
  putStrLn "Leaving Galculator"
  resetTerminal Nothing
  return ()

-------------------------------------------------------------------------------

-- | Initializes a new session with a given state.
startGalculator :: FreshT [String] GalcState a -> GalcSt -> IO a
startGalculator g state =
  aux (evalFreshT g (map show ([1..]::[Integer]))) state
  where aux :: GalcState a -> GalcSt -> IO a
        aux g' state' = do
          ref <- newIORef state'
          unGalcState g' ref

-------------------------------------------------------------------------------

prompt :: String
prompt = "Galculator> "

-------------------------------------------------------------------------------

interactiveLoop :: FreshT [String] GalcState ()
interactiveLoop = runErrorT (interactiveLoop') >> return ()

-------------------------------------------------------------------------------

interactiveLoop' :: GalcStateT ()
interactiveLoop' = do
  cmd <- liftIO . readline $ prompt
  exit <- maybe (return False) aux cmd
  if exit then return () else interactiveLoop'
  where
    aux c = if null . removeSpaces $ c
            then return False
            else (do
              liftIO . addHistory $ c
              runCommand =<< parser c) `catchError` showError

-------------------------------------------------------------------------------

showError :: GalcError -> GalcStateT Bool
showError = keepGoing . liftIO . putStrLn . (++) "***Galculator error:\n" . show

-------------------------------------------------------------------------------

completeCommand :: String -> Int -> Int -> IO (Maybe (String, [String]))
completeCommand str _ _ = do
  let lst = foldr (\c r -> if str `isPrefixOf` c then c:r else r) [] commands
  case lst of
    [] -> return Nothing
    [x] -> return $ Just (x,[])
    xs -> return $ Just (getCommonPrefix xs, xs)

-------------------------------------------------------------------------------
-- Stollen from GHCi
getCommonPrefix :: [String] -> String
getCommonPrefix [] = ""
getCommonPrefix (str:ss) = foldl common str ss
  where common _ "" = ""
        common "" _ = ""
        common (c:cs) (d:ds)
          | c == d = c : common cs ds
          | otherwise = ""

-------------------------------------------------------------------------------
-- Stollen from GHC Utils
removeSpaces :: String -> String
removeSpaces = reverse . dropWhile isSpace . reverse . dropWhile isSpace

-------------------------------------------------------------------------------

galculatorBanner :: String
galculatorBanner =
 "   ___    __    _      ___  _   _  _         __   _____  __   ___ \n" ++
 "  / _ \\  /  \\  | |    / __|| | | || |       /  \\ |_   _|/   \\|    \\\n" ++
 " / /_\\/ / /\\ \\ | |   | |   | | | || |      / /\\ \\  | |  | | ||    /\n" ++
 "/ /_\\\\ / ___  \\| |___| |__ | |_| || |___  / ___  \\ | |  | | || |\\ \\\n" ++
 "\\____//_/   \\_/ \\____|\\___|\\____/  \\____|/_/   \\_/ |_|  \\___/|_|  \\_\\\n\n" ++
 " Paulo Silva (paufil@di.uminho.pt)\n" ++
 " Universidade do Minho, Braga, Portugal\n"

-------------------------------------------------------------------------------
 

Theme by Vikram Singh | Powered by WebSVN v2.3.3