@@ -28,6 +28,7 @@ module Dodo
28
28
, encloseWithSeparator
29
29
, foldWithSeparator
30
30
, foldWith
31
+ , locally
31
32
, print
32
33
, Printer (..)
33
34
, plainText
@@ -48,7 +49,7 @@ import Data.String as String
48
49
import Data.String.Regex as Regex
49
50
import Data.String.Regex.Flags (global )
50
51
import Data.String.Regex.Unsafe (unsafeRegex )
51
- import Dodo.Internal (Doc (..), Position , bothNotEmpty , isEmpty , notEmpty )
52
+ import Dodo.Internal (Doc (..), Position , LocalOptions , bothNotEmpty , isEmpty , notEmpty )
52
53
import Dodo.Internal (Doc , Position , bothNotEmpty , isEmpty , notEmpty ) as Exports
53
54
import Dodo.Internal.Buffer (Buffer )
54
55
import Dodo.Internal.Buffer as Buffer
@@ -193,6 +194,11 @@ foldWithSeparator separator = foldWith (\a b -> a <> (separator <> b))
193
194
foldWith :: forall f a . Foldable f => (Doc a -> Doc a -> Doc a ) -> f (Doc a ) -> Doc a
194
195
foldWith f = foldr (bothNotEmpty f) mempty
195
196
197
+ -- | *EXPERIMENTAL:* modifies printing state and options locally for a document.
198
+ -- | This may change or be removed at any time.
199
+ locally :: forall a . (LocalOptions -> LocalOptions ) -> Doc a -> Doc a
200
+ locally = Local
201
+
196
202
-- | Custom printers can be used to render richer documents than just plain
197
203
-- | text.
198
204
-- | * `emptyBuffer` - The initial buffer.
@@ -255,6 +261,7 @@ data DocCmd a
255
261
| Dedent String Int
256
262
| LeaveAnnotation a (List a )
257
263
| LeaveFlexGroup (Doc a ) (Doc a )
264
+ | LeaveLocal LocalOptions
258
265
259
266
data FlexGroupStatus b a
260
267
= NoFlexGroup
@@ -267,6 +274,7 @@ type FlexGroupState b a =
267
274
, annotations :: List a
268
275
, indentSpaces :: String
269
276
, stack :: List (DocCmd a )
277
+ , options :: PrintOptions
270
278
}
271
279
272
280
type DocState b a =
@@ -275,15 +283,39 @@ type DocState b a =
275
283
, annotations :: List a
276
284
, indentSpaces :: String
277
285
, flexGroup :: FlexGroupStatus b a
286
+ , options :: PrintOptions
278
287
}
279
288
280
289
resetState :: forall a b . FlexGroupState b a -> DocState b a
281
- resetState { position, buffer, annotations, indentSpaces } =
282
- { position, buffer, annotations, indentSpaces, flexGroup: NoFlexGroup }
290
+ resetState { position, buffer, annotations, indentSpaces, options } =
291
+ { position, buffer, annotations, indentSpaces, flexGroup: NoFlexGroup , options }
283
292
284
293
storeState :: forall a b . List (DocCmd a ) -> DocState b a -> FlexGroupState b a
285
- storeState stack { position, buffer, annotations, indentSpaces } =
286
- { position, buffer, annotations, indentSpaces, stack }
294
+ storeState stack { position, buffer, annotations, indentSpaces, options } =
295
+ { position, buffer, annotations, indentSpaces, stack, options }
296
+
297
+ storeOptions :: forall a b . Int -> LocalOptions -> DocState b a -> DocState b a
298
+ storeOptions prevIndent localOptions state = do
299
+ let
300
+ newOptions =
301
+ { indentUnit: localOptions.indentUnit
302
+ , indentWidth: localOptions.indentWidth
303
+ , pageWidth: localOptions.pageWidth
304
+ , ribbonRatio: localOptions.ribbonRatio
305
+ }
306
+ state
307
+ { indentSpaces = localOptions.indentSpaces
308
+ , options = newOptions
309
+ , position
310
+ { pageWidth = newOptions.pageWidth
311
+ , ribbonWidth = calcRibbonWidth newOptions prevIndent
312
+ , nextIndent = localOptions.indent
313
+ }
314
+ }
315
+
316
+ calcRibbonWidth :: PrintOptions -> Int -> Int
317
+ calcRibbonWidth { pageWidth, ribbonRatio } n =
318
+ max 0 $ Int .ceil $ mul ribbonRatio $ Int .toNumber $ pageWidth - n
287
319
288
320
-- | Prints a documents given a printer and print options.
289
321
-- |
@@ -297,11 +329,8 @@ storeState stack { position, buffer, annotations, indentSpaces } =
297
329
print :: forall b a r . Printer b a r -> PrintOptions -> Doc a -> r
298
330
print (Printer printer) opts = flip go initState <<< pure <<< Doc
299
331
where
300
- ribbonRatio :: Number
301
- ribbonRatio = max 0.0 (min 1.0 opts.ribbonRatio)
302
-
303
- calcRibbonWidth :: Int -> Int
304
- calcRibbonWidth = max 0 <<< Int .ceil <<< mul ribbonRatio <<< Int .toNumber <<< (opts.pageWidth - _)
332
+ initOptions :: PrintOptions
333
+ initOptions = opts { ribbonRatio = max 0.0 (min 1.0 opts.ribbonRatio) }
305
334
306
335
initState :: DocState b a
307
336
initState =
@@ -310,13 +339,14 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
310
339
, column: 0
311
340
, indent: 0
312
341
, nextIndent: 0
313
- , pageWidth: opts .pageWidth
314
- , ribbonWidth: calcRibbonWidth 0
342
+ , pageWidth: initOptions .pageWidth
343
+ , ribbonWidth: calcRibbonWidth initOptions 0
315
344
}
316
345
, buffer: Buffer .new printer.emptyBuffer
317
346
, annotations: List.Nil
318
347
, indentSpaces: " "
319
348
, flexGroup: NoFlexGroup
349
+ , options: initOptions
320
350
}
321
351
322
352
go :: List (DocCmd a ) -> DocState b a -> r
@@ -356,7 +386,7 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
356
386
{ line = state.position.line + 1
357
387
, column = 0
358
388
, indent = state.position.nextIndent
359
- , ribbonWidth = calcRibbonWidth state.position.nextIndent
389
+ , ribbonWidth = calcRibbonWidth state.options state. position.nextIndent
360
390
}
361
391
, buffer = Buffer .modify printer.writeBreak state.buffer
362
392
, flexGroup = NoFlexGroup
@@ -367,7 +397,7 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
367
397
{ position
368
398
{ indent = state.position.nextIndent + opts.indentWidth
369
399
, nextIndent = state.position.nextIndent + opts.indentWidth
370
- , ribbonWidth = calcRibbonWidth (state.position.nextIndent + opts.indentWidth)
400
+ , ribbonWidth = calcRibbonWidth state.options (state.position.nextIndent + opts.indentWidth)
371
401
}
372
402
, indentSpaces = state.indentSpaces <> opts.indentUnit
373
403
}
@@ -382,7 +412,7 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
382
412
{ position
383
413
{ indent = state.position.nextIndent + width
384
414
, nextIndent = state.position.nextIndent + width
385
- , ribbonWidth = calcRibbonWidth (state.position.nextIndent + width)
415
+ , ribbonWidth = calcRibbonWidth state.options (state.position.nextIndent + width)
386
416
}
387
417
, indentSpaces = state.indentSpaces <> power " " width
388
418
}
@@ -423,6 +453,18 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
423
453
{ annotations = ann : state.annotations
424
454
, buffer = Buffer .modify (printer.enterAnnotation ann state.annotations) state.buffer
425
455
}
456
+ Local k doc1 -> do
457
+ let
458
+ prevOptions =
459
+ { indent: state.position.indent
460
+ , indentSpaces: state.indentSpaces
461
+ , indentUnit: state.options.indentUnit
462
+ , indentWidth: state.options.indentWidth
463
+ , pageWidth: state.options.pageWidth
464
+ , ribbonRatio: state.options.ribbonRatio
465
+ }
466
+ localOptions = k prevOptions
467
+ go (Doc doc1 : LeaveLocal prevOptions: stk) $ storeOptions state.position.indent localOptions state
426
468
Empty ->
427
469
go stk state
428
470
LeaveFlexGroup doc1 doc2 -> case state.flexGroup of
@@ -445,3 +487,5 @@ print (Printer printer) opts = flip go initState <<< pure <<< Doc
445
487
{ annotations = anns
446
488
, buffer = Buffer .modify (printer.leaveAnnotation ann anns) state.buffer
447
489
}
490
+ LeaveLocal prevOptions ->
491
+ go stk $ storeOptions state.position.indent prevOptions state
0 commit comments