Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ New Grammars:

Grammars:

- enh(ruby) lots of small Ruby cleanups/improvements [Josh Goebel][]
- enh(objectivec) add `type` and `variable.language` scopes [Josh Goebel][]
- enh(xml) support processing instructions (#3492) [Josh Goebel][]
- enh(ruby ) better support multi-line IRB prompts
Expand Down
4 changes: 2 additions & 2 deletions src/highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ const HLJS = function(hljs) {
*/
function emitMultiClass(scope, match) {
let i = 1;
// eslint-disable-next-line no-undefined
while (match[i] !== undefined) {
const max = match.length - 1;
while (i <= max) {
if (!scope._emit[i]) { i++; continue; }
const klass = language.classNameAliases[scope[i]] || scope[i];
const text = match[i];
Expand Down
185 changes: 138 additions & 47 deletions src/languages/ruby.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,71 @@ Category: common
export default function(hljs) {
const regex = hljs.regex;
const RUBY_METHOD_RE = '([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)';
// TODO: move concepts like CAMEL_CASE into `modes.js`
const CLASS_NAME_RE = regex.either(
/\b([A-Z]+[a-z0-9]+)+/,
// ends in caps
/\b([A-Z]+[a-z0-9]+)+[A-Z]+/,
)
;
const CLASS_NAME_WITH_NAMESPACE_RE = regex.concat(CLASS_NAME_RE, /(::\w+)*/)
const RUBY_KEYWORDS = {
keyword:
'and then defined module in return redo if BEGIN retry end for self when '
+ 'next until do begin unless END rescue else break undef not super class case '
+ 'require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor '
+ '__FILE__',
built_in: 'proc lambda',
literal:
'true false nil'
"variable.constant": [
"__FILE__",
"__LINE__"
],
"variable.language": [
"self",
"super",
],
keyword: [
"alias",
"and",
"attr_accessor",
"attr_reader",
"attr_writer",
"begin",
"BEGIN",
"break",
"case",
"class",
"defined",
"do",
"else",
"elsif",
"end",
"END",
"ensure",
"for",
"if",
"in",
"include",
"module",
"next",
"not",
"or",
"redo",
"require",
"rescue",
"retry",
"return",
"then",
"undef",
"unless",
"until",
"when",
"while",
"yield",
],
built_in: [
"proc",
"lambda"
],
literal: [
"true",
"false",
"nil"
]
};
const YARDOCTAG = {
className: 'doctag',
Expand All @@ -42,7 +98,7 @@ export default function(hljs) {
relevance: 10
}
),
hljs.COMMENT('^__END__', '\\n$')
hljs.COMMENT('^__END__', hljs.MATCH_NOTHING_RE)
];
const SUBST = {
className: 'subst',
Expand Down Expand Up @@ -156,49 +212,82 @@ export default function(hljs) {
};

const PARAMS = {
className: 'params',
begin: '\\(',
end: '\\)',
endsParent: true,
variants: [
{
match: /\(\)/,
},
{
className: 'params',
begin: /\(/,
end: /(?=\))/,
excludeBegin: true,
endsParent: true,
keywords: RUBY_KEYWORDS,
}
]
};

const CLASS_DEFINITION = {
variants: [
{
match: [
/class\s+/,
CLASS_NAME_WITH_NAMESPACE_RE,
/\s+<\s+/,
CLASS_NAME_WITH_NAMESPACE_RE
]
},
{
match: [
/class\s+/,
CLASS_NAME_WITH_NAMESPACE_RE
]
}
],
scope: {
2: "title.class",
4: "title.class.inherited"
},
keywords: RUBY_KEYWORDS
};

const UPPER_CASE_CONSTANT = {
relevance: 0,
match: /\b[A-Z][A-Z_0-9]+\b/,
className: "variable.constant"
};

const METHOD_DEFINITION = {
match: [
/def/, /\s+/,
RUBY_METHOD_RE
],
scope: {
1: "keyword",
3: "title.function"
},
contains: [
PARAMS
]
};

const OBJECT_CREATION = {
relevance: 0,
match: [
CLASS_NAME_WITH_NAMESPACE_RE,
/\.new[ (]/
],
scope: {
1: "title.class"
}
};

const RUBY_DEFAULT_CONTAINS = [
STRING,
{
className: 'class',
beginKeywords: 'class module',
end: '$|;',
illegal: /=/,
contains: [
hljs.inherit(hljs.TITLE_MODE, { begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|!)?' }),
{
begin: '<\\s*',
contains: [
{
begin: '(' + hljs.IDENT_RE + '::)?' + hljs.IDENT_RE,
// we already get points for <, we don't need poitns
// for the name also
relevance: 0
}
]
}
].concat(COMMENT_MODES)
},
{
className: 'function',
// def method_name(
// def method_name;
// def method_name (end of line)
begin: regex.concat(/def\s+/, regex.lookahead(RUBY_METHOD_RE + "\\s*(\\(|;|$)")),
relevance: 0, // relevance comes from kewords
keywords: "def",
end: '$|;',
contains: [
hljs.inherit(hljs.TITLE_MODE, { begin: RUBY_METHOD_RE }),
PARAMS
].concat(COMMENT_MODES)
},
CLASS_DEFINITION,
OBJECT_CREATION,
UPPER_CASE_CONSTANT,
METHOD_DEFINITION,
{
// swallow namespace qualifiers before symbols
begin: hljs.IDENT_RE + '::' },
Expand Down Expand Up @@ -227,6 +316,8 @@ export default function(hljs) {
className: 'params',
begin: /\|/,
end: /\|/,
excludeBegin: true,
excludeEnd: true,
relevance: 0, // this could be a lot of things (in other languages) other than params
keywords: RUBY_KEYWORDS
},
Expand Down
2 changes: 1 addition & 1 deletion test/markup/erb/default.expect.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<span class="hljs-comment">&lt;%# this is a comment %&gt;</span><span class="language-xml">

&lt;%</span><span class="language-ruby"> <span class="hljs-variable">@posts</span>.each <span class="hljs-keyword">do</span> <span class="hljs-params">|post|</span> </span><span class="language-xml">%&gt;
&lt;%</span><span class="language-ruby"> <span class="hljs-variable">@posts</span>.each <span class="hljs-keyword">do</span> |<span class="hljs-params">post</span>| </span><span class="language-xml">%&gt;
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>&lt;%=</span><span class="language-ruby"> link_to post.title, post </span><span class="language-xml">%&gt;<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
&lt;%</span><span class="language-ruby"> <span class="hljs-keyword">end</span> </span><span class="language-xml">%&gt;

Expand Down
2 changes: 1 addition & 1 deletion test/markup/haml/default.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<span class="hljs-comment"> /html comment</span>
<span class="hljs-comment"> -# ignore this line</span>
<span class="hljs-tag"> %<span class="hljs-selector-tag">ul</span>(<span class="hljs-attr">style</span>=<span class="hljs-string">&#x27;margin: 0&#x27;</span>)</span>
-<span class="language-ruby">items.each <span class="hljs-keyword">do</span> <span class="hljs-params">|i|</span></span>
-<span class="language-ruby">items.each <span class="hljs-keyword">do</span> |<span class="hljs-params">i</span>|</span>
<span class="hljs-tag"> %<span class="hljs-selector-tag">i</span></span>= i
=<span class="language-ruby"> variable</span>
=<span class="language-ruby">variable2</span>
Expand Down
4 changes: 2 additions & 2 deletions test/markup/ruby/heredoc.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ message = <span class="hljs-string">&lt;&lt;-MESSAGE.chomp
This looks good
MESSAGE</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span></span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>()
msg = <span class="hljs-string">&lt;&lt;-HTML
&lt;div&gt;
&lt;h4&gt;<span class="hljs-subst">#{bar}</span>&lt;/h4&gt;
&lt;/div&gt;
HTML</span>
<span class="hljs-keyword">end</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span></span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">baz</span>()
msg = <span class="hljs-string">&lt;&lt;~FOO
&lt;div&gt;
&lt;h4&gt;<span class="hljs-subst">#{bar}</span>&lt;/h4&gt;
Expand Down
6 changes: 3 additions & 3 deletions test/markup/ruby/prompt.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<span class="hljs-meta prompt_">jruby-1.7.16 :001 &gt;</span> <span class="hljs-string">&quot;RVM-Format&quot;</span>

<span class="hljs-meta prompt_">&gt;&gt;</span> obj = OpenStruct.new <span class="hljs-symbol">:integer</span> =&gt; <span class="hljs-number">987</span>, <span class="hljs-symbol">:symbol</span> =&gt; <span class="hljs-symbol">:so_great</span>
<span class="hljs-meta prompt_">&gt;&gt;</span> obj = <span class="hljs-title class_">OpenStruct</span>.new <span class="hljs-symbol">:integer</span> =&gt; <span class="hljs-number">987</span>, <span class="hljs-symbol">:symbol</span> =&gt; <span class="hljs-symbol">:so_great</span>
=&gt; #&lt;OpenStruct integer=987, symbol=:so_great&gt;
<span class="hljs-meta prompt_">&gt;&gt;</span> [obj,obj,obj]
=&gt; [#&lt;OpenStruct integer=987, symbol=:so_great&gt;, #&lt;OpenStruct integer=987, symbol=:so_great&gt;, #&lt;OpenStruct integer=987, symbol=:so_great&gt;]
Expand All @@ -22,8 +22,8 @@

<span class="hljs-meta prompt_">irb(main):002:0&gt;</span> test = <span class="hljs-number">1</span>

<span class="hljs-meta prompt_">irb(main):001:1*</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Secret</span></span>
<span class="hljs-meta prompt_">irb(main):002:2*</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">[]</span><span class="hljs-params">(x)</span></span>
<span class="hljs-meta prompt_">irb(main):001:1*</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Secret</span>
<span class="hljs-meta prompt_">irb(main):002:2*</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">[]</span>(<span class="hljs-params">x</span>)
<span class="hljs-meta prompt_">irb(main):003:2*</span> <span class="hljs-string">&quot;TREASURE&quot;</span> <span class="hljs-keyword">if</span> x==<span class="hljs-number">42</span>
<span class="hljs-meta prompt_">irb(main):004:1*</span> <span class="hljs-keyword">end</span>
<span class="hljs-meta prompt_">irb(main):005:0&gt;</span> <span class="hljs-keyword">end</span>
Expand Down