----------------------------------------------------------------------------- -- | -- Module : XMonad.Actions.Eval -- Copyright : (c) 2009 Daniel Schoepe -- License : BSD3-style (see LICENSE) -- -- Maintainer : Daniel Schoepe <daniel.schoepe@gmail.com> -- Stability : unstable -- Portability : unportable -- -- Evaluate haskell expressions at runtime in the running xmonad instance. -- ----------------------------------------------------------------------------- module XMonad.Actions.Eval ( -- * Usage -- $usage -- * Documentation -- $documentation evalExpression , evalExpressionWithReturn , EvalConfig(..) , defaultEvalConfig ) where import XMonad.Core import XMonad.Util.Run import Language.Haskell.Interpreter import Data.List -- $usage -- This module provides functions to evaluate haskell expressions at runtime -- To use it, bind a key to evalExpression, for example in combination with a prompt: -- -- > import XMonad -- > import XMonad.Actions.Eval -- > import XMonad.Prompt.Input -- > .. -- > , ((modMask,xK_t), inputPrompt defaultXPConfig "Eval" >>= flip whenJust (evalExpression defaultEvalConfig)) -- -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings". -- $documentation -- In here due to the apparent lack of a replace function in the standard library. -- (Used for correctly displaying newlines in error messages) replace :: Eq a => [a] -> [a] -> [a] -> [a] replace lst@(x:xs) sub repl | sub `isPrefixOf` lst = repl ++ replace (drop (length sub) lst) sub repl | otherwise = x:(replace xs sub repl) replace _ _ _ = [] -- | Configuration structure data EvalConfig = EvalConfig { handleError :: InterpreterError -> X String -- ^ Function to handle errors , imports :: [(ModuleName,Maybe String)] -- ^ Modules to import for interpreting the expression. -- The pair consists of the module name and an optional -- qualification of the imported module. , modules :: [String] -- ^ Other source files that should be loaded -- The definitions of these modules will be visible -- regardless of whether they are exported. } -- | Defaults for evaluating expressions. defaultEvalConfig :: EvalConfig defaultEvalConfig = EvalConfig { handleError = handleErrorDefault , imports = [("Prelude",Nothing),("XMonad",Nothing), ("XMonad.StackSet",Just "W"),("XMonad.Core",Nothing)] , modules = [] } -- | Default way to handle(in this case: display) an error during interpretation of an expression. handleErrorDefault :: InterpreterError -> X String handleErrorDefault err = io (safeSpawn "/usr/bin/xmessage" [replace (show err) "\\n" "\n"]) >> return "Error" -- | Returns an Interpreter action that loads the desired modules and interprets the expression. interpret' :: EvalConfig -> String -> Interpreter (X String) interpret' conf s = do loadModules $ modules conf setTopLevelModules =<< getLoadedModules setImportsQ $ imports conf interpret ("show `fmap` ("++s++")") (return "") -- | Evaluates a given expression whose result type has to be an instance of Show evalExpressionWithReturn :: EvalConfig -> String -> X String evalExpressionWithReturn conf s = io (runInterpreter $ interpret' conf s) >>= either (handleError conf) id -- | Evaluates a given expression, but discard the returned value. Provided for -- more convenient use in keybindings evalExpression :: EvalConfig -> String -> X () evalExpression cnf = (>> return ()) . evalExpressionWithReturn cnf