gitlab-rouge 1.9.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.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +23 -0
  3. data/LICENSE +186 -0
  4. data/bin/rougify +16 -0
  5. data/gitlab-rouge.gemspec +17 -0
  6. data/lib/rouge.rb +57 -0
  7. data/lib/rouge/cli.rb +363 -0
  8. data/lib/rouge/demos/apache +21 -0
  9. data/lib/rouge/demos/applescript +2 -0
  10. data/lib/rouge/demos/c +8 -0
  11. data/lib/rouge/demos/clojure +5 -0
  12. data/lib/rouge/demos/coffeescript +5 -0
  13. data/lib/rouge/demos/common_lisp +1 -0
  14. data/lib/rouge/demos/conf +4 -0
  15. data/lib/rouge/demos/cpp +8 -0
  16. data/lib/rouge/demos/csharp +5 -0
  17. data/lib/rouge/demos/css +4 -0
  18. data/lib/rouge/demos/dart +6 -0
  19. data/lib/rouge/demos/diff +7 -0
  20. data/lib/rouge/demos/elixir +1 -0
  21. data/lib/rouge/demos/erb +1 -0
  22. data/lib/rouge/demos/erlang +7 -0
  23. data/lib/rouge/demos/factor +5 -0
  24. data/lib/rouge/demos/gherkin +17 -0
  25. data/lib/rouge/demos/glsl +14 -0
  26. data/lib/rouge/demos/go +7 -0
  27. data/lib/rouge/demos/groovy +9 -0
  28. data/lib/rouge/demos/haml +5 -0
  29. data/lib/rouge/demos/handlebars +7 -0
  30. data/lib/rouge/demos/haskell +6 -0
  31. data/lib/rouge/demos/html +8 -0
  32. data/lib/rouge/demos/http +14 -0
  33. data/lib/rouge/demos/ini +4 -0
  34. data/lib/rouge/demos/io +11 -0
  35. data/lib/rouge/demos/java +5 -0
  36. data/lib/rouge/demos/javascript +1 -0
  37. data/lib/rouge/demos/json +1 -0
  38. data/lib/rouge/demos/json-doc +1 -0
  39. data/lib/rouge/demos/liquid +11 -0
  40. data/lib/rouge/demos/literate_coffeescript +3 -0
  41. data/lib/rouge/demos/literate_haskell +7 -0
  42. data/lib/rouge/demos/llvm +20 -0
  43. data/lib/rouge/demos/lua +12 -0
  44. data/lib/rouge/demos/make +6 -0
  45. data/lib/rouge/demos/markdown +4 -0
  46. data/lib/rouge/demos/matlab +6 -0
  47. data/lib/rouge/demos/moonscript +16 -0
  48. data/lib/rouge/demos/nginx +5 -0
  49. data/lib/rouge/demos/nim +27 -0
  50. data/lib/rouge/demos/objective_c +14 -0
  51. data/lib/rouge/demos/ocaml +12 -0
  52. data/lib/rouge/demos/perl +5 -0
  53. data/lib/rouge/demos/php +3 -0
  54. data/lib/rouge/demos/plaintext +1 -0
  55. data/lib/rouge/demos/powershell +49 -0
  56. data/lib/rouge/demos/prolog +9 -0
  57. data/lib/rouge/demos/properties +7 -0
  58. data/lib/rouge/demos/puppet +6 -0
  59. data/lib/rouge/demos/python +6 -0
  60. data/lib/rouge/demos/qml +9 -0
  61. data/lib/rouge/demos/r +8 -0
  62. data/lib/rouge/demos/racket +24 -0
  63. data/lib/rouge/demos/ruby +9 -0
  64. data/lib/rouge/demos/rust +12 -0
  65. data/lib/rouge/demos/sass +3 -0
  66. data/lib/rouge/demos/scala +3 -0
  67. data/lib/rouge/demos/scheme +4 -0
  68. data/lib/rouge/demos/scss +5 -0
  69. data/lib/rouge/demos/sed +4 -0
  70. data/lib/rouge/demos/shell +2 -0
  71. data/lib/rouge/demos/slim +17 -0
  72. data/lib/rouge/demos/smalltalk +6 -0
  73. data/lib/rouge/demos/sml +4 -0
  74. data/lib/rouge/demos/sql +1 -0
  75. data/lib/rouge/demos/swift +5 -0
  76. data/lib/rouge/demos/tcl +1 -0
  77. data/lib/rouge/demos/tex +1 -0
  78. data/lib/rouge/demos/toml +9 -0
  79. data/lib/rouge/demos/tulip +14 -0
  80. data/lib/rouge/demos/vb +4 -0
  81. data/lib/rouge/demos/viml +5 -0
  82. data/lib/rouge/demos/xml +2 -0
  83. data/lib/rouge/demos/yaml +4 -0
  84. data/lib/rouge/formatter.rb +50 -0
  85. data/lib/rouge/formatters/html.rb +117 -0
  86. data/lib/rouge/formatters/null.rb +19 -0
  87. data/lib/rouge/formatters/terminal256.rb +176 -0
  88. data/lib/rouge/lexer.rb +443 -0
  89. data/lib/rouge/lexers/apache.rb +68 -0
  90. data/lib/rouge/lexers/apache/keywords.yml +453 -0
  91. data/lib/rouge/lexers/apple_script.rb +367 -0
  92. data/lib/rouge/lexers/c.rb +212 -0
  93. data/lib/rouge/lexers/clojure.rb +112 -0
  94. data/lib/rouge/lexers/coffeescript.rb +174 -0
  95. data/lib/rouge/lexers/common_lisp.rb +345 -0
  96. data/lib/rouge/lexers/conf.rb +24 -0
  97. data/lib/rouge/lexers/cpp.rb +66 -0
  98. data/lib/rouge/lexers/csharp.rb +88 -0
  99. data/lib/rouge/lexers/css.rb +271 -0
  100. data/lib/rouge/lexers/dart.rb +104 -0
  101. data/lib/rouge/lexers/diff.rb +31 -0
  102. data/lib/rouge/lexers/elixir.rb +108 -0
  103. data/lib/rouge/lexers/erb.rb +56 -0
  104. data/lib/rouge/lexers/erlang.rb +118 -0
  105. data/lib/rouge/lexers/factor.rb +302 -0
  106. data/lib/rouge/lexers/gherkin.rb +137 -0
  107. data/lib/rouge/lexers/gherkin/keywords.rb +14 -0
  108. data/lib/rouge/lexers/glsl.rb +135 -0
  109. data/lib/rouge/lexers/go.rb +178 -0
  110. data/lib/rouge/lexers/groovy.rb +104 -0
  111. data/lib/rouge/lexers/haml.rb +228 -0
  112. data/lib/rouge/lexers/handlebars.rb +79 -0
  113. data/lib/rouge/lexers/haskell.rb +183 -0
  114. data/lib/rouge/lexers/html.rb +94 -0
  115. data/lib/rouge/lexers/http.rb +80 -0
  116. data/lib/rouge/lexers/ini.rb +57 -0
  117. data/lib/rouge/lexers/io.rb +68 -0
  118. data/lib/rouge/lexers/java.rb +76 -0
  119. data/lib/rouge/lexers/javascript.rb +297 -0
  120. data/lib/rouge/lexers/liquid.rb +287 -0
  121. data/lib/rouge/lexers/literate_coffeescript.rb +33 -0
  122. data/lib/rouge/lexers/literate_haskell.rb +36 -0
  123. data/lib/rouge/lexers/llvm.rb +84 -0
  124. data/lib/rouge/lexers/lua.rb +122 -0
  125. data/lib/rouge/lexers/lua/builtins.rb +22 -0
  126. data/lib/rouge/lexers/make.rb +116 -0
  127. data/lib/rouge/lexers/markdown.rb +154 -0
  128. data/lib/rouge/lexers/matlab.rb +74 -0
  129. data/lib/rouge/lexers/matlab/builtins.rb +11 -0
  130. data/lib/rouge/lexers/moonscript.rb +110 -0
  131. data/lib/rouge/lexers/nginx.rb +71 -0
  132. data/lib/rouge/lexers/nim.rb +152 -0
  133. data/lib/rouge/lexers/objective_c.rb +197 -0
  134. data/lib/rouge/lexers/ocaml.rb +111 -0
  135. data/lib/rouge/lexers/perl.rb +197 -0
  136. data/lib/rouge/lexers/php.rb +173 -0
  137. data/lib/rouge/lexers/php/builtins.rb +204 -0
  138. data/lib/rouge/lexers/plain_text.rb +25 -0
  139. data/lib/rouge/lexers/powershell.rb +96 -0
  140. data/lib/rouge/lexers/prolog.rb +64 -0
  141. data/lib/rouge/lexers/properties.rb +55 -0
  142. data/lib/rouge/lexers/puppet.rb +128 -0
  143. data/lib/rouge/lexers/python.rb +228 -0
  144. data/lib/rouge/lexers/qml.rb +72 -0
  145. data/lib/rouge/lexers/r.rb +56 -0
  146. data/lib/rouge/lexers/racket.rb +542 -0
  147. data/lib/rouge/lexers/ruby.rb +415 -0
  148. data/lib/rouge/lexers/rust.rb +191 -0
  149. data/lib/rouge/lexers/sass.rb +74 -0
  150. data/lib/rouge/lexers/sass/common.rb +180 -0
  151. data/lib/rouge/lexers/scala.rb +142 -0
  152. data/lib/rouge/lexers/scheme.rb +112 -0
  153. data/lib/rouge/lexers/scss.rb +34 -0
  154. data/lib/rouge/lexers/sed.rb +170 -0
  155. data/lib/rouge/lexers/shell.rb +152 -0
  156. data/lib/rouge/lexers/slim.rb +228 -0
  157. data/lib/rouge/lexers/smalltalk.rb +116 -0
  158. data/lib/rouge/lexers/sml.rb +347 -0
  159. data/lib/rouge/lexers/sql.rb +140 -0
  160. data/lib/rouge/lexers/swift.rb +144 -0
  161. data/lib/rouge/lexers/tcl.rb +192 -0
  162. data/lib/rouge/lexers/tex.rb +72 -0
  163. data/lib/rouge/lexers/toml.rb +71 -0
  164. data/lib/rouge/lexers/tulip.rb +75 -0
  165. data/lib/rouge/lexers/vb.rb +164 -0
  166. data/lib/rouge/lexers/viml.rb +101 -0
  167. data/lib/rouge/lexers/viml/keywords.rb +12 -0
  168. data/lib/rouge/lexers/xml.rb +59 -0
  169. data/lib/rouge/lexers/yaml.rb +364 -0
  170. data/lib/rouge/plugins/redcarpet.rb +30 -0
  171. data/lib/rouge/regex_lexer.rb +439 -0
  172. data/lib/rouge/template_lexer.rb +22 -0
  173. data/lib/rouge/text_analyzer.rb +48 -0
  174. data/lib/rouge/theme.rb +195 -0
  175. data/lib/rouge/themes/base16.rb +130 -0
  176. data/lib/rouge/themes/colorful.rb +67 -0
  177. data/lib/rouge/themes/github.rb +71 -0
  178. data/lib/rouge/themes/molokai.rb +82 -0
  179. data/lib/rouge/themes/monokai.rb +92 -0
  180. data/lib/rouge/themes/monokai_sublime.rb +90 -0
  181. data/lib/rouge/themes/thankful_eyes.rb +71 -0
  182. data/lib/rouge/token.rb +182 -0
  183. data/lib/rouge/util.rb +101 -0
  184. data/lib/rouge/version.rb +7 -0
  185. metadata +231 -0
