1
- {-# LANGUAGE ExistentialQuantification, NamedFieldPuns #-}
1
+ {-# LANGUAGE ExistentialQuantification, NamedFieldPuns, RankNTypes #-}
2
2
3
3
-----------------------------------------------------------------------------
4
4
-- |
@@ -24,6 +24,9 @@ module Distribution.Client.ParseUtils (
24
24
SectionDescr (.. ),
25
25
liftSection ,
26
26
27
+ -- * FieldGrammar sections
28
+ FGSectionDescr (.. ),
29
+
27
30
-- * Parsing and printing flat config
28
31
parseFields ,
29
32
ppFields ,
@@ -39,6 +42,9 @@ module Distribution.Client.ParseUtils (
39
42
)
40
43
where
41
44
45
+ import Distribution.Client.Compat.Prelude hiding (empty , get )
46
+ import Prelude ()
47
+
42
48
import Distribution.Deprecated.ParseUtils
43
49
( FieldDescr (.. ), ParseResult (.. ), warning , LineNo , lineNo
44
50
, Field (.. ), liftField , readFieldsFlat )
@@ -48,12 +54,22 @@ import Distribution.Deprecated.ViewAsFieldDescr
48
54
import Distribution.Simple.Command
49
55
( OptionField )
50
56
51
- import Control.Monad ( foldM )
52
57
import Text.PrettyPrint ( (<+>) , ($+$) )
53
58
import qualified Data.Map as Map
54
59
import qualified Text.PrettyPrint as Disp
55
60
( (<>) , Doc , text , colon , vcat , empty , isEmpty , nest )
56
61
62
+ -- For new parser stuff
63
+ import Distribution.CabalSpecVersion (cabalSpecLatest )
64
+ import Distribution.FieldGrammar (FieldGrammar , partitionFields , parseFieldGrammar )
65
+ import Distribution.Fields.ParseResult (runParseResult )
66
+ import Distribution.Parsec.Error (showPError )
67
+ import Distribution.Parsec.Position (Position (.. ))
68
+ import Distribution.Parsec.Warning (showPWarning )
69
+ import Distribution.Simple.Utils (fromUTF8BS , toUTF8BS )
70
+ import qualified Distribution.Fields as F
71
+ import qualified Distribution.FieldGrammar as FG
72
+
57
73
58
74
-------------------------
59
75
-- FieldDescr utilities
@@ -107,6 +123,15 @@ data SectionDescr a = forall b. SectionDescr {
107
123
sectionEmpty :: b
108
124
}
109
125
126
+ -- | 'FieldGrammar' section description
127
+ data FGSectionDescr a = forall s . FGSectionDescr
128
+ { fgSectionName :: String
129
+ , fgSectionGrammar :: forall g . (FieldGrammar g , Applicative (g s )) => g s s
130
+ -- todo: add subsections?
131
+ , fgSectionGet :: a -> [(String , s )]
132
+ , fgSectionSet :: LineNo -> String -> s -> a -> ParseResult a
133
+ }
134
+
110
135
-- | To help construction of config file descriptions in a modular way it is
111
136
-- useful to define fields and sections on local types and then hoist them
112
137
-- into the parent types when combining them in bigger descriptions.
@@ -191,13 +216,18 @@ ppSection name arg fields def cur
191
216
-- | Much like 'parseFields' but it also allows subsections. The permitted
192
217
-- subsections are given by a list of 'SectionDescr's.
193
218
--
194
- parseFieldsAndSections :: [FieldDescr a ] -> [SectionDescr a ] -> a
195
- -> [Field ] -> ParseResult a
196
- parseFieldsAndSections fieldDescrs sectionDescrs =
219
+ parseFieldsAndSections
220
+ :: [FieldDescr a ] -- ^ field
221
+ -> [SectionDescr a ] -- ^ legacy sections
222
+ -> [FGSectionDescr a ] -- ^ FieldGrammar sections
223
+ -> a
224
+ -> [Field ] -> ParseResult a
225
+ parseFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs =
197
226
foldM setField
198
227
where
199
- fieldMap = Map. fromList [ (fieldName f, f) | f <- fieldDescrs ]
200
- sectionMap = Map. fromList [ (sectionName s, s) | s <- sectionDescrs ]
228
+ fieldMap = Map. fromList [ (fieldName f, f) | f <- fieldDescrs ]
229
+ sectionMap = Map. fromList [ (sectionName s, s) | s <- sectionDescrs ]
230
+ fgSectionMap = Map. fromList [ (fgSectionName s, s) | s <- fgSectionDescrs ]
201
231
202
232
setField a (F line name value) =
203
233
case Map. lookup name fieldMap of
@@ -208,10 +238,25 @@ parseFieldsAndSections fieldDescrs sectionDescrs =
208
238
return a
209
239
210
240
setField a (Section line name param fields) =
211
- case Map. lookup name sectionMap of
212
- Just (SectionDescr _ fieldDescrs' sectionDescrs' _ set sectionEmpty) -> do
213
- b <- parseFieldsAndSections fieldDescrs' sectionDescrs' sectionEmpty fields
241
+ case Left <$> Map. lookup name sectionMap <|> Right <$> Map. lookup name fgSectionMap of
242
+ Just (Left ( SectionDescr _ fieldDescrs' sectionDescrs' _ set sectionEmpty) ) -> do
243
+ b <- parseFieldsAndSections fieldDescrs' sectionDescrs' [] sectionEmpty fields
214
244
set line param b a
245
+ Just (Right (FGSectionDescr _ grammar _getter setter)) -> do
246
+ let fields1 = mapMaybe convertField fields
247
+ (fields2, sections) = partitionFields fields1
248
+ -- TODO: recurse into sections
249
+ for_ (concat sections) $ \ (FG. MkSection (F. Name (Position line' _) name') _ _) ->
250
+ warning $ " Unrecognized section '" ++ fromUTF8BS name'
251
+ ++ " ' on line " ++ show line'
252
+ case runParseResult $ parseFieldGrammar cabalSpecLatest fields2 grammar of
253
+ (warnings, Right b) -> do
254
+ for_ warnings $ \ w -> warning $ showPWarning " ???" w
255
+ setter line param b a
256
+ (warnings, Left (_, errs)) -> do
257
+ for_ warnings $ \ w -> warning $ showPWarning " ???" w
258
+ case errs of
259
+ err :| _errs -> fail $ showPError " ???" err
215
260
Nothing -> do
216
261
warning $ " Unrecognized section '" ++ name
217
262
++ " ' on line " ++ show line
@@ -221,17 +266,31 @@ parseFieldsAndSections fieldDescrs sectionDescrs =
221
266
warning $ " Unrecognized stanza on line " ++ show (lineNo block)
222
267
return accum
223
268
269
+ convertField :: Field -> Maybe (F. Field Position )
270
+ convertField (F line name str) = Just $
271
+ F. Field (F. Name pos (toUTF8BS name)) [ F. FieldLine pos $ toUTF8BS str ]
272
+ where
273
+ pos = Position line 0
274
+ -- arguments omitted
275
+ convertField (Section line name _arg fields) = Just $
276
+ F. Section (F. Name pos (toUTF8BS name)) [] (mapMaybe convertField fields)
277
+ where
278
+ pos = Position line 0
279
+ -- silently omitted.
280
+ convertField IfBlock {} = Nothing
281
+
282
+
224
283
-- | Much like 'ppFields' but also pretty prints any subsections. Subsection
225
284
-- are only shown if they are non-empty.
226
285
--
227
286
-- Note that unlike 'ppFields', at present it does not support printing
228
287
-- default values. If needed, adding such support would be quite reasonable.
229
288
--
230
- ppFieldsAndSections :: [FieldDescr a ] -> [SectionDescr a ] -> a -> Disp. Doc
231
- ppFieldsAndSections fieldDescrs sectionDescrs val =
289
+ ppFieldsAndSections :: [FieldDescr a ] -> [SectionDescr a ] -> [ FGSectionDescr a ] -> a -> Disp. Doc
290
+ ppFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs val =
232
291
ppFields fieldDescrs Nothing val
233
292
$+$
234
- Disp. vcat
293
+ Disp. vcat (
235
294
[ Disp. text " " $+$ sectionDoc
236
295
| SectionDescr {
237
296
sectionName, sectionGet,
@@ -240,24 +299,57 @@ ppFieldsAndSections fieldDescrs sectionDescrs val =
240
299
, (param, x) <- sectionGet val
241
300
, let sectionDoc = ppSectionAndSubsections
242
301
sectionName param
243
- sectionFields sectionSubsections x
302
+ sectionFields sectionSubsections [] x
303
+ , not (Disp. isEmpty sectionDoc)
304
+ ] ++
305
+ [ Disp. text " " $+$ sectionDoc
306
+ | FGSectionDescr { fgSectionName, fgSectionGrammar, fgSectionGet } <- fgSectionDescrs
307
+ , (param, x) <- fgSectionGet val
308
+ , let sectionDoc = ppFgSection fgSectionName param fgSectionGrammar x
244
309
, not (Disp. isEmpty sectionDoc)
245
- ]
310
+ ])
246
311
247
312
-- | Unlike 'ppSection' which has to be called directly, this gets used via
248
313
-- 'ppFieldsAndSections' and so does not need to be exported.
249
314
--
250
315
ppSectionAndSubsections :: String -> String
251
- -> [FieldDescr a ] -> [SectionDescr a ] -> a -> Disp. Doc
252
- ppSectionAndSubsections name arg fields sections cur
316
+ -> [FieldDescr a ] -> [SectionDescr a ] -> [ FGSectionDescr a ] -> a -> Disp. Doc
317
+ ppSectionAndSubsections name arg fields sections fgSections cur
253
318
| Disp. isEmpty fieldsDoc = Disp. empty
254
319
| otherwise = Disp. text name <+> argDoc
255
320
$+$ (Disp. nest 2 fieldsDoc)
256
321
where
257
- fieldsDoc = showConfig fields sections cur
322
+ fieldsDoc = showConfig fields sections fgSections cur
258
323
argDoc | arg == " " = Disp. empty
259
324
| otherwise = Disp. text arg
260
325
326
+ -- |
327
+ --
328
+ -- TODO: subsections
329
+ -- TODO: this should simply build 'PrettyField'
330
+ ppFgSection
331
+ :: String -- ^ section name
332
+ -> String -- ^ parameter
333
+ -> FG. PrettyFieldGrammar a a
334
+ -> a
335
+ -> Disp. Doc
336
+ ppFgSection secName arg grammar x
337
+ | null prettyFields = Disp. empty
338
+ | otherwise =
339
+ Disp. text secName <+> argDoc
340
+ $+$ (Disp. nest 2 fieldsDoc)
341
+ where
342
+ prettyFields = FG. prettyFieldGrammar cabalSpecLatest grammar x
343
+
344
+ argDoc | arg == " " = Disp. empty
345
+ | otherwise = Disp. text arg
346
+
347
+ fieldsDoc = Disp. vcat
348
+ [ Disp. text fname' <<>> Disp. colon <<>> doc
349
+ | F. PrettyField _ fname doc <- prettyFields -- TODO: this skips sections
350
+ , let fname' = fromUTF8BS fname
351
+ ]
352
+
261
353
262
354
-----------------------------------------------
263
355
-- Top level config file parsing and printing
@@ -268,15 +360,15 @@ ppSectionAndSubsections name arg fields sections cur
268
360
--
269
361
-- It accumulates the result on top of a given initial (typically empty) value.
270
362
--
271
- parseConfig :: [FieldDescr a ] -> [SectionDescr a ] -> a
363
+ parseConfig :: [FieldDescr a ] -> [SectionDescr a ] -> [ FGSectionDescr a ] -> a
272
364
-> String -> ParseResult a
273
- parseConfig fieldDescrs sectionDescrs empty str =
274
- parseFieldsAndSections fieldDescrs sectionDescrs empty
365
+ parseConfig fieldDescrs sectionDescrs fgSectionDescrs empty str =
366
+ parseFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs empty
275
367
=<< readFieldsFlat str
276
368
277
369
-- | Render a value in the config file syntax, based on a description of the
278
370
-- configuration file in terms of its fields and sections.
279
371
--
280
- showConfig :: [FieldDescr a ] -> [SectionDescr a ] -> a -> Disp. Doc
372
+ showConfig :: [FieldDescr a ] -> [SectionDescr a ] -> [ FGSectionDescr a ] -> a -> Disp. Doc
281
373
showConfig = ppFieldsAndSections
282
374
0 commit comments