oppen 0.9.6 → 0.9.7

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: 209072194fbb082bd25f2583b7f930e38c79ca042c21e711e18dd7295ee00e86
4
- data.tar.gz: 6eeb620d7d3bd6599477a46a2a5b9df86db2bc8c6a0f07a619d065245393127f
3
+ metadata.gz: b656616fe07cf5b29b8dfa43f0b72ed6dbf80c56a9ca6790745a8db27f058ed7
4
+ data.tar.gz: 3d46ddc3a703d029ac22460ac504cf2928f95d804d32e0266f0de7ffbbfd3359
5
5
  SHA512:
6
- metadata.gz: a2f8d7bd7b199b7ef0d5a97feebbe456fea9e557f6535760ad84b21a304d73c52ea954f392e7c07e0b682844fe86c0c8ccc4ef6786057785cba9f02f58c31c14
7
- data.tar.gz: 31a73892d3afff56d85c60a6756d6fedbd2bce259d7ca259b662a7f7002549fcb53146f2fb1a32136ae2c8cca03b20ded90d95a814363d18d0d80192db79c39b
6
+ metadata.gz: 7b69f0365a507dc9fca546cbfea064593a48d0d85140cd894ed2ff256e13c4c0e772bf9e0d2b29f9eefd9121c8b3adf03da93137c15b3c9570f6a7e49ed435b2
7
+ data.tar.gz: aa608fa2238dc8eea6bf3ce5d03f10e6f8059eda98c02d1e53fa06f9ac9301b03b42e54b38ed4f945c28766c4959b441cc190b76f0f176a72c7f52967096258a
data/lib/oppen/mixins.rb CHANGED
@@ -21,30 +21,50 @@ module Oppen
21
21
  #
22
22
  # @param tokens [Array[Token]]
23
23
  # @param base_indent [Integer]
24
+ # @param printer_name [String]
24
25
  #
25
26
  # @return [String]
26
- def tokens_to_wadler(tokens, base_indent = 4)
27
+ def tokens_to_wadler(tokens, base_indent: 0, printer_name: 'out')
28
+ nb_spaces = base_indent
27
29
  out = StringIO.new
