prettier_print 0.1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 907080c33747b11f43d7165ca49678637e042a6f72e49af0f07ada0c8a41326f
4
- data.tar.gz: fce6553a15d281741ba58aa27572824457ff74546c5bb4d5ef0e5ba6a4dc67c8
3
+ metadata.gz: 5392f4dae350d56612ec1850aa3ca28bb51e5776690e213d31cf1671db789fac
4
+ data.tar.gz: 72494c92f76eafe77b4afd04e2c8da7d45a209dd4d1c9b2d5aaf5820b3153050
5
5
  SHA512:
6
- metadata.gz: afadb2cc911c46b55a2abf07818481fc41472f050ac18bfb6a08016a4586222832d937a816a47b1ce313dbfbfe9c1577cf37b646ebbc6dbff4b2a4f9b57c78e1
7
- data.tar.gz: 31076563a9afa16bd4ba137c13ac27eaa3e45cb392923d02a9097260b945bb133829e02258284210ac1661ebb87fa5db0cd2f7803197e40780d116202e42ce41
6
+ metadata.gz: 9db5ca110447b075995e72c89cdaa0d881d9e7cef6786820ff1bec18b1cc1fc05c035717b7a8641a67a0586c8612a5a3a11933d9f95f5248f5fb95bb378b547d
7
+ data.tar.gz: de1c9038d6c84db2d9e2f8bf047b446abe3b4561cbf6700c8c925244adb46dffdcb2c2b19dfa23e800ba44cc09f77aa64d00f6848449e22a31b6617a375d8e8e
data/CHANGELOG.md CHANGED
@@ -6,11 +6,38 @@ 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.1] - 2022-10-18
10
+
11
+ ### Changed
12
+
13
+ * `breakable_return` - should also break parent
14
+
15
+ ## [1.0.0] - 2022-10-17
16
+
17
+ ### Added
18
+
19
+ * `breakable_space` - a shortcut for `breakable`
20
+ * `breakable_empty` - a shortcut for `breakable("")`
21
+ * `breakable_force` - a shortcut for `breakable("", force: true)`
22
+ * `breakable_return` - a shortcut for `breakable(" ", indent: false, force: true)`
23
+ * 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.
24
+
25
+ ### Changed
26
+
27
+ * `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.
28
+
29
+ ### Removed
30
+
31
+ * There is no longer a `PrettierPrint::DefaultBuffer` class. Since there were only ever two implementations, those implementations now no longer share a parent.
32
+ * `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.
33
+
9
34
  ## [0.1.0] - 2022-05-13
10
35
 
11
36
  ### Added
12
37
 
13
38
  - 🎉 Initial release! 🎉
14
39
 
15
- [unreleased]: https://github.com/ruby-syntax-tree/prettier_print/compare/v0.1.0...HEAD
16
- [0.1.0]: https://github.com/ruby-syntax-tree/prettier_print/compare/...v0.1.0
40
+ [unreleased]: https://github.com/ruby-syntax-tree/prettier_print/compare/v1.0.1...HEAD
41
+ [1.0.1]: https://github.com/ruby-syntax-tree/prettier_print/compare/v1.0.0...v1.0.1
42
+ [1.0.0]: https://github.com/ruby-syntax-tree/prettier_print/compare/v0.1.0...v1.0.0
43
+ [0.1.0]: https://github.com/ruby-syntax-tree/prettier_print/compare/df51ce...v0.1.0
data/Gemfile.lock CHANGED
@@ -1,17 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prettier_print (0.1.0)
4
+ prettier_print (1.0.1)
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.3)
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. It can also be a string, in which case that value will be used at the beginning of each line, as in:
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class PrettierPrint
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.1"
5
5
  end
@@ -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 the default output buffer that provides a base implementation of
264
- # trim! that does nothing. It's effectively a wrapper around whatever output
265
- # object was given to the format command.
266
- class DefaultBuffer
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.gsub!(/[\t ]*\z/, "")
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 < DefaultBuffer
303
+ class ArrayBuffer
304
+ attr_reader :output
305
+
302
306
  def initialize(output = [])
