rouge 4.7.0 → 5.0.0

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +11 -4
  3. data/bin/rougify +3 -4
  4. data/lib/rouge/cli.rb +7 -10
  5. data/lib/rouge/demos/abap +30 -4
  6. data/lib/rouge/demos/dylan +8 -0
  7. data/lib/rouge/demos/kick_assembler +14 -0
  8. data/lib/rouge/demos/pdf +29 -0
  9. data/lib/rouge/demos/thrift +15 -0
  10. data/lib/rouge/demos/veryl +24 -0
  11. data/lib/rouge/eager.rb +3 -0
  12. data/lib/rouge/formatters/html.rb +8 -1
  13. data/lib/rouge/formatters/html_debug.rb +16 -0
  14. data/lib/rouge/formatters/html_legacy.rb +15 -1
  15. data/lib/rouge/formatters/html_legacy_table.rb +57 -0
  16. data/lib/rouge/formatters/html_line_highlighter.rb +11 -4
  17. data/lib/rouge/formatters/html_line_table.rb +8 -3
  18. data/lib/rouge/formatters/html_linewise.rb +11 -2
  19. data/lib/rouge/formatters/html_pygments.rb +6 -1
  20. data/lib/rouge/formatters/html_table.rb +47 -21
  21. data/lib/rouge/formatters/terminal256.rb +3 -3
  22. data/lib/rouge/formatters/tex.rb +1 -1
  23. data/lib/rouge/guesser.rb +1 -1
  24. data/lib/rouge/guessers/disambiguation.rb +2 -2
  25. data/lib/rouge/guessers/glob_mapping.rb +2 -2
  26. data/lib/rouge/guessers/modeline.rb +2 -2
  27. data/lib/rouge/lexer.rb +40 -21
  28. data/lib/rouge/lexers/abap/builtins.rb +187 -0
  29. data/lib/rouge/lexers/abap.rb +70 -178
  30. data/lib/rouge/lexers/ada.rb +1 -1
  31. data/lib/rouge/lexers/apache/keywords.rb +3 -11
  32. data/lib/rouge/lexers/apache.rb +25 -24
  33. data/lib/rouge/lexers/apex.rb +2 -2
  34. data/lib/rouge/lexers/apiblueprint.rb +2 -2
  35. data/lib/rouge/lexers/bicep.rb +2 -2
  36. data/lib/rouge/lexers/biml.rb +36 -9
  37. data/lib/rouge/lexers/brightscript.rb +3 -4
  38. data/lib/rouge/lexers/c.rb +9 -5
  39. data/lib/rouge/lexers/console.rb +11 -5
  40. data/lib/rouge/lexers/cpp.rb +10 -12
  41. data/lib/rouge/lexers/crystal.rb +1 -1
  42. data/lib/rouge/lexers/css.rb +21 -2
  43. data/lib/rouge/lexers/cuda.rb +4 -4
  44. data/lib/rouge/lexers/cython.rb +26 -50
  45. data/lib/rouge/lexers/dafny.rb +1 -1
  46. data/lib/rouge/lexers/dart.rb +2 -0
  47. data/lib/rouge/lexers/datastudio.rb +1 -1
  48. data/lib/rouge/lexers/digdag.rb +2 -3
  49. data/lib/rouge/lexers/dylan.rb +109 -0
  50. data/lib/rouge/lexers/ecl.rb +3 -3
  51. data/lib/rouge/lexers/elixir.rb +14 -9
  52. data/lib/rouge/lexers/escape.rb +1 -1
  53. data/lib/rouge/lexers/factor.rb +1 -1
  54. data/lib/rouge/lexers/freefem.rb +2 -2
  55. data/lib/rouge/lexers/ghc_cmm.rb +1 -1
  56. data/lib/rouge/lexers/ghc_core.rb +1 -1
  57. data/lib/rouge/lexers/gherkin/keywords.rb +10 -6
  58. data/lib/rouge/lexers/gherkin.rb +28 -26
  59. data/lib/rouge/lexers/gjs.rb +2 -2
  60. data/lib/rouge/lexers/glsl/builtins.rb +17 -0
  61. data/lib/rouge/lexers/glsl.rb +50 -113
  62. data/lib/rouge/lexers/go.rb +1 -1
  63. data/lib/rouge/lexers/gradle.rb +2 -2
  64. data/lib/rouge/lexers/groovy.rb +6 -0
  65. data/lib/rouge/lexers/gts.rb +2 -2
  66. data/lib/rouge/lexers/hack.rb +4 -6
  67. data/lib/rouge/lexers/haxe.rb +2 -2
  68. data/lib/rouge/lexers/hlsl.rb +6 -6
  69. data/lib/rouge/lexers/hocon.rb +2 -2
  70. data/lib/rouge/lexers/hql.rb +15 -19
  71. data/lib/rouge/lexers/idris.rb +1 -1
  72. data/lib/rouge/lexers/igorpro/builtins.rb +1530 -0
  73. data/lib/rouge/lexers/igorpro.rb +49 -520
  74. data/lib/rouge/lexers/irb.rb +3 -3
  75. data/lib/rouge/lexers/isbl.rb +7 -43
  76. data/lib/rouge/lexers/j.rb +1 -1
  77. data/lib/rouge/lexers/json5.rb +2 -2
  78. data/lib/rouge/lexers/json_doc.rb +2 -2
  79. data/lib/rouge/lexers/jsp.rb +119 -119
  80. data/lib/rouge/lexers/jsx.rb +2 -2
  81. data/lib/rouge/lexers/kick_assembler.rb +100 -0
  82. data/lib/rouge/lexers/kotlin.rb +5 -0
  83. data/lib/rouge/lexers/lasso/keywords.rb +6 -6
  84. data/lib/rouge/lexers/lasso.rb +9 -11
  85. data/lib/rouge/lexers/liquid.rb +5 -6
  86. data/lib/rouge/lexers/llvm/keywords.rb +3 -12
  87. data/lib/rouge/lexers/llvm.rb +5 -16
  88. data/lib/rouge/lexers/lua/keywords.rb +11 -13
  89. data/lib/rouge/lexers/lua.rb +8 -7
  90. data/lib/rouge/lexers/lutin.rb +5 -4
  91. data/lib/rouge/lexers/m68k.rb +3 -3
  92. data/lib/rouge/lexers/mason.rb +110 -110
  93. data/lib/rouge/lexers/mathematica/keywords.rb +1 -3
  94. data/lib/rouge/lexers/mathematica.rb +6 -7
  95. data/lib/rouge/lexers/matlab/keywords.rb +2 -2
  96. data/lib/rouge/lexers/matlab.rb +5 -5
  97. data/lib/rouge/lexers/meson.rb +1 -1
  98. data/lib/rouge/lexers/mojo.rb +6 -2
  99. data/lib/rouge/lexers/moonscript.rb +19 -17
  100. data/lib/rouge/lexers/nesasm.rb +6 -6
  101. data/lib/rouge/lexers/nial.rb +7 -8
  102. data/lib/rouge/lexers/nim.rb +3 -3
  103. data/lib/rouge/lexers/nix.rb +10 -8
  104. data/lib/rouge/lexers/objective_c.rb +3 -3
  105. data/lib/rouge/lexers/objective_cpp.rb +3 -2
  106. data/lib/rouge/lexers/ocaml.rb +2 -2
  107. data/lib/rouge/lexers/openedge.rb +9 -9
  108. data/lib/rouge/lexers/pdf.rb +109 -0
  109. data/lib/rouge/lexers/php/keywords.rb +136 -138
  110. data/lib/rouge/lexers/php.rb +58 -9
  111. data/lib/rouge/lexers/plsql.rb +8 -9
  112. data/lib/rouge/lexers/postscript.rb +1 -1
  113. data/lib/rouge/lexers/powershell.rb +1 -1
  114. data/lib/rouge/lexers/python.rb +110 -65
  115. data/lib/rouge/lexers/qml.rb +2 -2
  116. data/lib/rouge/lexers/reasonml.rb +2 -2
  117. data/lib/rouge/lexers/rego.rb +53 -53
  118. data/lib/rouge/lexers/rescript.rb +2 -2
  119. data/lib/rouge/lexers/robot_framework.rb +12 -12
  120. data/lib/rouge/lexers/{coq.rb → rocq.rb} +15 -6
  121. data/lib/rouge/lexers/ruby.rb +33 -7
  122. data/lib/rouge/lexers/rust.rb +1 -0
  123. data/lib/rouge/lexers/sas.rb +164 -165
  124. data/lib/rouge/lexers/sass/common.rb +1 -1
  125. data/lib/rouge/lexers/sass.rb +2 -2
  126. data/lib/rouge/lexers/scss.rb +2 -2
  127. data/lib/rouge/lexers/sed.rb +1 -1
  128. data/lib/rouge/lexers/shell.rb +5 -5
  129. data/lib/rouge/lexers/slice.rb +2 -2
  130. data/lib/rouge/lexers/sparql.rb +1 -1
  131. data/lib/rouge/lexers/sqf/keywords.rb +5 -3
  132. data/lib/rouge/lexers/sqf.rb +3 -4
  133. data/lib/rouge/lexers/stan.rb +9 -15
  134. data/lib/rouge/lexers/svelte.rb +2 -2
  135. data/lib/rouge/lexers/swift.rb +2 -2
  136. data/lib/rouge/lexers/tcl.rb +1 -1
  137. data/lib/rouge/lexers/terraform.rb +2 -2
  138. data/lib/rouge/lexers/thrift.rb +120 -0
  139. data/lib/rouge/lexers/tsx.rb +3 -3
  140. data/lib/rouge/lexers/ttcn3.rb +1 -1
  141. data/lib/rouge/lexers/twig.rb +2 -2
  142. data/lib/rouge/lexers/typescript.rb +3 -3
  143. data/lib/rouge/lexers/varnish.rb +8 -8
  144. data/lib/rouge/lexers/veryl.rb +109 -0
  145. data/lib/rouge/lexers/viml/keywords.rb +5 -7
  146. data/lib/rouge/lexers/viml.rb +8 -10
  147. data/lib/rouge/lexers/vue.rb +2 -2
  148. data/lib/rouge/lexers/xquery.rb +2 -1
  149. data/lib/rouge/lexers/yaml.rb +13 -1
  150. data/lib/rouge/lexers/yang.rb +42 -74
  151. data/lib/rouge/lexers/zig.rb +10 -10
  152. data/lib/rouge/plugins/redcarpet.rb +3 -2
  153. data/lib/rouge/regex_lexer.rb +25 -14
  154. data/lib/rouge/themes/gruvbox.rb +3 -0
  155. data/lib/rouge/token.rb +1 -1
  156. data/lib/rouge/util.rb +1 -1
  157. data/lib/rouge/version.rb +1 -1
  158. data/lib/rouge.rb +70 -59
  159. data/lib/rubocop/cop/rouge/no_building_alternation_pattern_in_regexp.rb +71 -0
  160. data/lib/rubocop/cop/rouge/no_huge_collections.rb +37 -0
  161. data/rouge.gemspec +8 -5
  162. metadata +40 -9
  163. data/lib/rouge/lexers/isbl/builtins.rb +0 -17
  164. data/lib/rouge/lexers/matlab/builtins.rb +0 -11
  165. /data/lib/rouge/demos/{coq → rocq} +0 -0
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'html'
4
+
3
5
  module Rouge