28
- write = ->(txt, nb_spaces) {
29
- out.write("#{' ' * nb_spaces}#{txt}\n")
30
+
31
+ write = ->(txt) {
32
+ out << (' ' * nb_spaces) << txt << "\n"
30
33
  }
31
- nb_spaces = base_indent
34
+ display_break_token = ->(token) {
35
+ if token.offset.positive?
36
+ write.("#{printer_name}.nest(#{token.offset}, \"\", \"\") {")
37
+ nb_spaces += 2
38
+ end
39
+
40
+ case token
41
+ in Token::LineBreak
42
+ write.("#{printer_name}.break(line_continuation: #{token.line_continuation.inspect})")
43
+ in Token::Break
44
+ write.("#{printer_name}.breakable(#{token.str.inspect}, width: #{token.width}, " \
45
+ "line_continuation: #{token.line_continuation.inspect})")
46
+ end
47
+
48
+ if token.offset.positive?
49
+ nb_spaces -= 2
50
+ write.('}')
51
+ end
52
+ }
53
+
32
54
  tokens.each do |token|
33
55
  case token
34
56
  in Token::String
35
- write.call("out.text '#{token}'", nb_spaces)
36
- in Token::LineBreak
37
- write.call('out.break', nb_spaces)
57
+ write.("#{printer_name}.text(#{token.value.inspect}, width: #{token.width})")
38
58
  in Token::Break
39
- write.call('out.breakable', nb_spaces)
59
+ display_break_token.(token)
40
60
  in Token::Begin
41
- write.call('out.group {', nb_spaces)
61
+ write.("#{printer_name}.group(#{token.offset}, \"\", \"\", #{token.break_type_name}) {")
42
62
  nb_spaces += 2
43
63
  in Token::End
44
64
  nb_spaces -= 2
45
- write.call('}', nb_spaces)
65
+ write.('}')
46
66
  in Token::EOF
47
- write.call('', nb_spaces) # new line
67
+ write.('') # new line
48
68
  end
49
69
  end
50
70
  out.string
@@ -64,6 +64,7 @@ module Oppen
64
64
  #
65
65
  # @return [String]
66
66
  def output
67
+ buffer.truncate(buffer.pos)
67
68
  buffer.string
68
69
  end
69
70
 
@@ -73,16 +74,17 @@ module Oppen
73
74
  #
74
75
  # @param token [Token]
75
76
  # @param token_width [Integer]
77
+ # @param trim_on_break [Integer] Number of trailing whitespace characters to trim.
76
78
  #
77
79
  # @return [Nil]
78
- def print(token, token_width)
80
+ def print(token, token_width, trim_on_break: 0)
79
81
  case token
80
82
  in Token::Begin
81
83
  handle_begin token, token_width
82
84
  in Token::End
83
85
  handle_end
84
86
  in Token::Break
85
- handle_break token, token_width
87
+ handle_break token, token_width, trim_on_break:
86
88
  in Token::String
87
89
  handle_string token, token_width
88
90
  end
@@ -131,11 +133,12 @@ module Oppen
131
133
  #
132
134
  # @param token [Token]
133
135
  # @param token_width [Integer]
136
+ # @param trim_on_break [Integer] Number of trailing whitespace characters to trim.
134
137
  #
135
138
  # @return [Nil]
136
139
  #
137
140
  # @see Token::Break
138
- def handle_break(token, token_width)
141
+ def handle_break(token, token_width, trim_on_break: 0)
139
142
  block = top
140
143
  case block.break_type
141
144
  in Token::BreakType::FITS
@@ -149,6 +152,7 @@ module Oppen
149
152
  else
150
153
  width - space
151
154
  end
155
+ erase(trim_on_break)
152
156
  write token.line_continuation
153
157
  print_new_line indent
154
158
  in Token::BreakType::INCONSISTENT
@@ -160,6 +164,7 @@ module Oppen
160
164
  else
161
165
  width - space
162
166
  end
167
+ erase(trim_on_break)
163
168
  write token.line_continuation
164
169
  print_new_line indent
165
170
  else
@@ -245,6 +250,18 @@ module Oppen
245
250
  buffer.write(obj.to_s)
246
251
  end
247
252
 
253
+ # Erase the last `count` characters.
254
+ #
255
+ # @param count [Integer]
256
+ #
257
+ # @return [Nil]
258
+ def erase(count = 0)
259
+ raise ArgumentError, "count = #{count} must be non-negative" if count.negative?
260
+
261
+ buffer.seek(-count, IO::SEEK_CUR)
262
+ @space += count
263
+ end
264
+
248
265
  # Add indentation by `amount`.
249
266
  #
250
267
  # @note Called Indent as well in the original paper.
@@ -255,7 +272,7 @@ module Oppen
255
272
  def indent(amount)
256
273
  raise ArgumentError 'Indenting using negative amount' if amount.negative?
257
274
 
258
- write genspace.call(amount) if amount.positive?
275
+ write genspace.(amount) if amount.positive?
259
276
  end
260
277
  end
261
278
  end
data/lib/oppen/printer.rb CHANGED
@@ -78,6 +78,7 @@ module Oppen
78
78
  n = 3 * width
79
79
 
80
80
  @config = config
81
+ @last_whitespaces_width = 0
81
82
  @left = 0
82
83
  @left_total = 1
83
84
  @print_stack = PrintStack.new width, new_line, config, space, out
@@ -110,7 +111,11 @@ module Oppen
110
111
  handle_end token
111
112
  in Token::Break
112
113
  handle_break token
114
+ in Token::Whitespace
115
+ @last_whitespaces_width += token.width
116
+ handle_string token
113
117
  in Token::String
118
+ @last_whitespaces_width = 0
114
119
  handle_string token
115
120
  end
116
121
  end
@@ -139,6 +144,9 @@ module Oppen
139
144
  @left_total = 1
140
145
  @right = 0
141
146
  @right_total = 1
147
+
148
+ # config.trim_trailing_whitespaces
149
+ @tokens[-1] = nil
142
150
  else
143
151
  advance_right
144
152
  end
@@ -179,6 +187,11 @@ module Oppen
179
187
  @left_total = 1
180
188
  @right = 0
181
189
  @right_total = 1
190
+
191
+ # config.trim_trailing_whitespaces
192
+ tokens[-1] = nil
193
+ print_stack.erase @last_whitespaces_width
194
+ @last_whitespaces_width = 0
182
195
  else
183
196
  advance_right
184
197
  end
@@ -202,7 +215,7 @@ module Oppen
202
215
  tokens[right] = token
203
216
  size[right] = token.width
204
217
  @right_total += token.width
205
- check_stream
218
+ check_stream if @last_whitespaces_width.zero?
206
219
  end
207
220
  end
208
221
 
@@ -249,7 +262,26 @@ module Oppen
249
262
  def advance_left(token, token_width)
250
263
  return if token_width.negative?
251
264
 
252
- print_stack.print token, token_width
265
+ trim_on_break =
266
+ if token.is_a?(Token::Break)
267
+ # Find the first previous String token.
268
+ idx = (left - 1) % tokens.length
269
+ while idx != right && tokens[idx] && !tokens[idx].is_a?(Token::String) \
270
+ && !tokens[idx].is_a?(Token::Break)
271
+ idx = (idx - 1) % tokens.length
272
+ end
273
+ # Sum the widths of the last whitespace tokens.
274
+ total = 0
275
+ while tokens[idx].is_a?(Token::Whitespace)
276
+ total += tokens[idx].width
277
+ idx = (idx - 1) % tokens.length
278
+ end
279
+ @last_whitespaces_width = 0
280
+ total
281
+ end
282
+ trim_on_break ||= 0
283
+
284
+ print_stack.print(token, token_width, trim_on_break:)
253
285
 
254
286
  case token
255
287
  when Token::Break
@@ -260,7 +292,7 @@ module Oppen
260
292
 
261
293
  return if left == right
262
294
 
263
- @left = (left + 1) % scan_stack.length
295
+ @left = (left + 1) % tokens.length
264
296
  advance_left tokens[left], size[left]
265
297
  end
266
298
 
data/lib/oppen/token.rb CHANGED
@@ -39,6 +39,12 @@ module Oppen
39
39
  def to_s = value
40
40
  end
41
41
 
42
+ # If a [Token::Break] follows [Token::Whitespace], and an actual break
43
+ # is issued, and `trim_trailing_whitespaces == true`, then all whitespace
44
+ # text will be omitted from the output.
45
+ class Whitespace < ::Oppen::Token::String
46
+ end
47
+
42
48
  # Break Token.
43
49
  class Break < Token
44
50
  # @return [String] If a new line is needed display this string before the new line
@@ -89,6 +95,17 @@ module Oppen
89
95
  @break_type = break_type
90
96
  super()
91
97
  end
98
+
99
+ # The break_type name as a String.
100
+ #
101
+ # @return [String]
102
+ def break_type_name
103
+ case @break_type
104
+ in BreakType::FITS then 'Oppen::Token::BreakType::FITS'
105
+ in BreakType::INCONSISTENT then 'Oppen::Token::BreakType::INCONSISTENT'
106
+ in BreakType::CONSISTENT then 'Oppen::Token::BreakType::CONSISTENT'
107
+ end
108
+ end
92
109
  end
93
110
 
94
111
  # End Token
data/lib/oppen/version.rb CHANGED
@@ -5,5 +5,5 @@ module Oppen
5
5
  # Oppen version
6
6
  #
7
7
  # @return [String] current version
8
- VERSION = '0.9.6' # managed by release.sh
8
+ VERSION = '0.9.7' # managed by release.sh
9
9
  end
data/lib/oppen.rb CHANGED
@@ -51,9 +51,11 @@ module Oppen
51
51
 
52
52
  attr_accessor :indent_anchor
53
53
 
54
- def initialize(indent_anchor: IndentAnchor::ON_BREAK, eager_print: false, upsize_stack: false)
54
+ def initialize(indent_anchor: IndentAnchor::ON_BREAK, eager_print: false,
55
+ trim_trailing_whitespaces: false, upsize_stack: false)
55
56
  @indent_anchor = indent_anchor
56
57
  @eager_print = eager_print
58
+ @trim_trailing_whitespaces = trim_trailing_whitespaces
57
59
  @upsize_stack = upsize_stack
58
60
  end
59
61
 
@@ -88,6 +90,8 @@ module Oppen
88
90
  # @return [Boolean]
89
91
  def eager_print? = @eager_print
90
92
 
93
+ def trim_trailing_whitespaces? = @trim_trailing_whitespaces
94
+
91
95
  def upsize_stack? = @upsize_stack
92
96
 
93
97
  # Default config for Oppen usage
@@ -98,8 +102,8 @@ module Oppen
98
102
 
99
103
  # Default config for Wadler usage
100
104
  # @return [Config]
101
- def self.wadler(eager_print: true, upsize_stack: true)
102
- new(indent_anchor: IndentAnchor::ON_BEGIN, eager_print:, upsize_stack:)
105
+ def self.wadler(eager_print: true, trim_trailing_whitespaces: true, upsize_stack: true)
106
+ new(indent_anchor: IndentAnchor::ON_BEGIN, eager_print:, trim_trailing_whitespaces:, upsize_stack:)
103
107
  end
104
108
  end
105
109
 
@@ -111,6 +115,13 @@ module Oppen
111
115
  Token::String.new(value, width:)
112
116
  end
113
117
 
118
+ # @see Token::Whitespace
119
+ #
120
+ # @return [Oppen::Token::Whitespace] a new Whitespace token.
121
+ def self.whitespace(value)
122
+ Token::Whitespace.new(value, width: value.bytesize)
123
+ end
124
+
114
125
  # @param str [String]
115
126
  # @param line_continuation [String] If a new line is needed display this string before the new line
116
127
  # @param offset [Integer]
data/lib/wadler/print.rb CHANGED
@@ -10,6 +10,7 @@ module Oppen
10
10
  attr_reader :new_line
11
11
  attr_reader :out
12
12
  attr_reader :tokens
13
+ attr_reader :whitespace
13
14
  attr_reader :width
14
15
 
15
16
  # @param config [Oppen::Config]
@@ -22,8 +23,11 @@ module Oppen
22
23
  # @param new_line [String]
23
24
  # @param out [Object] should have a write and string method
24
25
  # @param width [Integer]
26
+ # @param whitespace [String] the whitespace character. Used to trim trailing whitespaces.
27
+ # @see Token::Whitespace
25
28
  def initialize(config: Config.wadler, space: ' ',
26
- new_line: "\n", out: StringIO.new, width: 80)
29
+ new_line: "\n", out: StringIO.new,
30
+ width: 80, whitespace: ' ')
27
31
  @config = config
