{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_HADDOCK show-extensions #-} -- | -- Module : Yi.Mode.GHCi -- License : GPL-2 -- Maintainer : yi-devel@googlegroups.com -- Stability : experimental -- Portability : portable -- -- A mode for GHCi, implemented as tweaks on Interaction mode module Yi.Mode.GHCi where import GHC.Generics (Generic) import Lens.Micro.Platform (makeLenses, (%~), (&), (.~)) import Data.Binary (Binary (..)) import Data.Default (Default (..)) import Data.Text () import qualified Data.Text as T (findIndex) import Data.Typeable (Typeable) import Yi.Buffer import Yi.Keymap (YiM, topKeymapA) import Yi.Keymap.Keys (Key (KHome), important, spec, (?>>!)) import Yi.Lexer.Alex (Tok) import Yi.Lexer.Compilation (Token ()) import qualified Yi.Mode.Interactive as I (mode, spawnProcessMode) import qualified Yi.Rope as R (toText) import Yi.Syntax.OnlineTree (Tree) import Yi.Types (YiVariable) -- | The process name to use to spawn GHCi. data GhciProcessName = GhciProcessName { _ghciProcessName :: FilePath -- ^ Command to run when spawning GHCi. , _ghciProcessArgs :: [String] -- ^ Args to pass to the process. } deriving (Typeable, Show, Generic) -- | The process name defaults to @ghci@. instance Default GhciProcessName where def = GhciProcessName { _ghciProcessName = "ghci" , _ghciProcessArgs = [] } instance Binary GhciProcessName makeLenses ''GhciProcessName -- | Setting this is a bit like '(setq haskell-program-name foo)' in -- emacs' @haskell-mode@. instance YiVariable GhciProcessName -- | Mode used for GHCi. Currently it just overrides 'KHome' key to go -- just before the prompt through the use of 'homeKey'. mode :: Mode (Tree (Tok Token)) mode = I.mode & modeNameA .~ "ghci" & modeKeymapA .~ topKeymapA %~ important (spec KHome ?>>! homeKey) -- | The GHCi prompt always begins with ">"; this goes to just before -- it, or if one is already at the start of the prompt, goes to the -- beginning of the line. (If at the beginning of the line, this -- pushes you forward to it.) homeKey :: BufferM () homeKey = readLnB >>= \l -> case T.findIndex ('>' ==) (R.toText l) of Nothing -> moveToSol Just pos -> do (_,mypos) <- getLineAndCol moveToSol >> if mypos == (pos + 2) then return () else moveXorEol (pos + 2) -- | Spawns an interactive process ("Yi.Mode.Interactive") with GHCi -- 'mode' over it. spawnProcess :: FilePath -- ^ Command to use. -> [String] -- ^ Process args. -> YiM BufferRef -- ^ Reference to the spawned buffer. spawnProcess = I.spawnProcessMode mode