opulent 0.0.9 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +9 -0
- data/.libold/opulent.rb +96 -0
- data/.libold/opulent/context.rb +80 -0
- data/.libold/opulent/engine.rb +88 -0
- data/.libold/opulent/filter.rb +101 -0
- data/.libold/opulent/logger.rb +67 -0
- data/.libold/opulent/nodes.rb +13 -0
- data/.libold/opulent/nodes/block.rb +29 -0
- data/.libold/opulent/nodes/comment.rb +35 -0
- data/.libold/opulent/nodes/control.rb +230 -0
- data/.libold/opulent/nodes/define.rb +42 -0
- data/.libold/opulent/nodes/eval.rb +41 -0
- data/.libold/opulent/nodes/expression.rb +28 -0
- data/.libold/opulent/nodes/filter.rb +70 -0
- data/.libold/opulent/nodes/helper.rb +69 -0
- data/.libold/opulent/nodes/node.rb +101 -0
- data/.libold/opulent/nodes/root.rb +62 -0
- data/.libold/opulent/nodes/text.rb +54 -0
- data/.libold/opulent/nodes/theme.rb +36 -0
- data/.libold/opulent/parser.rb +252 -0
- data/.libold/opulent/parser/block.rb +70 -0
- data/.libold/opulent/parser/comment.rb +32 -0
- data/.libold/opulent/parser/control.rb +83 -0
- data/.libold/opulent/parser/define.rb +39 -0
- data/.libold/opulent/parser/eval.rb +33 -0
- data/.libold/opulent/parser/expression.rb +350 -0
- data/.libold/opulent/parser/filter.rb +41 -0
- data/.libold/opulent/parser/node.rb +232 -0
- data/.libold/opulent/parser/root.rb +96 -0
- data/.libold/opulent/parser/text.rb +114 -0
- data/.libold/opulent/parser/theme.rb +36 -0
- data/.libold/opulent/preprocessor.rb +102 -0
- data/.libold/opulent/runtime.rb +144 -0
- data/.libold/opulent/template.rb +43 -0
- data/.libold/opulent/tokens.rb +276 -0
- data/.libold/opulent/version.rb +5 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +102 -0
- data/Rakefile +6 -0
- data/benchmark/benchmark.rb +46 -0
- data/benchmark/cases/node/node.haml +17 -0
- data/benchmark/cases/node/node.op +14 -0
- data/benchmark/cases/node/node.slim +19 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/docs/syntax.md +3 -0
- data/docs/usage.md +3 -0
- data/lib/opulent.rb +11 -64
- data/lib/opulent/compiler.rb +132 -0
- data/lib/opulent/compiler/block.rb +31 -0
- data/lib/opulent/compiler/comment.rb +22 -0
- data/lib/opulent/compiler/control.rb +152 -0
- data/lib/opulent/compiler/define.rb +88 -0
- data/lib/opulent/compiler/eval.rb +15 -0
- data/lib/opulent/compiler/filter.rb +54 -0
- data/lib/opulent/compiler/node.rb +232 -0
- data/lib/opulent/compiler/root.rb +19 -0
- data/lib/opulent/compiler/text.rb +60 -0
- data/lib/opulent/context.rb +88 -0
- data/lib/opulent/engine.rb +60 -0
- data/lib/opulent/filters.rb +222 -0
- data/lib/opulent/logger.rb +47 -0
- data/lib/opulent/parser.rb +196 -0
- data/lib/opulent/parser/block.rb +56 -0
- data/lib/opulent/parser/comment.rb +27 -0
- data/lib/opulent/parser/control.rb +112 -0
- data/lib/opulent/parser/define.rb +30 -0
- data/lib/opulent/parser/eval.rb +21 -0
- data/lib/opulent/parser/expression.rb +344 -0
- data/lib/opulent/parser/filter.rb +25 -0
- data/lib/opulent/parser/node.rb +246 -0
- data/lib/opulent/parser/root.rb +48 -0
- data/lib/opulent/parser/text.rb +127 -0
- data/lib/opulent/settings.rb +79 -0
- data/lib/opulent/template.rb +67 -0
- data/lib/opulent/tokens.rb +166 -0
- data/lib/opulent/version.rb +4 -0
- data/opulent.gemspec +36 -0
- metadata +160 -7
@@ -0,0 +1,41 @@
|
|
1
|
+
# @SugarCube
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
module Parser
|
5
|
+
# @Text
|
6
|
+
module Filter
|
7
|
+
# Check if we match an compile time filter
|
8
|
+
#
|
9
|
+
# :filter
|
10
|
+
#
|
11
|
+
# @param parent [Node] Parent node to which we append the element
|
12
|
+
#
|
13
|
+
def filter_element(parent)
|
14
|
+
if lookahead :filter_lookahead
|
15
|
+
# Get current line's indentation
|
16
|
+
indent = accept_unstripped(:indent) || ""
|
17
|
+
|
18
|
+
if (filter_name = accept :filter)
|
19
|
+
# Get element attributes
|
20
|
+
atts = attributes({}) || {}
|
21
|
+
|
22
|
+
# Create a new node and set its extension
|
23
|
+
filter_node = @create.filter filter_name.to_sym, atts, parent, indent.size
|
24
|
+
|
25
|
+
# Accept inline text or multiline text feed as first child
|
26
|
+
if(text_node = text filter_node, indent, true)
|
27
|
+
#filter_node.atts = accept_unstripped(:line_feed)
|
28
|
+
error :fiter unless accept_line(:line_feed).strip.empty?
|
29
|
+
end
|
30
|
+
accept_unstripped(:newline)
|
31
|
+
|
32
|
+
# Get everything under the filter and set it as the node value
|
33
|
+
filter_node.value += get_indented_lines(indent.size)
|
34
|
+
|
35
|
+
return filter_node
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
module Parser
|
5
|
+
# @node
|
6
|
+
module Node
|
7
|
+
# Check if we match an node node with its attributes and possibly
|
8
|
+
# inline text
|
9
|
+
#
|
10
|
+
# node [ attributes ] Inline text
|
11
|
+
#
|
12
|
+
# @param parent [Node] Parent node to which we append the node
|
13
|
+
#
|
14
|
+
def node(parent, indent = nil)
|
15
|
+
if (name = lookahead :identifier_lookahead)
|
16
|
+
return nil if Tokens.keyword name
|
17
|
+
|
18
|
+
# Get current line's indentation
|
19
|
+
unless indent
|
20
|
+
indent = accept_unstripped(:indent) || ""
|
21
|
+
indent = indent.size
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get a theme if set, or set append definitions to the default
|
25
|
+
# element namespace
|
26
|
+
if (theme_name = accept_unstripped(:theme_node))
|
27
|
+
theme_name = theme_name.to_sym
|
28
|
+
else
|
29
|
+
theme_name = Engine::DEFAULT_THEME
|
30
|
+
end
|
31
|
+
|
32
|
+
# Accept either explicit node_name or implicit :div node_name
|
33
|
+
# with shorthand attributes
|
34
|
+
if (node_name = accept :identifier)
|
35
|
+
shorthand = shorthand_attributes
|
36
|
+
elsif (shorthand = shorthand_attributes)
|
37
|
+
node_name = :div
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get leading and trailing whitespace
|
41
|
+
if accept_line_unstripped :leading_whitespace
|
42
|
+
leading_whitespace = true
|
43
|
+
if accept_line_unstripped :leading_trailing_whitespace
|
44
|
+
trailing_whitespace = true
|
45
|
+
end
|
46
|
+
elsif accept_line_unstripped :trailing_whitespace
|
47
|
+
trailing_whitespace = true
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get wrapped node attributes
|
51
|
+
atts = attributes(shorthand) || {}
|
52
|
+
|
53
|
+
# Inherit attributes from definition
|
54
|
+
extension = extend_attributes
|
55
|
+
|
56
|
+
# Get unwrapped node attributes
|
57
|
+
atts = attributes_assignments atts, false
|
58
|
+
|
59
|
+
# Create a new node and set its extension
|
60
|
+
_node = @create.node node_name.to_sym, atts, parent, indent, []
|
61
|
+
_node.extension = extension
|
62
|
+
_node.theme = theme_name
|
63
|
+
_node.whitespace = [leading_whitespace, trailing_whitespace]
|
64
|
+
|
65
|
+
if(accept_line :inline_child)
|
66
|
+
if (child_node = node _node, indent + Engine[:indent])
|
67
|
+
_node.push child_node
|
68
|
+
else
|
69
|
+
error :inline_child
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if(close = accept_line :self_enclosing)
|
74
|
+
_node.self_enclosing = true
|
75
|
+
unless close.strip.empty?
|
76
|
+
undo close
|
77
|
+
error :self_enclosing
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Accept inline text or multiline text feed as first child
|
82
|
+
if(text_node = text _node, " " * indent, false)
|
83
|
+
text_node.indent += Engine[:indent]
|
84
|
+
_node.push text_node unless text_node.nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
return _node
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def shorthand_attributes(atts = {})
|
92
|
+
find_shorthand = Proc.new do
|
93
|
+
Engine[:shorthand].find do |key, value|
|
94
|
+
if accept_unstripped :"shorthand@#{key}"
|
95
|
+
key
|
96
|
+
else
|
97
|
+
false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
while (attribute = find_shorthand[])
|
103
|
+
key = attribute[0]
|
104
|
+
|
105
|
+
# Get the attribute value and process it
|
106
|
+
if (value = accept_unstripped(:identifier))
|
107
|
+
value = @create.expression "\"#{value}\""
|
108
|
+
elsif (value = (accept_unstripped(:exp_string) || paranthesis))
|
109
|
+
value = @create.expression "#{value}"
|
110
|
+
else
|
111
|
+
error :shorthand
|
112
|
+
end
|
113
|
+
|
114
|
+
# IDs are unique, the rest of the attributes turn into arrays in
|
115
|
+
# order to allow multiple values or identifiers
|
116
|
+
if key == :id
|
117
|
+
atts[key] = value
|
118
|
+
else
|
119
|
+
if atts[key].is_a? Array
|
120
|
+
atts[key] << value
|
121
|
+
elsif atts[key]
|
122
|
+
atts[key] = [atts[key], value]
|
123
|
+
else
|
124
|
+
atts[key] = [value]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
return atts
|
130
|
+
end
|
131
|
+
|
132
|
+
# Extend node attributes with hash from
|
133
|
+
#
|
134
|
+
# [hash]
|
135
|
+
#
|
136
|
+
def extend_attributes
|
137
|
+
if (accept_unstripped :extend_attributes)
|
138
|
+
bracket = accept_unstripped :brackets, :*
|
139
|
+
extension = expression
|
140
|
+
accept bracket.to_sym, :*
|
141
|
+
return extension
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Check if we match node attributes
|
146
|
+
#
|
147
|
+
# [ assignments ]
|
148
|
+
#
|
149
|
+
# @param as_parameters [Boolean] Accept or reject identifier nodes
|
150
|
+
#
|
151
|
+
def attributes(list)
|
152
|
+
if (bracket = accept_unstripped :brackets)
|
153
|
+
attributes_assignments list
|
154
|
+
accept bracket.to_sym, :*
|
155
|
+
end
|
156
|
+
|
157
|
+
return list
|
158
|
+
end
|
159
|
+
|
160
|
+
# Check if we match an expression node or
|
161
|
+
# a node node
|
162
|
+
#
|
163
|
+
# [ assignments ]
|
164
|
+
#
|
165
|
+
# @param parent [Hash] Parent to which we append nodes
|
166
|
+
# @param as_parameters [Boolean] Accept or reject identifier nodes
|
167
|
+
#
|
168
|
+
def attributes_assignments(parent, wrapped = true)
|
169
|
+
unless wrapped
|
170
|
+
return parent if lookahead(:assignment_lookahead).nil?
|
171
|
+
end
|
172
|
+
|
173
|
+
if (argument = accept :identifier)
|
174
|
+
argument = argument.to_sym
|
175
|
+
|
176
|
+
if accept :assignment
|
177
|
+
# Check if we have an attribute escape or not
|
178
|
+
escaped = if accept_unstripped :assignment_unescaped
|
179
|
+
false
|
180
|
+
else
|
181
|
+
true
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get the argument value if we have an assignment
|
185
|
+
if (value = expression(false, wrapped))
|
186
|
+
value.escaped = escaped
|
187
|
+
|
188
|
+
# Check if our argument already exists in the attributes list, and
|
189
|
+
# if it does, check if it's an array. If it isn't, turn it into an
|
190
|
+
# array literal, otherwise push the value into it. However, id
|
191
|
+
# attributes do not get turned into arrays as they are supposed
|
192
|
+
# to be unique
|
193
|
+
if parent[argument] && argument != :id
|
194
|
+
# Check if argument is already an array, otherwise create an
|
195
|
+
# array in which we will add values
|
196
|
+
if parent[argument].is_a? Array
|
197
|
+
parent[argument] << value
|
198
|
+
else
|
199
|
+
new_parent = []
|
200
|
+
new_parent.push parent[argument]
|
201
|
+
|
202
|
+
parent[argument] = new_parent
|
203
|
+
parent[argument] << value
|
204
|
+
end
|
205
|
+
else
|
206
|
+
parent[argument] = value
|
207
|
+
end
|
208
|
+
else
|
209
|
+
error :assignments_colon
|
210
|
+
end
|
211
|
+
else
|
212
|
+
parent[argument] = @create.expression "true" unless parent[argument]
|
213
|
+
end
|
214
|
+
|
215
|
+
# If our attributes are wrapped, we allow method calls without
|
216
|
+
# paranthesis, ruby style, therefore we need a terminator to signify
|
217
|
+
# the expression end. If they are not wrapped (inline), we require
|
218
|
+
# paranthesis and allow inline calls
|
219
|
+
if wrapped && accept_line(:assignment_terminator)
|
220
|
+
attributes_assignments parent, wrapped
|
221
|
+
elsif lookahead(:assignment_lookahead)
|
222
|
+
attributes_assignments parent, wrapped
|
223
|
+
end
|
224
|
+
|
225
|
+
return parent
|
226
|
+
elsif !parent.empty?
|
227
|
+
error :assignments_comma
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
module Parser
|
5
|
+
# @Root
|
6
|
+
module Root
|
7
|
+
# Check if we match any root element. This is the starting point of the
|
8
|
+
# parser and it checks for any elements which can be considered as root
|
9
|
+
#
|
10
|
+
# @param parent [Node] Parent element to append to
|
11
|
+
# @param min_indent [Integer] Minimum indent to which the root responds
|
12
|
+
#
|
13
|
+
def root(parent)
|
14
|
+
# Starting line of the root method
|
15
|
+
starting_line = @current_line
|
16
|
+
|
17
|
+
# Skip any whitespace at the beginning of the document
|
18
|
+
accept_unstripped :newline
|
19
|
+
|
20
|
+
if(element = define(parent))
|
21
|
+
# Add definition elements to the root's knowledgebase and add elements
|
22
|
+
# and evaluate elements to their parent elements
|
23
|
+
if parent.is_a? Nodes::Root
|
24
|
+
@root.themes[Engine::DEFAULT_THEME][element.name] = element
|
25
|
+
elsif parent.is_a? Nodes::Theme
|
26
|
+
@root.themes[parent.name][element.name] = element
|
27
|
+
else
|
28
|
+
error :definition
|
29
|
+
end
|
30
|
+
elsif(element = theme(parent))
|
31
|
+
# Theme nodes cannot be nested, so we accept only a root parent and
|
32
|
+
# we add the node in the themes hash and we allow reopening the theme
|
33
|
+
# and adding more definitions to it, ruby style
|
34
|
+
if parent.is_a? Nodes::Root
|
35
|
+
@root.themes[element.name] ||= {}
|
36
|
+
else
|
37
|
+
error :theme
|
38
|
+
end
|
39
|
+
elsif (element = node(parent) ||
|
40
|
+
text(parent) ||
|
41
|
+
comment(parent) ||
|
42
|
+
control(parent) ||
|
43
|
+
evaluate(parent) ||
|
44
|
+
filter_element(parent) ||
|
45
|
+
html_text(parent))
|
46
|
+
parent.push element
|
47
|
+
elsif (element = block_yield(parent))
|
48
|
+
# Handle yield node by searching for ther definition parent node
|
49
|
+
yield_parent = element.parent
|
50
|
+
begin
|
51
|
+
until [Nodes::Define, Nodes::Root].include? yield_parent.class
|
52
|
+
yield_parent = yield_parent.parent
|
53
|
+
end
|
54
|
+
rescue NoMethodError
|
55
|
+
error :yield_parent
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add the yield element to the parent and keep a pointer to the parent
|
59
|
+
# for each yield element to avoid recursive searching as much as
|
60
|
+
# possible
|
61
|
+
parent.push element
|
62
|
+
yield_parent.yields << parent
|
63
|
+
elsif (element = block(parent))
|
64
|
+
# Blocks will be set as separate entities for the parent element in
|
65
|
+
# order to replace them fast in the definition yields
|
66
|
+
parent.blocks[element.name] ||= []
|
67
|
+
parent.blocks[element.name] << element
|
68
|
+
end
|
69
|
+
|
70
|
+
next_indent = lookahead(:indent_lookahead, false).length
|
71
|
+
if element
|
72
|
+
if next_indent > element.indent
|
73
|
+
# If we have an indentation which is greater than the current one,
|
74
|
+
# set the current element as a root element and add children to it
|
75
|
+
root element
|
76
|
+
elsif next_indent < element.indent
|
77
|
+
# If we have an indentation which is smaller than the current one,
|
78
|
+
# go through the current element's ancestors until we find one with
|
79
|
+
# the same indentation as the next element
|
80
|
+
next_parent = element.parent
|
81
|
+
while next_parent.indent > next_indent
|
82
|
+
next_parent = next_parent.parent
|
83
|
+
end
|
84
|
+
next_parent = next_parent.parent
|
85
|
+
|
86
|
+
root next_parent
|
87
|
+
else
|
88
|
+
# If the indentation level stays the same, the parent element will
|
89
|
+
# remain the current one
|
90
|
+
root parent
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# @SugarCube
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
module Parser
|
5
|
+
# @Text
|
6
|
+
module Text
|
7
|
+
# Match one line or multiline, escaped or unescaped text
|
8
|
+
#
|
9
|
+
def text(parent, indent = nil, only_multiline = true)
|
10
|
+
indent = indent || accept_unstripped(:indent) || ""
|
11
|
+
|
12
|
+
# Try to see if we can match a multiline operator. If we can accept only
|
13
|
+
# multiline, which is the case for filters, undo the operation.
|
14
|
+
if accept_line :multiline
|
15
|
+
multiline = true
|
16
|
+
elsif only_multiline
|
17
|
+
return undo indent unless lookahead :print_lookahead
|
18
|
+
end
|
19
|
+
|
20
|
+
indent = indent.size
|
21
|
+
|
22
|
+
# Unescaped Print Eval
|
23
|
+
if (text_feed = accept_unstripped :unescaped_print)
|
24
|
+
text_node = @create.print(text_feed.strip, false, parent, indent)
|
25
|
+
# Escaped Print Eval
|
26
|
+
elsif (text_feed = accept_unstripped :escaped_print)
|
27
|
+
text_node = @create.print(text_feed.strip, true, parent, indent)
|
28
|
+
# Unescaped Text
|
29
|
+
elsif (text_feed = accept_unstripped :unescaped_text)
|
30
|
+
text_node = @create.text(text_feed.strip, false, parent, indent)
|
31
|
+
# Escaped Text
|
32
|
+
elsif (text_feed = accept_unstripped :escaped_text)
|
33
|
+
text_node = @create.text(text_feed.strip, true, parent, indent)
|
34
|
+
else
|
35
|
+
# Undo by adding the found intentation back
|
36
|
+
undo indent
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
if text_node
|
42
|
+
text_node
|
43
|
+
if multiline
|
44
|
+
text_node.value += accept_unstripped(:newline) || ""
|
45
|
+
text_node.value += get_indented_lines(indent)
|
46
|
+
|
47
|
+
text_node
|
48
|
+
else
|
49
|
+
accept_unstripped :newline
|
50
|
+
|
51
|
+
text_node.value.strip!
|
52
|
+
text_node.value = text_node.value[1..-1] if text_node.value[0] == '\\'
|
53
|
+
text_node.value.size > 0 ? text_node : nil
|
54
|
+
end
|
55
|
+
else
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Match one line or multiline, escaped or unescaped text
|
61
|
+
#
|
62
|
+
def html_text(parent)
|
63
|
+
indent = accept_unstripped(:indent) || ""
|
64
|
+
indent_size = indent.size
|
65
|
+
|
66
|
+
if (text_feed = accept_unstripped :html_text)
|
67
|
+
text_node = @create.text(text_feed.strip, false, parent, indent_size)
|
68
|
+
accept_unstripped :newline
|
69
|
+
pp text_feed
|
70
|
+
return text_node
|
71
|
+
else
|
72
|
+
return undo indent
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Match a whitespace by preventing code trimming
|
77
|
+
#
|
78
|
+
def whitespace(required = false)
|
79
|
+
accept_unstripped :whitespace, required
|
80
|
+
end
|
81
|
+
|
82
|
+
# Gather all the lines which have higher indentation than the one given as
|
83
|
+
# parameter and put them into the buffer
|
84
|
+
#
|
85
|
+
# @param indentation [Fixnum] parent node strating indentation
|
86
|
+
#
|
87
|
+
def get_indented_lines(indent)
|
88
|
+
buffer = ''
|
89
|
+
|
90
|
+
# Get the next indentation after the parent line
|
91
|
+
# and set it as primary indent
|
92
|
+
first_indent = lookahead(:indent_lookahead, false).size
|
93
|
+
next_indent = first_indent
|
94
|
+
|
95
|
+
# While the indentation is smaller, add the line feed to our buffer
|
96
|
+
while next_indent > indent
|
97
|
+
# Get leading whitespace trimmed with first_indent's size
|
98
|
+
next_line_indent = accept_unstripped(:indent)[first_indent..-1] || ""
|
99
|
+
next_line_indent = next_line_indent.size
|
100
|
+
|
101
|
+
# Add next line feed, prepend the indent and append the newline
|
102
|
+
buffer += " " * next_line_indent if next_line_indent > 0
|
103
|
+
buffer += accept_unstripped(:line_feed) || ""
|
104
|
+
buffer += accept_unstripped(:newline) || ""
|
105
|
+
|
106
|
+
# Get next indentation and repeat
|
107
|
+
next_indent = lookahead(:indent_lookahead, false).size
|
108
|
+
end
|
109
|
+
|
110
|
+
buffer
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|