@@ -0,0 +1,439 @@
1
+ # -*- coding: utf-8 -*- #
2
+
3
+ module Rouge
4
+ # @abstract
5
+ # A stateful lexer that uses sets of regular expressions to
6
+ # tokenize a string. Most lexers are instances of RegexLexer.
7
+ class RegexLexer < Lexer
8
+ # A rule is a tuple of a regular expression to test, and a callback
9
+ # to perform if the test succeeds.
10
+ #
11
+ # @see StateDSL#rule
12
+ class Rule
13
+ attr_reader :callback
14
+ attr_reader :re
15
+ attr_reader :beginning_of_line
16
+ def initialize(re, callback)
17
+ @re = re
18
+ @callback = callback
19
+ @beginning_of_line = re.source[0] == ?^
20
+ end
21
+
22
+ def inspect
23
+ "#<Rule #{@re.inspect}>"
24
+ end
25
+ end
26
+
27
+ # a State is a named set of rules that can be tested for or
28
+ # mixed in.
29
+ #
30
+ # @see RegexLexer.state
31
+ class State
32
+ attr_reader :name, :rules
33
+ def initialize(name, rules)
34
+ @name = name
35
+ @rules = rules
36
+ end
37
+
38
+ def inspect
39
+ "#<#{self.class.name} #{@name.inspect}>"
40
+ end
41
+ end
42
+
43
+ class StateDSL
44
+ attr_reader :rules
45
+ def initialize(name, &defn)
46
+ @name = name
47
+ @defn = defn
48
+ @rules = []
49
+ end
50
+
51
+ def to_state(lexer_class)
52
+ load!
53
+ rules = @rules.map do |rule|
54
+ rule.is_a?(String) ? lexer_class.get_state(rule) : rule
55
+ end
56
+ State.new(@name, rules)
57
+ end
58
+
59
+ def prepended(&defn)
60
+ parent_defn = @defn
61
+ StateDSL.new(@name) do
62
+ instance_eval(&defn)
63
+ instance_eval(&parent_defn)
64
+ end
65
+ end
66
+
67
+ def appended(&defn)
68
+ parent_defn = @defn
69
+ StateDSL.new(@name) do
70
+ instance_eval(&parent_defn)
71
+ instance_eval(&defn)
72
+ end
73
+ end
74
+
75
+ protected
76
+ # Define a new rule for this state.
77
+ #
78
+ # @overload rule(re, token, next_state=nil)
79
+ # @overload rule(re, &callback)
80
+ #
81
+ # @param [Regexp] re
82
+ # a regular expression for this rule to test.
83
+ # @param [String] tok
84
+ # the token type to yield if `re` matches.
85
+ # @param [#to_s] next_state
86
+ # (optional) a state to push onto the stack if `re` matches.
87
+ # If `next_state` is `:pop!`, the state stack will be popped
88
+ # instead.
89
+ # @param [Proc] callback
90
+ # a block that will be evaluated in the context of the lexer
91
+ # if `re` matches. This block has access to a number of lexer
92
+ # methods, including {RegexLexer#push}, {RegexLexer#pop!},
93
+ # {RegexLexer#token}, and {RegexLexer#delegate}. The first
94
+ # argument can be used to access the match groups.
95
+ def rule(re, tok=nil, next_state=nil, &callback)
96
+ if tok.nil? && callback.nil?
97
+ raise "please pass `rule` a token to yield or a callback"
98
+ end
99
+
100
+ callback ||= case next_state
101
+ when :pop!
102
+ proc do |stream|
103
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
104
+ @output_stream.call(tok, stream[0])
105
+ puts " popping stack: #{1}" if @debug
106
+ @stack.pop or raise 'empty stack!'
107
+ end
108
+ when :push
109
+ proc do |stream|
110
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
111
+ @output_stream.call(tok, stream[0])
112
+ puts " pushing #{@stack.last.name}" if @debug
113
+ @stack.push(@stack.last)
114
+ end
115
+ when Symbol
116
+ proc do |stream|
117
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
118
+ @output_stream.call(tok, stream[0])
119
+ state = @states[next_state] || self.class.get_state(next_state)
120
+ puts " pushing #{state.name}" if @debug
121
+ @stack.push(state)
122
+ end
123
+ when nil
124
+ proc do |stream|
125
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
126
+ @output_stream.call(tok, stream[0])
127
+ end
128
+ else
129
+ raise "invalid next state: #{next_state.inspect}"
130
+ end
131
+
132
+ rules << Rule.new(re, callback)
133
+ end
134
+
135
+ # Mix in the rules from another state into this state. The rules
136
+ # from the mixed-in state will be tried in order before moving on
137
+ # to the rest of the rules in this state.
138
+ def mixin(state)
139
+ rules << state.to_s
140
+ end
141
+
142
+ private
143
+ def load!
144
+ return if @loaded
145
+ @loaded = true
146
+ instance_eval(&@defn)
147
+ end
148
+ end
149
+
150
+ # The states hash for this lexer.
151
+ # @see state
152
+ def self.states
153
+ @states ||= {}
154
+ end
155
+
156
+ def self.state_definitions
157
+ @state_definitions ||= InheritableHash.new(superclass.state_definitions)
158
+ end
159
+ @state_definitions = {}
160
+
161
+ def self.replace_state(name, new_defn)
162
+ states[name] = nil
163
+ state_definitions[name] = new_defn
164
+ end
165
+
166
+ # The routines to run at the beginning of a fresh lex.
167
+ # @see start
168
+ def self.start_procs
169
+ @start_procs ||= InheritableList.new(superclass.start_procs)
170
+ end
171
+ @start_procs = []
172
+
173
+ # Specify an action to be run every fresh lex.
174
+ #
175
+ # @example
176
+ # start { puts "I'm lexing a new string!" }
177
+ def self.start(&b)
178
+ start_procs << b
179
+ end
180
+
181
+ # Define a new state for this lexer with the given name.
182
+ # The block will be evaluated in the context of a {StateDSL}.
183
+ def self.state(name, &b)
184
+ name = name.to_s
185
+ state_definitions[name] = StateDSL.new(name, &b)
186
+ end
187
+
188
+ def self.prepend(name, &b)
189
+ name = name.to_s
190
+ dsl = state_definitions[name] or raise "no such state #{name.inspect}"
191
+ replace_state(name, dsl.prepended(&b))
192
+ end
193
+
194
+ def self.append(state, &b)
195
+ name = name.to_s
196
+ dsl = state_definitions[name] or raise "no such state #{name.inspect}"
197
+ replace_state(name, dsl.appended(&b))
198
+ end
199
+
200
+ # @private
201
+ def self.get_state(name)
202
+ return name if name.is_a? State
203
+
204
+ states[name.to_sym] ||= begin
205
+ defn = state_definitions[name.to_s] or raise "unknown state: #{name.inspect}"
206
+ defn.to_state(self)
207
+ end
208
+ end
209
+
210
+ # @private
211
+ def get_state(state_name)
212
+ self.class.get_state(state_name)
213
+ end
214
+
215
+ # The state stack. This is initially the single state `[:root]`.
216
+ # It is an error for this stack to be empty.
217
+ # @see #state
218
+ def stack
219
+ @stack ||= [get_state(:root)]
220
+ end
221
+
222
+ # The current state - i.e. one on top of the state stack.
223
+ #
224
+ # NB: if the state stack is empty, this will throw an error rather
225
+ # than returning nil.
226
+ def state
227
+ stack.last or raise 'empty stack!'
228
+ end
229
+
230
+ # reset this lexer to its initial state. This runs all of the
231
+ # start_procs.
232
+ def reset!
233
+ @stack = nil
234
+ @current_stream = nil
235
+
236
+ self.class.start_procs.each do |pr|
237
+ instance_eval(&pr)
238
+ end
239
+ end
240
+
241
+ # This implements the lexer protocol, by yielding [token, value] pairs.
242
+ #
243
+ # The process for lexing works as follows, until the stream is empty:
244
+ #
245
+ # 1. We look at the state on top of the stack (which by default is
246
+ # `[:root]`).
247
+ # 2. Each rule in that state is tried until one is successful. If one
248
+ # is found, that rule's callback is evaluated - which may yield
249
+ # tokens and manipulate the state stack. Otherwise, one character
250
+ # is consumed with an `'Error'` token, and we continue at (1.)
251
+ #
252
+ # @see #step #step (where (2.) is implemented)
253
+ def stream_tokens(str, &b)
254
+ stream = StringScanner.new(str)
255
+
256
+ @current_stream = stream
257
+ @output_stream = b
258
+ @states = self.class.states
259
+ @null_steps = 0
260
+
261
+ until stream.eos?
262
+ if @debug
263
+ puts "lexer: #{self.class.tag}"
264
+ puts "stack: #{stack.map(&:name).inspect}"
265
+ puts "stream: #{stream.peek(20).inspect}"
266
+ end
267
+
268
+ success = step(state, stream)
269
+
270
+ if !success
271
+ puts " no match, yielding Error" if @debug
272
+ b.call(Token::Tokens::Error, stream.getch)
273
+ end
274
+ end
275
+ end
276
+
277
+ # The number of successive scans permitted without consuming
278
+ # the input stream. If this is exceeded, the match fails.
279
+ MAX_NULL_SCANS = 5
280
+
281
+ # Runs one step of the lex. Rules in the current state are tried
282
+ # until one matches, at which point its callback is called.
283
+ #
284
+ # @return true if a rule was tried successfully
285
+ # @return false otherwise.
286
+ def step(state, stream)
287
+ state.rules.each do |rule|
288
+ if rule.is_a?(State)
289
+ puts " entering mixin #{rule.name}" if @debug
290
+ return true if step(rule, stream)
291
+ puts " exiting mixin #{rule.name}" if @debug
292
+ else
293
+ puts " trying #{rule.inspect}" if @debug
294
+
295
+ # XXX HACK XXX
296
+ # StringScanner's implementation of ^ is b0rken.
297
+ # see http://bugs.ruby-lang.org/issues/7092
298
+ # TODO: this doesn't cover cases like /(a|^b)/, but it's
299
+ # the most common, for now...
300
+ next if rule.beginning_of_line && !stream.beginning_of_line?
301
+
302
+ if size = stream.skip(rule.re)
303
+ puts " got #{stream[0].inspect}" if @debug
304
+
305
+ instance_exec(stream, &rule.callback)
306
+
307
+ if size.zero?
308
+ @null_steps += 1
309
+ if @null_steps > MAX_NULL_SCANS
310
+ puts " too many scans without consuming the string!" if @debug
311
+ return false
312
+ end
313
+ else
314
+ @null_steps = 0
315
+ end
316
+
317
+ return true
318
+ end
319
+ end
320
+ end
321
+
322
+ false
323
+ end
324
+
325
+ # Yield a token.
326
+ #
327
+ # @param tok
328
+ # the token type
329
+ # @param val
330
+ # (optional) the string value to yield. If absent, this defaults
331
+ # to the entire last match.
332
+ def token(tok, val=@current_stream[0])
333
+ yield_token(tok, val)
334
+ end
335
+
336
+ # @deprecated
337
+ #
338
+ # Yield a token with the next matched group. Subsequent calls
339
+ # to this method will yield subsequent groups.
340
+ def group(tok)
341
+ raise "RegexLexer#group is deprecated: use #groups instead"
342
+ end
343
+
344
+ # Yield tokens corresponding to the matched groups of the current
345
+ # match.
346
+ def groups(*tokens)
347
+ tokens.each_with_index do |tok, i|
348
+ yield_token(tok, @current_stream[i+1])
349
+ end
350
+ end
351
+
352
+ # Delegate the lex to another lexer. The #lex method will be called
353
+ # with `:continue` set to true, so that #reset! will not be called.
354
+ # In this way, a single lexer can be repeatedly delegated to while
355
+ # maintaining its own internal state stack.
356
+ #
357
+ # @param [#lex] lexer
358
+ # The lexer or lexer class to delegate to
359
+ # @param [String] text
360
+ # The text to delegate. This defaults to the last matched string.
361
+ def delegate(lexer, text=nil)
362
+ puts " delegating to #{lexer.inspect}" if @debug
363
+ text ||= @current_stream[0]
364
+
365
+ lexer.lex(text, :continue => true) do |tok, val|
366
+ puts " delegated token: #{tok.inspect}, #{val.inspect}" if @debug
367
+ yield_token(tok, val)
368
+ end
369
+ end
370
+
371
+ def recurse(text=nil)
372
+ delegate(self.class, text)
373
+ end
374
+
375
+ # Push a state onto the stack. If no state name is given and you've
376
+ # passed a block, a state will be dynamically created using the
377
+ # {StateDSL}.
378
+ def push(state_name=nil, &b)
379
+ push_state = if state_name
380
+ get_state(state_name)
381
+ elsif block_given?
382
+ StateDSL.new(b.inspect, &b).to_state(self.class)
383
+ else
384
+ # use the top of the stack by default
385
+ self.state
386
+ end
387
+
388
+ puts " pushing #{push_state.name}" if @debug
389
+ stack.push(push_state)
390
+ end
391
+
392
+ # Pop the state stack. If a number is passed in, it will be popped
393
+ # that number of times.
394
+ def pop!(times=1)
395
+ raise 'empty stack!' if stack.empty?
396
+
397
+ puts " popping stack: #{times}" if @debug
398
+
399
+ stack.pop(times)
400
+
401
+ nil
402
+ end
403
+
404
+ # replace the head of the stack with the given state
405
+ def goto(state_name)
406
+ raise 'empty stack!' if stack.empty?
407
+
408
+ puts " going to state #{state_name} " if @debug
409
+ stack[-1] = get_state(state_name)
410
+ end
411
+
412
+ # reset the stack back to `[:root]`.
413
+ def reset_stack
414
+ puts ' resetting stack' if @debug
415
+ stack.clear
416
+ stack.push get_state(:root)
417
+ end
418
+
419
+ # Check if `state_name` is in the state stack.
420
+ def in_state?(state_name)
421
+ state_name = state_name.to_s
422
+ stack.any? do |state|
423
+ state.name == state_name.to_s
424
+ end
425
+ end
426
+
427
+ # Check if `state_name` is the state on top of the state stack.
428
+ def state?(state_name)
429
+ state_name.to_s == state.name
430
+ end
431
+
432
+ private
433
+ def yield_token(tok, val)
434
+ return if val.nil? || val.empty?
435
+ puts " yielding #{tok.qualname}, #{val.inspect}" if @debug
436
+ @output_stream.yield(tok, val)
437
+ end
438
+ end
439
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*- #
2
+
3
+ module Rouge
4
+ # @abstract
5
+ # A TemplateLexer is one that accepts a :parent option, to specify
6
+ # which language is being templated. The lexer class can specify its
7
+ # own default for the parent lexer, which is otherwise defaulted to
8
+ # HTML.
9
+ class TemplateLexer < RegexLexer
10
+ # the parent lexer - the one being templated.
11
+ def parent
12
+ return @parent if instance_variable_defined? :@parent
13
+ @parent = option(:parent) || 'html'
14
+ if @parent.is_a? ::String
15
+ lexer_class = Lexer.find(@parent)
16
+ @parent = lexer_class.new(self.options)
17
+ end
18
+ end
19
+
20
+ start { parent.reset! }
21
+ end
22
+ end