28
32
  @current_indent = 0
29
33
  @space = space
@@ -31,20 +35,37 @@ module Oppen
31
35
  @new_line = new_line
32
36
  @out = out
33
37
  @tokens = []
38
+ @whitespace = whitespace
34
39
  end
35
40
 
36
- # @return [String]
37
- def output
41
+ # Add missing Begin, End or EOF tokens.
42
+ # @return [Nil]
43
+ def add_missing_begin_and_end
38
44
  if !tokens.first.is_a? Token::Begin
39
45
  tokens.unshift Oppen.begin_consistent(offset: 0)
40
46
  tokens << Oppen.end
41
47
  end
42
- if !tokens.last.is_a? Oppen::Token::EOF
43
- tokens << Oppen.eof
44
- end
48
+ tokens << Oppen.eof if !tokens.last.is_a?(Oppen::Token::EOF)
49
+ end
50
+
51
+ # Generate the output string of the built list of tokens
52
+ # using Oppen's pretty printing algorithm.
53
+ #
54
+ # @return [String]
55
+ def output
56
+ add_missing_begin_and_end
45
57
  Oppen.print(tokens:, new_line:, config:, space:, out:, width:)
46
58
  end
47
59
 
60
+ # Generate the the list of Wadler commands needed to build the built
61
+ # list of tokens.
62
+ #
63
+ # @return [String]
64
+ def show_print_commands(**)
65
+ add_missing_begin_and_end
66
+ Oppen.tokens_to_wadler(tokens, **)
67
+ end
68
+
48
69
  # @param indent [Integer] group indentation
