-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathOptions.hs
More file actions
161 lines (142 loc) · 4.69 KB
/
Options.hs
File metadata and controls
161 lines (142 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
module Options
( Options (..),
getOptionsFromArgv,
versionNumber,
versionString,
usageMessage,
Config (..),
initConfig,
)
where
import Data.Aeson.Types hiding
( Options,
defaultOptions,
)
import GHC.Generics (Generic)
import System.Console.GetOpt
import System.Environment (getArgs)
import Text.Read (readMaybe)
getOptionsFromArgv :: IO Options
getOptionsFromArgv = do
-- extract options for Agda from ARGV
(argvForALS, argvForAgda) <- extractAgdaOpts <$> getArgs
-- parse options for ALS
(opts, _) <- parseOpts argvForALS
-- save options for Agda back
return $ opts {optRawAgdaOptions = argvForAgda}
usageMessage :: String
usageMessage = usageInfo usage options ++ usageAboutAgdaOptions
--------------------------------------------------------------------------------
-- | Command-line arguments
data Options = Options
{ optViaTCP :: Maybe Int,
optRawAgdaOptions :: [String],
optRawResponses :: Bool,
optSetup :: Bool,
optHelp :: Bool,
optVersion :: Bool
}
defaultOptions :: Options
defaultOptions =
Options {optViaTCP = Nothing, optRawAgdaOptions = [], optRawResponses = False, optSetup = False, optHelp = False, optVersion = False}
options :: [OptDescr (Options -> Options)]
options =
[ Option
['h']
["help"]
(NoArg (\opts -> opts {optHelp = True}))
"print this help message",
Option
['p']
["port"]
( OptArg
( \port opts -> case port of
Just n -> opts {optViaTCP = readMaybe n}
Nothing -> opts {optViaTCP = Just 4096}
)
"PORT"
)
"talk with the editor via TCP port (4096 as default)",
Option
[]
["raw"]
(NoArg (\opts -> opts {optRawResponses = True}))
"return all responses in raw JSON format",
#if MIN_VERSION_Agda(2,8,0)
Option
[]
["setup"]
(NoArg (\opts -> opts {optSetup = True}))
"run Agda setup and exit",
#endif
Option
['V']
["version"]
(NoArg (\opts -> opts {optVersion = True}))
"print version information and exit"
]
versionNumber :: Int
versionNumber = 6
versionString :: String
versionString =
#if MIN_VERSION_Agda(2,8,0)
"Agda v2.8.0 Language Server v" <> show versionNumber <> suffix
#elif MIN_VERSION_Agda(2,7,0)
"Agda v2.7.0.1 Language Server v" <> show versionNumber <> suffix
#elif MIN_VERSION_Agda(2,6,4)
"Agda v2.6.4.3 Language Server v" <> show versionNumber <> suffix
#else
error "Unsupported Agda version"
#endif
where
#ifdef wasm32_HOST_ARCH
suffix = " (WebAssembly build)"
#else
suffix = ""
#endif
usage :: String
usage = versionString <> "\nUsage: als [Options...]\n"
usageAboutAgdaOptions :: String
usageAboutAgdaOptions = "\n +AGDA [Options for Agda ...] -AGDA\n To pass command line options to Agda, put them in between '+AGDA' and '-AGDA'\n For example:\n als -p=3000 +AGDA --cubical -AGDA\n If you are using agda-mode on VS Code, put them in the Settings at:\n agdaMode.connection.commandLineOptions\n"
parseOpts :: [String] -> IO (Options, [String])
parseOpts argv = case getOpt Permute options argv of
(o, n, []) -> return (foldl (flip id) defaultOptions o, n)
(_, _, errs) -> ioError $ userError $ concat errs ++ usageInfo usage options
-- | Removes RTS options from a list of options (stolen from Agda)
stripRTS :: [String] -> [String]
stripRTS [] = []
stripRTS ("--RTS" : argv) = argv
stripRTS (arg : argv)
| is "+RTS" arg = stripRTS $ drop 1 $ dropWhile (not . is "-RTS") argv
| otherwise = arg : stripRTS argv
where
is x arg = [x] == take 1 (words arg)
-- | Extract Agda options (+AGDA ... -AGDA) from a list of options
--
-- >>> extractAgdaOpts [ "als1", "+AGDA", "agda1", "-AGDA", "als2", "+AGDA", "agda2" ]
-- (["als1","als2"],["agda1","agda2"])
extractAgdaOpts :: [String] -> ([String], [String])
extractAgdaOpts argv = go False argv
where
go False ("+AGDA":xs) = go True xs
go True ("-AGDA":xs) = go False xs
go inagda (arg:xs) =
let (forALS, forAgda) = go inagda xs in
if inagda
then (forALS, arg:forAgda)
else (arg:forALS, forAgda)
go _ [] = ([], [])
--------------------------------------------------------------------------------
newtype Config = Config {configRawAgdaOptions :: [String]}
deriving (Eq, Show, Generic)
instance FromJSON Config where
parseJSON (Object v) = Config <$> v .: "commandLineOptions"
-- We do not expect a non-Object value here.
-- We could use empty to fail, but typeMismatch
-- gives a much more informative error message.
parseJSON invalid =
prependFailure "parsing Config failed, " (typeMismatch "Object" invalid)
initConfig :: Config
initConfig = Config []