ghc-mod/src/GHCMod/Options.hs

167 lines
5.3 KiB
Haskell
Raw Normal View History

2015-12-05 20:55:12 +00:00
module GHCMod.Options (
parseArgs,
GhcModCommands(..)
) where
import Options.Applicative
import Options.Applicative.Types
import Language.Haskell.GhcMod.Types
import Control.Arrow
import GHCMod.Options.Commands
import GHCMod.Version
2015-12-06 16:22:21 +00:00
import GHCMod.Options.DocUtils
2015-12-05 20:55:12 +00:00
parseArgs :: IO (Options, GhcModCommands)
parseArgs =
execParser opts
where
opts = info (argAndCmdSpec <**> helpVersion)
2015-12-06 16:22:21 +00:00
$$ fullDesc
## header "ghc-mod: Happy Haskell Programming"
2015-12-05 20:55:12 +00:00
helpVersion :: Parser (a -> a)
helpVersion =
2015-12-06 16:22:21 +00:00
helper
<*> abortOption (InfoMsg ghcModVersion)
$$ long "version"
## help "Print the version of the program."
<*> argument r
$$ value id
## metavar ""
2015-12-05 20:55:12 +00:00
where
r :: ReadM (a -> a)
r = do
v <- readerAsk
case v of
"help" -> readerAbort ShowHelpText
"version" -> readerAbort $ InfoMsg ghcModVersion
_ -> return id
argAndCmdSpec :: Parser (Options, GhcModCommands)
argAndCmdSpec = (,) <$> globalArgSpec <*> commandsSpec
splitOn :: Eq a => a -> [a] -> ([a], [a])
splitOn c = second (drop 1) . break (==c)
getLogLevel :: Int -> GmLogLevel
getLogLevel = toEnum . min 7
logLevelParser :: Parser GmLogLevel
logLevelParser =
2015-12-06 16:22:21 +00:00
getLogLevel
<$> silentSwitch
<||> logLevelSwitch
<||> logLevelOption
2015-12-05 20:55:12 +00:00
where
logLevelOption =
2015-12-06 16:22:21 +00:00
option int
$$ long "verbose"
## metavar "LEVEL"
## value 4
## showDefault
## help "Set log level. (0-7)"
2015-12-05 20:55:12 +00:00
logLevelSwitch =
2015-12-06 16:22:21 +00:00
(4+) . length <$> many $$ flag' ()
$$ short 'v'
## help "Increase log level"
silentSwitch = flag' 0
$$ long "silent"
## short 's'
## help "Be silent, set log level to 0"
2015-12-05 20:55:12 +00:00
outputOptsSpec :: Parser OutputOpts
2015-12-06 16:22:21 +00:00
outputOptsSpec = OutputOpts
<$> logLevelParser
<*> flag PlainStyle LispStyle
$$ long "tolisp"
## short 'l'
## help "Format output as an S-Expression"
<*> LineSeparator <$$> strOption
$$ long "boundary"
## long "line-separator"
## short 'b'
## metavar "SEP"
## value "\0"
## showDefault
## help "Output line separator"
<*> optional $$ splitOn ',' <$$> strOption
$$ long "line-prefix"
## metavar "OUT,ERR"
## help "Output prefixes"
2015-12-05 20:55:12 +00:00
programsArgSpec :: Parser Programs
2015-12-06 16:22:21 +00:00
programsArgSpec = Programs
<$> strOption
$$ long "with-ghc"
## value "ghc"
## showDefault
## help "GHC executable to use"
<*> strOption
$$ long "with-ghc-pkg"
## value "ghc-pkg"
## showDefault
## help "ghc-pkg executable to use (only needed when guessing from GHC path fails)"
<*> strOption
$$ long "with-cabal"
## value "cabal"
## showDefault
## help "cabal-install executable to use"
<*> strOption
$$ long "with-stack"
## value "stack"
## showDefault
## help "stack executable to use"
2015-12-05 20:55:12 +00:00
globalArgSpec :: Parser Options
2015-12-06 16:22:21 +00:00
globalArgSpec = Options
<$> outputOptsSpec
<*> programsArgSpec
<*> many $$ strOption
$$ long "ghcOpt"
## long "ghc-option"
## short 'g'
## metavar "OPT"
## help "Option to be passed to GHC"
<*> many fileMappingSpec
2015-12-05 20:55:12 +00:00
where
{-
File map docs:
CLI options:
* `--map-file "file1.hs=file2.hs"` can be used to tell
ghc-mod that it should take source code for `file1.hs` from `file2.hs`.
`file1.hs` can be either full path, or path relative to project root.
`file2.hs` has to be either relative to project root,
or full path (preferred).
* `--map-file "file.hs"` can be used to tell ghc-mod that it should take
2015-12-05 23:45:54 +00:00
source code for `file.hs` from stdin. File end marker is `\n\EOT\n`,
i.e. `\x0A\x04\x0A`. `file.hs` may or may not exist, and should be
2015-12-05 20:55:12 +00:00
either full path, or relative to project root.
Interactive commands:
* `map-file file.hs` -- tells ghc-modi to read `file.hs` source from stdin.
Works the same as second form of `--map-file` CLI option.
* `unmap-file file.hs` -- unloads previously mapped file, so that it's
no longer mapped. `file.hs` can be full path or relative to
project root, either will work.
Exposed functions:
* `loadMappedFile :: FilePath -> FilePath -> GhcModT m ()` -- maps `FilePath`,
given as first argument to take source from `FilePath` given as second
argument. Works exactly the same as first form of `--map-file`
CLI option.
* `loadMappedFileSource :: FilePath -> String -> GhcModT m ()` -- maps
`FilePath`, given as first argument to have source as given
by second argument. Works exactly the same as second form of `--map-file`
CLI option, sans reading from stdin.
* `unloadMappedFile :: FilePath -> GhcModT m ()` -- unmaps `FilePath`, given as
first argument, and removes any temporary files created when file was
mapped. Works exactly the same as `unmap-file` interactive command
-}
fileMappingSpec =
2015-12-06 16:22:21 +00:00
getFileMapping . splitOn '=' <$> strOption
$$ long "map-file"
## metavar "MAPPING"
## help "Redirect one file to another, --map-file \"file1.hs=file2.hs\""
2015-12-05 20:55:12 +00:00
getFileMapping = second (\i -> if null i then Nothing else Just i)