303
- super(output)
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.gsub!(/[\t ]*\z/, "")
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
- case output
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 = [[IndentLevel.new(genspace: genspace), MODE_BREAK, doc]]
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 Text
761
- doc.objects.each { |object| buffer << object }
762
- position += doc.width
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
- commands << [
774
- indent,
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
- next_cmd = [indent, MODE_FLAT, doc.contents]
781
- commands << if !doc.break? &&
782
- fits?(next_cmd, commands, maxwidth - position)
783
- next_cmd
688
+
689
+ if doc.break?
690
+ commands += doc.contents.reverse.map { |part| [indent, MODE_BREAK, part] }
784
691
  else
785
- [indent, MODE_BREAK, doc.contents]
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
- commands += line_suffixes.sort_by(&line_suffix_sort)
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.value
834
- position = indent.length
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,42 @@ 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
+ break_parent
813
+ end
814
+
864
815
  # A convenience method which is same as follows:
865
816
  #
866
817
  # text(",")
867
818
  # breakable
868
819
  def comma_breakable
869
820
  text(",")
870
- breakable
821
+ breakable_space
871
822
  end
872
823
 
873
824
  # This is similar to #breakable except the decision to break or not is
@@ -896,18 +847,18 @@ class PrettierPrint
896
847
  queue = [node]
897
848
  width = 0
898
849
 
899
- until queue.empty?
900
- doc = queue.shift
901
-
850
+ while (doc = queue.shift)
902
851
  case doc
903
- when Text
904
- width += doc.width
905
- when Indent, Align, Group
852
+ when String
853
+ width += doc.length
854
+ when Group, Indent, Align
906
855
  queue = doc.contents + queue
907
- when IfBreak
908
- queue = doc.break_contents + queue
909
856
  when Breakable
910
857
  width = 0
858
+ when IfBreak
859
+ queue = doc.break_contents + queue
860
+ when Text
861
+ width += doc.width
911
862
  end
912
863
  end
913
864
 
@@ -918,26 +869,16 @@ class PrettierPrint
918
869
  # no newlines are present in the output. If a newline is being forced into
919
870
  # the output, the replace value will be used.
920
871
  def remove_breaks(node, replace = "; ")
921
- marker = Object.new
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]
872
+ queue = [node]
933
873
 
874
+ while (doc = queue.shift)
934
875
  case doc
935
876
  when Align, Indent, Group
936
877
  doc.contents.map! { |child| remove_breaks_with(child, replace) }
937
- stack += doc.contents.reverse
878
+ queue += doc.contents
938
879
  when IfBreak
939
880
  doc.flat_contents.map! { |child| remove_breaks_with(child, replace) }
940
- stack += doc.flat_contents.reverse
881
+ queue += doc.flat_contents
941
882
  end
942
883
  end
943
884
  end
@@ -967,13 +908,14 @@ class PrettierPrint
967
908
  # q.comma_breakable
968
909
  # xxx 3
969
910
  def seplist(list, sep=nil, iter_method=:each) # :yield: element
970
- sep ||= lambda { comma_breakable }
971
911
  first = true
972
912
  list.__send__(iter_method) {|*v|
973
913
  if first
974
914
  first = false
975
- else
915
+ elsif sep
976
916
  sep.call
917
+ else
918
+ comma_breakable
977
919
  end
978
920
  RUBY_VERSION >= "3.0" ? yield(*v, **{}) : yield(*v)
979
921
  }
@@ -1013,26 +955,20 @@ class PrettierPrint
1013
955
  indent: true,
1014
956
  force: false
1015
957
  )
1016
- doc = Breakable.new(separator, width, indent: indent, force: !!force)
1017
-
1018
- target << doc
958
+ target << Breakable.new(separator, width, indent: indent, force: !!force)
1019
959
  break_parent if force == true
1020
-
1021
- doc
1022
960
  end
1023
961
 
1024
962
  # This inserts a BreakParent node into the print tree which forces the
1025
963
  # surrounding and all parent group nodes to break.
1026
964
  def break_parent
1027
- doc = BreakParent.new
965
+ doc = BREAK_PARENT
1028
966
  target << doc
1029
967
 
1030
968
  groups.reverse_each do |group|
1031
969
  break if group.break?
1032
970
  group.break
1033
971
  end
1034
-
1035
- doc
1036
972
  end
1037
973
 
1038
974
  # This inserts a Trim node into the print tree which, when printed, will clear
