module Yi.Main (
main,
do_args,
ConsoleConfig(..),
Err(..),
) where
import Prelude ()
import Control.Monad.Error
import Data.Char
import Data.List (intercalate, length)
import Distribution.Text (display)
import System.Console.GetOpt
import System.Exit
#include "ghcconfig.h"
import Yi.Config
import Yi.Config.Default
import Yi.Core
import Yi.File
import Paths_yi
#ifdef FRONTEND_COCOA
import HOC (withAutoreleasePool)
#endif
frontendNames :: [String]
frontendNames = fmap fst' availableFrontends
where fst' :: (a,UIBoot) -> a
fst' (x,_) = x
data Err = Err String ExitCode
instance Error Err where
strMsg s = Err s (ExitFailure 1)
data ConsoleConfig =
ConsoleConfig {
ghcOptions :: [String],
selfCheck :: Bool
}
defaultConsoleConfig :: ConsoleConfig
defaultConsoleConfig =
ConsoleConfig {
ghcOptions = [],
selfCheck = False
}
data Opts = Help
| Version
| LineNo String
| EditorNm String
| File String
| Frontend String
| ConfigFile String
| SelfCheck
| GhcOption String
| Debug
| OpenInTabs
editors :: [(String,Config -> Config)]
editors = [("emacs", toEmacsStyleConfig),
("vim", toVimStyleConfig),
("vim2", toVim2StyleConfig),
("cua", toCuaStyleConfig)]
options :: [OptDescr Opts]
options =
[ Option [] ["self-check"] (NoArg SelfCheck) "Run self-checks"
, Option ['f'] ["frontend"] (ReqArg Frontend "FRONTEND") frontendHelp
, Option ['y'] ["config-file"] (ReqArg ConfigFile "PATH") "Specify a configuration file"
, Option ['V'] ["version"] (NoArg Version) "Show version information"
, Option ['h'] ["help"] (NoArg Help) "Show this help"
, Option [] ["debug"] (NoArg Debug) "Write debug information in a log file"
, Option ['l'] ["line"] (ReqArg LineNo "NUM") "Start on line number"
, Option [] ["as"] (ReqArg EditorNm "EDITOR") editorHelp
, Option [] ["ghc-option"] (ReqArg GhcOption "OPTION") "Specify option to pass to ghc when compiling configuration file"
, Option [openInTabsShort] [openInTabsLong] (NoArg OpenInTabs) "Open files in tabs"
] where frontendHelp = ("Select frontend, which can be one of:\n"
++ intercalate ", " frontendNames)
editorHelp = ("Start with editor keymap, where editor is one of:\n"
++ (intercalate ", " . fmap fst) editors)
openInTabsShort :: Char
openInTabsShort = 'p'
openInTabsLong :: String
openInTabsLong = "open-in-tabs"
usage, versinfo :: String
usage = usageInfo ("Usage: yi [option...] [file]") options
versinfo = "yi " ++ display version
do_args :: Config -> [String] -> Either Err (Config, ConsoleConfig)
do_args cfg args =
case (getOpt (ReturnInOrder File) options args) of
(os, [], []) -> foldM (getConfig shouldOpenInTabs) (cfg, defaultConsoleConfig) os
(_, _, errs) -> fail (concat errs)
where
shouldOpenInTabs = ("--" ++ openInTabsLong) `elem` args
|| ('-':[openInTabsShort]) `elem` args
getConfig :: Bool -> (Config, ConsoleConfig) -> Opts -> Either Err (Config, ConsoleConfig)
getConfig shouldOpenInTabs (cfg, cfgcon) opt =
case opt of
Frontend f -> case lookup f availableFrontends of
Just frontEnd -> return (cfg { startFrontEnd = frontEnd }, cfgcon)
Nothing -> fail "Panic: frontend not found"
Help -> throwError $ Err usage ExitSuccess
Version -> throwError $ Err versinfo ExitSuccess
Debug -> return (cfg { debugMode = True }, cfgcon)
LineNo l -> case startActions cfg of
x : xs -> return (cfg { startActions = x:makeAction (gotoLn (read l)):xs }, cfgcon)
[] -> fail "The `-l' option must come after a file argument"
File filename -> if shouldOpenInTabs && (length (startActions cfg) > 0) then
prependActions [YiA (editFile filename), EditorA newTabE]
else
prependAction (editFile filename)
EditorNm emul -> case lookup (fmap toLower emul) editors of
Just modifyCfg -> return $ (modifyCfg cfg, cfgcon)
Nothing -> fail $ "Unknown emulation: " ++ show emul
GhcOption ghcOpt -> return (cfg, cfgcon { ghcOptions = ghcOptions cfgcon ++ [ghcOpt] })
_ -> return (cfg, cfgcon)
where
prependActions as = return $ (cfg { startActions = (fmap makeAction as) ++ startActions cfg }, cfgcon)
prependAction a = return $ (cfg { startActions = makeAction a : startActions cfg}, cfgcon)
main :: (Config, ConsoleConfig) -> Maybe Editor -> IO ()
main (cfg, _cfgcon) state = do
#ifdef FRONTEND_COCOA
withAutoreleasePool $ do
#endif
when (debugMode cfg) $ initDebug ".yi.dbg"
startEditor cfg state