prettier_print 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/Gemfile.lock +3 -2
- data/README.md +1 -5
- data/lib/prettier_print/version.rb +1 -1
- data/lib/prettier_print.rb +207 -229
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9996ce5492af60b6cea9099175af9c31752da258be9de73b9f8e66d55ec5cecb
|
4
|
+
data.tar.gz: 472a728da7f9c4c8fba5fe93664e50a984cb80ecec14efedfcd94decc72c7593
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57bb92ec550e11a69502c3f9e7668e0f4c6528025a3a0e45986c4f32f755e43d47342128d1c75fde952853ffe5eb4dddd4ff9f235ab1d30bef66a212f41f9f86
|
7
|
+
data.tar.gz: eb6ad1645c41cc33ada93ea8570c626968cc09f1f374d11f5bc5c526d375febb43629b09cdbf15e941e8f2d6ec27294e7c8755da4c6e2e94594094b15de23572
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [1.0.0] - 2022-10-17
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
* `breakable_space` - a shortcut for `breakable`
|
14
|
+
* `breakable_empty` - a shortcut for `breakable("")`
|
15
|
+
* `breakable_force` - a shortcut for `breakable("", force: true)`
|
16
|
+
* `breakable_return` - a shortcut for `breakable(" ", indent: false, force: true)`
|
17
|
+
* Strings can now be added directly to the output buffer, which means they don't have to be placed into the `Text` node. This cuts down on quite a bit of allocations.
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
|
21
|
+
* `trim` now strips its whitespace using `rstrip!` instead of a custom `gsub!`. This means that other forms of whitespace beyond tabs and spaces are included. This shouldn't really impact anyone unless they're using vertical tab or something in combination with `trim` and wanted them to stay in.
|
22
|
+
|
23
|
+
### Removed
|
24
|
+
|
25
|
+
* There is no longer a `PrettierPrint::DefaultBuffer` class. Since there were only ever two implementations, those implementations now no longer share a parent.
|
26
|
+
* `PrettierPrint::IndentLevel` is now entirely gone. This was mostly an implementation detail, and no one should have been relying on it anyway. However, it means that the ability to use nest with a string literal is now gone as well. It can be created again by using seplist though, so the functionality just isn't there in the shortcut version. This means we're able to keep track of indentation as a single integer again, which drastically simplifies the code.
|
27
|
+
|
9
28
|
## [0.1.0] - 2022-05-13
|
10
29
|
|
11
30
|
### Added
|
data/Gemfile.lock
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
prettier_print (
|
4
|
+
prettier_print (1.0.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
power_assert (2.0.1)
|
10
10
|
rake (13.0.6)
|
11
|
-
test-unit (3.5.
|
11
|
+
test-unit (3.5.5)
|
12
12
|
power_assert
|
13
13
|
|
14
14
|
PLATFORMS
|
15
|
+
arm64-darwin-21
|
15
16
|
x86_64-darwin-21
|
16
17
|
x86_64-linux
|
17
18
|
|
data/README.md
CHANGED
@@ -137,11 +137,7 @@ This node increases the indentation by a fixed number of spaces or a string. It
|
|
137
137
|
q.nest(2) {}
|
138
138
|
```
|
139
139
|
|
140
|
-
It accepts a block that specifies the contents of the alignment node. The value that you're indenting by can be positive or negative.
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
q.nest("-->") {}
|
144
|
-
```
|
140
|
+
It accepts a block that specifies the contents of the alignment node. The value that you're indenting by can be positive or negative.
|
145
141
|
|
146
142
|
#### `BreakParent`
|
147
143
|
|
data/lib/prettier_print.rb
CHANGED
@@ -120,6 +120,13 @@ class PrettierPrint
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
# Below here are the most common combination of options that are created when
|
124
|
+
# creating new breakables. They are here to cut down on some allocations.
|
125
|
+
BREAKABLE_SPACE = Breakable.new(" ", 1, indent: true, force: false)
|
126
|
+
BREAKABLE_EMPTY = Breakable.new("", 0, indent: true, force: false)
|
127
|
+
BREAKABLE_FORCE = Breakable.new(" ", 1, indent: true, force: true)
|
128
|
+
BREAKABLE_RETURN = Breakable.new(" ", 1, indent: false, force: true)
|
129
|
+
|
123
130
|
# A node in the print tree that forces the surrounding group to print out in
|
124
131
|
# the "break" mode as opposed to the "flat" mode. Useful for when you need to
|
125
132
|
# force a newline into a group.
|
@@ -129,6 +136,10 @@ class PrettierPrint
|
|
129
136
|
end
|
130
137
|
end
|
131
138
|
|
139
|
+
# Since there's really no difference in these instances, just using the same
|
140
|
+
# one saves on some allocations.
|
141
|
+
BREAK_PARENT = BreakParent.new
|
142
|
+
|
132
143
|
# A node in the print tree that represents a group of items which the printer
|
133
144
|
# should try to fit onto one line. This is the basic command to tell the
|
134
145
|
# printer when to break. Groups are usually nested, and the printer will try
|
@@ -254,19 +265,23 @@ class PrettierPrint
|
|
254
265
|
end
|
255
266
|
end
|
256
267
|
|
268
|
+
# Since all of the instances here are the same, we can reuse the same one to
|
269
|
+
# cut down on allocations.
|
270
|
+
TRIM = Trim.new
|
271
|
+
|
257
272
|
# When building up the contents in the output buffer, it's convenient to be
|
258
273
|
# able to trim trailing whitespace before newlines. If the output object is a
|
259
274
|
# string or array or strings, then we can do this with some gsub calls. If
|
260
275
|
# not, then this effectively just wraps the output object and forwards on
|
261
276
|
# calls to <<.
|
262
277
|
module Buffer
|
263
|
-
# This is
|
264
|
-
# trim! that
|
265
|
-
#
|
266
|
-
class
|
278
|
+
# This is an output buffer that wraps a string output object. It provides a
|
279
|
+
# trim! method that trims off trailing whitespace from the string using
|
280
|
+
# gsub!.
|
281
|
+
class StringBuffer
|
267
282
|
attr_reader :output
|
268
283
|
|
269
|
-
def initialize(output =
|
284
|
+
def initialize(output = "".dup)
|
270
285
|
@output = output
|
271
286
|
end
|
272
287
|
|
@@ -274,22 +289,9 @@ class PrettierPrint
|
|
274
289
|
@output << object
|
275
290
|
end
|
276
291
|
|
277
|
-
def trim!
|
278
|
-
0
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
# This is an output buffer that wraps a string output object. It provides a
|
283
|
-
# trim! method that trims off trailing whitespace from the string using
|
284
|
-
# gsub!.
|
285
|
-
class StringBuffer < DefaultBuffer
|
286
|
-
def initialize(output = "".dup)
|
287
|
-
super(output)
|
288
|
-
end
|
289
|
-
|
290
292
|
def trim!
|
291
293
|
length = output.length
|
292
|
-
output.
|
294
|
+
output.rstrip!
|
293
295
|
length - output.length
|
294
296
|
end
|
295
297
|
end
|
@@ -298,9 +300,15 @@ class PrettierPrint
|
|
298
300
|
# trim! method that trims off trailing whitespace from the last element in
|
299
301
|
# the array if it's an unfrozen string using the same method as the
|
300
302
|
# StringBuffer.
|
301
|
-
class ArrayBuffer
|
303
|
+
class ArrayBuffer
|
304
|
+
attr_reader :output
|
305
|
+
|
302
306
|
def initialize(output = [])
|
303
|
-
|
307
|
+
@output = output
|
308
|
+
end
|
309
|
+
|
310
|
+
def <<(object)
|
311
|
+
@output << object
|
304
312
|
end
|
305
313
|
|
306
314
|
def trim!
|
@@ -315,7 +323,7 @@ class PrettierPrint
|
|
315
323
|
|
316
324
|
if output.any? && output.last.is_a?(String) && !output.last.frozen?
|
317
325
|
length = output.last.length
|
318
|
-
output.last.
|
326
|
+
output.last.rstrip!
|
319
327
|
trimmed += length - output.last.length
|
320
328
|
end
|
321
329
|
|
@@ -326,14 +334,7 @@ class PrettierPrint
|
|
326
334
|
# This is a switch for building the correct output buffer wrapper class for
|
327
335
|
# the given output object.
|
328
336
|
def self.for(output)
|
329
|
-
|
330
|
-
when String
|
331
|
-
StringBuffer.new(output)
|
332
|
-
when Array
|
333
|
-
ArrayBuffer.new(output)
|
334
|
-
else
|
335
|
-
DefaultBuffer.new(output)
|
336
|
-
end
|
337
|
+
output.is_a?(String) ? StringBuffer.new(output) : ArrayBuffer.new(output)
|
337
338
|
end
|
338
339
|
end
|
339
340
|
|
@@ -482,88 +483,6 @@ class PrettierPrint
|
|
482
483
|
end
|
483
484
|
end
|
484
485
|
|
485
|
-
# This object represents the current level of indentation within the printer.
|
486
|
-
# It has the ability to generate new levels of indentation through the #align
|
487
|
-
# and #indent methods.
|
488
|
-
class IndentLevel
|
489
|
-
IndentPart = Object.new
|
490
|
-
DedentPart = Object.new
|
491
|
-
|
492
|
-
StringAlignPart = Struct.new(:n)
|
493
|
-
NumberAlignPart = Struct.new(:n)
|
494
|
-
|
495
|
-
attr_reader :genspace, :value, :length, :queue, :root
|
496
|
-
|
497
|
-
def initialize(
|
498
|
-
genspace:,
|
499
|
-
value: genspace.call(0),
|
500
|
-
length: 0,
|
501
|
-
queue: [],
|
502
|
-
root: nil
|
503
|
-
)
|
504
|
-
@genspace = genspace
|
505
|
-
@value = value
|
506
|
-
@length = length
|
507
|
-
@queue = queue
|
508
|
-
@root = root
|
509
|
-
end
|
510
|
-
|
511
|
-
# This can accept a whole lot of different kinds of objects, due to the
|
512
|
-
# nature of the flexibility of the Align node.
|
513
|
-
def align(n)
|
514
|
-
case n
|
515
|
-
when NilClass
|
516
|
-
self
|
517
|
-
when String
|
518
|
-
indent(StringAlignPart.new(n))
|
519
|
-
else
|
520
|
-
indent(n < 0 ? DedentPart : NumberAlignPart.new(n))
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
def indent(part = IndentPart)
|
525
|
-
next_value = genspace.call(0)
|
526
|
-
next_length = 0
|
527
|
-
next_queue = (part == DedentPart ? queue[0...-1] : [*queue, part])
|
528
|
-
|
529
|
-
last_spaces = 0
|
530
|
-
|
531
|
-
add_spaces = ->(count) do
|
532
|
-
next_value << genspace.call(count)
|
533
|
-
next_length += count
|
534
|
-
end
|
535
|
-
|
536
|
-
flush_spaces = -> do
|
537
|
-
add_spaces[last_spaces] if last_spaces > 0
|
538
|
-
last_spaces = 0
|
539
|
-
end
|
540
|
-
|
541
|
-
next_queue.each do |next_part|
|
542
|
-
case next_part
|
543
|
-
when IndentPart
|
544
|
-
flush_spaces.call
|
545
|
-
add_spaces.call(2)
|
546
|
-
when StringAlignPart
|
547
|
-
flush_spaces.call
|
548
|
-
next_value += next_part.n
|
549
|
-
next_length += next_part.n.length
|
550
|
-
when NumberAlignPart
|
551
|
-
last_spaces += next_part.n
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
|
-
flush_spaces.call
|
556
|
-
|
557
|
-
IndentLevel.new(
|
558
|
-
genspace: genspace,
|
559
|
-
value: next_value,
|
560
|
-
length: next_length,
|
561
|
-
queue: next_queue,
|
562
|
-
root: root
|
563
|
-
)
|
564
|
-
end
|
565
|
-
end
|
566
|
-
|
567
486
|
# When printing, you can optionally specify the value that should be used
|
568
487
|
# whenever a group needs to be broken onto multiple lines. In this case the
|
569
488
|
# default is \n.
|
@@ -734,7 +653,7 @@ class PrettierPrint
|
|
734
653
|
|
735
654
|
# This is our command stack. A command consists of a triplet of an
|
736
655
|
# indentation level, the mode (break or flat), and a doc node.
|
737
|
-
commands = [[
|
656
|
+
commands = [[0, MODE_BREAK, doc]]
|
738
657
|
|
739
658
|
# This is a small optimization boolean. It keeps track of whether or not
|
740
659
|
# when we hit a group node we should check if it fits on the same line.
|
@@ -750,49 +669,35 @@ class PrettierPrint
|
|
750
669
|
# priority set on the line suffix and the index it was in the original
|
751
670
|
# array.
|
752
671
|
line_suffix_sort = ->(line_suffix) do
|
753
|
-
[-line_suffix.last, -line_suffixes.index(line_suffix)]
|
672
|
+
[-line_suffix.last.priority, -line_suffixes.index(line_suffix)]
|
754
673
|
end
|
755
674
|
|
756
675
|
# This is a linear stack instead of a mutually recursive call defined on
|
757
676
|
# the individual doc nodes for efficiency.
|
758
677
|
while (indent, mode, doc = commands.pop)
|
759
678
|
case doc
|
760
|
-
when
|
761
|
-
|
762
|
-
position += doc.
|
763
|
-
when Array
|
764
|
-
doc.reverse_each { |part| commands << [indent, mode, part] }
|
765
|
-
when Indent
|
766
|
-
commands << [indent.indent, mode, doc.contents]
|
767
|
-
when Align
|
768
|
-
commands << [indent.align(doc.indent), mode, doc.contents]
|
769
|
-
when Trim
|
770
|
-
position -= buffer.trim!
|
679
|
+
when String
|
680
|
+
buffer << doc
|
681
|
+
position += doc.length
|
771
682
|
when Group
|
772
683
|
if mode == MODE_FLAT && !should_remeasure
|
773
|
-
|
774
|
-
|
775
|
-
doc.break? ? MODE_BREAK : MODE_FLAT,
|
776
|
-
doc.contents
|
777
|
-
]
|
684
|
+
next_mode = doc.break? ? MODE_BREAK : MODE_FLAT
|
685
|
+
commands += doc.contents.reverse.map { |part| [indent, next_mode, part] }
|
778
686
|
else
|
779
687
|
should_remeasure = false
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
next_cmd
|
688
|
+
|
689
|
+
if doc.break?
|
690
|
+
commands += doc.contents.reverse.map { |part| [indent, MODE_BREAK, part] }
|
784
691
|
else
|
785
|
-
[indent,
|
692
|
+
next_commands = doc.contents.reverse.map { |part| [indent, MODE_FLAT, part] }
|
693
|
+
|
694
|
+
if fits?(next_commands, commands, maxwidth - position)
|
695
|
+
commands += next_commands
|
696
|
+
else
|
697
|
+
commands += next_commands.map { |command| command[1] = MODE_BREAK; command }
|
698
|
+
end
|
786
699
|
end
|
787
700
|
end
|
788
|
-
when IfBreak
|
789
|
-
if mode == MODE_BREAK && doc.break_contents.any?
|
790
|
-
commands << [indent, mode, doc.break_contents]
|
791
|
-
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
792
|
-
commands << [indent, mode, doc.flat_contents]
|
793
|
-
end
|
794
|
-
when LineSuffix
|
795
|
-
line_suffixes << [indent, mode, doc.contents, doc.priority]
|
796
701
|
when Breakable
|
797
702
|
if mode == MODE_FLAT
|
798
703
|
if doc.force?
|
@@ -813,28 +718,45 @@ class PrettierPrint
|
|
813
718
|
# to flush them now, as we are about to add a newline.
|
814
719
|
if line_suffixes.any?
|
815
720
|
commands << [indent, mode, doc]
|
816
|
-
|
817
|
-
line_suffixes
|
721
|
+
|
722
|
+
line_suffixes.sort_by(&line_suffix_sort).each do |(indent, mode, doc)|
|
723
|
+
commands += doc.contents.reverse.map { |part| [indent, mode, part] }
|
724
|
+
end
|
725
|
+
|
726
|
+
line_suffixes.clear
|
818
727
|
next
|
819
728
|
end
|
820
729
|
|
821
730
|
if !doc.indent?
|
822
731
|
buffer << newline
|
823
|
-
|
824
|
-
if indent.root
|
825
|
-
buffer << indent.root.value
|
826
|
-
position = indent.root.length
|
827
|
-
else
|
828
|
-
position = 0
|
829
|
-
end
|
732
|
+
position = 0
|
830
733
|
else
|
831
734
|
position -= buffer.trim!
|
832
735
|
buffer << newline
|
833
|
-
buffer << indent
|
834
|
-
position = indent
|
736
|
+
buffer << genspace.call(indent)
|
737
|
+
position = indent
|
738
|
+
end
|
739
|
+
when Indent
|
740
|
+
next_indent = indent + 2
|
741
|
+
commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
|
742
|
+
when Align
|
743
|
+
next_indent = indent + doc.indent
|
744
|
+
commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
|
745
|
+
when Trim
|
746
|
+
position -= buffer.trim!
|
747
|
+
when IfBreak
|
748
|
+
if mode == MODE_BREAK && doc.break_contents.any?
|
749
|
+
commands += doc.break_contents.reverse.map { |part| [indent, mode, part] }
|
750
|
+
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
751
|
+
commands += doc.flat_contents.reverse.map { |part| [indent, mode, part] }
|
835
752
|
end
|
753
|
+
when LineSuffix
|
754
|
+
line_suffixes << [indent, mode, doc]
|
836
755
|
when BreakParent
|
837
756
|
# do nothing
|
757
|
+
when Text
|
758
|
+
doc.objects.each { |object| buffer << object }
|
759
|
+
position += doc.width
|
838
760
|
else
|
839
761
|
# Special case where the user has defined some way to get an extra doc
|
840
762
|
# node that we don't explicitly support into the list. In this case
|
@@ -861,13 +783,41 @@ class PrettierPrint
|
|
861
783
|
# Helper node builders
|
862
784
|
# ----------------------------------------------------------------------------
|
863
785
|
|
786
|
+
# The vast majority of breakable calls you receive while formatting are a
|
787
|
+
# space in flat mode and a newline in break mode. Since this is so common,
|
788
|
+
# we have a method here to skip past unnecessary calculation.
|
789
|
+
def breakable_space
|
790
|
+
target << BREAKABLE_SPACE
|
791
|
+
end
|
792
|
+
|
793
|
+
# Another very common breakable call you receive while formatting is an
|
794
|
+
# empty string in flat mode and a newline in break mode. Similar to
|
795
|
+
# breakable_space, this is here for avoid unnecessary calculation.
|
796
|
+
def breakable_empty
|
797
|
+
target << BREAKABLE_EMPTY
|
798
|
+
end
|
799
|
+
|
800
|
+
# The final of the very common breakable calls you receive while formatting
|
801
|
+
# is the normal breakable space but with the addition of the break_parent.
|
802
|
+
def breakable_force
|
803
|
+
target << BREAKABLE_FORCE
|
804
|
+
break_parent
|
805
|
+
end
|
806
|
+
|
807
|
+
# This is the same shortcut as breakable_force, except that it doesn't indent
|
808
|
+
# the next line. This is necessary if you're trying to preserve some custom
|
809
|
+
# formatting like a multi-line string.
|
810
|
+
def breakable_return
|
811
|
+
target << BREAKABLE_RETURN
|
812
|
+
end
|
813
|
+
|
864
814
|
# A convenience method which is same as follows:
|
865
815
|
#
|
866
816
|
# text(",")
|
867
817
|
# breakable
|
868
818
|
def comma_breakable
|
869
819
|
text(",")
|
870
|
-
|
820
|
+
breakable_space
|
871
821
|
end
|
872
822
|
|
873
823
|
# This is similar to #breakable except the decision to break or not is
|
@@ -896,18 +846,18 @@ class PrettierPrint
|
|
896
846
|
queue = [node]
|
897
847
|
width = 0
|
898
848
|
|
899
|
-
|
900
|
-
doc = queue.shift
|
901
|
-
|
849
|
+
while (doc = queue.shift)
|
902
850
|
case doc
|
903
|
-
when
|
904
|
-
width += doc.
|
905
|
-
when Indent, Align
|
851
|
+
when String
|
852
|
+
width += doc.length
|
853
|
+
when Group, Indent, Align
|
906
854
|
queue = doc.contents + queue
|
907
|
-
when IfBreak
|
908
|
-
queue = doc.break_contents + queue
|
909
855
|
when Breakable
|
910
856
|
width = 0
|
857
|
+
when IfBreak
|
858
|
+
queue = doc.break_contents + queue
|
859
|
+
when Text
|
860
|
+
width += doc.width
|
911
861
|
end
|
912
862
|
end
|
913
863
|
|
@@ -918,26 +868,16 @@ class PrettierPrint
|
|
918
868
|
# no newlines are present in the output. If a newline is being forced into
|
919
869
|
# the output, the replace value will be used.
|
920
870
|
def remove_breaks(node, replace = "; ")
|
921
|
-
|
922
|
-
stack = [node]
|
923
|
-
|
924
|
-
while stack.any?
|
925
|
-
doc = stack.pop
|
926
|
-
|
927
|
-
if doc == marker
|
928
|
-
stack.pop
|
929
|
-
next
|
930
|
-
end
|
931
|
-
|
932
|
-
stack += [doc, marker]
|
871
|
+
queue = [node]
|
933
872
|
|
873
|
+
while (doc = queue.shift)
|
934
874
|
case doc
|
935
875
|
when Align, Indent, Group
|
936
876
|
doc.contents.map! { |child| remove_breaks_with(child, replace) }
|
937
|
-
|
877
|
+
queue += doc.contents
|
938
878
|
when IfBreak
|
939
879
|
doc.flat_contents.map! { |child| remove_breaks_with(child, replace) }
|
940
|
-
|
880
|
+
queue += doc.flat_contents
|
941
881
|
end
|
942
882
|
end
|
943
883
|
end
|
@@ -967,13 +907,14 @@ class PrettierPrint
|
|
967
907
|
# q.comma_breakable
|
968
908
|
# xxx 3
|
969
909
|
def seplist(list, sep=nil, iter_method=:each) # :yield: element
|
970
|
-
sep ||= lambda { comma_breakable }
|
971
910
|
first = true
|
972
911
|
list.__send__(iter_method) {|*v|
|
973
912
|
if first
|
974
913
|
first = false
|
975
|
-
|
914
|
+
elsif sep
|
976
915
|
sep.call
|
916
|
+
else
|
917
|
+
comma_breakable
|
977
918
|
end
|
978
919
|
RUBY_VERSION >= "3.0" ? yield(*v, **{}) : yield(*v)
|
979
920
|
}
|
@@ -1013,26 +954,20 @@ class PrettierPrint
|
|
1013
954
|
indent: true,
|
1014
955
|
force: false
|
1015
956
|
)
|
1016
|
-
|
1017
|
-
|
1018
|
-
target << doc
|
957
|
+
target << Breakable.new(separator, width, indent: indent, force: !!force)
|
1019
958
|
break_parent if force == true
|
1020
|
-
|
1021
|
-
doc
|
1022
959
|
end
|
1023
960
|
|
1024
961
|
# This inserts a BreakParent node into the print tree which forces the
|
1025
962
|
# surrounding and all parent group nodes to break.
|
1026
963
|
def break_parent
|
1027
|
-
doc =
|
964
|
+
doc = BREAK_PARENT
|
1028
965
|
target << doc
|
1029
966
|
|
1030
967
|
groups.reverse_each do |group|
|
1031
968
|
break if group.break?
|
1032
969
|
group.break
|
1033
970
|
end
|
1034
|
-
|
1035
|
-
doc
|
1036
971
|
end
|
1037
972
|
|
1038
973
|
# This inserts a Trim node into the print tree which, when printed, will clear
|
@@ -1040,10 +975,7 @@ class PrettierPrint
|
|
1040
975
|
# case where you need to delete printed indentation and force the next node
|
1041
976
|
# to start at the beginning of the line.
|
1042
977
|
def trim
|
1043
|
-
|
1044
|
-
target << doc
|
1045
|
-
|
1046
|
-
doc
|
978
|
+
target << TRIM
|
1047
979
|
end
|
1048
980
|
|
1049
981
|
# ----------------------------------------------------------------------------
|
@@ -1089,15 +1021,36 @@ class PrettierPrint
|
|
1089
1021
|
# A small DSL-like object used for specifying the alternative contents to be
|
1090
1022
|
# printed if the surrounding group doesn't break for an IfBreak node.
|
1091
1023
|
class IfBreakBuilder
|
1092
|
-
attr_reader :
|
1024
|
+
attr_reader :q, :flat_contents
|
1093
1025
|
|
1094
|
-
def initialize(
|
1095
|
-
@
|
1096
|
-
@
|
1026
|
+
def initialize(q, flat_contents)
|
1027
|
+
@q = q
|
1028
|
+
@flat_contents = flat_contents
|
1097
1029
|
end
|
1098
1030
|
|
1099
|
-
def if_flat
|
1100
|
-
|
1031
|
+
def if_flat
|
1032
|
+
q.with_target(flat_contents) { yield }
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
# When we already know that groups are broken, we don't actually need to track
|
1037
|
+
# the flat versions of the contents. So this builder version is effectively a
|
1038
|
+
# no-op, but we need it to maintain the same API. The only thing this can
|
1039
|
+
# impact is that if there's a forced break in the flat contents, then we need
|
1040
|
+
# to propagate that break up the whole tree.
|
1041
|
+
class IfFlatIgnore
|
1042
|
+
attr_reader :q
|
1043
|
+
|
1044
|
+
def initialize(q)
|
1045
|
+
@q = q
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def if_flat
|
1049
|
+
contents = []
|
1050
|
+
group = Group.new(0, contents: contents)
|
1051
|
+
|
1052
|
+
q.with_target(contents) { yield }
|
1053
|
+
q.break_parent if group.break?
|
1101
1054
|
end
|
1102
1055
|
end
|
1103
1056
|
|
@@ -1111,31 +1064,50 @@ class PrettierPrint
|
|
1111
1064
|
# In the example above, if the surrounding group is broken it will print 'do'
|
1112
1065
|
# and if it is not it will print '{'.
|
1113
1066
|
def if_break
|
1114
|
-
|
1067
|
+
break_contents = []
|
1068
|
+
flat_contents = []
|
1069
|
+
|
1070
|
+
doc = IfBreak.new(break_contents: break_contents, flat_contents: flat_contents)
|
1115
1071
|
target << doc
|
1116
1072
|
|
1117
|
-
with_target(
|
1118
|
-
|
1073
|
+
with_target(break_contents) { yield }
|
1074
|
+
|
1075
|
+
if groups.last.break?
|
1076
|
+
IfFlatIgnore.new(self)
|
1077
|
+
else
|
1078
|
+
IfBreakBuilder.new(self, flat_contents)
|
1079
|
+
end
|
1119
1080
|
end
|
1120
1081
|
|
1121
1082
|
# This is similar to if_break in that it also inserts an IfBreak node into the
|
1122
1083
|
# print tree, however it's starting from the flat contents, and cannot be used
|
1123
1084
|
# to build the break contents.
|
1124
1085
|
def if_flat
|
1125
|
-
|
1126
|
-
|
1086
|
+
if groups.last.break?
|
1087
|
+
contents = []
|
1088
|
+
group = Group.new(0, contents: contents)
|
1127
1089
|
|
1128
|
-
|
1090
|
+
with_target(contents) { yield }
|
1091
|
+
break_parent if group.break?
|
1092
|
+
else
|
1093
|
+
flat_contents = []
|
1094
|
+
doc = IfBreak.new(break_contents: [], flat_contents: flat_contents)
|
1095
|
+
target << doc
|
1096
|
+
|
1097
|
+
with_target(flat_contents) { yield }
|
1098
|
+
doc
|
1099
|
+
end
|
1129
1100
|
end
|
1130
1101
|
|
1131
1102
|
# Very similar to the #nest method, this indents the nested content by one
|
1132
1103
|
# level by inserting an Indent node into the print tree. The contents of the
|
1133
1104
|
# node are determined by the block.
|
1134
1105
|
def indent
|
1135
|
-
|
1106
|
+
contents = []
|
1107
|
+
doc = Indent.new(contents: contents)
|
1136
1108
|
target << doc
|
1137
1109
|
|
1138
|
-
with_target(
|
1110
|
+
with_target(contents) { yield }
|
1139
1111
|
doc
|
1140
1112
|
end
|
1141
1113
|
|
@@ -1152,10 +1124,11 @@ class PrettierPrint
|
|
1152
1124
|
# Increases left margin after newline with +indent+ for line breaks added in
|
1153
1125
|
# the block.
|
1154
1126
|
def nest(indent)
|
1155
|
-
|
1127
|
+
contents = []
|
1128
|
+
doc = Align.new(indent: indent, contents: contents)
|
1156
1129
|
target << doc
|
1157
1130
|
|
1158
|
-
with_target(
|
1131
|
+
with_target(contents) { yield }
|
1159
1132
|
doc
|
1160
1133
|
end
|
1161
1134
|
|
@@ -1192,7 +1165,7 @@ class PrettierPrint
|
|
1192
1165
|
# fit onto the remaining space on the current line. If we finish printing
|
1193
1166
|
# all of the commands or if we hit a newline, then we return true. Otherwise
|
1194
1167
|
# if we continue printing past the remaining space, we return false.
|
1195
|
-
def fits?(
|
1168
|
+
def fits?(next_commands, rest_commands, remaining)
|
1196
1169
|
# This is the index in the remaining commands that we've handled so far.
|
1197
1170
|
# We reverse through the commands and add them to the stack if we've run
|
1198
1171
|
# out of nodes to handle.
|
@@ -1200,7 +1173,7 @@ class PrettierPrint
|
|
1200
1173
|
|
1201
1174
|
# This is our stack of commands, very similar to the commands list in the
|
1202
1175
|
# print method.
|
1203
|
-
commands = [
|
1176
|
+
commands = [*next_commands]
|
1204
1177
|
|
1205
1178
|
# This is our output buffer, really only necessary to keep track of
|
1206
1179
|
# because we could encounter a Trim doc node that would actually add
|
@@ -1219,25 +1192,12 @@ class PrettierPrint
|
|
1219
1192
|
indent, mode, doc = commands.pop
|
1220
1193
|
|
1221
1194
|
case doc
|
1222
|
-
when
|
1223
|
-
|
1224
|
-
remaining -= doc.
|
1225
|
-
when Array
|
1226
|
-
doc.reverse_each { |part| commands << [indent, mode, part] }
|
1227
|
-
when Indent
|
1228
|
-
commands << [indent.indent, mode, doc.contents]
|
1229
|
-
when Align
|
1230
|
-
commands << [indent.align(doc.indent), mode, doc.contents]
|
1231
|
-
when Trim
|
1232
|
-
remaining += fit_buffer.trim!
|
1195
|
+
when String
|
1196
|
+
fit_buffer << doc
|
1197
|
+
remaining -= doc.length
|
1233
1198
|
when Group
|
1234
|
-
|
1235
|
-
|
1236
|
-
if mode == MODE_BREAK && doc.break_contents.any?
|
1237
|
-
commands << [indent, mode, doc.break_contents]
|
1238
|
-
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
1239
|
-
commands << [indent, mode, doc.flat_contents]
|
1240
|
-
end
|
1199
|
+
next_mode = doc.break? ? MODE_BREAK : mode
|
1200
|
+
commands += doc.contents.reverse.map { |part| [indent, next_mode, part] }
|
1241
1201
|
when Breakable
|
1242
1202
|
if mode == MODE_FLAT && !doc.force?
|
1243
1203
|
fit_buffer << doc.separator
|
@@ -1246,6 +1206,23 @@ class PrettierPrint
|
|
1246
1206
|
end
|
1247
1207
|
|
1248
1208
|
return true
|
1209
|
+
when Indent
|
1210
|
+
next_indent = indent + 2
|
1211
|
+
commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
|
1212
|
+
when Align
|
1213
|
+
next_indent = indent + doc.indent
|
1214
|
+
commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
|
1215
|
+
when Trim
|
1216
|
+
remaining += fit_buffer.trim!
|
1217
|
+
when IfBreak
|
1218
|
+
if mode == MODE_BREAK && doc.break_contents.any?
|
1219
|
+
commands += doc.break_contents.reverse.map { |part| [indent, mode, part] }
|
1220
|
+
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
1221
|
+
commands += doc.flat_contents.reverse.map { |part| [indent, mode, part] }
|
1222
|
+
end
|
1223
|
+
when Text
|
1224
|
+
doc.objects.each { |object| fit_buffer << object }
|
1225
|
+
remaining -= doc.width
|
1249
1226
|
end
|
1250
1227
|
end
|
1251
1228
|
|
@@ -1255,8 +1232,9 @@ class PrettierPrint
|
|
1255
1232
|
# Resets the group stack and target array so that this pretty printer object
|
1256
1233
|
# can continue to be used before calling flush again if desired.
|
1257
1234
|
def reset
|
1258
|
-
|
1259
|
-
@
|
1235
|
+
contents = []
|
1236
|
+
@groups = [Group.new(0, contents: contents)]
|
1237
|
+
@target = contents
|
1260
1238
|
end
|
1261
1239
|
|
1262
1240
|
def remove_breaks_with(doc, replace)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prettier_print
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Newton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -50,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
50
|
- !ruby/object:Gem::Version
|
51
51
|
version: '0'
|
52
52
|
requirements: []
|
53
|
-
rubygems_version: 3.
|
53
|
+
rubygems_version: 3.3.21
|
54
54
|
signing_key:
|
55
55
|
specification_version: 4
|
56
56
|
summary: A drop-in replacement for the prettyprint gem with more functionality.
|