49
70
  # @param open_obj [String] group opening delimiter
50
71
  # @param close_obj [String] group closing delimiter
@@ -84,11 +105,9 @@ module Oppen
84
105
  # @param indent [Integer] nest indentation
85
106
  # @param open_obj [String] nest opening delimiter
86
107
  # @param close_obj [String] nest closing delimiter
87
- # @param break_type [Oppen::Token::BreakType] nest breaking type
88
108
  #
89
109
  # @return [Nil]
90
- def nest(indent, open_obj = '', close_obj = '',
91
- break_type = Oppen::Token::BreakType::CONSISTENT)
110
+ def nest(indent, open_obj = '', close_obj = '')
92
111
  raise ArgumentError, "#{open_obj.nil? ? 'open_obj' : 'close_obj'} cannot be nil" \
93
112
  if open_obj.nil? || close_obj.nil?
94
113
 
@@ -115,7 +134,16 @@ module Oppen
115
134
  #
116
135
  # @return [Nil]
117
136
  def text(value, width: value.length)
118
- tokens << Oppen.string(value, width:)
137
+ if config.trim_trailing_whitespaces? && value.match(/((?:#{Regexp.escape(whitespace)})+)\z/)
138
+ match = Regexp.last_match(1)
139
+ matched_length = match.length
140
+ if value.length != matched_length
141
+ tokens << Oppen.string(value[0...-matched_length], width: width - matched_length)
142
+ end
143
+ tokens << Oppen.whitespace(match)
144
+ else
145
+ tokens << Oppen.string(value, width:)
146
+ end
119
147
  end
120
148
 
121
149
  # @param str [String]
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oppen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amine Mike El Maalouf <amine.el-maalouf@epita.fr>
8
- - Firas al-Khalil <firasalkhalil@gmail.com>
8
+ - Firas al-Khalil <firas.alkhalil@faveod.com>
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-11-25 00:00:00.000000000 Z
12
+ date: 2024-12-05 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Implementation of the Oppen's pretty printing algorithm
15
15
  email: