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 +4 -4
- data/lib/oppen/mixins.rb +31 -11
- data/lib/oppen/print_stack.rb +21 -4
- data/lib/oppen/printer.rb +35 -3
- data/lib/oppen/token.rb +17 -0
- data/lib/oppen/version.rb +1 -1
- data/lib/oppen.rb +14 -3
- data/lib/wadler/print.rb +38 -10
- 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: b656616fe07cf5b29b8dfa43f0b72ed6dbf80c56a9ca6790745a8db27f058ed7
|
4
|
+
data.tar.gz: 3d46ddc3a703d029ac22460ac504cf2928f95d804d32e0266f0de7ffbbfd3359
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
27
|
+
def tokens_to_wadler(tokens, base_indent: 0, printer_name: 'out')
|
28
|
+
nb_spaces = base_indent
|
27
29
|
out = StringIO.new
|
28
|
-
|
29
|
-
|
30
|
+
|
31
|
+
write = ->(txt) {
|
32
|
+
out << (' ' * nb_spaces) << txt << "\n"
|
30
33
|
}
|
31
|
-
|
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.
|
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
|
-
|
59
|
+
display_break_token.(token)
|
40
60
|
in Token::Begin
|
41
|
-
write.
|
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.
|
65
|
+
write.('}')
|
46
66
|
in Token::EOF
|
47
|
-
write.
|
67
|
+
write.('') # new line
|
48
68
|
end
|
49
69
|
end
|
50
70
|
out.string
|
data/lib/oppen/print_stack.rb
CHANGED
@@ -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.
|
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
|
-
|
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) %
|
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
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,
|
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,
|
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
|
-
#
|
37
|
-
|
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?
|
43
|
-
|
44
|
-
|
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
|
-
|
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.
|
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 <
|
8
|
+
- Firas al-Khalil <firas.alkhalil@faveod.com>
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
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:
|