@@ -1040,10 +976,7 @@ class PrettierPrint
1040
976
  # case where you need to delete printed indentation and force the next node
1041
977
  # to start at the beginning of the line.
1042
978
  def trim
1043
- doc = Trim.new
1044
- target << doc
1045
-
1046
- doc
979
+ target << TRIM
1047
980
  end
1048
981
 
1049
982
  # ----------------------------------------------------------------------------
@@ -1089,15 +1022,36 @@ class PrettierPrint
1089
1022
  # A small DSL-like object used for specifying the alternative contents to be
1090
1023
  # printed if the surrounding group doesn't break for an IfBreak node.
1091
1024
  class IfBreakBuilder
1092
- attr_reader :builder, :if_break
1025
+ attr_reader :q, :flat_contents
1093
1026
 
1094
- def initialize(builder, if_break)
1095
- @builder = builder
1096
- @if_break = if_break
1027
+ def initialize(q, flat_contents)
1028
+ @q = q
1029
+ @flat_contents = flat_contents
1097
1030
  end
1098
1031
 
1099
- def if_flat(&block)
1100
- builder.with_target(if_break.flat_contents, &block)
1032
+ def if_flat
1033
+ q.with_target(flat_contents) { yield }
1034
+ end
1035
+ end
1036
+
1037
+ # When we already know that groups are broken, we don't actually need to track
1038
+ # the flat versions of the contents. So this builder version is effectively a
1039
+ # no-op, but we need it to maintain the same API. The only thing this can
1040
+ # impact is that if there's a forced break in the flat contents, then we need
1041
+ # to propagate that break up the whole tree.
1042
+ class IfFlatIgnore
1043
+ attr_reader :q
1044
+
1045
+ def initialize(q)
1046
+ @q = q
1047
+ end
1048
+
1049
+ def if_flat
1050
+ contents = []
1051
+ group = Group.new(0, contents: contents)
1052
+
1053
+ q.with_target(contents) { yield }
1054
+ q.break_parent if group.break?
1101
1055
  end
1102
1056
  end
1103
1057
 
@@ -1111,31 +1065,50 @@ class PrettierPrint
1111
1065
  # In the example above, if the surrounding group is broken it will print 'do'
1112
1066
  # and if it is not it will print '{'.
1113
1067
  def if_break
1114
- doc = IfBreak.new
1068
+ break_contents = []
1069
+ flat_contents = []
1070
+
1071
+ doc = IfBreak.new(break_contents: break_contents, flat_contents: flat_contents)
1115
1072
  target << doc
1116
1073
 
1117
- with_target(doc.break_contents) { yield }
1118
- IfBreakBuilder.new(self, doc)
1074
+ with_target(break_contents) { yield }
1075
+
1076
+ if groups.last.break?
1077
+ IfFlatIgnore.new(self)
1078
+ else
1079
+ IfBreakBuilder.new(self, flat_contents)
1080
+ end
1119
1081
  end
1120
1082
 
1121
1083
  # This is similar to if_break in that it also inserts an IfBreak node into the
1122
1084
  # print tree, however it's starting from the flat contents, and cannot be used
1123
1085
  # to build the break contents.
1124
1086
  def if_flat
1125
- doc = IfBreak.new
1126
- target << doc
1087
+ if groups.last.break?
1088
+ contents = []
1089
+ group = Group.new(0, contents: contents)
1127
1090
 
1128
- with_target(doc.flat_contents) { yield }
1091
+ with_target(contents) { yield }
1092
+ break_parent if group.break?
1093
+ else
1094
+ flat_contents = []
1095
+ doc = IfBreak.new(break_contents: [], flat_contents: flat_contents)
1096
+ target << doc
1097
+
1098
+ with_target(flat_contents) { yield }
1099
+ doc
1100
+ end
1129
1101
  end
1130
1102
 
1131
1103
  # Very similar to the #nest method, this indents the nested content by one
1132
1104
  # level by inserting an Indent node into the print tree. The contents of the
1133
1105
  # node are determined by the block.
1134
1106
  def indent
1135
- doc = Indent.new
1107
+ contents = []
1108
+ doc = Indent.new(contents: contents)
1136
1109
  target << doc
1137
1110
 
