----------------------------------------------------------------------------- -- -- Module : Data.hs -- Copyright : (c) Neil Mitchell 2007 -- License : -- -- Maintainer : -- Stability : unstable -- Portability : not portable, uses Gtk2Hs -- -- Defines the core data structures for GuiHaskell. -- -- Data passes around some global state. Data includes -- EvalState, which holds the states of the individual -- compilers that GuiHaskell can run. -- ----------------------------------------------------------------------------- module Data ( Data(..), Evaluator(..), Handles(..), empty, getHandles, setHandles, setCurrentFile, setupFonts, appendText, appendRed, applyEscape, promptCmd ) where import PropLang.Gtk import PropLang.Variable import Data.Map (Map) import qualified Data.Map as M import Control.Concurrent (ThreadId) import System.IO (Handle) import System.Process (ProcessHandle) import Text.EscapeCodes import Control.Monad import Numeric import Graphics.UI.Gtk hiding (Action, Window, ComboBox, MenuItem, TextView, ToolButton, FontButton, Event, onClicked, onChanged) data Data = Data { -- Main Window and friends window :: Window , txtOut :: TextView , txtIn :: TextView , txtSelect :: TextEntry , sb :: StatusBar , tbRun :: ToolButton , tbStop :: ToolButton , tbRestart :: ToolButton , tbOpen :: ToolButton , tbRecent :: ToolButton , tbProfile :: ToolButton , tbPref :: ToolButton , cbCompiler :: ComboBox , fbFont :: FontButton , miFile :: MenuItem , miOpen :: MenuItem , miQuit :: MenuItem , miEdit :: MenuItem , miCut :: MenuItem , miCopy :: MenuItem , miPaste :: MenuItem , miView :: MenuItem , miTools :: MenuItem , miRun :: MenuItem , miProfile :: MenuItem , miPref :: MenuItem , miHelp :: MenuItem , miAbout :: MenuItem -- Preferences Dialog and friends , wndPref :: Window , txtExecutable :: TextEntry , txtProfCFlags :: TextEntry , txtProfRFlags :: TextEntry , tbClose :: ToolButton -- About dialog , wndAbout :: Window , running :: Var Bool -- is the code executing , filename :: Var (Maybe FilePath) -- the main file loaded , outputTags :: Var [String] , history :: Var ([String], [String]) -- command history -- Configuration variables , profCFlags :: Var String , profRFlags :: Var String , executable :: Var FilePath , font :: Var String -- -- Stores the current evaluator and -- the states of background evaluators -- -- When a new evaluator is chosen, the -- current evaluator is swapped into the list -- and the new evalutor is put into current , current :: Var Evaluator , states :: Var (Map Evaluator Handles) } -- -- A data structure for storing the compiler-specific -- details -- data Handles = Handles { handle :: Handle, process :: ProcessHandle, outId :: ThreadId, errId :: ThreadId } -- hack! -- shouldn't matter as long as you use Var like an IORef -- maybe ProcessHandle should instantiate Eq instance Eq Handles where _ == _ = True data Evaluator = Hugs | GHCi deriving (Show, Read, Eq, Ord) -- So Main doesn't need to import Map empty :: Map Evaluator Handles empty = M.empty -- Probably belongs in Evaluator.hs promptCmd :: Evaluator -> String -> String promptCmd Hugs xs = ":set -p\"" ++ xs ++ "\"" promptCmd GHCi xs = ":set prompt " ++ xs -- Get the current evaluator getHandles :: Data -> IO (Maybe Handles) getHandles dat = do c <- getVar $ current dat s <- getVar $ states dat return $ M.lookup c s -- Set the handles for the current evaluator setHandles :: Data -> Maybe Handles -> IO () setHandles dat hndls = do c <- getVar $ current dat s <- getVar $ states dat case hndls of Nothing -> states dat -< M.delete c s Just x -> case M.lookup c s of Nothing -> states dat -< M.insert c x s Just _ -> states dat -< M.adjust (\_ -> x) c s -- Set the currently open file setCurrentFile :: Data -> Maybe FilePath -> IO () setCurrentFile dat path = do filename dat -< path -- -- -- setupFonts :: Data -> IO () setupFonts dat@Data{txtOut=out,txtIn=inp} = do buf <- textviewBuffer out tags <- textBufferGetTagTable buf fontStr <- getVar $ (fbFont dat)!text mapM (addTags tags) [minBound..maxBound] fdesc <- fontDescriptionFromString fontStr widgetModifyFont (getTextViewRaw out) (Just fdesc) widgetModifyFont (getTextViewRaw inp) (Just fdesc) where addTags tags col = do let name = show col (r,g,b) = getColor col f x = let xs = showHex x "" in ['0' | length xs == 1] ++ xs css = "#" ++ f r ++ f g ++ f b tagFg <- textTagNew (Just $ "fg" ++ name) tagBg <- textTagNew (Just $ "bg" ++ name) textTagTableAdd tags tagFg textTagTableAdd tags tagBg set tagFg [textTagForeground := css] set tagBg [textTagBackground := css] -- -- Append text to output area -- appendText :: Data -> String -> IO () appendText dat@Data{txtOut=out} s = do buf <- textviewBuffer out end <- textBufferGetEndIter buf textBufferInsert buf end s len <- textBufferGetCharCount buf strt <- textBufferGetIterAtOffset buf (len - length s) end2 <- textBufferGetEndIter buf tags <- getVar (outputTags dat) mapM_ (f buf strt end2) tags where f buf strt end tag = textBufferApplyTagByName buf tag strt end appendRed :: Data -> String -> IO () appendRed dat msg = do let tags = outputTags dat res <- getVar tags tags -< ["fgRed"] appendText dat msg tags -< res applyEscape :: Data -> EscapeCode -> IO () applyEscape dat (FormatAttribute Normal) = outputTags dat -< [] applyEscape dat (FormatForeground Green) = outputTags dat -< ["fgGreen"] applyEscape _ _ = return () --when_ :: Monad m => Bool -> m () -> m () --when_ b x = when b (x >> return ())