Merge "Workarounds for HLJS parsing issues"

This commit is contained in:
Wyatt Allen 2016-11-28 23:06:47 +00:00 committed by Gerrit Code Review
commit 82ef5ed510
2 changed files with 86 additions and 0 deletions

View File

@ -78,6 +78,10 @@
'gr-diff gr-syntax gr-syntax-selector-class': true,
};
var CPP_DIRECTIVE_WITH_LT_PATTERN = /^\s*#(if|define).*</;
var JAVA_PARAM_ANNOT_PATTERN = /(@[^\s]+)\(([^)]+)\)/g;
var GLOBAL_LT_PATTERN = /</g;
Polymer({
is: 'gr-syntax-layer',
@ -301,6 +305,7 @@
var result;
if (this._baseLanguage && baseLine !== undefined) {
baseLine = this._workaround(this._baseLanguage, baseLine);
result = this._hljs.highlight(this._baseLanguage, baseLine, true,
state.baseContext);
this.push('_baseRanges', this._rangesFromString(result.value));
@ -308,6 +313,7 @@
}
if (this._revisionLanguage && revisionLine !== undefined) {
revisionLine = this._workaround(this._revisionLanguage, revisionLine);
result = this._hljs.highlight(this._revisionLanguage, revisionLine,
true, state.revisionContext);
this.push('_revisionRanges', this._rangesFromString(result.value));
@ -315,6 +321,50 @@
}
},
/**
* Ad hoc fixes for HLJS parsing bugs. Rewrite lines of code in constrained
* cases before sending them into HLJS so that they parse correctly.
*
* Important notes:
* * These tests should be as constrained as possible to avoid interfering
* with code it shouldn't AND to avoid executing regexes as much as
* possible.
* * These tests should document the issue clearly enough that the test can
* be condidently removed when the issue is solved in HLJS.
* * These tests should rewrite the line of code to have the same number of
* characters. This method rewrites the string that gets parsed, but NOT
* the string that gets displayed and highlighted. Thus, the positions
* must be consistent.
*
* @param {!string} language The name of the HLJS language plugin in use.
* @param {!string} line The line of code to potentially rewrite.
* @return {string} A potentially-rewritten line of code.
*/
_workaround: function(language, line) {
/**
* Prevent confusing < and << operators for the start of a meta string by
* converting them to a different operator.
* {@see Issue 4864}
* {@see https://github.com/isagalaev/highlight.js/issues/1341}
*/
if (language === 'cpp' && CPP_DIRECTIVE_WITH_LT_PATTERN.test(line)) {
return line.replace(GLOBAL_LT_PATTERN, '|');
}
/**
* Prevent confusing the closing paren of a parameterized Java annotation
* being applied to a formal argument as the closing paren of the argument
* list. Rewrite the parens as spaces.
* {@see Issue 4776}
* {@see https://github.com/isagalaev/highlight.js/issues/1324}
*/
if (language === 'java' && JAVA_PARAM_ANNOT_PATTERN.test(line)) {
return line.replace(JAVA_PARAM_ANNOT_PATTERN, '$1 $2 ');
}
return line;
},
/**
* Tells whether the state has exhausted its current section.
* @param {!Object} state

View File

@ -404,5 +404,41 @@ limitations under the License.
state = {sectionIndex: 3, lineIndex: 4};
assert.isTrue(element._isSectionDone(state));
});
test('workaround CPP LT directive', function() {
// Does nothing to regular line.
var line = 'int main(int argc, char** argv) { return 0; }';
assert.equal(element._workaround('cpp', line), line);
// Does nothing to include directive.
line = '#include <stdio>';
assert.equal(element._workaround('cpp', line), line);
// Converts left-shift operator in #define.
line = '#define GiB (1ull << 30)';
var expected = '#define GiB (1ull || 30)';
assert.equal(element._workaround('cpp', line), expected);
// Converts less-than operator in #if.
line = ' #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)';
expected = ' #if __GNUC__ | 4 || (__GNUC__ == 4 && __GNUC_MINOR__ | 1)';
assert.equal(element._workaround('cpp', line), expected);
});
test('workaround Java param-annotation', function() {
// Does nothing to regular line.
var line = 'public static void foo(int bar) { }';
assert.equal(element._workaround('java', line), line);
// Does nothing to regular annotation.
var line = 'public static void foo(@Nullable int bar) { }';
assert.equal(element._workaround('java', line), line);
// Converts parameterized annotation.
line = 'public static void foo(@SuppressWarnings("unused") int bar) { }';
var expected = 'public static void foo(@SuppressWarnings "unused" ' +
' int bar) { }';
assert.equal(element._workaround('java', line), expected);
});
});
</script>