1138
- with_target(doc.contents) { yield }
1111
+ with_target(contents) { yield }
1139
1112
  doc
1140
1113
  end
1141
1114
 
@@ -1152,10 +1125,11 @@ class PrettierPrint
1152
1125
  # Increases left margin after newline with +indent+ for line breaks added in
1153
1126
  # the block.
1154
1127
  def nest(indent)
1155
- doc = Align.new(indent: indent)
1128
+ contents = []
1129
+ doc = Align.new(indent: indent, contents: contents)
1156
1130
  target << doc
1157
1131
 
1158
- with_target(doc.contents) { yield }
1132
+ with_target(contents) { yield }
1159
1133
  doc
1160
1134
  end
1161
1135
 
@@ -1192,7 +1166,7 @@ class PrettierPrint
1192
1166
  # fit onto the remaining space on the current line. If we finish printing
1193
1167
  # all of the commands or if we hit a newline, then we return true. Otherwise
1194
1168
  # if we continue printing past the remaining space, we return false.
1195
- def fits?(next_command, rest_commands, remaining)
1169
+ def fits?(next_commands, rest_commands, remaining)
1196
1170
  # This is the index in the remaining commands that we've handled so far.
1197
1171
  # We reverse through the commands and add them to the stack if we've run
1198
1172
  # out of nodes to handle.
@@ -1200,7 +1174,7 @@ class PrettierPrint
1200
1174
 
1201
1175
  # This is our stack of commands, very similar to the commands list in the
1202
1176
  # print method.
1203
- commands = [next_command]
1177
+ commands = [*next_commands]
1204
1178
 
1205
1179
  # This is our output buffer, really only necessary to keep track of
1206
1180
  # because we could encounter a Trim doc node that would actually add
@@ -1219,25 +1193,12 @@ class PrettierPrint
1219
1193
  indent, mode, doc = commands.pop
1220
1194
 
1221
1195
  case doc
1222
- when Text
1223
- doc.objects.each { |object| fit_buffer << object }
1224
- remaining -= doc.width
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!
1196
+ when String
1197
+ fit_buffer << doc
1198
+ remaining -= doc.length
1233
1199
  when Group
1234
- commands << [indent, doc.break? ? MODE_BREAK : mode, doc.contents]
1235
- when IfBreak
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
1200
+ next_mode = doc.break? ? MODE_BREAK : mode
1201
+ commands += doc.contents.reverse.map { |part| [indent, next_mode, part] }
1241
1202
  when Breakable
1242
1203
  if mode == MODE_FLAT && !doc.force?
1243
1204
  fit_buffer << doc.separator
@@ -1246,6 +1207,23 @@ class PrettierPrint
1246
1207
  end
1247
1208
 
1248
1209
  return true
1210
+ when Indent
1211
+ next_indent = indent + 2
1212
+ commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
1213
+ when Align
1214
+ next_indent = indent + doc.indent
1215
+ commands += doc.contents.reverse.map { |part| [next_indent, mode, part] }
1216
+ when Trim
1217
+ remaining += fit_buffer.trim!
1218
+ when IfBreak
1219
+ if mode == MODE_BREAK && doc.break_contents.any?
1220
+ commands += doc.break_contents.reverse.map { |part| [indent, mode, part] }
1221
+ elsif mode == MODE_FLAT && doc.flat_contents.any?
1222
+ commands += doc.flat_contents.reverse.map { |part| [indent, mode, part] }
1223
+ end
1224
+ when Text
1225
+ doc.objects.each { |object| fit_buffer << object }
1226
+ remaining -= doc.width
1249
1227
  end
1250
1228
  end
1251
1229
 
@@ -1255,8 +1233,9 @@ class PrettierPrint
1255
1233
  # Resets the group stack and target array so that this pretty printer object
1256
1234
  # can continue to be used before calling flush again if desired.
1257
1235
  def reset
1258
- @groups = [Group.new(0)]
1259
- @target = @groups.last.contents
1236
+ contents = []
1237
+ @groups = [Group.new(0, contents: contents)]
1238
+ @target = contents
1260
1239
  end
1261
1240
 
1262
1241
  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: 0.1.0
4
+ version: 1.0.1
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-05-14 00:00:00.000000000 Z
11
+ date: 2022-10-18 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.4.0.dev
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.