Fix diff generation for long lines

This commit is contained in:
Rodrigo Fernandes 2017-10-16 22:00:03 +01:00
parent 1b0af44179
commit 16d63a92ab
No known key found for this signature in database
GPG key ID: 0DB4CC00D1C2DFB1
6 changed files with 121 additions and 55 deletions

View file

@ -97,6 +97,7 @@ The HTML output accepts a Javascript object with configuration. Possible options
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default is `none`
- `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500`
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
- `templates`: object with previously compiled templates to replace parts of the html
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)

View file

@ -57,6 +57,7 @@
"dependencies": {
"diff": "^3.3.1",
"hogan.js": "^3.0.2",
"lodash": "^4.17.4",
"whatwg-fetch": "^2.0.3"
},
"devDependencies": {

View file

@ -8,48 +8,49 @@
(function() {
var diffParser = require('./diff-parser.js').DiffParser;
var htmlPrinter = require('./html-printer.js').HtmlPrinter;
var utils = require('./utils.js').Utils;
function Diff2Html() {
}
/*
* Line diff type configuration
var config = {
'wordByWord': true, // (default)
// OR
'charByChar': true
};
*/
var defaultConfig = {
wordByWord: true,
outputFormat: 'line-by-line',
matching: 'none',
matchWordsThreshold: 0.25,
matchingMaxComparisons: 2500,
maxLineLengthHighlight: 10000
};
/*
* Generates json object from string diff input
*/
Diff2Html.prototype.getJsonFromDiff = function(diffInput, config) {
var configOrEmpty = config || {};
return diffParser.generateDiffJson(diffInput, configOrEmpty);
var cfg = utils.safeConfig(config, defaultConfig);
return diffParser.generateDiffJson(diffInput, cfg);
};
/*
* Generates the html diff. The config parameter configures the output/input formats and other options
*/
Diff2Html.prototype.getPrettyHtml = function(diffInput, config) {
var configOrEmpty = config || {};
var cfg = utils.safeConfig(config, defaultConfig);
var diffJson = diffInput;
if (!configOrEmpty.inputFormat || configOrEmpty.inputFormat === 'diff') {
diffJson = diffParser.generateDiffJson(diffInput, configOrEmpty);
if (!cfg.inputFormat || cfg.inputFormat === 'diff') {
diffJson = diffParser.generateDiffJson(diffInput, cfg);
}
var fileList = '';
if (configOrEmpty.showFiles === true) {
fileList = htmlPrinter.generateFileListSummary(diffJson, configOrEmpty);
if (cfg.showFiles === true) {
fileList = htmlPrinter.generateFileListSummary(diffJson, cfg);
}
var diffOutput = '';
if (configOrEmpty.outputFormat === 'side-by-side') {
diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty);
if (cfg.outputFormat === 'side-by-side') {
diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, cfg);
} else {
diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty);
diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, cfg);
}
return fileList + diffOutput;
@ -63,40 +64,40 @@
* Generates pretty html from string diff input
*/
Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) {
var configOrEmpty = config || {};
configOrEmpty.inputFormat = 'diff';
configOrEmpty.outputFormat = 'line-by-line';
return this.getPrettyHtml(diffInput, configOrEmpty);
var cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'diff';
cfg.outputFormat = 'line-by-line';
return this.getPrettyHtml(diffInput, cfg);
};
/*
* Generates pretty html from a json object
*/
Diff2Html.prototype.getPrettyHtmlFromJson = function(diffJson, config) {
var configOrEmpty = config || {};
configOrEmpty.inputFormat = 'json';
configOrEmpty.outputFormat = 'line-by-line';
return this.getPrettyHtml(diffJson, configOrEmpty);
var cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'json';
cfg.outputFormat = 'line-by-line';
return this.getPrettyHtml(diffJson, cfg);
};
/*
* Generates pretty side by side html from string diff input
*/
Diff2Html.prototype.getPrettySideBySideHtmlFromDiff = function(diffInput, config) {
var configOrEmpty = config || {};
configOrEmpty.inputFormat = 'diff';
configOrEmpty.outputFormat = 'side-by-side';
return this.getPrettyHtml(diffInput, configOrEmpty);
var cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'diff';
cfg.outputFormat = 'side-by-side';
return this.getPrettyHtml(diffInput, cfg);
};
/*
* Generates pretty side by side html from a json object
*/
Diff2Html.prototype.getPrettySideBySideHtmlFromJson = function(diffJson, config) {
var configOrEmpty = config || {};
configOrEmpty.inputFormat = 'json';
configOrEmpty.outputFormat = 'side-by-side';
return this.getPrettyHtml(diffJson, configOrEmpty);
var cfg = utils.safeConfig(config, defaultConfig);
cfg.inputFormat = 'json';
cfg.outputFormat = 'side-by-side';
return this.getPrettyHtml(diffJson, cfg);
};
var diffObject = new Diff2Html();

View file

@ -144,6 +144,20 @@
unprefixedLine1 = diffLine1.substr(prefixSize);
unprefixedLine2 = diffLine2.substr(prefixSize);
if (unprefixedLine1.length > config.maxLineLengthHighlight ||
unprefixedLine2.length > config.maxLineLengthHighlight) {
return {
first: {
prefix: linePrefix1,
line: utils.escape(unprefixedLine1)
},
second: {
prefix: linePrefix2,
line: utils.escape(unprefixedLine2)
}
};
}
var diff;
if (config.charByChar) {
diff = jsDiff.diffChars(unprefixedLine1, unprefixedLine2);

View file

@ -6,6 +6,8 @@
*/
(function() {
var lodash = require('lodash');
function Utils() {
}
@ -39,5 +41,11 @@
return value || '';
};
Utils.prototype.safeConfig = function(cfg, defaultConfig) {
var newCfg = {};
lodash.merge(newCfg, defaultConfig, cfg);
return newCfg;
};
module.exports.Utils = new Utils();
})();

View file

@ -24,7 +24,7 @@ $(document).ready(function() {
var $outputFormat = $('#diff-url-options-output-format');
var $showFiles = $('#diff-url-options-show-files');
var $matching = $('#diff-url-options-matching');
var $wordThreshold = $('#diff-url-options-match-words-threshold');
var $wordsThreshold = $('#diff-url-options-match-words-threshold');
var $matchingMaxComparisons = $('#diff-url-options-matching-max-comparisons');
if (window.location.search) {
@ -38,10 +38,13 @@ $(document).ready(function() {
$outputFormat
.add($showFiles)
.add($matching)
.add($wordThreshold)
.add($wordsThreshold)
.add($matchingMaxComparisons)
.change(function() {
smartDraw();
.change(function(e) {
console.log('');
console.log(e);
console.log('');
smartDraw(null, true);
});
function getUrlFromSearch(search) {
@ -56,6 +59,22 @@ $(document).ready(function() {
return null;
}
function getParamsFromSearch(search) {
var map = {};
try {
search
.split('?')[1]
.split('&')
.map(function(e) {
var values = e.split('=');
map[values[0]] = values[1];
});
} catch (_ignore) {
}
return map;
}
function bind() {
$('#url-btn').click(function(e) {
e.preventDefault();
@ -124,13 +143,13 @@ $(document).ready(function() {
};
}
function smartDraw(urlOpt) {
function smartDraw(urlOpt, forced) {
var url = urlOpt || $url.val();
var req = prepareUrl(url);
draw(req);
draw(req, forced);
}
function draw(req) {
function draw(req, forced) {
if (!validateUrl(req.url)) {
console.error('Invalid url provided!');
return;
@ -141,7 +160,7 @@ $(document).ready(function() {
var outputFormat = $outputFormat.val();
var showFiles = $showFiles.is(':checked');
var matching = $matching.val();
var wordThreshold = $wordThreshold.val();
var wordsThreshold = $wordsThreshold.val();
var matchingMaxComparisons = $matchingMaxComparisons.val();
fetch(req.url, {
@ -163,16 +182,34 @@ $(document).ready(function() {
$container.css({'width': ''});
}
diff2htmlUi.draw(container, {
outputFormat: outputFormat,
showFiles: showFiles,
matching: matching,
matchWordsThreshold: wordThreshold,
matchingMaxComparisons: matchingMaxComparisons,
synchronisedScroll: true
});
diff2htmlUi.fileListCloseable(container, false);
diff2htmlUi.highlightCode(container);
var params = getParamsFromSearch(window.location.search);
delete params[searchParam];
if (forced) {
params['outputFormat'] = outputFormat;
params['showFiles'] = showFiles;
params['matching'] = matching;
params['wordsThreshold'] = wordsThreshold;
params['matchingMaxComparisons'] = matchingMaxComparisons;
} else {
params['outputFormat'] = params['outputFormat'] || outputFormat;
params['showFiles'] = String(params['showFiles']) !== 'false' || (params['showFiles'] === null && showFiles);
params['matching'] = params['matching'] || matching;
params['wordsThreshold'] = params['wordsThreshold'] || wordsThreshold;
params['matchingMaxComparisons'] = params['matchingMaxComparisons'] || matchingMaxComparisons;
$outputFormat.val(params['outputFormat']);
$showFiles.prop('checked', params['showFiles']);
$matching.val(params['matching']);
$wordsThreshold.val(params['wordsThreshold']);
$matchingMaxComparisons.val(params['matchingMaxComparisons']);
}
params['synchronisedScroll'] = params['synchronisedScroll'] || true;
diff2htmlUi.draw(container, params);
diff2htmlUi.fileListCloseable(container, params['fileListCloseable'] || false);
params['highlight'] && diff2htmlUi.highlightCode(container);
});
}
@ -181,10 +218,14 @@ $(document).ready(function() {
}
function updateUrl(url) {
var currentUrl = getUrlFromSearch(window.location.search);
var params = getParamsFromSearch(window.location.search);
if (currentUrl === url) return;
if (params[searchParam] === url) return;
window.location = 'demo.html?' + searchParam + '=' + url;
params[searchParam] = url;
var paramString = Object.keys(params).map(function(k) { return k + '=' + params[k]; }).join('&');
window.location = 'demo.html?' + paramString;
}
});