Merge pull request #76 from rtfpessoa/improve-highlight

Improve highlight
This commit is contained in:
Rodrigo Fernandes 2016-05-14 11:33:44 +01:00
commit 07abb77208
4 changed files with 335 additions and 164 deletions

View file

@ -24,6 +24,20 @@
<script>
var lineDiffExample =
'diff --git a/src/core/init.java b/src/core/init.java\n' +
'index e49196a..50f310c 100644\n' +
'--- a/src/core/init.java\n' +
'+++ b/src/core/init.java\n' +
'@@ -101,7 +101,7 @@\n' +
' /**\n' +
' * Setter for property filesize.\n' +
' *\n' +
" * @param filesize value of property 'filesize'.\n" +
' */\n' +
' public void setFilesize(int filesize) {\n' +
'- this.filesizeOld = filesizeOld;\n' +
'+ this.filesizeNew = filesizeNew;\n' +
' }\n' +
'diff --git a/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/coverage.init b/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/coverage.init\n' +
'index fc56817..e8e7e49 100644\n' +
'--- a/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/src/very/long/file/path/coverage.init\n' +

View file

@ -13,12 +13,10 @@
padding: 5px 10px;
border-bottom: 1px solid #d8d8d8;
background-color: #f7f7f7;
font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}
.d2h-file-stats {
display: inline;
font-size: 12px;
text-align: center;
}
@ -49,6 +47,8 @@
.d2h-file-name-wrapper {
display: inline-flex;
width: 90%;
font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 15px;
}
.d2h-file-name {
@ -65,10 +65,10 @@
}
.d2h-diff-table {
border-collapse: collapse;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
width: 100%;
border-collapse: collapse;
font-family: "Menlo", "Consolas", monospace;
font-size: 13px;
}
.d2h-diff-tbody > tr > td > div {
@ -258,7 +258,6 @@ ins.d2h-change, del.d2h-change {
.d2h-file-list-line {
text-align: left;
font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}
.d2h-file-list-line .d2h-file-name {

View file

@ -8,10 +8,12 @@
*
*/
/*global $, hljs*/
/*global $, hljs, Diff2Html*/
(function() {
var highlightJS = require('./highlight.js-internals.js').HighlightJS;
var diffJson = null;
var defaultTarget = "body";
var currentSelectionColumnId = -1;
@ -69,15 +71,50 @@
var $target = that._getTarget(targetId);
var languages = that._getLanguages($target);
// pass the languages to the highlightjs plugin
hljs.configure({languages: languages});
// collect all the diff files and execute the highlight on their lines
var $files = $target.find(".d2h-file-wrapper");
$files.map(function(_i, file) {
var oldLinesState;
var newLinesState;
var $file = $(file);
var language = $file.data("lang");
// collect all the code lines and execute the highlight on them
var $codeLines = $target.find(".d2h-code-line-ctn");
$codeLines.map(function(i, line) {
hljs.highlightBlock(line);
var $codeLines = $file.find(".d2h-code-line-ctn");
$codeLines.map(function(_j, line) {
var $line = $(line);
var text = line.textContent;
var lineParent = line.parentNode;
var lineState;
if (lineParent.className.indexOf("d2h-del") !== -1) {
lineState = oldLinesState;
} else {
lineState = newLinesState;
}
var result = hljs.getLanguage(language) ? hljs.highlight(language, text, true, lineState) : hljs.highlightAuto(text);
if (lineParent.className.indexOf("d2h-del") !== -1) {
oldLinesState = result.top;
} else if (lineParent.className.indexOf("d2h-ins") !== -1) {
newLinesState = result.top;
} else {
oldLinesState = result.top;
newLinesState = result.top;
}
var originalStream = highlightJS.nodeStream(line);
if (originalStream.length) {
var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
resultNode.innerHTML = result.value;
result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text);
}
$line.addClass("hljs");
$line.addClass(result.language);
$line.html(result.value);
});
});
};
@ -97,24 +134,6 @@
return $target;
};
Diff2HtmlUI.prototype._getLanguages = function($target) {
var allFileLanguages = [];
if (diffJson) {
// collect all the file extensions in the json
allFileLanguages = diffJson.map(function(line) {
return line.language;
});
} else {
$target.find(".d2h-file-wrapper").map(function(i, file) {
allFileLanguages.push($(file).data("lang"));
});
}
// return only distinct languages
return this._distinct(allFileLanguages);
};
Diff2HtmlUI.prototype._getHashTag = function() {
var docUrl = document.URL;
var hashTagIndex = docUrl.indexOf('#');

View file

@ -0,0 +1,139 @@
/*
*
* highlight.js
* Author: isagalaev
*
*/
(function() {
function HighlightJS() {
}
/*
* Copied from Highlight.js Private API
* Will be removed when this part of the API is exposed
*/
/* Utility functions */
function escape(value) {
return value.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
}
function tag(node) {
return node.nodeName.toLowerCase();
}
/* Stream merging */
HighlightJS.prototype.nodeStream = function(node) {
var result = [];
(function _nodeStream(node, offset) {
for (var child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType == 3)
offset += child.nodeValue.length;
else if (child.nodeType == 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
// Prevent void elements from having an end tag that would actually
// double them in the output. There are more void elements in HTML
// but we list only those realistically expected in code display.
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
}
return offset;
})(node, 0);
return result;
};
HighlightJS.prototype.mergeStreams = function(original, highlighted, value) {
var processed = 0;
var result = '';
var nodeStack = [];
function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset != highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
}
/*
To avoid starting the stream just before it should stop the order is
ensured that original always starts first and closes last:
if (event1 == 'start' && event2 == 'start')
return original;
if (event1 == 'start' && event2 == 'stop')
return highlighted;
if (event1 == 'stop' && event2 == 'start')
return original;
if (event1 == 'stop' && event2 == 'stop')
return highlighted;
... which is collapsed to:
*/
return highlighted[0].event == 'start' ? original : highlighted;
}
function open(node) {
function attrStr(a) {
return ' ' + a.nodeName + '="' + escape(a.value) + '"';
}
result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attrStr).join('') + '>';
}
function close(node) {
result += '</' + tag(node) + '>';
}
function render(event) {
(event.event == 'start' ? open : close)(event.node);
}
while (original.length || highlighted.length) {
var stream = selectStream();
result += escape(value.substr(processed, stream[0].offset - processed));
processed = stream[0].offset;
if (stream == original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (stream == original && stream.length && stream[0].offset == processed);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event == 'start') {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escape(value.substr(processed));
};
/* **** Highlight.js Private API **** */
module.exports.HighlightJS = new HighlightJS();
})();