[d24f17c] | 1 | /**
|
---|
| 2 | * @param {string} value
|
---|
| 3 | * @returns {RegExp}
|
---|
| 4 | * */
|
---|
| 5 |
|
---|
| 6 | /**
|
---|
| 7 | * @param {RegExp | string } re
|
---|
| 8 | * @returns {string}
|
---|
| 9 | */
|
---|
| 10 | function source(re) {
|
---|
| 11 | if (!re) return null;
|
---|
| 12 | if (typeof re === "string") return re;
|
---|
| 13 |
|
---|
| 14 | return re.source;
|
---|
| 15 | }
|
---|
| 16 |
|
---|
| 17 | /**
|
---|
| 18 | * @param {RegExp | string } re
|
---|
| 19 | * @returns {string}
|
---|
| 20 | */
|
---|
| 21 | function lookahead(re) {
|
---|
| 22 | return concat('(?=', re, ')');
|
---|
| 23 | }
|
---|
| 24 |
|
---|
| 25 | /**
|
---|
| 26 | * @param {...(RegExp | string) } args
|
---|
| 27 | * @returns {string}
|
---|
| 28 | */
|
---|
| 29 | function concat(...args) {
|
---|
| 30 | const joined = args.map((x) => source(x)).join("");
|
---|
| 31 | return joined;
|
---|
| 32 | }
|
---|
| 33 |
|
---|
| 34 | /*
|
---|
| 35 | Language: Ruby
|
---|
| 36 | Description: Ruby is a dynamic, open source programming language with a focus on simplicity and productivity.
|
---|
| 37 | Website: https://www.ruby-lang.org/
|
---|
| 38 | Author: Anton Kovalyov <anton@kovalyov.net>
|
---|
| 39 | Contributors: Peter Leonov <gojpeg@yandex.ru>, Vasily Polovnyov <vast@whiteants.net>, Loren Segal <lsegal@soen.ca>, Pascal Hurni <phi@ruby-reactive.org>, Cedric Sohrauer <sohrauer@googlemail.com>
|
---|
| 40 | Category: common
|
---|
| 41 | */
|
---|
| 42 |
|
---|
| 43 | function ruby(hljs) {
|
---|
| 44 | const RUBY_METHOD_RE = '([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)';
|
---|
| 45 | const RUBY_KEYWORDS = {
|
---|
| 46 | keyword:
|
---|
| 47 | 'and then defined module in return redo if BEGIN retry end for self when ' +
|
---|
| 48 | 'next until do begin unless END rescue else break undef not super class case ' +
|
---|
| 49 | 'require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor ' +
|
---|
| 50 | '__FILE__',
|
---|
| 51 | built_in: 'proc lambda',
|
---|
| 52 | literal:
|
---|
| 53 | 'true false nil'
|
---|
| 54 | };
|
---|
| 55 | const YARDOCTAG = {
|
---|
| 56 | className: 'doctag',
|
---|
| 57 | begin: '@[A-Za-z]+'
|
---|
| 58 | };
|
---|
| 59 | const IRB_OBJECT = {
|
---|
| 60 | begin: '#<',
|
---|
| 61 | end: '>'
|
---|
| 62 | };
|
---|
| 63 | const COMMENT_MODES = [
|
---|
| 64 | hljs.COMMENT(
|
---|
| 65 | '#',
|
---|
| 66 | '$',
|
---|
| 67 | {
|
---|
| 68 | contains: [ YARDOCTAG ]
|
---|
| 69 | }
|
---|
| 70 | ),
|
---|
| 71 | hljs.COMMENT(
|
---|
| 72 | '^=begin',
|
---|
| 73 | '^=end',
|
---|
| 74 | {
|
---|
| 75 | contains: [ YARDOCTAG ],
|
---|
| 76 | relevance: 10
|
---|
| 77 | }
|
---|
| 78 | ),
|
---|
| 79 | hljs.COMMENT('^__END__', '\\n$')
|
---|
| 80 | ];
|
---|
| 81 | const SUBST = {
|
---|
| 82 | className: 'subst',
|
---|
| 83 | begin: /#\{/,
|
---|
| 84 | end: /\}/,
|
---|
| 85 | keywords: RUBY_KEYWORDS
|
---|
| 86 | };
|
---|
| 87 | const STRING = {
|
---|
| 88 | className: 'string',
|
---|
| 89 | contains: [
|
---|
| 90 | hljs.BACKSLASH_ESCAPE,
|
---|
| 91 | SUBST
|
---|
| 92 | ],
|
---|
| 93 | variants: [
|
---|
| 94 | {
|
---|
| 95 | begin: /'/,
|
---|
| 96 | end: /'/
|
---|
| 97 | },
|
---|
| 98 | {
|
---|
| 99 | begin: /"/,
|
---|
| 100 | end: /"/
|
---|
| 101 | },
|
---|
| 102 | {
|
---|
| 103 | begin: /`/,
|
---|
| 104 | end: /`/
|
---|
| 105 | },
|
---|
| 106 | {
|
---|
| 107 | begin: /%[qQwWx]?\(/,
|
---|
| 108 | end: /\)/
|
---|
| 109 | },
|
---|
| 110 | {
|
---|
| 111 | begin: /%[qQwWx]?\[/,
|
---|
| 112 | end: /\]/
|
---|
| 113 | },
|
---|
| 114 | {
|
---|
| 115 | begin: /%[qQwWx]?\{/,
|
---|
| 116 | end: /\}/
|
---|
| 117 | },
|
---|
| 118 | {
|
---|
| 119 | begin: /%[qQwWx]?</,
|
---|
| 120 | end: />/
|
---|
| 121 | },
|
---|
| 122 | {
|
---|
| 123 | begin: /%[qQwWx]?\//,
|
---|
| 124 | end: /\//
|
---|
| 125 | },
|
---|
| 126 | {
|
---|
| 127 | begin: /%[qQwWx]?%/,
|
---|
| 128 | end: /%/
|
---|
| 129 | },
|
---|
| 130 | {
|
---|
| 131 | begin: /%[qQwWx]?-/,
|
---|
| 132 | end: /-/
|
---|
| 133 | },
|
---|
| 134 | {
|
---|
| 135 | begin: /%[qQwWx]?\|/,
|
---|
| 136 | end: /\|/
|
---|
| 137 | },
|
---|
| 138 | // in the following expressions, \B in the beginning suppresses recognition of ?-sequences
|
---|
| 139 | // where ? is the last character of a preceding identifier, as in: `func?4`
|
---|
| 140 | {
|
---|
| 141 | begin: /\B\?(\\\d{1,3})/
|
---|
| 142 | },
|
---|
| 143 | {
|
---|
| 144 | begin: /\B\?(\\x[A-Fa-f0-9]{1,2})/
|
---|
| 145 | },
|
---|
| 146 | {
|
---|
| 147 | begin: /\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/
|
---|
| 148 | },
|
---|
| 149 | {
|
---|
| 150 | begin: /\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/
|
---|
| 151 | },
|
---|
| 152 | {
|
---|
| 153 | begin: /\B\?\\(c|C-)[\x20-\x7e]/
|
---|
| 154 | },
|
---|
| 155 | {
|
---|
| 156 | begin: /\B\?\\?\S/
|
---|
| 157 | },
|
---|
| 158 | { // heredocs
|
---|
| 159 | begin: /<<[-~]?'?(\w+)\n(?:[^\n]*\n)*?\s*\1\b/,
|
---|
| 160 | returnBegin: true,
|
---|
| 161 | contains: [
|
---|
| 162 | {
|
---|
| 163 | begin: /<<[-~]?'?/
|
---|
| 164 | },
|
---|
| 165 | hljs.END_SAME_AS_BEGIN({
|
---|
| 166 | begin: /(\w+)/,
|
---|
| 167 | end: /(\w+)/,
|
---|
| 168 | contains: [
|
---|
| 169 | hljs.BACKSLASH_ESCAPE,
|
---|
| 170 | SUBST
|
---|
| 171 | ]
|
---|
| 172 | })
|
---|
| 173 | ]
|
---|
| 174 | }
|
---|
| 175 | ]
|
---|
| 176 | };
|
---|
| 177 |
|
---|
| 178 | // Ruby syntax is underdocumented, but this grammar seems to be accurate
|
---|
| 179 | // as of version 2.7.2 (confirmed with (irb and `Ripper.sexp(...)`)
|
---|
| 180 | // https://docs.ruby-lang.org/en/2.7.0/doc/syntax/literals_rdoc.html#label-Numbers
|
---|
| 181 | const decimal = '[1-9](_?[0-9])*|0';
|
---|
| 182 | const digits = '[0-9](_?[0-9])*';
|
---|
| 183 | const NUMBER = {
|
---|
| 184 | className: 'number',
|
---|
| 185 | relevance: 0,
|
---|
| 186 | variants: [
|
---|
| 187 | // decimal integer/float, optionally exponential or rational, optionally imaginary
|
---|
| 188 | {
|
---|
| 189 | begin: `\\b(${decimal})(\\.(${digits}))?([eE][+-]?(${digits})|r)?i?\\b`
|
---|
| 190 | },
|
---|
| 191 |
|
---|
| 192 | // explicit decimal/binary/octal/hexadecimal integer,
|
---|
| 193 | // optionally rational and/or imaginary
|
---|
| 194 | {
|
---|
| 195 | begin: "\\b0[dD][0-9](_?[0-9])*r?i?\\b"
|
---|
| 196 | },
|
---|
| 197 | {
|
---|
| 198 | begin: "\\b0[bB][0-1](_?[0-1])*r?i?\\b"
|
---|
| 199 | },
|
---|
| 200 | {
|
---|
| 201 | begin: "\\b0[oO][0-7](_?[0-7])*r?i?\\b"
|
---|
| 202 | },
|
---|
| 203 | {
|
---|
| 204 | begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"
|
---|
| 205 | },
|
---|
| 206 |
|
---|
| 207 | // 0-prefixed implicit octal integer, optionally rational and/or imaginary
|
---|
| 208 | {
|
---|
| 209 | begin: "\\b0(_?[0-7])+r?i?\\b"
|
---|
| 210 | }
|
---|
| 211 | ]
|
---|
| 212 | };
|
---|
| 213 |
|
---|
| 214 | const PARAMS = {
|
---|
| 215 | className: 'params',
|
---|
| 216 | begin: '\\(',
|
---|
| 217 | end: '\\)',
|
---|
| 218 | endsParent: true,
|
---|
| 219 | keywords: RUBY_KEYWORDS
|
---|
| 220 | };
|
---|
| 221 |
|
---|
| 222 | const RUBY_DEFAULT_CONTAINS = [
|
---|
| 223 | STRING,
|
---|
| 224 | {
|
---|
| 225 | className: 'class',
|
---|
| 226 | beginKeywords: 'class module',
|
---|
| 227 | end: '$|;',
|
---|
| 228 | illegal: /=/,
|
---|
| 229 | contains: [
|
---|
| 230 | hljs.inherit(hljs.TITLE_MODE, {
|
---|
| 231 | begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|!)?'
|
---|
| 232 | }),
|
---|
| 233 | {
|
---|
| 234 | begin: '<\\s*',
|
---|
| 235 | contains: [
|
---|
| 236 | {
|
---|
| 237 | begin: '(' + hljs.IDENT_RE + '::)?' + hljs.IDENT_RE,
|
---|
| 238 | // we already get points for <, we don't need poitns
|
---|
| 239 | // for the name also
|
---|
| 240 | relevance: 0
|
---|
| 241 | }
|
---|
| 242 | ]
|
---|
| 243 | }
|
---|
| 244 | ].concat(COMMENT_MODES)
|
---|
| 245 | },
|
---|
| 246 | {
|
---|
| 247 | className: 'function',
|
---|
| 248 | // def method_name(
|
---|
| 249 | // def method_name;
|
---|
| 250 | // def method_name (end of line)
|
---|
| 251 | begin: concat(/def\s+/, lookahead(RUBY_METHOD_RE + "\\s*(\\(|;|$)")),
|
---|
| 252 | relevance: 0, // relevance comes from kewords
|
---|
| 253 | keywords: "def",
|
---|
| 254 | end: '$|;',
|
---|
| 255 | contains: [
|
---|
| 256 | hljs.inherit(hljs.TITLE_MODE, {
|
---|
| 257 | begin: RUBY_METHOD_RE
|
---|
| 258 | }),
|
---|
| 259 | PARAMS
|
---|
| 260 | ].concat(COMMENT_MODES)
|
---|
| 261 | },
|
---|
| 262 | {
|
---|
| 263 | // swallow namespace qualifiers before symbols
|
---|
| 264 | begin: hljs.IDENT_RE + '::'
|
---|
| 265 | },
|
---|
| 266 | {
|
---|
| 267 | className: 'symbol',
|
---|
| 268 | begin: hljs.UNDERSCORE_IDENT_RE + '(!|\\?)?:',
|
---|
| 269 | relevance: 0
|
---|
| 270 | },
|
---|
| 271 | {
|
---|
| 272 | className: 'symbol',
|
---|
| 273 | begin: ':(?!\\s)',
|
---|
| 274 | contains: [
|
---|
| 275 | STRING,
|
---|
| 276 | {
|
---|
| 277 | begin: RUBY_METHOD_RE
|
---|
| 278 | }
|
---|
| 279 | ],
|
---|
| 280 | relevance: 0
|
---|
| 281 | },
|
---|
| 282 | NUMBER,
|
---|
| 283 | {
|
---|
| 284 | // negative-look forward attemps to prevent false matches like:
|
---|
| 285 | // @ident@ or $ident$ that might indicate this is not ruby at all
|
---|
| 286 | className: "variable",
|
---|
| 287 | begin: '(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])' + `(?![A-Za-z])(?![@$?'])`
|
---|
| 288 | },
|
---|
| 289 | {
|
---|
| 290 | className: 'params',
|
---|
| 291 | begin: /\|/,
|
---|
| 292 | end: /\|/,
|
---|
| 293 | relevance: 0, // this could be a lot of things (in other languages) other than params
|
---|
| 294 | keywords: RUBY_KEYWORDS
|
---|
| 295 | },
|
---|
| 296 | { // regexp container
|
---|
| 297 | begin: '(' + hljs.RE_STARTERS_RE + '|unless)\\s*',
|
---|
| 298 | keywords: 'unless',
|
---|
| 299 | contains: [
|
---|
| 300 | {
|
---|
| 301 | className: 'regexp',
|
---|
| 302 | contains: [
|
---|
| 303 | hljs.BACKSLASH_ESCAPE,
|
---|
| 304 | SUBST
|
---|
| 305 | ],
|
---|
| 306 | illegal: /\n/,
|
---|
| 307 | variants: [
|
---|
| 308 | {
|
---|
| 309 | begin: '/',
|
---|
| 310 | end: '/[a-z]*'
|
---|
| 311 | },
|
---|
| 312 | {
|
---|
| 313 | begin: /%r\{/,
|
---|
| 314 | end: /\}[a-z]*/
|
---|
| 315 | },
|
---|
| 316 | {
|
---|
| 317 | begin: '%r\\(',
|
---|
| 318 | end: '\\)[a-z]*'
|
---|
| 319 | },
|
---|
| 320 | {
|
---|
| 321 | begin: '%r!',
|
---|
| 322 | end: '![a-z]*'
|
---|
| 323 | },
|
---|
| 324 | {
|
---|
| 325 | begin: '%r\\[',
|
---|
| 326 | end: '\\][a-z]*'
|
---|
| 327 | }
|
---|
| 328 | ]
|
---|
| 329 | }
|
---|
| 330 | ].concat(IRB_OBJECT, COMMENT_MODES),
|
---|
| 331 | relevance: 0
|
---|
| 332 | }
|
---|
| 333 | ].concat(IRB_OBJECT, COMMENT_MODES);
|
---|
| 334 |
|
---|
| 335 | SUBST.contains = RUBY_DEFAULT_CONTAINS;
|
---|
| 336 | PARAMS.contains = RUBY_DEFAULT_CONTAINS;
|
---|
| 337 |
|
---|
| 338 | // >>
|
---|
| 339 | // ?>
|
---|
| 340 | const SIMPLE_PROMPT = "[>?]>";
|
---|
| 341 | // irb(main):001:0>
|
---|
| 342 | const DEFAULT_PROMPT = "[\\w#]+\\(\\w+\\):\\d+:\\d+>";
|
---|
| 343 | const RVM_PROMPT = "(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>";
|
---|
| 344 |
|
---|
| 345 | const IRB_DEFAULT = [
|
---|
| 346 | {
|
---|
| 347 | begin: /^\s*=>/,
|
---|
| 348 | starts: {
|
---|
| 349 | end: '$',
|
---|
| 350 | contains: RUBY_DEFAULT_CONTAINS
|
---|
| 351 | }
|
---|
| 352 | },
|
---|
| 353 | {
|
---|
| 354 | className: 'meta',
|
---|
| 355 | begin: '^(' + SIMPLE_PROMPT + "|" + DEFAULT_PROMPT + '|' + RVM_PROMPT + ')(?=[ ])',
|
---|
| 356 | starts: {
|
---|
| 357 | end: '$',
|
---|
| 358 | contains: RUBY_DEFAULT_CONTAINS
|
---|
| 359 | }
|
---|
| 360 | }
|
---|
| 361 | ];
|
---|
| 362 |
|
---|
| 363 | COMMENT_MODES.unshift(IRB_OBJECT);
|
---|
| 364 |
|
---|
| 365 | return {
|
---|
| 366 | name: 'Ruby',
|
---|
| 367 | aliases: [
|
---|
| 368 | 'rb',
|
---|
| 369 | 'gemspec',
|
---|
| 370 | 'podspec',
|
---|
| 371 | 'thor',
|
---|
| 372 | 'irb'
|
---|
| 373 | ],
|
---|
| 374 | keywords: RUBY_KEYWORDS,
|
---|
| 375 | illegal: /\/\*/,
|
---|
| 376 | contains: [
|
---|
| 377 | hljs.SHEBANG({
|
---|
| 378 | binary: "ruby"
|
---|
| 379 | })
|
---|
| 380 | ]
|
---|
| 381 | .concat(IRB_DEFAULT)
|
---|
| 382 | .concat(COMMENT_MODES)
|
---|
| 383 | .concat(RUBY_DEFAULT_CONTAINS)
|
---|
| 384 | };
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | module.exports = ruby;
|
---|