rouge-alda 3.3.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 (335) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +28 -0
  3. data/LICENSE +186 -0
  4. data/bin/rougify +18 -0
  5. data/lib/rouge/cli.rb +432 -0
  6. data/lib/rouge/demos/abap +6 -0
  7. data/lib/rouge/demos/actionscript +4 -0
  8. data/lib/rouge/demos/alda +10 -0
  9. data/lib/rouge/demos/apache +21 -0
  10. data/lib/rouge/demos/apiblueprint +33 -0
  11. data/lib/rouge/demos/applescript +2 -0
  12. data/lib/rouge/demos/awk +4 -0
  13. data/lib/rouge/demos/biml +38 -0
  14. data/lib/rouge/demos/bsl +7 -0
  15. data/lib/rouge/demos/c +8 -0
  16. data/lib/rouge/demos/ceylon +7 -0
  17. data/lib/rouge/demos/cfscript +18 -0
  18. data/lib/rouge/demos/clojure +5 -0
  19. data/lib/rouge/demos/cmake +7 -0
  20. data/lib/rouge/demos/coffeescript +5 -0
  21. data/lib/rouge/demos/common_lisp +1 -0
  22. data/lib/rouge/demos/conf +4 -0
  23. data/lib/rouge/demos/console +6 -0
  24. data/lib/rouge/demos/coq +13 -0
  25. data/lib/rouge/demos/cpp +8 -0
  26. data/lib/rouge/demos/crystal +45 -0
  27. data/lib/rouge/demos/csharp +5 -0
  28. data/lib/rouge/demos/css +4 -0
  29. data/lib/rouge/demos/d +16 -0
  30. data/lib/rouge/demos/dart +6 -0
  31. data/lib/rouge/demos/diff +7 -0
  32. data/lib/rouge/demos/digdag +19 -0
  33. data/lib/rouge/demos/docker +9 -0
  34. data/lib/rouge/demos/dot +5 -0
  35. data/lib/rouge/demos/eiffel +30 -0
  36. data/lib/rouge/demos/elixir +1 -0
  37. data/lib/rouge/demos/elm +4 -0
  38. data/lib/rouge/demos/erb +1 -0
  39. data/lib/rouge/demos/erlang +7 -0
  40. data/lib/rouge/demos/factor +5 -0
  41. data/lib/rouge/demos/fortran +22 -0
  42. data/lib/rouge/demos/fsharp +12 -0
  43. data/lib/rouge/demos/gherkin +17 -0
  44. data/lib/rouge/demos/glsl +14 -0
  45. data/lib/rouge/demos/go +7 -0
  46. data/lib/rouge/demos/gradle +10 -0
  47. data/lib/rouge/demos/graphql +17 -0
  48. data/lib/rouge/demos/groovy +9 -0
  49. data/lib/rouge/demos/hack +5 -0
  50. data/lib/rouge/demos/haml +5 -0
  51. data/lib/rouge/demos/handlebars +7 -0
  52. data/lib/rouge/demos/haskell +6 -0
  53. data/lib/rouge/demos/hcl +7 -0
  54. data/lib/rouge/demos/html +8 -0
  55. data/lib/rouge/demos/http +14 -0
  56. data/lib/rouge/demos/hylang +10 -0
  57. data/lib/rouge/demos/idlang +8 -0
  58. data/lib/rouge/demos/igorpro +9 -0
  59. data/lib/rouge/demos/ini +4 -0
  60. data/lib/rouge/demos/io +11 -0
  61. data/lib/rouge/demos/irb +4 -0
  62. data/lib/rouge/demos/irb_output +2 -0
  63. data/lib/rouge/demos/java +5 -0
  64. data/lib/rouge/demos/javascript +1 -0
  65. data/lib/rouge/demos/jinja +9 -0
  66. data/lib/rouge/demos/json +1 -0
  67. data/lib/rouge/demos/json-doc +1 -0
  68. data/lib/rouge/demos/jsonnet +28 -0
  69. data/lib/rouge/demos/jsp +29 -0
  70. data/lib/rouge/demos/jsx +17 -0
  71. data/lib/rouge/demos/julia +11 -0
  72. data/lib/rouge/demos/kotlin +3 -0
  73. data/lib/rouge/demos/lasso +12 -0
  74. data/lib/rouge/demos/liquid +11 -0
  75. data/lib/rouge/demos/literate_coffeescript +3 -0
  76. data/lib/rouge/demos/literate_haskell +7 -0
  77. data/lib/rouge/demos/llvm +20 -0
  78. data/lib/rouge/demos/lua +12 -0
  79. data/lib/rouge/demos/m68k +16 -0
  80. data/lib/rouge/demos/make +6 -0
  81. data/lib/rouge/demos/markdown +4 -0
  82. data/lib/rouge/demos/mathematica +8 -0
  83. data/lib/rouge/demos/matlab +6 -0
  84. data/lib/rouge/demos/moonscript +16 -0
  85. data/lib/rouge/demos/mosel +10 -0
  86. data/lib/rouge/demos/mxml +22 -0
  87. data/lib/rouge/demos/nasm +26 -0
  88. data/lib/rouge/demos/nginx +5 -0
  89. data/lib/rouge/demos/nim +27 -0
  90. data/lib/rouge/demos/nix +19 -0
  91. data/lib/rouge/demos/objective_c +18 -0
  92. data/lib/rouge/demos/ocaml +12 -0
  93. data/lib/rouge/demos/pascal +14 -0
  94. data/lib/rouge/demos/perl +5 -0
  95. data/lib/rouge/demos/php +3 -0
  96. data/lib/rouge/demos/plaintext +1 -0
  97. data/lib/rouge/demos/plist +142 -0
  98. data/lib/rouge/demos/pony +17 -0
  99. data/lib/rouge/demos/powershell +49 -0
  100. data/lib/rouge/demos/praat +26 -0
  101. data/lib/rouge/demos/prolog +9 -0
  102. data/lib/rouge/demos/prometheus +9 -0
  103. data/lib/rouge/demos/properties +7 -0
  104. data/lib/rouge/demos/protobuf +5 -0
  105. data/lib/rouge/demos/puppet +6 -0
  106. data/lib/rouge/demos/python +6 -0
  107. data/lib/rouge/demos/q +2 -0
  108. data/lib/rouge/demos/qml +9 -0
  109. data/lib/rouge/demos/r +8 -0
  110. data/lib/rouge/demos/racket +24 -0
  111. data/lib/rouge/demos/ruby +9 -0
  112. data/lib/rouge/demos/rust +12 -0
  113. data/lib/rouge/demos/sass +3 -0
  114. data/lib/rouge/demos/scala +3 -0
  115. data/lib/rouge/demos/scheme +4 -0
  116. data/lib/rouge/demos/scss +5 -0
  117. data/lib/rouge/demos/sed +4 -0
  118. data/lib/rouge/demos/shell +2 -0
  119. data/lib/rouge/demos/sieve +10 -0
  120. data/lib/rouge/demos/slim +17 -0
  121. data/lib/rouge/demos/smalltalk +6 -0
  122. data/lib/rouge/demos/smarty +12 -0
  123. data/lib/rouge/demos/sml +4 -0
  124. data/lib/rouge/demos/sqf +14 -0
  125. data/lib/rouge/demos/sql +1 -0
  126. data/lib/rouge/demos/swift +5 -0
  127. data/lib/rouge/demos/tap +5 -0
  128. data/lib/rouge/demos/tcl +1 -0
  129. data/lib/rouge/demos/terraform +31 -0
  130. data/lib/rouge/demos/tex +1 -0
  131. data/lib/rouge/demos/toml +9 -0
  132. data/lib/rouge/demos/tsx +17 -0
  133. data/lib/rouge/demos/tulip +13 -0
  134. data/lib/rouge/demos/turtle +26 -0
  135. data/lib/rouge/demos/twig +9 -0
  136. data/lib/rouge/demos/typescript +1 -0
  137. data/lib/rouge/demos/vala +8 -0
  138. data/lib/rouge/demos/vb +4 -0
  139. data/lib/rouge/demos/verilog +27 -0
  140. data/lib/rouge/demos/vhdl +23 -0
  141. data/lib/rouge/demos/viml +14 -0
  142. data/lib/rouge/demos/vue +11 -0
  143. data/lib/rouge/demos/wollok +11 -0
  144. data/lib/rouge/demos/xml +2 -0
  145. data/lib/rouge/demos/yaml +4 -0
  146. data/lib/rouge/formatter.rb +76 -0
  147. data/lib/rouge/formatters/html.rb +38 -0
  148. data/lib/rouge/formatters/html_inline.rb +31 -0
  149. data/lib/rouge/formatters/html_legacy.rb +45 -0
  150. data/lib/rouge/formatters/html_linewise.rb +28 -0
  151. data/lib/rouge/formatters/html_pygments.rb +18 -0
  152. data/lib/rouge/formatters/html_table.rb +62 -0
  153. data/lib/rouge/formatters/null.rb +20 -0
  154. data/lib/rouge/formatters/terminal256.rb +181 -0
  155. data/lib/rouge/guesser.rb +57 -0
  156. data/lib/rouge/guessers/disambiguation.rb +106 -0
  157. data/lib/rouge/guessers/filename.rb +27 -0
  158. data/lib/rouge/guessers/glob_mapping.rb +45 -0
  159. data/lib/rouge/guessers/mimetype.rb +16 -0
  160. data/lib/rouge/guessers/modeline.rb +46 -0
  161. data/lib/rouge/guessers/source.rb +31 -0
  162. data/lib/rouge/guessers/util.rb +34 -0
  163. data/lib/rouge/lexer.rb +462 -0
  164. data/lib/rouge/lexers/abap.rb +240 -0
  165. data/lib/rouge/lexers/actionscript.rb +196 -0
  166. data/lib/rouge/lexers/alda.rb +43 -0
  167. data/lib/rouge/lexers/apache/keywords.yml +764 -0
  168. data/lib/rouge/lexers/apache.rb +73 -0
  169. data/lib/rouge/lexers/apiblueprint.rb +49 -0
  170. data/lib/rouge/lexers/apple_script.rb +369 -0
  171. data/lib/rouge/lexers/awk.rb +162 -0
  172. data/lib/rouge/lexers/biml.rb +43 -0
  173. data/lib/rouge/lexers/bsl.rb +82 -0
  174. data/lib/rouge/lexers/c.rb +213 -0
  175. data/lib/rouge/lexers/ceylon.rb +124 -0
  176. data/lib/rouge/lexers/cfscript.rb +154 -0
  177. data/lib/rouge/lexers/clojure.rb +113 -0
  178. data/lib/rouge/lexers/cmake.rb +207 -0
  179. data/lib/rouge/lexers/coffeescript.rb +175 -0
  180. data/lib/rouge/lexers/common_lisp.rb +346 -0
  181. data/lib/rouge/lexers/conf.rb +25 -0
  182. data/lib/rouge/lexers/console.rb +137 -0
  183. data/lib/rouge/lexers/coq.rb +188 -0
  184. data/lib/rouge/lexers/cpp.rb +79 -0
  185. data/lib/rouge/lexers/crystal.rb +430 -0
  186. data/lib/rouge/lexers/csharp.rb +115 -0
  187. data/lib/rouge/lexers/css.rb +274 -0
  188. data/lib/rouge/lexers/d.rb +177 -0
  189. data/lib/rouge/lexers/dart.rb +105 -0
  190. data/lib/rouge/lexers/diff.rb +33 -0
  191. data/lib/rouge/lexers/digdag.rb +70 -0
  192. data/lib/rouge/lexers/docker.rb +51 -0
  193. data/lib/rouge/lexers/dot.rb +69 -0
  194. data/lib/rouge/lexers/eiffel.rb +66 -0
  195. data/lib/rouge/lexers/elixir.rb +134 -0
  196. data/lib/rouge/lexers/elm.rb +90 -0
  197. data/lib/rouge/lexers/erb.rb +53 -0
  198. data/lib/rouge/lexers/erlang.rb +115 -0
  199. data/lib/rouge/lexers/factor.rb +303 -0
  200. data/lib/rouge/lexers/fortran.rb +178 -0
  201. data/lib/rouge/lexers/fsharp.rb +119 -0
  202. data/lib/rouge/lexers/gherkin/keywords.rb +16 -0
  203. data/lib/rouge/lexers/gherkin.rb +138 -0
  204. data/lib/rouge/lexers/glsl.rb +136 -0
  205. data/lib/rouge/lexers/go.rb +175 -0
  206. data/lib/rouge/lexers/gradle.rb +38 -0
  207. data/lib/rouge/lexers/graphql.rb +254 -0
  208. data/lib/rouge/lexers/groovy.rb +113 -0
  209. data/lib/rouge/lexers/hack.rb +49 -0
  210. data/lib/rouge/lexers/haml.rb +230 -0
  211. data/lib/rouge/lexers/handlebars.rb +80 -0
  212. data/lib/rouge/lexers/haskell.rb +198 -0
  213. data/lib/rouge/lexers/hcl.rb +163 -0
  214. data/lib/rouge/lexers/html.rb +140 -0
  215. data/lib/rouge/lexers/http.rb +81 -0
  216. data/lib/rouge/lexers/hylang.rb +94 -0
  217. data/lib/rouge/lexers/idlang.rb +312 -0
  218. data/lib/rouge/lexers/igorpro.rb +664 -0
  219. data/lib/rouge/lexers/ini.rb +54 -0
  220. data/lib/rouge/lexers/io.rb +69 -0
  221. data/lib/rouge/lexers/irb.rb +67 -0
  222. data/lib/rouge/lexers/java.rb +88 -0
  223. data/lib/rouge/lexers/javascript.rb +283 -0
  224. data/lib/rouge/lexers/jinja.rb +138 -0
  225. data/lib/rouge/lexers/json.rb +30 -0
  226. data/lib/rouge/lexers/json_doc.rb +24 -0
  227. data/lib/rouge/lexers/jsonnet.rb +152 -0
  228. data/lib/rouge/lexers/jsp.rb +120 -0
  229. data/lib/rouge/lexers/jsx.rb +104 -0
  230. data/lib/rouge/lexers/julia.rb +167 -0
  231. data/lib/rouge/lexers/kotlin.rb +127 -0
  232. data/lib/rouge/lexers/lasso/keywords.yml +446 -0
  233. data/lib/rouge/lexers/lasso.rb +215 -0
  234. data/lib/rouge/lexers/liquid.rb +288 -0
  235. data/lib/rouge/lexers/literate_coffeescript.rb +34 -0
  236. data/lib/rouge/lexers/literate_haskell.rb +37 -0
  237. data/lib/rouge/lexers/llvm.rb +81 -0
  238. data/lib/rouge/lexers/lua/builtins.rb +24 -0
  239. data/lib/rouge/lexers/lua.rb +126 -0
  240. data/lib/rouge/lexers/m68k.rb +144 -0
  241. data/lib/rouge/lexers/make.rb +113 -0
  242. data/lib/rouge/lexers/markdown.rb +155 -0
  243. data/lib/rouge/lexers/mathematica/builtins.rb +13 -0
  244. data/lib/rouge/lexers/mathematica.rb +96 -0
  245. data/lib/rouge/lexers/matlab/builtins.rb +13 -0
  246. data/lib/rouge/lexers/matlab.rb +72 -0
  247. data/lib/rouge/lexers/moonscript.rb +115 -0
  248. data/lib/rouge/lexers/mosel.rb +232 -0
  249. data/lib/rouge/lexers/mxml.rb +69 -0
  250. data/lib/rouge/lexers/nasm.rb +199 -0
  251. data/lib/rouge/lexers/nginx.rb +72 -0
  252. data/lib/rouge/lexers/nim.rb +153 -0
  253. data/lib/rouge/lexers/nix.rb +211 -0
  254. data/lib/rouge/lexers/objective_c.rb +195 -0
  255. data/lib/rouge/lexers/ocaml.rb +101 -0
  256. data/lib/rouge/lexers/pascal.rb +67 -0
  257. data/lib/rouge/lexers/perl.rb +201 -0
  258. data/lib/rouge/lexers/php/builtins.rb +196 -0
  259. data/lib/rouge/lexers/php.rb +194 -0
  260. data/lib/rouge/lexers/plain_text.rb +27 -0
  261. data/lib/rouge/lexers/plist.rb +47 -0
  262. data/lib/rouge/lexers/pony.rb +94 -0
  263. data/lib/rouge/lexers/powershell.rb +679 -0
  264. data/lib/rouge/lexers/praat.rb +351 -0
  265. data/lib/rouge/lexers/prolog.rb +61 -0
  266. data/lib/rouge/lexers/prometheus.rb +123 -0
  267. data/lib/rouge/lexers/properties.rb +52 -0
  268. data/lib/rouge/lexers/protobuf.rb +71 -0
  269. data/lib/rouge/lexers/puppet.rb +129 -0
  270. data/lib/rouge/lexers/python.rb +247 -0
  271. data/lib/rouge/lexers/q.rb +125 -0
  272. data/lib/rouge/lexers/qml.rb +74 -0
  273. data/lib/rouge/lexers/r.rb +90 -0
  274. data/lib/rouge/lexers/racket.rb +545 -0
  275. data/lib/rouge/lexers/ruby.rb +439 -0
  276. data/lib/rouge/lexers/rust.rb +198 -0
  277. data/lib/rouge/lexers/sass/common.rb +181 -0
  278. data/lib/rouge/lexers/sass.rb +75 -0
  279. data/lib/rouge/lexers/scala.rb +143 -0
  280. data/lib/rouge/lexers/scheme.rb +113 -0
  281. data/lib/rouge/lexers/scss.rb +35 -0
  282. data/lib/rouge/lexers/sed.rb +173 -0
  283. data/lib/rouge/lexers/shell.rb +190 -0
  284. data/lib/rouge/lexers/sieve.rb +97 -0
  285. data/lib/rouge/lexers/slim.rb +229 -0
  286. data/lib/rouge/lexers/smalltalk.rb +117 -0
  287. data/lib/rouge/lexers/smarty.rb +81 -0
  288. data/lib/rouge/lexers/sml.rb +345 -0
  289. data/lib/rouge/lexers/sqf/commands.rb +15 -0
  290. data/lib/rouge/lexers/sqf.rb +109 -0
  291. data/lib/rouge/lexers/sql.rb +141 -0
  292. data/lib/rouge/lexers/swift.rb +182 -0
  293. data/lib/rouge/lexers/tap.rb +89 -0
  294. data/lib/rouge/lexers/tcl.rb +193 -0
  295. data/lib/rouge/lexers/terraform.rb +105 -0
  296. data/lib/rouge/lexers/tex.rb +70 -0
  297. data/lib/rouge/lexers/toml.rb +68 -0
  298. data/lib/rouge/lexers/tsx.rb +20 -0
  299. data/lib/rouge/lexers/tulip.rb +108 -0
  300. data/lib/rouge/lexers/turtle.rb +64 -0
  301. data/lib/rouge/lexers/twig.rb +40 -0
  302. data/lib/rouge/lexers/typescript/common.rb +34 -0
  303. data/lib/rouge/lexers/typescript.rb +23 -0
  304. data/lib/rouge/lexers/vala.rb +78 -0
  305. data/lib/rouge/lexers/vb.rb +165 -0
  306. data/lib/rouge/lexers/verilog.rb +165 -0
  307. data/lib/rouge/lexers/vhdl.rb +98 -0
  308. data/lib/rouge/lexers/viml/keywords.rb +14 -0
  309. data/lib/rouge/lexers/viml.rb +102 -0
  310. data/lib/rouge/lexers/vue.rb +124 -0
  311. data/lib/rouge/lexers/wollok.rb +104 -0
  312. data/lib/rouge/lexers/xml.rb +58 -0
  313. data/lib/rouge/lexers/yaml.rb +374 -0
  314. data/lib/rouge/plugins/redcarpet.rb +31 -0
  315. data/lib/rouge/regex_lexer.rb +442 -0
  316. data/lib/rouge/template_lexer.rb +21 -0
  317. data/lib/rouge/text_analyzer.rb +50 -0
  318. data/lib/rouge/theme.rb +214 -0
  319. data/lib/rouge/themes/base16.rb +131 -0
  320. data/lib/rouge/themes/colorful.rb +68 -0
  321. data/lib/rouge/themes/github.rb +72 -0
  322. data/lib/rouge/themes/gruvbox.rb +168 -0
  323. data/lib/rouge/themes/igor_pro.rb +21 -0
  324. data/lib/rouge/themes/molokai.rb +83 -0
  325. data/lib/rouge/themes/monokai.rb +93 -0
  326. data/lib/rouge/themes/monokai_sublime.rb +92 -0
  327. data/lib/rouge/themes/pastie.rb +70 -0
  328. data/lib/rouge/themes/thankful_eyes.rb +75 -0
  329. data/lib/rouge/themes/tulip.rb +70 -0
  330. data/lib/rouge/token.rb +183 -0
  331. data/lib/rouge/util.rb +102 -0
  332. data/lib/rouge/version.rb +8 -0
  333. data/lib/rouge.rb +84 -0
  334. data/rouge.gemspec +25 -0
  335. metadata +384 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rouge
