ghc-mod/Language/Haskell/GhcMod/Options/Commands.hs

293 lines
10 KiB
Haskell
Raw Normal View History

2015-12-09 22:13:58 +00:00
-- ghc-mod: Making Haskell development *more* fun
-- Copyright (C) 2015 Nikolay Yakimov <root@livid.pp.ru>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
2015-12-20 10:48:47 +00:00
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
module Language.Haskell.GhcMod.Options.Commands where
2015-12-05 20:55:12 +00:00
import Options.Applicative
import Options.Applicative.Types
2015-12-20 03:31:14 +00:00
import Options.Applicative.Builder.Internal
import Language.Haskell.GhcMod.Types
import Language.Haskell.GhcMod.Read
import Language.Haskell.GhcMod.Options.DocUtils
import Language.Haskell.GhcMod.Options.Help
2015-12-05 20:55:12 +00:00
type Symbol = String
type Expr = String
type Module = String
type Line = Int
type Col = Int
type Point = (Line, Col)
data GhcModCommands =
CmdLang
| CmdFlag
| CmdDebug
| CmdBoot
| CmdNukeCaches
| CmdRoot
| CmdLegacyInteractive
| CmdModules Bool
| CmdDumpSym
2015-12-05 20:55:12 +00:00
| CmdFind Symbol
| CmdDoc Module
| CmdLint LintOpts FilePath
| CmdBrowse BrowseOpts [Module]
| CmdDebugComponent [String]
| CmdCheck [FilePath]
| CmdExpand [FilePath]
| CmdInfo FilePath Symbol
| CmdType FilePath Point
| CmdSplit FilePath Point
| CmdSig FilePath Point
| CmdAuto FilePath Point
| CmdRefine FilePath Point Expr
2015-12-26 23:00:43 +00:00
| CmdTest FilePath
-- interactive-only commands
| CmdMapFile FilePath
| CmdUnmapFile FilePath
| CmdQuit
2015-12-20 12:02:31 +00:00
deriving (Show)
2015-12-05 20:55:12 +00:00
commandsSpec :: Parser GhcModCommands
commandsSpec =
hsubparser commands
commands :: Mod CommandFields GhcModCommands
commands =
command "lang"
2015-12-06 18:30:03 +00:00
$$ info (pure CmdLang)
$$ progDesc "List all known GHC language extensions"
2015-12-06 16:22:21 +00:00
<> command "flag"
2015-12-06 18:30:03 +00:00
$$ info (pure CmdFlag)
$$ progDesc "List GHC -f<foo> flags"
2015-12-06 16:22:21 +00:00
<> command "debug"
2015-12-06 18:30:03 +00:00
$$ info (pure CmdDebug)
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"Print debugging information. Please include"
\\ "the output in any bug reports you submit"
2015-12-06 16:22:21 +00:00
<> command "debug-component"
2015-12-06 18:30:03 +00:00
$$ info debugComponentArgSpec
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"Debugging information related to cabal component"
\\ "resolution"
2015-12-06 16:22:21 +00:00
<> command "boot"
2015-12-06 18:30:03 +00:00
$$ info (pure CmdBoot)
$$ progDesc "Internal command used by the emacs frontend"
-- <> command "nuke-caches"
-- $$ info (pure CmdNukeCaches) idm
2015-12-06 16:22:21 +00:00
<> command "root"
2015-12-06 18:30:03 +00:00
$$ info (pure CmdRoot)
2015-12-20 10:48:47 +00:00
$$ progDesc'
"Try to find the project directory."
<=> desc $$$ do
"For Cabal projects this is the"
\\ "directory containing the cabal file, for projects"
\\ "that use a cabal sandbox but have no cabal file"
\\ "this is the directory containing the cabal.sandbox.config"
\\ "file and otherwise this is the current directory"
2015-12-06 16:22:21 +00:00
<> command "legacy-interactive"
2015-12-20 03:31:14 +00:00
$$ info legacyInteractiveArgSpec
2015-12-06 18:30:03 +00:00
$$ progDesc "ghc-modi compatibility mode"
2015-12-06 16:22:21 +00:00
<> command "list"
2015-12-06 18:30:03 +00:00
$$ info modulesArgSpec
$$ progDesc "List all visible modules"
2015-12-06 16:22:21 +00:00
<> command "modules"
2015-12-06 18:30:03 +00:00
$$ info modulesArgSpec
$$ progDesc "List all visible modules"
2015-12-06 16:22:21 +00:00
<> command "dumpsym"
$$ info (pure CmdDumpSym) idm
2015-12-06 16:22:21 +00:00
<> command "find"
2015-12-06 18:30:03 +00:00
$$ info findArgSpec
$$ progDesc "List all modules that define SYMBOL"
2015-12-06 16:22:21 +00:00
<> command "doc"
2015-12-06 18:30:03 +00:00
$$ info docArgSpec
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"Try finding the html documentation directory"
\\ "for the given MODULE"
2015-12-06 16:22:21 +00:00
<> command "lint"
2015-12-06 18:30:03 +00:00
$$ info lintArgSpec
$$ progDesc "Check files using `hlint'"
2015-12-06 16:22:21 +00:00
<> command "browse"
2015-12-06 18:30:03 +00:00
$$ info browseArgSpec
$$ progDesc "List symbols in a module"
2015-12-06 16:22:21 +00:00
<> command "check"
2015-12-06 18:30:03 +00:00
$$ info checkArgSpec
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"Load the given files using GHC and report errors/warnings,"
\\ "but don't produce output files"
2015-12-06 16:22:21 +00:00
<> command "expand"
2015-12-06 18:30:03 +00:00
$$ info expandArgSpec
$$ progDesc "Like `check' but also pass `-ddump-splices' to GHC"
2015-12-06 16:22:21 +00:00
<> command "info"
2015-12-06 18:30:03 +00:00
$$ info infoArgSpec
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"Look up an identifier in the context"
\\ "of FILE (like ghci's `:info')"
2015-12-06 16:22:21 +00:00
<> command "type"
2015-12-06 18:30:03 +00:00
$$ info typeArgSpec
$$ progDesc "Get the type of the expression under (LINE,COL)"
2015-12-06 16:22:21 +00:00
<> command "split"
2015-12-06 18:30:03 +00:00
$$ info splitArgSpec
$$ progDesc
2015-12-06 16:22:21 +00:00
"Split a function case by examining a type's constructors"
2015-12-20 10:48:47 +00:00
<=> desc $$$ do
"For example given the following code snippet:"
code $ do
"f :: [a] -> a"
"f x = _body"
"would be replaced by:"
code $ do
"f :: [a] -> a"
"f [] = _body"
"f (x:xs) = _body"
"(See https://github.com/kazu-yamamoto/ghc-mod/pull/274)"
2015-12-06 18:30:03 +00:00
<> command "sig"
$$ info sigArgSpec
$$ progDesc "Generate initial code given a signature"
2015-12-20 10:48:47 +00:00
<=> desc $$$ do
"For example when (LINE,COL) is on the"
\\ "signature in the following code snippet:"
code "func :: [a] -> Maybe b -> (a -> b) -> (a,b)"
"ghc-mod would add the following on the next line:"
code "func x y z f = _func_body"
"(See: https://github.com/kazu-yamamoto/ghc-mod/pull/274)"
2015-12-06 16:22:21 +00:00
<> command "auto"
2015-12-06 18:30:03 +00:00
$$ info autoArgSpec
$$ progDesc "Try to automatically fill the contents of a hole"
2015-12-06 16:22:21 +00:00
<> command "refine"
2015-12-06 18:30:03 +00:00
$$ info refineArgSpec
$$ progDesc "Refine the typed hole at (LINE,COL) given EXPR"
2015-12-20 10:48:47 +00:00
<=> desc $$$ do
"For example if EXPR is `filter', which has type"
\\ "`(a -> Bool) -> [a] -> [a]' and (LINE,COL) is on"
\\ " the hole `_body' in the following code snippet:"
code $ do
"filterNothing :: [Maybe a] -> [a]"
"filterNothing xs = _body"
"ghc-mod changes the code to get a value of type"
\\ " `[a]', which results in:"
code "filterNothing xs = filter _body_1 _body_2"
"(See also: https://github.com/kazu-yamamoto/ghc-mod/issues/311)"
<> command "test"
$$ info (CmdTest <$> strArg "FILE")
$$ progDesc ""
2015-12-05 20:55:12 +00:00
interactiveCommandsSpec :: Parser GhcModCommands
interactiveCommandsSpec =
hsubparser'
$ commands
<> command "map-file"
$$ info mapArgSpec
$$ progDesc "tells ghc-modi to read `file.hs` source from stdin"
2015-12-20 10:48:47 +00:00
<=> desc $$$ do
"Works the same as second form of"
\\ "`--map-file` CLI option."
<> command "unmap-file"
$$ info unmapArgSpec
2015-12-20 10:48:47 +00:00
$$ progDesc' $$$ do
"unloads previously mapped file,"
\\ "so that it's no longer mapped."
<=> desc $$$ do
"`file.hs` can be full path or relative"
\\ "to project root, either will work."
<> command "quit"
2015-12-20 03:31:14 +00:00
$$ info (pure CmdQuit)
$$ progDesc "Exit interactive mode"
<> command ""
$$ info (pure CmdQuit) idm
2015-12-05 20:55:12 +00:00
strArg :: String -> Parser String
strArg = argument str . metavar
filesArgsSpec :: ([String] -> b) -> Parser b
filesArgsSpec x = x <$> some (strArg "FILES..")
locArgSpec :: (String -> (Int, Int) -> b) -> Parser b
2015-12-06 16:22:21 +00:00
locArgSpec x = x
<$> strArg "FILE"
<*> ( (,)
<$> argument int (metavar "LINE")
<*> argument int (metavar "COL")
)
2015-12-05 20:55:12 +00:00
modulesArgSpec, docArgSpec, findArgSpec,
2015-12-05 20:55:12 +00:00
lintArgSpec, browseArgSpec, checkArgSpec, expandArgSpec,
infoArgSpec, typeArgSpec, autoArgSpec, splitArgSpec,
sigArgSpec, refineArgSpec, debugComponentArgSpec,
2015-12-20 03:31:14 +00:00
mapArgSpec, unmapArgSpec, legacyInteractiveArgSpec :: Parser GhcModCommands
2015-12-05 20:55:12 +00:00
2015-12-06 16:22:21 +00:00
modulesArgSpec = CmdModules
<$> switch
2015-12-06 18:30:03 +00:00
$$ long "detailed"
<=> short 'd'
<=> help "Print package modules belong to"
2015-12-05 20:55:12 +00:00
findArgSpec = CmdFind <$> strArg "SYMBOL"
docArgSpec = CmdDoc <$> strArg "MODULE"
2015-12-06 16:22:21 +00:00
lintArgSpec = CmdLint
<$> LintOpts <$$> many $$ strOption
2015-12-06 18:30:03 +00:00
$$ long "hlintOpt"
<=> short 'h'
<=> help "Option to be passed to hlint"
2015-12-06 16:22:21 +00:00
<*> strArg "FILE"
browseArgSpec = CmdBrowse
<$> (BrowseOpts
<$> switch
2015-12-06 18:30:03 +00:00
$$ long "operators"
<=> short 'o'
<=> help "Also print operators"
2015-12-06 16:22:21 +00:00
<*> switch
2015-12-06 18:30:03 +00:00
$$ long "detailed"
<=> short 'd'
<=> help "Print symbols with accompanying signature"
2015-12-06 16:22:21 +00:00
<*> switch
2015-12-06 18:30:03 +00:00
$$ long "qualified"
<=> short 'q'
<=> help "Qualify symbols"
2015-12-06 16:22:21 +00:00
)
<*> some (strArg "MODULE")
2015-12-05 20:55:12 +00:00
debugComponentArgSpec = filesArgsSpec CmdDebugComponent
checkArgSpec = filesArgsSpec CmdCheck
expandArgSpec = filesArgsSpec CmdExpand
2015-12-06 16:22:21 +00:00
infoArgSpec = CmdInfo
<$> strArg "FILE"
<*> strArg "SYMBOL"
2015-12-05 20:55:12 +00:00
typeArgSpec = locArgSpec CmdType
autoArgSpec = locArgSpec CmdAuto
splitArgSpec = locArgSpec CmdSplit
sigArgSpec = locArgSpec CmdSig
refineArgSpec = locArgSpec CmdRefine <*> strArg "SYMBOL"
2015-12-20 03:31:14 +00:00
mapArgSpec = CmdMapFile <$> strArg "FILE"
unmapArgSpec = CmdUnmapFile <$> strArg "FILE"
legacyInteractiveArgSpec = const CmdLegacyInteractive <$>
optional interactiveCommandsSpec
hsubparser' :: Mod CommandFields a -> Parser a
hsubparser' m = mkParser d g rdr
2015-12-20 03:31:14 +00:00
where
Mod _ d g = m `mappend` metavar ""
(cmds, subs) = mkCommand m
rdr = CmdReader cmds (fmap add_helper . subs)
add_helper pinfo = pinfo
{ infoParser = infoParser pinfo <**> helper }
2015-12-05 22:32:09 +00:00
int :: ReadM Int
int = do
v <- readerAsk
maybe (readerError $ "Not a number \"" ++ v ++ "\"") return $ readMaybe v