4
6
  module Lexers
5
- load_lexer 'html.rb'
6
-
7
7
  class Vue < HTML
8
8
  desc 'Vue.js single-file components'
9
9
  tag 'vue'
@@ -1,9 +1,10 @@
1
1
  # -*- coding: utf-8 -*- #
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative 'xpath'
5
+
4
6
  module Rouge
5
7
  module Lexers
6
- load_lexer 'xpath.rb'
7
8
  class XQuery < XPath
8
9
  title 'XQuery'
9
10
  desc 'XQuery 3.1: An XML Query Language'
@@ -172,12 +172,24 @@ module Rouge
172
172
  end
173
173
 
174
174
  state :block_nodes do
175
- # implicit key
175
+ # implicit unquoted key
176
176
  rule %r/([^#,?\[\]{}"'\n]+)(:)(?=\s|$)/ do |m|
177
177
  groups Name::Attribute, Punctuation::Indicator
178
178
  set_indent m[0], :implicit => true
179
179
  end
180
180
 
181
+ # implicit double-quoted key
182
+ rule %r/("(?:[^\n"]|\\")*")(\s*)(:)(?=\s|$)/ do |m|
183
+ groups Name::Attribute, Text, Punctuation::Indicator
184
+ set_indent m[0], :implicit => true
185
+ end
186
+
187
+ # implicit single-quoted key
188
+ rule %r/('(?:[^\n']|\\')*')(\s*)(:)(?=\s|$)/ do |m|
189
+ groups Name::Attribute, Text, Punctuation::Indicator
190
+ set_indent m[0], :implicit => true
191
+ end
192
+
181
193
  # literal and folded scalars
182
194
  rule %r/[\|>][+-]?/ do
183
195
  token Punctuation::Indicator
@@ -13,74 +13,56 @@ module Rouge
13
13
  id = /[\w-]+(?=[^\w\-\:])\b/
14
14
 
15
15
  #Keywords from RFC7950 ; oriented at BNF style
16
- def self.top_stmts_keywords
17
- @top_stms_keywords ||= Set.new %w(
18
- module submodule
19
- )
20
- end
16
+ top_keywords = Set.new %w(module submodule)
21
17
 
22
- def self.module_header_stmts_keywords
23
- @module_header_stmts_keywords ||= Set.new %w(
24
- belongs-to namespace prefix yang-version
25
- )
26
- end
18
+ module_header_keywords = Set.new %w(belongs-to namespace prefix yang-version)
27
19
 
28
- def self.meta_stmts_keywords
29
- @meta_stmts_keywords ||= Set.new %w(
30
- contact description organization reference revision
31
- )
32
- end
20
+ meta_keywords = Set.new %w(contact description organization reference revision)
33
21
 
34
- def self.linkage_stmts_keywords
35
- @linkage_stmts_keywords ||= Set.new %w(
36
- import include revision-date
37
- )
38
- end
22
+ linkage_keywords = Set.new %w(import include revision-date)
39
23
 
40
- def self.body_stmts_keywords
41
- @body_stms_keywords ||= Set.new %w(
42
- action argument augment deviation extension feature grouping identity
43
- if-feature input notification output rpc typedef
44
- )
45
- end
24
+ body_keywords = Set.new %w(
25
+ action argument augment deviation extension feature grouping identity
26
+ if-feature input notification output rpc typedef
27
+ )
46
28
 
47
- def self.data_def_stmts_keywords
48
- @data_def_stms_keywords ||= Set.new %w(
49
- anydata anyxml case choice config container deviate leaf leaf-list
50
- list must presence refine uses when
51
- )
52
- end
29
+ data_def_keywords = Set.new %w(
30
+ anydata anyxml case choice config container deviate leaf leaf-list
31
+ list must presence refine uses when
32
+ )
53
33
 
54
- def self.type_stmts_keywords
55
- @type_stmts_keywords ||= Set.new %w(
56
- base bit default enum error-app-tag error-message fraction-digits
57
- length max-elements min-elements modifier ordered-by path pattern
58
- position range require-instance status type units value yin-element
59
- )
60
- end
34
+ type_keywords = Set.new %w(
35
+ base bit default enum error-app-tag error-message fraction-digits
36
+ length max-elements min-elements modifier ordered-by path pattern
37
+ position range require-instance status type units value yin-element
38
+ )
61
39
 
62
- def self.list_stmts_keywords
63
- @list_stmts_keywords ||= Set.new %w(
64
- key mandatory unique
65
- )
66
- end
40
+ list_keywords = Set.new %w(
41
+ key mandatory unique
42
+ )
67
43
 
68
44
  #RFC7950 other keywords
69
- def self.constants_keywords
70
- @constants_keywords ||= Set.new %w(
71
- add current delete deprecated false invert-match max min
72
- not-supported obsolete replace true unbounded user
73
- )
74
- end
45
+ CONSTANTS = Set.new %w(
46
+ add current delete deprecated false invert-match max min
47
+ not-supported obsolete replace true unbounded user
48
+ )
75
49
 
76
50
  #RFC7950 Built-In Types
77
- def self.types
78
- @types ||= Set.new %w(
79
- binary bits boolean decimal64 empty enumeration identityref
80
- instance-identifier int16 int32 int64 int8 leafref string uint16
81
- uint32 uint64 uint8 union
82
- )
83
- end
51
+ TYPES = Set.new %w(
52
+ binary bits boolean decimal64 empty enumeration identityref
53
+ instance-identifier int16 int32 int64 int8 leafref string uint16
54
+ uint32 uint64 uint8 union
55
+ )
56
+
57
+ DECLARATIONS =
58
+ top_keywords +
59
+ module_header_keywords +
60
+ meta_keywords +
61
+ linkage_keywords +
62
+ body_keywords +
63
+ data_def_keywords +
64
+ type_keywords +
65
+ list_keywords
84
66
 
85
67
  state :comment do
86
68
  rule %r/[^*\/]/, Comment
@@ -115,25 +97,11 @@ module Rouge
115
97
  rule id do |m|
116
98
  name = m[0].downcase
117
99
 
118
- if self.class.top_stmts_keywords.include? name
119
- token Keyword::Declaration
120
- elsif self.class.module_header_stmts_keywords.include? name
121
- token Keyword::Declaration
122
- elsif self.class.meta_stmts_keywords.include? name
123
- token Keyword::Declaration
124
- elsif self.class.linkage_stmts_keywords.include? name
125
- token Keyword::Declaration
126
- elsif self.class.body_stmts_keywords.include? name
127
- token Keyword::Declaration
128
- elsif self.class.data_def_stmts_keywords.include? name
129
- token Keyword::Declaration
130
- elsif self.class.type_stmts_keywords.include? name
131
- token Keyword::Declaration
132
- elsif self.class.list_stmts_keywords.include? name
100
+ if DECLARATIONS.include?(name)
133
101
  token Keyword::Declaration
134
- elsif self.class.types.include? name
102
+ elsif TYPES.include? name
135
103
  token Keyword::Type
136
- elsif self.class.constants_keywords.include? name
104
+ elsif CONSTANTS.include? name
137
105
  token Name::Constant
138
106
  else
139
107
  token Name
@@ -84,16 +84,16 @@ module Rouge
84
84
  rule %r/([.]?)(\s*)(@?#{id})(\s*)([(]?)/ do |m|
85
85
  name = m[3]
86
86
  t = if self.class.keywords.include? name
87
- Keyword
88
- elsif self.class.builtins.include? name
89
- Name::Builtin
90
- elsif !m[1].empty? && !m[5].empty?
91
- Name::Function
92
- elsif !m[1].empty?
93
- Name::Property
94
- else
95
- Name
96
- end
87
+ Keyword
88
+ elsif self.class.builtins.include? name
89
+ Name::Builtin
90
+ elsif !m[1].empty? && !m[5].empty?
91
+ Name::Function
92
+ elsif !m[1].empty?
93
+ Name::Property
94
+ else
95
+ Name
96
+ end
97
97
 
98
98
  groups Punctuation, Text, t, Text, Punctuation
99
99
  end
@@ -25,12 +25,13 @@ module Rouge
25
25
  end
26
26
 
27
27
  formatter = rouge_formatter(lexer)
28
- formatter.format(lexer.lex(code))
28
+ formatted = formatter.format(lexer.lex(code))
29
+ %(<pre class="highlight #{lexer.tag}"><code>#{formatted}</code></pre>)
29
30
  end
30
31
 
31
32
  # override this method for custom formatting behavior
32
33
  def rouge_formatter(lexer)
33
- Formatters::HTMLLegacy.new(:css_class => "highlight #{lexer.tag}")
34
+ Rouge::Formatters::HTML.new
34
35
  end
35
36
  end
36
37
  end
@@ -37,6 +37,12 @@ module Rouge
37
37
  end
38
38
  end
39
39
 
40
+ # exception class for fallthrough - using an exception is slightly faster
41
+ # than catch { ... }, but it is not semantically an error that should be
42
+ # rescued from.
43
+ class Fallthrough < Exception # rubocop:disable Lint/InheritException
44
+ end
45
+
40
46
  # A rule is a tuple of a regular expression to test, and a callback
41
47
  # to perform if the test succeeds.
42
48
  #
@@ -44,11 +50,9 @@ module Rouge
44
50
  class Rule
45
51
  attr_reader :callback
46
52
  attr_reader :re
47
- attr_reader :beginning_of_line
48
53
  def initialize(re, callback)
49
54
  @re = re
50
55
  @callback = callback
51
- @beginning_of_line = re.source[0] == ?^
52
56
  end
53
57
 
54
58
  def inspect
@@ -322,7 +326,7 @@ module Rouge
322
326
  #
323
327
  # @see #step #step (where (2.) is implemented)
324
328
  def stream_tokens(str, &b)
325
- stream = StringScanner.new(str)
329
+ stream = StringScanner.new(str, fixed_anchor: true)
326
330
 
327
331
  @current_stream = stream
328
332
  @output_stream = b
@@ -333,7 +337,7 @@ module Rouge
333
337
  if @debug
334
338
  puts
335
339
  puts "lexer: #{self.class.tag}"
336
- puts "stack: #{stack.map(&:name).map(&:to_sym).inspect}"
340
+ puts "stack: #{stack.map { |s| s.name.to_sym }.inspect}"
337
341
  puts "stream: #{stream.peek(20).inspect}"
338
342
  end
339
343
 
@@ -341,7 +345,7 @@ module Rouge
341
345
 
342
346
  if !success
343
347
  puts " no match, yielding Error" if @debug
344
- b.call(Token::Tokens::Error, stream.getch)
348
+ yield(Token::Tokens::Error, stream.getch)
345
349
  end
346
350
  end
347
351
  end
@@ -364,18 +368,9 @@ module Rouge
364
368
  else
365
369
  puts " trying: #{rule.inspect}" if @debug
366
370
 
367
- # XXX HACK XXX
368
- # StringScanner's implementation of ^ is b0rken.
369
- # see http://bugs.ruby-lang.org/issues/7092
370
- # TODO: this doesn't cover cases like /(a|^b)/, but it's
371
- # the most common, for now...
372
- next if rule.beginning_of_line && !stream.beginning_of_line?
373
-
374
371
  if (size = stream.skip(rule.re))
375
372
  puts " got: #{stream[0].inspect}" if @debug
376
373
 
377
- instance_exec(stream, &rule.callback)
378
-
379
374
  if size.zero?
380
375
  @null_steps += 1
381
376
  if @null_steps > MAX_NULL_SCANS
@@ -386,6 +381,13 @@ module Rouge
386
381
  @null_steps = 0
387
382
  end
388
383
 
384
+ begin
385
+ instance_exec(stream, &rule.callback)
386
+ rescue Fallthrough
387
+ stream.unscan
388
+ next
389
+ end
390
+
389
391
  return true
390
392
  end
391
393
  end
@@ -440,10 +442,19 @@ module Rouge
440
442
  end
441
443
  end
442
444
 
445
+ # Re-lexes the given text (or the most recently matched string if
446
+ # none is given) with the current lexer.
443
447
  def recurse(text=nil)
444
448
  delegate(self.class, text)
445
449
  end
446
450
 
451
+ # Breaks out of the current rule block and continues to match later
452
+ # rules, as if the current regex had not matched. Does not affect
453
+ # the stack.
454
+ def fallthrough!
455
+ raise Fallthrough
456
+ end
457
+
447
458
  # Push a state onto the stack. If no state name is given and you've
448
459
  # passed a block, a state will be dynamically created using the
449
460
  # {StateDSL}.
@@ -10,6 +10,7 @@ module Rouge
10
10
  class Gruvbox < CSSTheme
11
11
  name 'gruvbox'
12
12
 
13
+ # rubocop:disable Naming/ConstantName
13
14
  # global Gruvbox colours {{{
14
15
  C_dark0_hard = '#1d2021'
15
16
  C_dark0 ='#282828'
@@ -122,6 +123,8 @@ module Rouge
122
123
  palette orange: C_faded_orange
123
124
  end
124
125
 
126
+ # rubocop:enable Naming/ConstantName
127
+
125
128
  dark!
126
129
  mode :light
127
130
 
data/lib/rouge/token.rb CHANGED
@@ -61,7 +61,7 @@ module Rouge
61
61
 
62
62
  def each_token(&b)
63
63
  Token.cache.each do |(_, t)|
64
- b.call(t)
64
+ yield(t)
65
65
  end
66
66
  end
67
67
  end
data/lib/rouge/util.rb CHANGED
@@ -24,7 +24,7 @@ module Rouge
24
24
 
25
25
  def each(&b)
26
26
  keys.each do |k|
27
- b.call(k, self[k])
27
+ yield(k, self[k])
28
28
  end
29
29
  end
30
30
 
data/lib/rouge/version.rb CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Rouge
5
5
  def self.version
6
- "4.7.0"
6
+ "5.0.0"
7
7
  end
8
8
  end
data/lib/rouge.rb CHANGED
@@ -3,6 +3,9 @@
3
3
 
4
4
  # stdlib
5
5
  require 'pathname'
6
+ require 'set'
7
+ require 'strscan'
8
+ require 'uri'
6
9
 
7
10
  # The containing module for Rouge
8
11
  module Rouge
@@ -11,7 +14,12 @@ module Rouge
11
14
  LIB_DIR = __dir__.freeze
12
15
 
13
16
  class << self
17
+ # @deprecated This method of reloading is incompatible with modern Ruby's
18
+ # expectations around global caching of `require`. It is deprecated with no
19
+ # replacement - consider reloading the entire process instead with something
20
+ # like Guard. This method will be removed in rouge 5.0.
14
21
  def reload!
22
+ Kernel::warn "Rouge.reload! is deprecated, with no replacement, and will be removed in 5.0. Use a reloading system like Guard instead."
15
23
  Object::send :remove_const, :Rouge
16
24
  Kernel::load __FILE__
17
25
  end
@@ -36,71 +44,74 @@ module Rouge
36
44
  formatter.format(lexer.lex(text), &b)
37
45
  end
38
46
 
39
- # Load a file relative to the `lib/rouge` path.
40
- #
41
- # @api private
42
- def load_file(path)
43
- Kernel::load File.join(LIB_DIR, "rouge/#{path}.rb")
44
- end
45
-
46
- # Load the lexers in the `lib/rouge/lexers` directory.
47
- #
48
- # @api private
49
- def load_lexers
50
- lexer_dir = Pathname.new(LIB_DIR) / "rouge/lexers"
51
- Pathname.glob(lexer_dir / '*.rb').each do |f|
52
- Lexers.load_lexer(f.relative_path_from(lexer_dir))
53
- end
47
+ def eager_load!
48
+ Rouge::Lexer.all.each(&:eager_load!)
54
49
  end
55
50
  end
56
51
  end
57
52
 
58
- Rouge.load_file 'version'
59
- Rouge.load_file 'util'
60
- Rouge.load_file 'text_analyzer'
61
- Rouge.load_file 'token'
53
+ require_relative 'rouge/version'
54
+ require_relative 'rouge/util'
55
+ require_relative 'rouge/text_analyzer'
56
+ require_relative 'rouge/token'
62
57
 
63
- Rouge.load_file 'lexer'
64
- Rouge.load_file 'regex_lexer'
65
- Rouge.load_file 'template_lexer'
58
+ require_relative 'rouge/lexer'
59
+ require_relative 'rouge/regex_lexer'
60
+ require_relative 'rouge/template_lexer'
66
61
 
67
- Rouge.load_lexers
62
+ # workaround for https://bugs.ruby-lang.org/issues/21870
63
+ # delete this entire begin/end block (or guard it against RUBY_VERSION)
64
+ # when that is fixed.
65
+ begin
66
+ old_verbose, $VERBOSE = $VERBOSE, false
67
+ require_relative 'rouge/lexers/xml'
68
+ require_relative 'rouge/lexers/css'
69
+ require_relative 'rouge/lexers/html'
70
+ require_relative 'rouge/lexers/julia'
71
+ ensure
72
+ $VERBOSE = old_verbose
73
+ end
74
+
75
+ Dir.glob('rouge/lexers/*.rb', base: __dir__).each do |file|
76
+ require_relative file
77
+ end
68
78
 
69
- Rouge.load_file 'guesser'
70
- Rouge.load_file 'guessers/util'
71
- Rouge.load_file 'guessers/glob_mapping'
72
- Rouge.load_file 'guessers/modeline'
73
- Rouge.load_file 'guessers/filename'
74
- Rouge.load_file 'guessers/mimetype'
75
- Rouge.load_file 'guessers/source'
76
- Rouge.load_file 'guessers/disambiguation'
79
+ require_relative 'rouge/guesser'
80
+ require_relative 'rouge/guessers/util'
81
+ require_relative 'rouge/guessers/glob_mapping'
82
+ require_relative 'rouge/guessers/modeline'
83
+ require_relative 'rouge/guessers/filename'
84
+ require_relative 'rouge/guessers/mimetype'
85
+ require_relative 'rouge/guessers/source'
86
+ require_relative 'rouge/guessers/disambiguation'
77
87
 
78
- Rouge.load_file 'formatter'
79
- Rouge.load_file 'formatters/html'
80
- Rouge.load_file 'formatters/html_table'
81
- Rouge.load_file 'formatters/html_pygments'
82
- Rouge.load_file 'formatters/html_legacy'
83
- Rouge.load_file 'formatters/html_linewise'
84
- Rouge.load_file 'formatters/html_line_highlighter'
85
- Rouge.load_file 'formatters/html_line_table'
86
- Rouge.load_file 'formatters/html_inline'
87
- Rouge.load_file 'formatters/terminal256'
88
- Rouge.load_file 'formatters/terminal_truecolor'
89
- Rouge.load_file 'formatters/tex'
90
- Rouge.load_file 'formatters/null'
88
+ require_relative 'rouge/formatter'
89
+ require_relative 'rouge/formatters/html'
90
+ require_relative 'rouge/formatters/html_table'
91
+ require_relative 'rouge/formatters/html_pygments'
92
+ require_relative 'rouge/formatters/html_legacy'
93
+ require_relative 'rouge/formatters/html_linewise'
94
+ require_relative 'rouge/formatters/html_line_highlighter'
95
+ require_relative 'rouge/formatters/html_line_table'
96
+ require_relative 'rouge/formatters/html_inline'
97
+ require_relative 'rouge/formatters/html_debug'
98
+ require_relative 'rouge/formatters/terminal256'
99
+ require_relative 'rouge/formatters/terminal_truecolor'
100
+ require_relative 'rouge/formatters/tex'
101
+ require_relative 'rouge/formatters/null'
91
102
 
92
- Rouge.load_file 'theme'
93
- Rouge.load_file 'tex_theme_renderer'
94
- Rouge.load_file 'themes/thankful_eyes'
95
- Rouge.load_file 'themes/colorful'
96
- Rouge.load_file 'themes/base16'
97
- Rouge.load_file 'themes/github'
98
- Rouge.load_file 'themes/igor_pro'
99
- Rouge.load_file 'themes/monokai'
100
- Rouge.load_file 'themes/molokai'
101
- Rouge.load_file 'themes/monokai_sublime'
102
- Rouge.load_file 'themes/gruvbox'
103
- Rouge.load_file 'themes/tulip'
104
- Rouge.load_file 'themes/pastie'
105
- Rouge.load_file 'themes/bw'
106
- Rouge.load_file 'themes/magritte'
103
+ require_relative 'rouge/theme'
104
+ require_relative 'rouge/tex_theme_renderer'
105
+ require_relative 'rouge/themes/thankful_eyes'
106
+ require_relative 'rouge/themes/colorful'
107
+ require_relative 'rouge/themes/base16'
108
+ require_relative 'rouge/themes/github'
109
+ require_relative 'rouge/themes/igor_pro'
110
+ require_relative 'rouge/themes/monokai'
111
+ require_relative 'rouge/themes/molokai'
112
+ require_relative 'rouge/themes/monokai_sublime'
113
+ require_relative 'rouge/themes/gruvbox'
114
+ require_relative 'rouge/themes/tulip'
115
+ require_relative 'rouge/themes/pastie'
116
+ require_relative 'rouge/themes/bw'
117
+ require_relative 'rouge/themes/magritte'
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rouge
6
+ # Checks for the use of `.join('|')` or `Regexp.union` inside
7
+ # interpolated regular expressions.
8
+ #
9
+ # Building alternation patterns by joining arrays or using
10
+ # `Regexp.union` inside a regexp harms performance — the regex
11
+ # engine must backtrack through every alternative on each match
12
+ # attempt. It also risks quoting bugs when values contain regex
13
+ # metacharacters.
14
+ #
15
+ # Prefer a `Set` lookup with a simple regex pattern instead.
16
+ #
17
+ # @example
18
+ # # bad — joins an array into a huge alternation regex
19
+ # KEYWORDS = %w[if else while ...]
20
+ # rule %r/\b(#{KEYWORDS.join('|')})\b/, Keyword
21
+ #
22
+ # # bad — Regexp.union inside a regex has the same problem
23
+ # rule %r/#{Regexp.union(keywords)}/
24
+ #
25
+ # # good — simple regex + Set lookup
26
+ # KEYWORDS = Set.new(%w[if else while ...])
27
+ # rule %r/\w+/ do |m|
28
+ # if KEYWORDS.include?(m[0])
29
+ # token Keyword
30
+ # else
31
+ # token Name
32
+ # end
33
+ # end
34
+ #
35
+ class NoBuildingAlternationPatternInRegexp < RuboCop::Cop::Base
36
+ MSG = 'Avoid building alternation patterns inside a regexp. ' \
37
+ 'Use a Set lookup with a simple regex pattern for performance.'
38
+
39
+ # @!method join_pipe_call?(node)
40
+ # Checks if a node is a `.join('|')` or `.join("|")` call.
41
+ def_node_matcher :join_pipe_call?, <<~PATTERN
42
+ (send _ :join (str "|"))
43
+ PATTERN
44
+
45
+ # @!method regexp_union_call?(node)
46
+ # Checks if a node is a `Regexp.union(...)` call.
47
+ def_node_matcher :regexp_union_call?, <<~PATTERN
48
+ (send (const nil? :Regexp) :union ...)
49
+ PATTERN
50
+
51
+ def on_regexp(node)
52
+ node.children.each do |child|
53
+ next unless child.begin_type?
54
+
55
+ find_offending_calls(child)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def find_offending_calls(begin_node)
62
+ begin_node.each_descendant(:send) do |send_node|
63
+ next unless join_pipe_call?(send_node) || regexp_union_call?(send_node)
64
+
65
+ add_offense(send_node)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,37 @@
1
+ module RuboCop
2
+ module Cop
3
+ module Rouge
4
+ class NoHugeCollections < RuboCop::Cop::Base
5
+ MSG = 'Avoid collections of over 300 elements. ' \
6
+ 'Place those in a lazy-loaded file, ideally ' \
7
+ 'generated by a Rake task from the relevant documentation.'
8
+
9
+
10
+ def_node_matcher :set_literal?, <<~PATTERN
11
+ (send (const nil? :Set) :[] ...)
12
+ PATTERN
13
+
14
+ RESTRICT_ON_SEND = [:[]]
15
+ MAX_SIZE = 300
16
+
17
+ Set["1", "2", "3"]
18
+ Set.new %w(1 2 3)
19
+
20
+ def on_send(node)
21
+ return unless set_literal?(node)
22
+
23
+ # adjust by 2 for the target and method name
24
+ if node.children.size - 2 > MAX_SIZE
25
+ add_offense(node)
26
+ end
27
+ end
28
+
29
+ def on_array(node)
30
+ if node.children.size >= MAX_SIZE
31
+ add_offense(node)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end