17
17
-- * Line wrapping in the 'usageInfo' output, plus a more compact
18
18
-- rendering of short options, and slightly less padding.
19
19
--
20
- -- If you want to take on the challenge of merging this with the GetOpt
21
- -- from the base package then go for it!
20
+ -- * Parsing of option arguments is allowed to fail.
21
+ --
22
+ -- * 'ReturnInOrder' argument order is removed.
22
23
--
23
24
{-# LANGUAGE TupleSections #-}
24
25
{-# LANGUAGE NamedFieldPuns #-}
@@ -36,8 +37,34 @@ module Distribution.GetOpt (
36
37
37
38
import Prelude ()
38
39
import Distribution.Compat.Prelude
39
- import System.Console.GetOpt
40
- ( ArgOrder (.. ), OptDescr (.. ), ArgDescr (.. ) )
40
+
41
+ -- | What to do with options following non-options
42
+ data ArgOrder a
43
+ = RequireOrder -- ^ no option processing after first non-option
44
+ | Permute -- ^ freely intersperse options and non-options
45
+
46
+ data OptDescr a = -- description of a single options:
47
+ Option [Char ] -- list of short option characters
48
+ [String ] -- list of long option strings (without "--")
49
+ (ArgDescr a ) -- argument descriptor
50
+ String -- explanation of option for user
51
+
52
+ instance Functor OptDescr where
53
+ fmap f (Option a b argDescr c) = Option a b (fmap f argDescr) c
54
+
55
+ -- | Describes whether an option takes an argument or not, and if so
56
+ -- how the argument is parsed to a value of type @a@.
57
+ --
58
+ -- Compared to System.Console.GetOpt, we allow for parse errors.
59
+ data ArgDescr a
60
+ = NoArg a -- ^ no argument expected
61
+ | ReqArg (String -> Either String a ) String -- ^ option requires argument
62
+ | OptArg (Maybe String -> Either String a ) String -- ^ optional argument
63
+
64
+ instance Functor ArgDescr where
65
+ fmap f (NoArg a) = NoArg (f a)
66
+ fmap f (ReqArg g s) = ReqArg (fmap f . g) s
67
+ fmap f (OptArg g s) = OptArg (fmap f . g) s
41
68
42
69
data OptKind a -- kind of cmd line arg (internal use only):
43
70
= Opt a -- an option
@@ -155,10 +182,8 @@ getOpt' ordering optDescr (arg:args) = procNextOpt opt ordering
155
182
procNextOpt (UnreqOpt u) _ = (os,xs,u: us,es)
156
183
procNextOpt (NonOpt x) RequireOrder = ([] ,x: rest,[] ,[] )
157
184
procNextOpt (NonOpt x) Permute = (os,x: xs,us,es)
158
- procNextOpt (NonOpt x) (ReturnInOrder f) = (f x : os, xs,us,es)
159
185
procNextOpt EndOfOpts RequireOrder = ([] ,rest,[] ,[] )
160
186
procNextOpt EndOfOpts Permute = ([] ,rest,[] ,[] )
161
- procNextOpt EndOfOpts (ReturnInOrder f) = (map f rest,[] ,[] ,[] )
162
187
procNextOpt (OptErr e) _ = (os,xs,us,e: es)
163
188
164
189
(opt,rest) = getNext arg args optDescr
@@ -181,15 +206,16 @@ longOpt ls rs optDescr = long ads arg rs
181
206
options = if null exact then getWith isPrefixOf else exact
182
207
ads = [ ad | Option _ _ ad _ <- options ]
183
208
optStr = " --" ++ opt
209
+ fromRes = fromParseResult optStr
184
210
185
211
long (_: _: _) _ rest = (errAmbig options optStr,rest)
186
212
long [NoArg a ] [] rest = (Opt a,rest)
187
213
long [NoArg _ ] (' =' : _) rest = (errNoArg optStr,rest)
188
214
long [ReqArg _ d] [] [] = (errReq d optStr,[] )
189
- long [ReqArg f _] [] (r: rest) = (Opt (f r),rest)
190
- long [ReqArg f _] (' =' : xs) rest = (Opt (f xs),rest)
191
- long [OptArg f _] [] rest = (Opt (f Nothing ),rest)
192
- long [OptArg f _] (' =' : xs) rest = (Opt (f (Just xs)),rest)
215
+ long [ReqArg f _] [] (r: rest) = (fromRes (f r),rest)
216
+ long [ReqArg f _] (' =' : xs) rest = (fromRes (f xs),rest)
217
+ long [OptArg f _] [] rest = (fromRes (f Nothing ),rest)
218
+ long [OptArg f _] (' =' : xs) rest = (fromRes (f (Just xs)),rest)
193
219
long _ _ rest = (UnreqOpt (" --" ++ ls),rest)
194
220
195
221
-- handle short option
@@ -198,15 +224,16 @@ shortOpt y ys rs optDescr = short ads ys rs
198
224
where options = [ o | o@ (Option ss _ _ _) <- optDescr, s <- ss, y == s ]
199
225
ads = [ ad | Option _ _ ad _ <- options ]
200
226
optStr = ' -' : [y]
227
+ fromRes = fromParseResult optStr
201
228
202
229
short (_: _: _) _ rest = (errAmbig options optStr,rest)
203
230
short (NoArg a : _) [] rest = (Opt a,rest)
204
231
short (NoArg a : _) xs rest = (Opt a,(' -' : xs): rest)
205
232
short (ReqArg _ d: _) [] [] = (errReq d optStr,[] )
206
- short (ReqArg f _: _) [] (r: rest) = (Opt (f r),rest)
207
- short (ReqArg f _: _) xs rest = (Opt (f xs),rest)
208
- short (OptArg f _: _) [] rest = (Opt (f Nothing ),rest)
209
- short (OptArg f _: _) xs rest = (Opt (f (Just xs)),rest)
233
+ short (ReqArg f _: _) [] (r: rest) = (fromRes (f r),rest)
234
+ short (ReqArg f _: _) xs rest = (fromRes (f xs),rest)
235
+ short (OptArg f _: _) [] rest = (fromRes (f Nothing ),rest)
236
+ short (OptArg f _: _) xs rest = (fromRes (f (Just xs)),rest)
210
237
short [] [] rest = (UnreqOpt optStr,rest)
211
238
short [] xs rest = (UnreqOpt (optStr++ xs),rest)
212
239
-- This is different vs upstream = (UnreqOpt optStr,('-':xs):rest)
@@ -215,9 +242,14 @@ shortOpt y ys rs optDescr = short ads ys rs
215
242
-- But why was no equivalent change required for longOpt? So could
216
243
-- this change go upstream?
217
244
245
+ fromParseResult :: String -> Either String a -> OptKind a
246
+ fromParseResult optStr res = case res of
247
+ Right x -> Opt x
248
+ Left err -> OptErr (" invalid argument to option `" ++ optStr ++ " ': " ++ err ++ " \n " )
249
+
218
250
-- miscellaneous error formatting
219
251
220
- errAmbig :: [OptDescr a ] -> String -> OptKind a
252
+ errAmbig :: [OptDescr a ] -> String -> OptKind b
221
253
errAmbig ods optStr = OptErr (usageInfo header ods)
222
254
where header = " option `" ++ optStr ++ " ' is ambiguous; could be one of:"
223
255
0 commit comments