4
+ module Guessers
5
+ module Util
6
+ module SourceNormalizer
7
+ UTF8_BOM = "\xEF\xBB\xBF"
8
+ UTF8_BOM_RE = /\A#{UTF8_BOM}/
9
+
10
+ # @param [String,nil] source
11
+ # @return [String,nil]
12
+ def self.normalize(source)
13
+ source.sub(UTF8_BOM_RE, '').gsub(/\r\n/, "\n")
14
+ end
15
+ end
16
+
17
+ def test_glob(pattern, path)
18
+ File.fnmatch?(pattern, path, File::FNM_DOTMATCH | File::FNM_CASEFOLD)
19
+ end
20
+
21
+ # @param [String,IO] source
22
+ # @return [String]
23
+ def get_source(source)
24
+ if source.respond_to?(:to_str)
25
+ SourceNormalizer.normalize(source.to_str)
26
+ elsif source.respond_to?(:read)
27
+ SourceNormalizer.normalize(source.read)
28
+ else
29
+ raise ArgumentError, "Invalid source: #{source.inspect}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,462 @@
1
+ # -*- coding: utf-8 -*- #
2
+ # frozen_string_literal: true
3
+
4
+ # stdlib
5
+ require 'strscan'
6
+ require 'cgi'
7
+ require 'set'
8
+
9
+ module Rouge
10
+ # @abstract
11
+ # A lexer transforms text into a stream of `[token, chunk]` pairs.
12
+ class Lexer
13
+ include Token::Tokens
14
+
15
+ @option_docs = {}
16
+
17
+ class << self
18
+ # Lexes `stream` with the given options. The lex is delegated to a
19
+ # new instance.
20
+ #
21
+ # @see #lex
22
+ def lex(stream, opts={}, &b)
23
+ new(opts).lex(stream, &b)
24
+ end
25
+
26
+ # Given a name in string, return the correct lexer class.
27
+ # @param [String] name
28
+ # @return [Class<Rouge::Lexer>,nil]
29
+ def find(name)
30
+ registry[name.to_s]
31
+ end
32
+
33
+ # Find a lexer, with fancy shiny features.
34
+ #
35
+ # * The string you pass can include CGI-style options
36
+ #
37
+ # Lexer.find_fancy('erb?parent=tex')
38
+ #
39
+ # * You can pass the special name 'guess' so we guess for you,
40
+ # and you can pass a second argument of the code to guess by
41
+ #
42
+ # Lexer.find_fancy('guess', "#!/bin/bash\necho Hello, world")
43
+ #
44
+ # This is used in the Redcarpet plugin as well as Rouge's own
45
+ # markdown lexer for highlighting internal code blocks.
46
+ #
47
+ def find_fancy(str, code=nil, additional_options={})
48
+
49
+ if str && !str.include?('?') && str != 'guess'
50
+ lexer_class = find(str)
51
+ return lexer_class && lexer_class.new(additional_options)
52
+ end
53
+
54
+ name, opts = str ? str.split('?', 2) : [nil, '']
55
+
56
+ # parse the options hash from a cgi-style string
57
+ opts = CGI.parse(opts || '').map do |k, vals|
58
+ val = case vals.size
59
+ when 0 then true
60
+ when 1 then vals[0]
61
+ else vals
62
+ end
63
+
64
+ [ k.to_s, val ]
65
+ end
66
+
67
+ opts = additional_options.merge(Hash[opts])
68
+
69
+ lexer_class = case name
70
+ when 'guess', nil
71
+ self.guess(:source => code, :mimetype => opts['mimetype'])
72
+ when String
73
+ self.find(name)
74
+ end
75
+
76
+ lexer_class && lexer_class.new(opts)
77
+ end
78
+
79
+ # Specify or get this lexer's title. Meant to be human-readable.
80
+ def title(t=nil)
81
+ if t.nil?
82
+ t = tag.capitalize
83
+ end
84
+ @title ||= t
85
+ end
86
+
87
+ # Specify or get this lexer's description.
88
+ def desc(arg=:absent)
89
+ if arg == :absent
90
+ @desc
91
+ else
92
+ @desc = arg
93
+ end
94
+ end
95
+
96
+ def option_docs
97
+ @option_docs ||= InheritableHash.new(superclass.option_docs)
98
+ end
99
+
100
+ def option(name, desc)
101
+ option_docs[name.to_s] = desc
102
+ end
103
+
104
+ # Specify or get the path name containing a small demo for
105
+ # this lexer (can be overriden by {demo}).
106
+ def demo_file(arg=:absent)
107
+ return @demo_file = Pathname.new(arg) unless arg == :absent
108
+
109
+ @demo_file = Pathname.new(__FILE__).dirname.join('demos', tag)
110
+ end
111
+
112
+ # Specify or get a small demo string for this lexer
113
+ def demo(arg=:absent)
114
+ return @demo = arg unless arg == :absent
115
+
116
+ @demo = File.read(demo_file, mode: 'rt:bom|utf-8')
117
+ end
118
+
119
+ # @return a list of all lexers.
120
+ def all
121
+ registry.values.uniq
122
+ end
123
+
124
+ # Guess which lexer to use based on a hash of info.
125
+ #
126
+ # This accepts the same arguments as Lexer.guess, but will never throw
127
+ # an error. It will return a (possibly empty) list of potential lexers
128
+ # to use.
129
+ def guesses(info={})
130
+ mimetype, filename, source = info.values_at(:mimetype, :filename, :source)
131
+ custom_globs = info[:custom_globs]
132
+
133
+ guessers = (info[:guessers] || []).dup
134
+
135
+ guessers << Guessers::Mimetype.new(mimetype) if mimetype
136
+ guessers << Guessers::GlobMapping.by_pairs(custom_globs, filename) if custom_globs && filename
137
+ guessers << Guessers::Filename.new(filename) if filename
138
+ guessers << Guessers::Modeline.new(source) if source
139
+ guessers << Guessers::Source.new(source) if source
140
+ guessers << Guessers::Disambiguation.new(filename, source) if source && filename
141
+
142
+ Guesser.guess(guessers, Lexer.all)
143
+ end
144
+
145
+ # Guess which lexer to use based on a hash of info.
146
+ #
147
+ # @option info :mimetype
148
+ # A mimetype to guess by
149
+ # @option info :filename
150
+ # A filename to guess by
151
+ # @option info :source
152
+ # The source itself, which, if guessing by mimetype or filename
153
+ # fails, will be searched for shebangs, <!DOCTYPE ...> tags, and
154
+ # other hints.
155
+ # @param [Proc] fallback called if multiple lexers are detected.
156
+ # If omitted, Guesser::Ambiguous is raised.
157
+ #
158
+ # @see Lexer.detect?
159
+ # @see Lexer.guesses
160
+ # @return [Class<Rouge::Lexer>]
161
+ def guess(info={}, &fallback)
162
+ lexers = guesses(info)
163
+
164
+ return Lexers::PlainText if lexers.empty?
165
+ return lexers[0] if lexers.size == 1
166
+
167
+ if fallback
168
+ fallback.call(lexers)
169
+ else
170
+ raise Guesser::Ambiguous.new(lexers)
171
+ end
172
+ end
173
+
174
+ def guess_by_mimetype(mt)
175
+ guess :mimetype => mt
176
+ end
177
+
178
+ def guess_by_filename(fname)
179
+ guess :filename => fname
180
+ end
181
+
182
+ def guess_by_source(source)
183
+ guess :source => source
184
+ end
185
+
186
+ def enable_debug!
187
+ @debug_enabled = true
188
+ end
189
+
190
+ def disable_debug!
191
+ @debug_enabled = false
192
+ end
193
+
194
+ def debug_enabled?
195
+ !!@debug_enabled
196
+ end
197
+
198
+ protected
199
+ # @private
200
+ def register(name, lexer)
201
+ registry[name.to_s] = lexer
202
+ end
203
+
204
+ public
205
+ # Used to specify or get the canonical name of this lexer class.
206
+ #
207
+ # @example
208
+ # class MyLexer < Lexer
209
+ # tag 'foo'
210
+ # end
211
+ #
212
+ # MyLexer.tag # => 'foo'
213
+ #
214
+ # Lexer.find('foo') # => MyLexer
215
+ def tag(t=nil)
216
+ return @tag if t.nil?
217
+
218
+ @tag = t.to_s
219
+ Lexer.register(@tag, self)
220
+ end
221
+
222
+ # Used to specify alternate names this lexer class may be found by.
223
+ #
224
+ # @example
225
+ # class Erb < Lexer
226
+ # tag 'erb'
227
+ # aliases 'eruby', 'rhtml'
228
+ # end
229
+ #
230
+ # Lexer.find('eruby') # => Erb
231
+ def aliases(*args)
232
+ args.map!(&:to_s)
233
+ args.each { |arg| Lexer.register(arg, self) }
234
+ (@aliases ||= []).concat(args)
235
+ end
236
+
237
+ # Specify a list of filename globs associated with this lexer.
238
+ #
239
+ # @example
240
+ # class Ruby < Lexer
241
+ # filenames '*.rb', '*.ruby', 'Gemfile', 'Rakefile'
242
+ # end
243
+ def filenames(*fnames)
244
+ (@filenames ||= []).concat(fnames)
245
+ end
246
+
247
+ # Specify a list of mimetypes associated with this lexer.
248
+ #
249
+ # @example
250
+ # class Html < Lexer
251
+ # mimetypes 'text/html', 'application/xhtml+xml'
252
+ # end
253
+ def mimetypes(*mts)
254
+ (@mimetypes ||= []).concat(mts)
255
+ end
256
+
257
+ # @private
258
+ def assert_utf8!(str)
259
+ return if %w(US-ASCII UTF-8 ASCII-8BIT).include? str.encoding.name
260
+ raise EncodingError.new(
261
+ "Bad encoding: #{str.encoding.names.join(',')}. " +
262
+ "Please convert your string to UTF-8."
263
+ )
264
+ end
265
+
266
+ private
267
+ def registry
268
+ @registry ||= {}
269
+ end
270
+ end
271
+
272
+ # -*- instance methods -*- #
273
+
274
+ attr_reader :options
275
+ # Create a new lexer with the given options. Individual lexers may
276
+ # specify extra options. The only current globally accepted option
277
+ # is `:debug`.
278
+ #
279
+ # @option opts :debug
280
+ # Prints debug information to stdout. The particular info depends
281
+ # on the lexer in question. In regex lexers, this will log the
282
+ # state stack at the beginning of each step, along with each regex
283
+ # tried and each stream consumed. Try it, it's pretty useful.
284
+ def initialize(opts={})
285
+ @options = {}
286
+ opts.each { |k, v| @options[k.to_s] = v }
287
+
288
+ @debug = Lexer.debug_enabled? && bool_option(:debug)
289
+ end
290
+
291
+ def as_bool(val)
292
+ case val
293
+ when nil, false, 0, '0', 'off'
294
+ false
295
+ when Array
296
+ val.empty? ? true : as_bool(val.last)
297
+ else
298
+ true
299
+ end
300
+ end
301
+
302
+ def as_string(val)
303
+ return as_string(val.last) if val.is_a?(Array)
304
+
305
+ val ? val.to_s : nil
306
+ end
307
+
308
+ def as_list(val)
309
+ case val
310
+ when Array
311
+ val.flat_map { |v| as_list(v) }
312
+ when String
313
+ val.split(',')
314
+ else
315
+ []
316
+ end
317
+ end
318
+
319
+ def as_lexer(val)
320
+ return as_lexer(val.last) if val.is_a?(Array)
321
+ return val.new(@options) if val.is_a?(Class) && val < Lexer
322
+
323
+ case val
324
+ when Lexer
325
+ val
326
+ when String
327
+ lexer_class = Lexer.find(val)
328
+ lexer_class && lexer_class.new(@options)
329
+ end
330
+ end
331
+
332
+ def as_token(val)
333
+ return as_token(val.last) if val.is_a?(Array)
334
+ case val
335
+ when Token
336
+ val
337
+ else
338
+ Token[val]
339
+ end
340
+ end
341
+
342
+ def bool_option(name, &default)
343
+ if @options.key?(name.to_s)
344
+ as_bool(@options[name.to_s])
345
+ else
346
+ default ? default.call : false
347
+ end
348
+ end
349
+
350
+ def string_option(name, &default)
351
+ as_string(@options.delete(name.to_s, &default))
352
+ end
353
+
354
+ def lexer_option(name, &default)
355
+ as_lexer(@options.delete(name.to_s, &default))
356
+ end
357
+
358
+ def list_option(name, &default)
359
+ as_list(@options.delete(name.to_s, &default))
360
+ end
361
+
362
+ def token_option(name, &default)
363
+ as_token(@options.delete(name.to_s, &default))
364
+ end
365
+
366
+ def hash_option(name, defaults, &val_cast)
367
+ name = name.to_s
368
+ out = defaults.dup
369
+
370
+ base = @options.delete(name.to_s)
371
+ base = {} unless base.is_a?(Hash)
372
+ base.each { |k, v| out[k.to_s] = val_cast ? val_cast.call(v) : v }
373
+
374
+ @options.keys.each do |key|
375
+ next unless key =~ /(\w+)\[(\w+)\]/ and $1 == name
376
+ value = @options.delete(key)
377
+
378
+ out[$2] = val_cast ? val_cast.call(value) : value
379
+ end
380
+
381
+ out
382
+ end
383
+
384
+ # @abstract
385
+ #
386
+ # Called after each lex is finished. The default implementation
387
+ # is a noop.
388
+ def reset!
389
+ end
390
+
391
+ # Given a string, yield [token, chunk] pairs. If no block is given,
392
+ # an enumerator is returned.
393
+ #
394
+ # @option opts :continue
395
+ # Continue the lex from the previous state (i.e. don't call #reset!)
396
+ def lex(string, opts={}, &b)
397
+ return enum_for(:lex, string, opts) unless block_given?
398
+
399
+ Lexer.assert_utf8!(string)
400
+
401
+ reset! unless opts[:continue]
402
+
403
+ # consolidate consecutive tokens of the same type
404
+ last_token = nil
405
+ last_val = nil
406
+ stream_tokens(string) do |tok, val|
407
+ next if val.empty?
408
+
409
+ if tok == last_token
410
+ last_val << val
411
+ next
412
+ end
413
+
414
+ b.call(last_token, last_val) if last_token
415
+ last_token = tok
416
+ last_val = val
417
+ end
418
+
419
+ b.call(last_token, last_val) if last_token
420
+ end
421
+
422
+ # delegated to {Lexer.tag}
423
+ def tag
424
+ self.class.tag
425
+ end
426
+
427
+ # @abstract
428
+ #
429
+ # Yield `[token, chunk]` pairs, given a prepared input stream. This
430
+ # must be implemented.
431
+ #
432
+ # @param [StringScanner] stream
433
+ # the stream
434
+ def stream_tokens(stream, &b)
435
+ raise 'abstract'
436
+ end
437
+
438
+ # @abstract
439
+ #
440
+ # Return true if there is an in-text indication (such as a shebang
441
+ # or DOCTYPE declaration) that this lexer should be used.
442
+ #
443
+ # @param [TextAnalyzer] text
444
+ # the text to be analyzed, with a couple of handy methods on it,
445
+ # like {TextAnalyzer#shebang?} and {TextAnalyzer#doctype?}
446
+ def self.detect?(text)
447
+ false
448
+ end
449
+ end
450
+
451
+ module Lexers
452
+ @_loaded_lexers = {}
453
+
454
+ def self.load_lexer(relpath)
455
+ return if @_loaded_lexers.key?(relpath)
456
+ @_loaded_lexers[relpath] = true
457
+
458
+ root = Pathname.new(__FILE__).dirname.join('lexers')
459
+ load root.join(relpath)
460
+ end
461
+ end
462
+ end