Skip to content

Commit 730f891

Browse files
authored
fix(parser) When ignoring a potential match highlighting can terminate early (highlightjs#2650)
1 parent 3abf3a2 commit 730f891

File tree

5 files changed

+45
-5
lines changed

5 files changed

+45
-5
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Version 10.2.0 (next up)
22

3+
Parser Engine:
4+
5+
- (fix) When ignoring a potential match highlighting can terminate early (#2649) [Josh Goebel][]
6+
37
New themes:
48

59
- *Gradient Light* by [Samia Ali]()

src/highlight.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,14 @@ const HLJS = function(hljs) {
261261
}
262262
}
263263

264+
/**
265+
* Advance a single character
266+
*/
267+
function advanceOne() {
268+
mode_buffer += codeToHighlight[index];
269+
index += 1;
270+
}
271+
264272
/**
265273
* Handle matching but then ignoring a sequence of text
266274
*
@@ -275,7 +283,7 @@ const HLJS = function(hljs) {
275283
} else {
276284
// no need to move the cursor, we still have additional regexes to try and
277285
// match at this very spot
278-
continueScanAtSamePosition = true;
286+
resumeScanAtSamePosition = true;
279287
return 0;
280288
}
281289
}
@@ -478,23 +486,32 @@ const HLJS = function(hljs) {
478486
var relevance = 0;
479487
var index = 0;
480488
var iterations = 0;
481-
var continueScanAtSamePosition = false;
489+
var resumeScanAtSamePosition = false;
482490

483491
try {
484492
top.matcher.considerAll();
485493

486494
for (;;) {
487495
iterations++;
488-
if (continueScanAtSamePosition) {
496+
if (resumeScanAtSamePosition) {
489497
// only regexes not matched previously will now be
490498
// considered for a potential match
491-
continueScanAtSamePosition = false;
499+
resumeScanAtSamePosition = false;
492500
} else {
493501
top.matcher.lastIndex = index;
494502
top.matcher.considerAll();
495503
}
504+
496505
const match = top.matcher.exec(codeToHighlight);
497506
// console.log("match", match[0], match.rule && match.rule.begin)
507+
508+
// if our failure to match was the result of a "resumed scan" then we
509+
// need to advance one position and revert to full scanning before we
510+
// decide there are truly no more matches at all to be had
511+
if (!match && top.matcher.resumingScanAtSamePosition()) {
512+
advanceOne();
513+
continue;
514+
}
498515
if (!match) break;
499516

500517
const beforeMatch = codeToHighlight.substring(index, match.index);

src/lib/mode_compiler.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ export function compileLanguage(language) {
142142
return matcher;
143143
}
144144

145+
resumingScanAtSamePosition() {
146+
return this.regexIndex != 0;
147+
}
148+
145149
considerAll() {
146150
this.regexIndex = 0;
147151
}

test/parser/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use strict';
22

33
describe('hljs', function() {
4+
require('./look-ahead-end-matchers');
5+
require('./resume-scan');
46
require('./reuse-endsWithParent');
57
require('./should-not-destroyData');
6-
require('./look-ahead-end-matchers');
8+
79
});

test/parser/resume-scan.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const hljs = require('../../build');
2+
3+
describe("bugs", function () {
4+
5+
describe("resume scan when a match is ignored", () => {
6+
it("should continue to highlight later matches", () => {
7+
hljs.highlight('java', 'ImmutablePair.of(Stuff.class, "bar")').value
8+
.should.equal(
9+
'ImmutablePair.of(Stuff.class, <span class="hljs-string">&quot;bar&quot;</span>)'
10+
)
11+
})
12+
})
13+
})

0 commit comments

Comments
 (0)