GithubHelp home page GithubHelp logo

rtfpessoa / diff2html Goto Github PK

View Code? Open in Web Editor NEW
2.7K 37.0 267.0 5.37 MB

Pretty diff to html javascript library (diff2html)

Home Page: https://diff2html.xyz

License: MIT License

JavaScript 1.28% CSS 4.10% HCL 0.97% TypeScript 87.15% Handlebars 5.72% Mustache 0.78% Shell 0.01%
diff parser pretty git html syntax-highlighting diff2html unified-diffs colorized typescript

diff2html's Introduction

diff2html

npm node npm GitHub Actions

npm weekly downloads npm monthly downloads npm yearly downloads npm downloads

jsdelivr CDN Downloads All Contributors

diff2html generates pretty HTML diffs from git diff or unified diff output.

Table of Contents

Features

  • Supports git and unified diffs

  • Line by line and Side by side diff

  • New and old line numbers

  • Inserted and removed lines

  • GitHub like visual style

  • Code syntax highlight

  • Line similarity matching

  • Easy code selection

Online Example

Go to diff2html

Distributions

Usage

Diff2Html can be used in various ways as listed in the distributions section. The two main ways are:

  • Diff2HtmlUI: using this wrapper makes it easy to inject the html in the DOM and adds some nice features to the diff, like syntax highlight.
  • Diff2Html: using the parser and html generator directly from the library gives you complete control about what you can do with the json or html generated.

Below you can find more details and examples about each option.

Diff Text Input

diff2html accepts the text contents of a unified diff or the superset format git diff (https://git-scm.com/docs/git-diff) (not combined or word diff). To provide multiples files as input just concatenate the diffs (just like the output of git diff).

Diff2HtmlUI Usage

Simple wrapper to ease simple tasks in the browser such as: code highlight and js effects

  • Invoke Diff2html
  • Inject output in DOM element
  • Enable collapsible file summary list
  • Enable syntax highlight of the code in the diffs

Diff2HtmlUI API

Create a Diff2HtmlUI instance

constructor(target: HTMLElement, diffInput?: string | DiffFile[]) // diff2html-ui, diff2html-ui-slim
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base

Generate and inject in the document the Pretty HTML representation of the diff

draw(): void

Enable extra features

synchronisedScroll(): void
fileListToggle(startVisible: boolean): void
highlightCode(): void
stickyFileHeaders(): void

Diff2HtmlUI Configuration

  • synchronisedScroll: scroll both panes in side-by-side mode: true or false, default is true
  • highlight: syntax highlight the code on the diff: true or false, default is true
  • fileListToggle: allow the file summary list to be toggled: true or false, default is true
  • fileListStartVisible: choose if the file summary list starts visible: true or false, default is false
  • fileContentToggle: allow each file contents to be toggled: true or false, default is true
  • stickyFileHeaders: make file headers sticky: true or false, default is true
  • All the options from Diff2Html are also valid configurations in Diff2HtmlUI

Diff2HtmlUI Browser

Mandatory HTML resource imports

<!-- CSS -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />

<!-- Javascripts -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>

Init

const targetElement = document.getElementById('destination-elem-id');
const configuration = { drawFileList: true, matching: 'lines' };

const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
// or
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffJson, configuration);

Draw

diff2htmlUi.draw();

Syntax Highlight

NOTE: The highlight.js css should come before the diff2html css

<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />

<!-- Javascripts -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>

Pass the option highlight with value true or invoke diff2htmlUi.highlightCode() after diff2htmlUi.draw().

document.addEventListener('DOMContentLoaded', () => {
  const diffString = `diff --git a/sample.js b/sample.js
  index 0000001..0ddf2ba
  --- a/sample.js
  +++ b/sample.js
  @@ -1 +1 @@
  -console.log("Hello World!")
  +console.log("Hello from Diff2Html!")`;
  const targetElement = document.getElementById('myDiffElement');
  const configuration = { drawFileList: true, matching: 'lines', highlight: true };
  const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
  diff2htmlUi.draw();
  diff2htmlUi.highlightCode();
});

When using the auto color scheme, you will need to specify both the light and dark themes for highlight.js to use.

<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css"
  media="screen and (prefers-color-scheme: light)"
/>
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css"
  media="screen and (prefers-color-scheme: dark)"
/>

Collapsable File Summary List

Add the dependencies.

<!-- Javascripts -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>

Invoke the Diff2HtmlUI helper Pass the option fileListToggle with value true or invoke diff2htmlUi.fileListToggle() after diff2htmlUi.draw().

document.addEventListener('DOMContentLoaded', () => {
  const targetElement = document.getElementById('myDiffElement');
  var diff2htmlUi = new Diff2HtmlUI(targetElement, lineDiffExample, { drawFileList: true, matching: 'lines' });
  diff2htmlUi.draw();
  diff2htmlUi.fileListToggle(false);
});

Diff2HtmlUI Examples

Example with plain HTML+CSS+JS

<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8" />
    <!-- Make sure to load the highlight.js CSS file before the Diff2Html CSS file -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css" />
    <link
      rel="stylesheet"
      type="text/css"
      href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"
    />
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
  </head>
  <script>
    const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;

    document.addEventListener('DOMContentLoaded', function () {
      var targetElement = document.getElementById('myDiffElement');
      var configuration = {
        drawFileList: true,
        fileListToggle: false,
        fileListStartVisible: false,
        fileContentToggle: false,
        matching: 'lines',
        outputFormat: 'side-by-side',
        synchronisedScroll: true,
        highlight: true,
        renderNothingWhenEmpty: false,
      };
      var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
      diff2htmlUi.draw();
      diff2htmlUi.highlightCode();
    });
  </script>
  <body>
    <div id="myDiffElement"></div>
  </body>
</html>

StimulusJS with TypeScript

import { Controller } from '@hotwired/stimulus';

import { Diff2HtmlUI, Diff2HtmlUIConfig } from 'diff2html/lib/ui/js/diff2html-ui-slim.js';

// Requires `yarn add highlight.js`
import 'highlight.js/styles/github.css';
import 'diff2html/bundles/css/diff2html.min.css';

export default class extends Controller {
  connect(): void {
    const diff2htmlUi = new Diff2HtmlUI(this.diffElement, this.unifiedDiff, this.diffConfiguration);

    diff2htmlUi.draw();
  }

  get unifiedDiff(): string {
    return this.data.get('unifiedDiff') || '';
  }

  get diffElement(): HTMLElement {
    return this.element as HTMLElement;
  }

  get diffConfiguration(): Diff2HtmlUIConfig {
    return {
      drawFileList: true,
      matching: 'lines',
    };
  }
}

Diff2Html Usage

Diff2Html API

JSON representation of the diff

function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[];

Pretty HTML representation of the diff

function html(diffInput: string | DiffFile[], configuration: Diff2HtmlConfig = {}): string;

Diff2Html Configuration

The HTML output accepts a Javascript object with configuration. Possible options:

  • outputFormat: the format of the output data: 'line-by-line' or 'side-by-side', default is 'line-by-line'
  • drawFileList: show a file list before the diff: true or false, default is true
  • srcPrefix: add a prefix to all source (before changes) filepaths, default is ''. Should match the prefix used when generating the diff.
  • dstPrefix: add a prefix to all destination (after changes) filepaths, default is ''. Should match the prefix used when generating the diff
  • diffMaxChanges: number of changed lines after which a file diff is deemed as too big and not displayed, default is undefined
  • diffMaxLineLength: number of characters in a diff line after which a file diff is deemed as too big and not displayed, default is undefined
  • diffTooBigMessage: function allowing to customize the message in case of file diff too big (if diffMaxChanges or diffMaxLineLength is set). Will be given a file index as a number and should return a string.
  • 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
  • maxLineLengthHighlight: only perform diff changes highlight if lines are smaller than this, default is 10000
  • diffStyle: show differences level in each line: 'word' or 'char', default is 'word'
  • renderNothingWhenEmpty: render nothing if the diff shows no change in its comparison: true or false, default is false
  • matchingMaxComparisons: perform at most this much comparisons for line matching a block of changes, default is 2500
  • maxLineSizeInBlockForComparison: maximum number of characters of the bigger line in a block to apply comparison, default is 200
  • compiledTemplates: object (Hogan.js template values) with previously compiled templates to replace parts of the html, default is {}. For example: { "tag-file-changed": Hogan.compile("<span class="d2h-tag d2h-changed d2h-changed-tag">MODIFIED</span>") }
  • rawTemplates: object (string values) with raw not compiled templates to replace parts of the html, default is {}. For example: { "tag-file-changed": "<span class="d2h-tag d2h-changed d2h-changed-tag">MODIFIED</span>" }

    For more information regarding the possible templates look into src/templates

  • highlightLanguages: Map of extension to language name, used for highlighting. This overrides the default language detection based on file extensions.
  • colorScheme: color scheme to use for the diff, default is light. Possible values are light, dark, and auto which will use the browser's preferred color scheme.

Diff2Html Browser

Import the stylesheet and the library code.

To load correctly in the Browser you need to include the stylesheet in the final HTML.

<!-- CSS -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />

<!-- Javascripts -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html.min.js"></script>

It will now be available as a global variable named Diff2Html.

document.addEventListener('DOMContentLoaded', () => {
  var diffHtml = Diff2Html.html('<Unified Diff String>', {
    drawFileList: true,
    matching: 'lines',
    outputFormat: 'side-by-side',
  });
  document.getElementById('destination-elem-id').innerHTML = diffHtml;
});

Diff2Html NPM / Node.js Library

const Diff2html = require('diff2html');
const diffJson = Diff2html.parse('<Unified Diff String>');
const diffHtml = Diff2html.html(diffJson, { drawFileList: true });
console.log(diffHtml);

Diff2Html Examples

Example with Angular

  • Typescript
import * as Diff2Html from 'diff2html';
import { Component, OnInit } from '@angular/core';

export class AppDiffComponent implements OnInit {
  outputHtml: string;
  constructor() {
    this.init();
  }

  ngOnInit() {}

  init() {
    let strInput =
      '--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n';
    let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: 'lines' });
    this.outputHtml = outputHtml;
  }
}
  • HTML
<!doctype html>
<html>
  <head>
    <title>diff2html</title>
  </head>
  <body>
    <div [innerHtml]="outputHtml"></div>
  </body>
</html>
  • .angular-cli.json - Add styles
"styles": [
  "diff2html.min.css"
]

Example with Vue.js

<template>
  <div v-html="prettyHtml" />
</template>

<script>
import * as Diff2Html from 'diff2html';
import 'diff2html/bundles/css/diff2html.min.css';

export default {
  data() {
    return {
      diffs:
        '--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n',
    };
  },
  computed: {
    prettyHtml() {
      return Diff2Html.html(this.diffs, {
        drawFileList: true,
        matching: 'lines',
        outputFormat: 'side-by-side',
      });
    },
  },
};
</script>

Troubleshooting

1. Out of memory or Slow execution

Causes:

  • Big files
  • Big lines

Fix:

  • Disable the line matching algorithm, by setting the option {"matching": "none"} when invoking diff2html

Contribute

This is a developer friendly project, all the contributions are welcome. To contribute just send a pull request with your changes following the guidelines described in CONTRIBUTING.md. I will try to review them as soon as possible.

Contributors

Thanks goes to these wonderful people (emoji key):


Rodrigo Fernandes

๐Ÿ’ป

stockmind

๐Ÿ’ป

Ivan Vorontsov

๐Ÿ’ป

Nick Brewer

๐Ÿ’ป

Matt Wade

๐Ÿ› ๐Ÿ’ป

Rafael Cortรชs

๐Ÿ’ป

Nuno Teixeira

๐Ÿ’ป

Koki Oyatsu

๐Ÿ› ๐Ÿ’ป

James Monger

๐Ÿ“–

Wessel van der Pal

๐Ÿ›ก๏ธ ๐Ÿ’ป

jk-kim

๐Ÿ’ป

Sergey Semenov

๐Ÿ› ๐Ÿ’ป

Nick Mitchell

๐Ÿ› ๐Ÿ’ป

Samir Aguiar

๐Ÿ“–

pubkey

๐Ÿ“– ๐Ÿ’ป

ะ˜ะปัŒั

๐Ÿ“–

Mohamed Akram

๐Ÿ› ๐Ÿ“– ๐Ÿ’ป

Eugene Marcotte

๐Ÿ’ป

Dima Sabanin

๐Ÿšง ๐Ÿ’ป

Ben Abbott

๐Ÿ“–

ๅผ˜ๆ ‘@้˜ฟ้‡Œ

๐Ÿ› ๐Ÿ“–

Mikko Rantanen

๐Ÿ›

Ann

๐Ÿ“–

escitalopram

๐Ÿ’ป

dependabot[bot]

๐Ÿ›ก๏ธ ๐Ÿšง

Josh Goldberg

๐Ÿ’ป

Aaron

๐Ÿ“–

Pierre Grimaud

๐Ÿ“–

Adam Jones

๐Ÿ“–

Arthur Charguรฉraud

๐Ÿ“–

Pierric Cistac

๐Ÿ“– ๐Ÿ’ป

Civan YavuzลŸen

๐Ÿ’ป

Tim Gates

๐Ÿ“–

campersau

๐Ÿ’ป

dependabot-preview[bot]

๐Ÿ’ป

This project follows the all-contributors specification. Contributions of any kind welcome!

License

Copyright 2014-present Rodrigo Fernandes. Released under the terms of the MIT license.

Thanks

This project is inspired in pretty-diff by Scott Gonzรกlez.


diff2html's People

Contributors

brewern avatar campersau avatar charguer avatar dependabot-preview[bot] avatar dependabot[bot] avatar ericcornelissen avatar escitalopram avatar furcypin avatar grimsteel avatar iliyazelenko avatar jameskmonger avatar jhwelch avatar jung-kim avatar kaishuu0123 avatar lantian avatar minami80630 avatar mohd-akram avatar mrfyda avatar nmatpt avatar pgrimaud avatar phaseone avatar pierrci avatar reustle avatar romellem avatar rtfpessoa avatar samiraguiar avatar shoito avatar sss0791 avatar stockmind avatar timgates42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diff2html's Issues

Binary files not listed in the diff

Hi,

I've made a diff from the following commit: https://github.com/rmpestano/last-changes-plugin/commit/1d620edfc16476650af3aa696389f42535f6034d

As you can see there are two files changes. The problem I'm facing is that diff2html is ignoring the binary file diff.

Here is the diff I've generated:

diff --git a/README.adoc b/README.adoc
index be99c75..9bbce57 100644
--- a/README.adoc
+++ b/README.adoc
@@ -20,7 +20,7 @@

 Last Changes is a *Jenkin plugin* that shows _rich VCS diffs_ between builds.

-IMPORTANT: Only `Git` and `Svn` are supported.
+IMPORTANT: Only `Git` and `Svn` based projects are supported.

 == Introduction

@@ -37,23 +37,23 @@

 == Objectives

-The main objective of this plugin is to have fast access to what has changed on a Jenkins build.
+The main objective of this plugin is to have _fast_ access to what has changed on a Jenkins build.

 Another interesting aspect is that it can easily help to find the `root cause` of a `failling build` by highlighting what has changed.

-Also the plugin _shines_ in a https://en.wikipedia.org/wiki/Continuous_delivery[*continuous delivery*^] environment, where each _commit_ generates a release candidate.
+And finally the plugin _shines_ in a https://en.wikipedia.org/wiki/Continuous_delivery[*continuous delivery*^] environment, where each _commit_ generates a release candidate.


 == How it works?

-. This plugin expects `git` or `svn` based builds.
+. This plugin expects `git` or `svn` based builds (a.k.a _Source Code Management_ configuration section).
 . While your job runs the plugin reads your build workspace to retrieve the current VCS revision;
 . The diff between `actual` and `previous` revisions will be stored;
 . The `diff` for each build can be viewed later in html format.

 IMPORTANT: To get most from this plugin use `periodically SCM pooling` to trigger your builds, http://www.nailedtothex.org/roller/kyle/entry/articles-jenkins-poll[more details here^].

-NOTE: The plugin *always* compare current revision with previous one even no new commit has been made.
+WARNING: The plugin *always* compare current revision with previous one even no new commit has been made.

 == Usage

diff --git a/last-changes-config.png b/last-changes-config.png
index 322248b..56fc1f2 100644
--- a/last-changes-config.png
+++ b/last-changes-config.png
Binary files differ

Here is the output where binary file change is ignored:

generated-diff

The html source from the page that uses diff2html can be found here:

jQuery(document).ready(function() {
                  var sidePanelTD=document.getElementById('side-panel');
                               if(sidePanelTD) {
                                 sidePanelTD.parentNode.removeChild(sidePanelTD);
                               }
                var diff2htmlUi = new Diff2HtmlUI({diff: buildChanges});

                    diff2htmlUi.draw('#line-by-line', {
                         inputFormat: 'json',
                         outputFormat: 'line-by-line',
                         showFiles: true,
                         synchronisedScroll: false,
                         matchWordsThreshold: '0.25',
                         matchingMaxComparisons: '1000.0',
                         matching: 'lines'
                         }
                        );
                    diff2htmlUi.fileListCloseable('#line-by-line', false);
                    diff2htmlUi.highlightCode('#line-by-line');

                }); //end documentReady

                var buildChanges = "diff --git a\/README.adoc b\/README.adoc\nindex be99c75..9bbce57 100644\n--- a\/README.adoc\n+++ b\/README.adoc\n@@ -20,7 +20,7 @@\n \r\n Last Changes is a *Jenkin plugin* that shows _rich VCS diffs_ between builds.\r\n \r\n-IMPORTANT: Only `Git` and `Svn` are supported.\r\n+IMPORTANT: Only `Git` and `Svn` based projects are supported.\r\n \r\n == Introduction\r\n \r\n@@ -37,23 +37,23 @@\n \r\n == Objectives\r\n \r\n-The main objective of this plugin is to have fast access to what has changed on a Jenkins build.\r\n+The main objective of this plugin is to have _fast_ access to what has changed on a Jenkins build.\r\n \r\n Another interesting aspect is that it can easily help to find the `root cause` of a `failling build` by highlighting what has changed.\r\n \r\n-Also the plugin _shines_ in a https:\/\/en.wikipedia.org\/wiki\/Continuous_delivery[*continuous delivery*^] environment, where each _commit_ generates a release candidate.\r\n+And finally the plugin _shines_ in a https:\/\/en.wikipedia.org\/wiki\/Continuous_delivery[*continuous delivery*^] environment, where each _commit_ generates a release candidate.\r\n \r\n \r\n == How it works?\r\n \r\n-. This plugin expects `git` or `svn` based builds.\r\n+. This plugin expects `git` or `svn` based builds (a.k.a _Source Code Management_ configuration section).\r\n . While your job runs the plugin reads your build workspace to retrieve the current VCS revision;\r\n . The diff between `actual` and `previous` revisions will be stored;\r\n . The `diff` for each build can be viewed later in html format.\r\n \r\n IMPORTANT: To get most from this plugin use `periodically SCM pooling` to trigger your builds, http:\/\/www.nailedtothex.org\/roller\/kyle\/entry\/articles-jenkins-poll[more details here^].\r\n \r\n-NOTE: The plugin *always* compare current revision with previous one even no new commit has been made.\r\n+WARNING: The plugin *always* compare current revision with previous one even no new commit has been made.\r\n \r\n == Usage\r\n \r\ndiff --git a\/last-changes-config.png b\/last-changes-config.png\nindex 322248b..56fc1f2 100644\n--- a\/last-changes-config.png\n+++ b\/last-changes-config.png\nBinary files differ\n";

Can you see something wrong?

thanks in advance.

Wordwrap function

diff2html 2.0.1 is working well for us at Ungit and I was able to fix our custom css bindings relatively easy from 1.6.x. Except for one feature, word wrap.

CSS word-wrap will not work with diff2html's resulting html code as it is not using actual whitespace, it is using &nbsp. Because of once easy CSS class injection fix for this feature is no longer viable.

  1. What is the reasoning behind the replacing spaces with &nbsp?
  2. Can we have a word wrap feature support from diff2html? (I'd rather not have to run the html gen function again)

Dumb question

I have an app that integrates with github and a self-hosted gitlab. How can I use your package to show diff between a master branch and a pull/merge request in my app?

Highlight is working not as supposed

It applies on line... but not on code block. For fast understanding here is a screenshot:

spectacle z25642

  1. It is applying on each line separatly. When it on the comment block - it doesn't understand that this is a comment block.
  2. It is applying on whole block. And now it is know about comment block.

It seems that with current approach (applying on line) it is not possible to allow normal highlight. Any ideas?

hide/show summary button sets wrong url

clicking the + sign next to the "files changed" sets the url incorrectly (logic is backwards).

When you first load the html file, the "+" sign is visible and the files changed are hidden.

but when you click it, it sets the URL to diff.html#d2h-hide-2t9. Clicking the (now changed to) minus sign, sets the URL to diff.html#d2h-show-w29. so, this seems backwards. clicking show should set the URL to a "show" status, and visa versa.

while we're on this topic..is it possible for you to change the +/- sign to something more obvious, like "show/hide", or "show files/hide files"?

i ask because the + sign is rather obscure and i'm using this for people who aren't as tech savvy, so a tiny '+' sign would probably largely go unnoticed.

[email protected] not working on client side.

Looking at the code borwserifying and importing nunjucks at client side will not be helpful either.

TypeError: nunjucks.configure is not a function
    at http://127.0.0.1:8333/js/ungit.js:2895:30
    at Object.<anonymous> (http://127.0.0.1:8333/js/ungit.js:2910:3)
    at Object.require.24../diff-parser.js (http://127.0.0.1:8333/js/ungit.js:2912:4)
    at s (http://127.0.0.1:8333/js/ungit.js:1:262)
    at http://127.0.0.1:8333/js/ungit.js:1:313
    at http://127.0.0.1:8333/js/ungit.js:2710:23
    at Object.require.23../diff-parser.js (http://127.0.0.1:8333/js/ungit.js:2873:3)
    at s (http://127.0.0.1:8333/js/ungit.js:1:262)
    at http://127.0.0.1:8333/js/ungit.js:1:313
    at http://127.0.0.1:8333/js/ungit.js:2675:27
    at Object.require.22../line-by-line-printer.js (http://127.0.0.1:8333/js/ungit.js:2693:3)
    at s (http://127.0.0.1:8333/js/ungit.js:1:262)
    at http://127.0.0.1:8333/js/ungit.js:1:313
    at http://127.0.0.1:8333/js/ungit.js:18316:21
    at Object.<anonymous> (http://127.0.0.1:8333/js/ungit.js:18415:3)
    at Object.require.diff2html../diff-parser.js (http://127.0.0.1:8333/js/ungit.js:18417:4)

Allow easy extention of diff2html

So as you know Ungit has been using diff2html and it has been great.

However, for implementing features like FredrikNoren/ungit#585, it would be rather difficult to do that without modifying the diff2html's source code. In fact, recent new feature "git commit on line level" feature had to do code replace like we do here on some of the diff2html's html code.

Is there an easier way to expose and extend diff2html for use cases like this?

Question: Diff2Html.getJsonFromDiff is not a function

I am trying to follow your docs, but haven't found any examples of usage, or function signature docs, have I missed something?

Without the above, I have guessed and created a script like this:

var fs = require('fs');
var Diff2Html = require('diff2html');
function processTutorial() {
    var files = [];
    var _files = getFiles('./tutorial/patches', files);
    var _loop_1 = function(path) {
        fs.readFile(path, 'utf8', function (err, data) {
            if (err) {
                throw err;
            }
            var content = Diff2Html.getJsonFromDiff(data);
            writeFile(content, path);
        });
    };
    for (var _i = 0, _files_1 = _files; _i < _files_1.length; _i++) {
        var path = _files_1[_i];
        _loop_1(path);
    }
}

Note - it's slightly ugly because it's compiled from typescript. When this is run, I get the following error:

Repos\docs\prepareTutorial.js:13
            Diff2Html.getPrettyHtml(data, { outputFormat: 'side-by-side' });
                      ^

TypeError: Diff2Html.getPrettyHtml is not a function
    at C:\Users\George\Source\Repos\docs\prepareTutorial.js:13:23
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)

What have I done wrong?

NB:

npm list diff2html
[email protected] C:\Users\George\Source\Repos\docs
`-- [email protected]

Empty div when parsing deleted file diff

diff2html outputs empty div when parsing deleted file diff.

> var diff2html = require('diff2html');
undefined
> diff2html.getPrettyHtmlFromDiff("diff --git a/test b/test\ndeleted file mode 100644\nindex 190a180..0000000\n--- a/test\n+++ /dev/null\n@@ -1 +0,0 @@\n-123");
'<div class="d2h-wrapper">\n</div>\n'

Fix diff parsing on windows line ending

Copied from rtfpessoa/diff2html-cli#16

when the diff diff2html-cli is given, has CRLF line endings, the generator will generate a valid html file, but it will act as if the source diff was empty.

obviously, this isn't ideal on windows -- especially when everything is so hard coded (cmd, powershell) to always output \r\n.

i'm not sure how fixable this is for you, or if it touches the entire code base (hope not). presently i'm running dos2unix on the diffs i create from hg, but of course that is a real hack and has its own pitfalls.

Improve sample page

  • Allow to see different option combinations (ex: matching lines, without files summary, ... )
  • Add some design to the page ๐Ÿ˜„

TypeError: diffInput.replace is not a function

So im trying to use this library with no success, in backend i do diff with php, first i tried sebiastian/diff library, after problems with it and google help i found that some people have same problems with that library too. So after that i have changed library to neos/diff but still same problems left.

i tried debugging this problem, is it suppose to call this function twice ? Because firstly diffInput is string ( data-diff) and second time its called diffInput is array.

[data-diff]:
@@ -1,3 +1,1 @@
-data
data
-data

javascript:

  $('.proxy-diff').each(function(){
        if ($(this).data('diff') !== '') {
            var diff2htmlUi = new Diff2HtmlUI({diff: $(this).data('diff')});
            diff2htmlUi.draw(this.id, {matching: 'lines'});
        }
  });

Stack trace:

diff2html.js:2555 Uncaught TypeError: diffInput.replace is not a function
DiffParser.generateDiffJson @ diff2html.js:2555
Diff2Html.getPrettyHtml @ diff2html.js:2827
Diff2HtmlUI.draw @ diff2html-ui.js:37
(anonymous function) @ proxy_list_show.js:11
each @ jquery.js:374
each @ jquery.js:139
initRevisionDiffs @ proxy_list_show.js:8
init @ proxy_list_show.js:4j @ jquery.js:3099
fireWith @ jquery.js:3211
ready @ jquery.js:3417I @ jquery.js:3433

Better diff files order

  • New files should be in the end of the diff (before deleted)
  • Deleted files should be in the end of the diff

Use semver correctly

I just wanted to upgrade to the latest version (^2.0.0-beta18) of diff2html by running npm up --save diff2html
But because you used semver the wrong way it installed ^2.0.0-beta9.
(Which is the specified behavior if you check http://semver.org/#spec-item-11)

To get the correct order you must separate beta and the number with a dot (^2.0.0-beta.18)

As beta comes lexicographically before beta9 there is no easy way to fix this with the beta naming schema. I'd propose you switch to release candidate: ^2.0.0-rc.1 and deprecate all beta versions.

npm deprecate diff2html@'>1.3.2 <2.0.0-rc.1' 'Incorrect version identifiers'

Failed to parse lines, starting in 0!

Hi,

Our diffs are generated in PHP with https://github.com/sebastianbergmann/diff. Here is an example diff:

"--- Original\n+++ New\n@@ @@\n-This is test.\n-A multiline test.\n-With some minor differencs.\n+This is a test.\n+A multi-line test.\n+With some minor differences.\n","translator_comment":"This is a test.\r\nA multi-line test.\r\nWith some minor differences."

While Diff2HtmlUI does parse the diff and shows HTML, it always throws error Failed to parse lines, starting in 0!.

Longer diffs then look like this:

Wrong numbering

As you can see in the image, the numbering is wrong. Also, further lines without diffs are still being shown. In above example, after line 2, there are no more diffs. Still, the complete file (200 more lines) is being shown.

Any idea?

Best,
Lionel

Line height is weird

After version 1.2.0 all the versions seem to be affected by a weird line height difference.
We notice this because the borders are not the same height as the line tr > td > div.

This can be easily fixed by lowering the line height in the div inside the table but that is not great since the lines get really close.

After lots of changes the CSS is kind of outdated and needs a refactor/cleaning.

Problems parsing diff blocks which with certain header statements

It seems the commit tagged as v2.0.0-rc.9 introduced some problems with parsing certain block header statements.

In this commit, lines 2575 in diff2html.js changed from

      if (currentFile && utils.startsWith(line, hunkHeaderPrefix)) {
        startBlock(line);
        return;
      }

to

      if (
        (currentFile && utils.startsWith(line, hunkHeaderPrefix)) ||
        (currentFile.isGitDiff && currentFile && currentFile.oldName && currentFile.newName && !currentBlock)
      ) {
        startBlock(line);
        return;
      }

A block is now potentially started before the hunkHeaderPrefix when parsing a diff produced by git with the --find-renames flag specified, leading to garbage in the displayed html diff.

An example of a block header as produced by git diff --find-renames:

diff --git a/****** b/******
similarity index 98%
rename from C:/******
rename to C:/******
index e01513b..f14a870 100644
--- a/C:/******
+++ b/C:/******
@@ -1,4 +1,32 @@

Performance issue

Hi guys,

I am facing some performance issues on some diffs which are taking too much time to render.

For example I've generated a diff from the last commit of this repository: 8fe49ab

the full diff content can be found here: http://pastebin.com/VUaXjSSt

I've reduced the diff to a small part and it still takes 20 seconds to render here on chrome (on firefox it asks to interrupt the script two times and then renders the page - attached an image), here is a code sample with the reduced diff:

<script>
    var lineDiffExample ="diff --git a\/bower.json b\/bower.json\nindex d4e58ce..0df139c 100644\n--- a\/bower.json\n+++ b\/bower.json\n@@ -1,6 +1,6 @@\n  currentBlock.oldStartLine2=oldLine2,currentBlock.newStartLine=newLine,currentBlock.header=line},createLine=function(line){var currentLine={};currentLine.content=line;var newLinePrefixes=currentFile.isCombined?[\"+\",\" +\"]:[\"+\"],delLinePrefixes=currentFile.isCombined?[\"-\",\" -\"]:[\"-\"];utils.startsWith(line,newLinePrefixes)?(currentFile.addedLines++,currentLine.type=LINE_TYPE.INSERTS,currentLine.oldNumber=null,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine)):utils.startsWith(line,delLinePrefixes)?(currentFile.deletedLines++,currentLine.type=LINE_TYPE.DELETES,currentLine.oldNumber=oldLine++,currentLine.newNumber=null,currentBlock.lines.push(currentLine)):(currentLine.type=LINE_TYPE.CONTEXT,currentLine.oldNumber=oldLine++,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine))},diffLines=diffInput.replace(\/\\\\ No newline at end of file\/g,\"\").replace(\/\\r\\n?\/g,\"\\n\").split(\"\\n\"),oldMode=\/^old mode (\\d{6})\/,newMode=\/^new mode (\\d{6})\/,deletedFileMode=\/^deleted file mode (\\d{6})\/,newFileMode=\/^new file mode (\\d{6})\/,copyFrom=\/^copy from \"?(.+)\"?\/,copyTo=\/^copy to \"?(.+)\"?\/,renameFrom=\/^rename from \"?(.+)\"?\/,renameTo=\/^rename to \"?(.+)\"?\/,similarityIndex=\/^similarity index (\\d+)%\/,dissimilarityIndex=\/^dissimilarity index (\\d+)%\/,index=\/^index ([0-9a-z]+)\\.\\.([0-9a-z]+)\\s*(\\d{6})?\/,combinedIndex=\/^index ([0-9a-z]+),([0-9a-z]+)\\.\\.([0-9a-z]+)\/,combinedMode=\/^mode (\\d{6}),(\\d{6})\\.\\.(\\d{6})\/,combinedNewFile=\/^new file mode (\\d{6})\/,combinedDeletedFile=\/^deleted file mode (\\d{6}),(\\d{6})\/;return diffLines.forEach(function(line){if(line&&!utils.startsWith(line,\"*\")){(utils.startsWith(line,\"diff\")||!currentFile||currentFile&&(currentFile.oldName&&utils.startsWith(line,\"--- \")||currentFile.newName&&utils.startsWith(line,\"+++ \")))&&startFile();var values;if(currentFile&&!currentFile.oldName&&utils.startsWith(line,\"--- \")&&(values=getSrcFilename(line,config)))return currentFile.oldName=values,void(currentFile.language=getExtension(currentFile.oldName,currentFile.language));if(currentFile&&!currentFile.newName&&utils.startsWith(line,\"+++ \")&&(values=getDstFilename(line,config)))return currentFile.newName=values,void(currentFile.language=getExtension(currentFile.newName,currentFile.language));if(currentFile&&utils.startsWith(line,\"@\"))return void startBlock(line);if(currentBlock&&(utils.startsWith(line,\"+\")||utils.startsWith(line,\"-\")||utils.startsWith(line,\" \")))return void createLine(line);(currentFile&&currentFile.blocks.length||currentBlock&&currentBlock.lines.length)&&startFile(),(values=oldMode.exec(line))?currentFile.oldMode=values[1]:(values=newMode.exec(line))?currentFile.newMode=values[1]:(values=deletedFileMode.exec(line))?(currentFile.deletedFileMode=values[1],currentFile.isDeleted=!0):(values=newFileMode.exec(line))?(currentFile.newFileMode=values[1],currentFile.isNew=!0):(values=copyFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isCopy=!0):(values=copyTo.exec(line))?(currentFile.newName=values[1],currentFile.isCopy=!0):(values=renameFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isRename=!0):(values=renameTo.exec(line))?(currentFile.newName=values[1],currentFile.isRename=!0):(values=similarityIndex.exec(line))?currentFile.unchangedPercentage=values[1]:(values=dissimilarityIndex.exec(line))?currentFile.changedPercentage=values[1]:(values=index.exec(line))?(currentFile.checksumBefore=values[1],currentFile.checksumAfter=values[2],values[3]&&(currentFile.mode=values[3])):(values=combinedIndex.exec(line))?(currentFile.checksumBefore=[values[2],values[3]],currentFile.checksumAfter=values[1]):(values=combinedMode.exec(line))?(currentFile.oldMode=[values[2],values[3]],currentFile.newMode=values[1]):(values=combinedNewFile.exec(line))?(currentFile.newFileMode=values[1],currentFile.isNew=!0):(values=combinedDeletedFile.exec(line))&&(currentFile.deletedFileMode=values[1],currentFile.isDeleted=!0)}}),saveBlock(),saveFile(),files},module.exports.DiffParser=new DiffParser}()},{\".\/utils.js\":32}],23:[function(require,module){(function(global){!function(){function Diff2Html(){}var diffParser=require(\".\/diff-parser.js\").DiffParser,fileLister=require(\".\/file-list-printer.js\").FileListPrinter,htmlPrinter=require(\".\/html-printer.js\").HtmlPrinter;Diff2Html.prototype.getJsonFromDiff=function(diffInput,config){var configOrEmpty=config||{};return diffParser.generateDiffJson(diffInput,configOrEmpty)},Diff2Html.prototype.getPrettyHtml=function(diffInput,config){var configOrEmpty=config||{},diffJson=diffInput;configOrEmpty.inputFormat&&\"diff\"!==configOrEmpty.inputFormat||(diffJson=diffParser.generateDiffJson(diffInput,configOrEmpty));var fileList=\"\";configOrEmpty.showFiles===!0&&(fileList=fileLister.generateFileList(diffJson,configOrEmpty));var diffOutput=\"\";return diffOutput=\"side-by-side\"===configOrEmpty.outputFormat?htmlPrinter.generateSideBySideJsonHtml(diffJson,configOrEmpty):htmlPrinter.generateLineByLineJsonHtml(diffJson,configOrEmpty),fileList+diffOutput},Diff2Html.prototype.getPrettyHtmlFromDiff=function(diffInput,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat=\"diff\",configOrEmpty.outputFormat=\"line-by-line\",this.getPrettyHtml(diffInput,configOrEmpty)},Diff2Html.prototype.getPrettyHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat=\"json\",configOrEmpty.outputFormat=\"line-by-line\",this.getPrettyHtml(diffJson,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromDiff=function(diffInput,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat=\"diff\",configOrEmpty.outputFormat=\"side-by-side\",this.getPrettyHtml(diffInput,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat=\"json\",configOrEmpty.outputFormat=\"side-by-side\",this.getPrettyHtml(diffJson,configOrEmpty)};var diffObject=new Diff2Html;module.exports.Diff2Html=diffObject,global.Diff2Html=diffObject}()}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\".\/diff-parser.js\":22,\".\/file-list-printer.js\":24,\".\/html-printer.js\":26}],24:[function(require,module){!function(){function FileListPrinter(){}var printerUtils=require(\".\/printer-utils.js\").PrinterUtils,hoganUtils=require(\".\/hoganjs-utils.js\").HoganJsUtils,baseTemplatesPath=\"file-summary\",iconsBaseTemplatesPath=\"icon\";FileListPrinter.prototype.generateFileList=function(diffFiles){var lineTemplate=hoganUtils.template(baseTemplatesPath,\"line\"),files=diffFiles.map(function(file){var fileTypeName=printerUtils.getFileTypeIcon(file),iconTemplate=hoganUtils.template(iconsBaseTemplatesPath,fileTypeName);return lineTemplate.render({fileHtmlId:printerUtils.getHtmlId(file),fileName:printerUtils.getDiffName(file),deletedLines:\"-\"+file.deletedLines,addedLines:\"+\"+file.addedLines},{fileIcon:iconTemplate})}).join(\"\\n\");return hoganUtils.render(baseTemplatesPath,\"wrapper\",{filesNumber:diffFiles.length,files:files})},module.exports.FileListPrinter=new FileListPrinter}()},{\".\/hoganjs-utils.js\":25,\".\/printer-utils.js\":28}],25:[function(require,module){(function(__dirname){!function(){function HoganJsUtils(){}var fs=require(\"fs\"),path=require(\"path\"),hogan=require(\"hogan.js\"),hoganTemplates=require(\".\/templates\/diff2html-templates.js\"),templatesPath=path.resolve(__dirname,\"templates\");HoganJsUtils.prototype.render=function(namespace,view,params,configuration){var template=this.template(namespace,view,configuration);return template?template.render(params):null},HoganJsUtils.prototype.template=function(namespace,view,configuration){var config=configuration||{},templateKey=this._templateKey(namespace,view);return this._getTemplate(templateKey,config)},HoganJsUtils.prototype._getTemplate=function(templateKey,config){var template;return config.noCache||(template=this._readFromCache(templateKey)),template||(template=this._loadTemplate(templateKey)),template},HoganJsUtils.prototype._loadTemplate=function(templateKey){var template;try{if(fs.readFileSync){var templatePath=path.join(templatesPath,templateKey),templateContent=fs.readFileSync(templatePath+\".mustache\",\"utf8\");template=hogan.compile(templateContent),hoganTemplates[templateKey]=template}}catch(e){console.error(\"Failed to read (template: \"+templateKey+\") from fs: \"+e.message)}return template},HoganJsUtils.prototype._readFromCache=function(templateKey){return hoganTemplates[templateKey]},HoganJsUtils.prototype._templateKey=function(namespace,view){return namespace+\"-\"+view},module.exports.HoganJsUtils=new HoganJsUtils}()}).call(this,\"\/src\")},{\".\/templates\/diff2html-templates.js\":31,fs:1,\"hogan.js\":20,path:2}],26:[function(require,module){!function(){function HtmlPrinter(){}var LineByLinePrinter=require(\".\/line-by-line-printer.js\").LineByLinePrinter,SideBySidePrinter=require(\".\/side-by-side-printer.js\").SideBySidePrinter;HtmlPrinter.prototype.generateLineByLineJsonHtml=function(diffFiles,config){var lineByLinePrinter=new LineByLinePrinter(config);return lineByLinePrinter.generateLineByLineJsonHtml(diffFiles)},HtmlPrinter.prototype.generateSideBySideJsonHtml=function(diffFiles,config){var sideBySidePrinter=new SideBySidePrinter(config);return sideBySidePrinter.generateSideBySideJsonHtml(diffFiles)},module.exports.HtmlPrinter=new HtmlPrinter}()},{\".\/line-by-line-printer.js\":27,\".\/side-by-side-printer.js\":30}],27:[function(require,module){!function(){function LineByLinePrinter(config){this.config=config}var diffParser=require(\".\/diff-parser.js\").DiffParser,printerUtils=require(\".\/printer-utils.js\").PrinterUtils,utils=require(\".\/utils.js\").Utils,Rematch=require(\".\/rematch.js\").Rematch,hoganUtils=require(\".\/hoganjs-utils.js\").HoganJsUtils,genericTemplatesPath=\"generic\",baseTemplatesPath=\"line-by-line\",iconsBaseTemplatesPath=\"icon\",tagsBaseTemplatesPath=\"tag\";LineByLinePrinter.prototype.makeFileDiffHtml=function(file,diffs){var fileDiffTemplate=hoganUtils.template(baseTemplatesPath,\"file-diff\"),filePathTemplate=hoganUtils.template(genericTemplatesPath,\"file-path\"),fileIconTemplate=hoganUtils.template(iconsBaseTemplatesPath,\"file\"),fileTagTemplate=hoganUtils.template(tagsBaseTemplatesPath,printerUtils.getFileTypeIcon(file));return fileDiffTemplate.render({file:file,fileHtmlId:printerUtils.getHtmlId(file),diffs:diffs,filePath:filePathTemplate.render({fileDiffName:printerUtils.getDiffName(file)},{fileIcon:fileIconTemplate,fileTag:fileTagTemplate})})},LineByLinePrinter.prototype.makeLineByLineHtmlWrapper=function(content){return hoganUtils.render(genericTemplatesPath,\"wrapper\",{content:content})},LineByLinePrinter.prototype.generateLineByLineJsonHtml=function(diffFiles){var that=this,htmlDiffs=diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?that._generateFileHtml(file):that._generateEmptyDiff(),that.makeFileDiffHtml(file,diffs)});return this.makeLineByLineHtmlWrapper(htmlDiffs.join(\"\\n\"))};var matcher=Rematch.rematch(function(a,b){var amod=a.content.substr(1),bmod=b.content.substr(1);return Rematch.distance(amod,bmod)});LineByLinePrinter.prototype.makeColumnLineNumberHtml=function(block){return hoganUtils.render(genericTemplatesPath,\"column-line-number\",{diffParser:diffParser,blockHeader:block.header,lineClass:\"d2h-code-linenumber\",contentClass:\"d2h-code-line\"})},LineByLinePrinter.prototype._generateFileHtml=function(file){var that=this;return file.blocks.map(function(block){function processChangeBlock(){var matches,insertType,deleteType,comparisons=oldLines.length*newLines.length,maxComparisons=that.config.matchingMaxComparisons||2500,doMatching=maxComparisons>comparisons&&(\"lines\"===that.config.matching||\"words\"===that.config.matching);doMatching?(matches=matcher(oldLines,newLines),insertType=diffParser.LINE_TYPE.INSERT_CHANGES,deleteType=diffParser.LINE_TYPE.DELETE_CHANGES):(matches=[[oldLines,newLines]],insertType=diffParser.LINE_TYPE.INSERTS,deleteType=diffParser.LINE_TYPE.DELETES),matches.forEach(function(match){oldLines=match[0],newLines=match[1];for(var oldLine,newLine,processedOldLines=[],processedNewLines=[],common=Math.min(oldLines.length,newLines.length),j=0;common>j;j++){oldLine=oldLines[j],newLine=newLines[j],that.config.isCombined=file.isCombined;var diff=printerUtils.diffHighlight(oldLine.content,newLine.content,that.config);processedOldLines+=that.makeLineHtml(deleteType,oldLine.oldNumber,oldLine.newNumber,diff.first.line,diff.first.prefix),processedNewLines+=that.makeLineHtml(insertType,newLine.oldNumber,newLine.newNumber,diff.second.line,diff.second.prefix)}lines+=processedOldLines+processedNewLines,lines+=that._processLines(oldLines.slice(common),newLines.slice(common))}),oldLines=[],newLines=[]}for(var lines=that.makeColumnLineNumberHtml(block),oldLines=[],newLines=[],i=0;i<block.lines.length;i++){var line=block.lines[i],escapedLine=utils.escape(line.content);line.type!==diffParser.LINE_TYPE.INSERTS&&(newLines.length>0||line.type!==diffParser.LINE_TYPE.DELETES&&oldLines.length>0)&&processChangeBlock(),line.type===diffParser.LINE_TYPE.CONTEXT?lines+=that.makeLineHtml(line.type,line.oldNumber,line.newNumber,escapedLine):line.type!==diffParser.LINE_TYPE.INSERTS||oldLines.length?line.type===diffParser.LINE_TYPE.DELETES?oldLines.push(line):line.type===diffParser.LINE_TYPE.INSERTS&&Boolean(oldLines.length)?newLines.push(line):(console.error(\"Unknown state in html line-by-line generator\"),processChangeBlock()):lines+=that.makeLineHtml(line.type,line.oldNumber,line.newNumber,escapedLine)}return processChangeBlock(),lines}).join(\"\\n\")},LineByLinePrinter.prototype._processLines=function(oldLines,newLines){for(var lines=\"\",i=0;i<oldLines.length;i++){var oldLine=oldLines[i],oldEscapedLine=utils.escape(oldLine.content);lines+=this.makeLineHtml(oldLine.type,oldLine.oldNumber,oldLine.newNumber,oldEscapedLine)}for(var j=0;j<newLines.length;j++){var newLine=newLines[j],newEscapedLine=utils.escape(newLine.content);lines+=this.makeLineHtml(newLine.type,newLine.oldNumber,newLine.newNumber,newEscapedLine)}return lines},LineByLinePrinter.prototype.makeLineHtml=function(type,oldNumber,newNumber,content,prefix){var lineNumberTemplate=hoganUtils.render(baseTemplatesPath,\"numbers\",{oldNumber:utils.valueOrEmpty(oldNumber),newNumber:utils.valueOrEmpty(newNumber)});return hoganUtils.render(genericTemplatesPath,\"line\",{type:type,lineClass:\"d2h-code-linenumber\",contentClass:\"d2h-code-line\",prefix:prefix&&utils.convertWhiteSpaceToNonBreakingSpace(prefix),content:content&&utils.convertWhiteSpaceToNonBreakingSpace(content),lineNumber:lineNumberTemplate})},LineByLinePrinter.prototype._generateEmptyDiff=function(){return hoganUtils.render(genericTemplatesPath,\"empty-diff\",{contentClass:\"d2h-code-line\",diffParser:diffParser})},module.exports.LineByLinePrinter=LineByLinePrinter}()},{\".\/diff-parser.js\":22,\".\/hoganjs-utils.js\":25,\".\/printer-utils.js\":28,\".\/rematch.js\":29,\".\/utils.js\":32}],28:[function(require,module){!function(){function PrinterUtils(){}function unifyPath(path){return path?path.replace(\"\\\\\",\"\/\"):path}function isDevNullName(name){return-1!==name.indexOf(\"dev\/null\")}function removeIns(line){return line.replace(\/(<ins[^>]*>((.|\\n)*?)<\\\/ins>)\/g,\"\")}function removeDel(line){return line.replace(\/(<del[^>]*>((.|\\n)*?)<\\\/del>)\/g,\"\")}var jsDiff=require(\"diff\"),utils=require(\".\/utils.js\").Utils,Rematch=require(\".\/rematch.js\").Rematch,separator=\"\/\";PrinterUtils.prototype.getHtmlId=function(file){var hashCode=function(text){var i,chr,len,hash=0;for(i=0,len=text.length;len>i;i++)chr=text.charCodeAt(i),hash=(hash<<5)-hash+chr,hash|=0;return hash};return\"d2h-\"+hashCode(this.getDiffName(file)).toString().slice(-6)},PrinterUtils.prototype.getDiffName=function(file){var oldFilename=unifyPath(file.oldName),newFilename=unifyPath(file.newName);if(oldFilename&&newFilename&&oldFilename!==newFilename&&!isDevNullName(oldFilename)&&!isDevNullName(newFilename)){for(var prefixPaths=[],suffixPaths=[],oldFilenameParts=oldFilename.split(separator),newFilenameParts=newFilename.split(separator),oldFilenamePartsSize=oldFilenameParts.length,newFilenamePartsSize=newFilenameParts.length,i=0,j=oldFilenamePartsSize-1,k=newFilenamePartsSize-1;j>i&&k>i&&oldFilenameParts[i]===newFilenameParts[i];)prefixPaths.push(newFilenameParts[i]),i+=1;for(;j>i&&k>i&&oldFilenameParts[j]===newFilenameParts[k];)suffixPaths.unshift(newFilenameParts[k]),j-=1,k-=1;var finalPrefix=prefixPaths.join(separator),finalSuffix=suffixPaths.join(separator),oldRemainingPath=oldFilenameParts.slice(i,j+1).join(separator),newRemainingPath=newFilenameParts.slice(i,k+1).join(separator);return finalPrefix.length&&finalSuffix.length?finalPrefix+separator+\"{\"+oldRemainingPath+\" \u2192 \"+newRemainingPath+\"}\"+separator+finalSuffix:finalPrefix.length?finalPrefix+separator+\"{\"+oldRemainingPath+\" \u2192 \"+newRemainingPath+\"}\":finalSuffix.length?\"{\"+oldRemainingPath+\" \u2192 \"+newRemainingPath+\"}\"+separator+finalSuffix:oldFilename+\" \u2192 \"+newFilename}return newFilename&&!isDevNullName(newFilename)?newFilename:oldFilename?oldFilename:\"unknown\/file\/path\"},PrinterUtils.prototype.getFileTypeIcon=function(file){var templateName=\"file-changed\";return file.isRename?templateName=\"file-renamed\":file.isCopy?templateName=\"file-renamed\":file.isNew?templateName=\"file-added\":file.isDeleted?templateName=\"file-deleted\":file.newName!==file.oldName&&(templateName=\"file-renamed\"),templateName},PrinterUtils.prototype.diffHighlight=function(diffLine1,diffLine2,config){var linePrefix1,linePrefix2,unprefixedLine1,unprefixedLine2,prefixSize=1;config.isCombined&&(prefixSize=2),linePrefix1=diffLine1.substr(0,prefixSize),linePrefix2=diffLine2.substr(0,prefixSize),unprefixedLine1=diffLine1.substr(prefixSize),unprefixedLine2=diffLine2.substr(prefixSize);var diff;diff=config.charByChar?jsDiff.diffChars(unprefixedLine1,unprefixedLine2):jsDiff.diffWordsWithSpace(unprefixedLine1,unprefixedLine2);var highlightedLine=\"\",changedWords=[];if(!config.charByChar&&\"words\"===config.matching){var treshold=.25;\"undefined\"!=typeof config.matchWordsThreshold&&(treshold=config.matchWordsThreshold);var matcher=Rematch.rematch(function(a,b){var amod=a.value,bmod=b.value;return Rematch.distance(amod,bmod)}),removed=diff.filter(function(element){return element.removed}),added=diff.filter(function(element){return element.added}),chunks=matcher(added,removed);chunks.forEach(function(chunk){if(1===chunk[0].length&&1===chunk[1].length){var dist=Rematch.distance(chunk[0][0].value,chunk[1][0].value);treshold>dist&&(changedWords.push(chunk[0][0]),changedWords.push(chunk[1][0]))}})}return diff.forEach(function(part){var addClass=changedWords.indexOf(part)>-1?\' class=\"d2h-change\"\':\"\",elemType=part.added?\"ins\":part.removed?\"del\":null,escapedValue=utils.escape(part.value);highlightedLine+=null!==elemType?\"<\"+elemType+addClass+\">\"+escapedValue+\"<\/\"+elemType+\">\":escapedValue}),{first:{prefix:linePrefix1,line:removeIns(highlightedLine)},second:{prefix:linePrefix2,line:removeDel(highlightedLine)}}},module.exports.PrinterUtils=new PrinterUtils}()},{\".\/rematch.js\":29,\".\/utils.js\":32,diff:13}],29:[function(require,module){!function(){function levenshtein(a,b){if(0==a.length)return b.length;if(0==b.length)return a.length;var i,matrix=[];for(i=0;i<=b.length;i++)matrix[i]=[i];var j;for(j=0;j<=a.length;j++)matrix[0][j]=j;for(i=1;i<=b.length;i++)for(j=1;j<=a.length;j++)matrix[i][j]=b.charAt(i-1)==a.charAt(j-1)?matrix[i-1][j-1]:Math.min(matrix[i-1][j-1]+1,Math.min(matrix[i][j-1]+1,matrix[i-1][j]+1));return matrix[b.length][a.length]}var Rematch={};Rematch.levenshtein=levenshtein,Rematch.distance=function(x,y){x=x.trim(),y=y.trim();var lev=levenshtein(x,y),score=lev\/(x.length+y.length);return score},Rematch.rematch=function(distanceFunction){function findBestMatch(a,b,cache){var cachecount=0;for(var key in cache)cachecount++;for(var bestMatch,bestMatchDist=1\/0,i=0;i<a.length;++i)for(var j=0;j<b.length;++j){var md,cacheKey=JSON.stringify([a[i],b[j]]);cache.hasOwnProperty(cacheKey)?md=cache[cacheKey]:(md=distanceFunction(a[i],b[j]),cache[cacheKey]=md),bestMatchDist>md&&(bestMatchDist=md,bestMatch={indexA:i,indexB:j,score:bestMatchDist})}return bestMatch}function group(a,b,level,cache){\"undefined\"==typeof cache&&(cache={});var bm=findBestMatch(a,b,cache);if(level||(level=0),!bm||a.length+b.length<3)return[[a,b]];var a1=a.slice(0,bm.indexA),b1=b.slice(0,bm.indexB),aMatch=[a[bm.indexA]],bMatch=[b[bm.indexB]],tailA=bm.indexA+1,tailB=bm.indexB+1,a2=a.slice(tailA),b2=b.slice(tailB),group1=group(a1,b1,level+1,cache),groupMatch=group(aMatch,bMatch,level+1,cache),group2=group(a2,b2,level+1,cache),result=groupMatch;return(bm.indexA>0||bm.indexB>0)&&(result=group1.concat(result)),(a.length>tailA||b.length>tailB)&&(result=result.concat(group2)),result}return group},module.exports.Rematch=Rematch}()},{}],30:[function(require,module){!function(){function SideBySidePrinter(config){this.config=config}var diffParser=require(\".\/diff-parser.js\").DiffParser,printerUtils=require(\".\/printer-utils.js\").PrinterUtils,utils=require(\".\/utils.js\").Utils,Rematch=require(\".\/rematch.js\").Rematch,hoganUtils=require(\".\/hoganjs-utils.js\").HoganJsUtils,genericTemplatesPath=\"generic\",baseTemplatesPath=\"side-by-side\",iconsBaseTemplatesPath=\"icon\",tagsBaseTemplatesPath=\"tag\",matcher=Rematch.rematch(function(a,b){var amod=a.content.substr(1),bmod=b.content.substr(1);return Rematch.distance(amod,bmod)});SideBySidePrinter.prototype.makeDiffHtml=function(file,diffs){var fileDiffTemplate=hoganUtils.template(baseTemplatesPath,\"file-diff\"),filePathTemplate=hoganUtils.template(genericTemplatesPath,\"file-path\"),fileIconTemplate=hoganUtils.template(iconsBaseTemplatesPath,\"file\"),fileTagTemplate=hoganUtils.template(tagsBaseTemplatesPath,printerUtils.getFileTypeIcon(file));\n-\n-return fileDiffTemplate.render({file:file,fileHtmlId:printerUtils.getHtmlId(file),diffs:diffs,filePath:filePathTemplate.render({fileDiffName:printerUtils.getDiffName(file)},{fileIcon:fileIconTemplate,fileTag:fileTagTemplate})})},SideBySidePrinter.prototype.generateSideBySideJsonHtml=function(diffFiles){var that=this,content=diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?that.generateSideBySideFileHtml(file):that.generateEmptyDiff(),that.makeDiffHtml(file,diffs)}).join(\"\\n\");return hoganUtils.render(genericTemplatesPath,\"wrapper\",{content:content})},SideBySidePrinter.prototype.makeSideHtml=function(blockHeader){return hoganUtils.render(genericTemplatesPath,\"column-line-number\",{diffParser:diffParser,blockHeader:blockHeader,lineClass:\"d2h-code-side-linenumber\",contentClass:\"d2h-code-side-line\"})},SideBySidePrinter.prototype.generateSideBySideFileHtml=function(file){var that=this,fileHtml={};return fileHtml.left=\"\",fileHtml.right=\"\",file.blocks.forEach(function(block){function processChangeBlock(){var matches,insertType,deleteType,comparisons=oldLines.length*newLines.length,maxComparisons=that.config.matchingMaxComparisons||2500,doMatching=maxComparisons>comparisons&&(\"lines\"===that.config.matching||\"words\"===that.config.matching);doMatching?(matches=matcher(oldLines,newLines),insertType=diffParser.LINE_TYPE.INSERT_CHANGES,deleteType=diffParser.LINE_TYPE.DELETE_CHANGES):(matches=[[oldLines,newLines]],insertType=diffParser.LINE_TYPE.INSERTS,deleteType=diffParser.LINE_TYPE.DELETES),matches.forEach(function(match){oldLines=match[0],newLines=match[1];for(var common=Math.min(oldLines.length,newLines.length),max=Math.max(oldLines.length,newLines.length),j=0;common>j;j++){var oldLine=oldLines[j],newLine=newLines[j];that.config.isCombined=file.isCombined;var diff=printerUtils.diffHighlight(oldLine.content,newLine.content,that.config);fileHtml.left+=that.generateSingleLineHtml(deleteType,oldLine.oldNumber,diff.first.line,diff.first.prefix),fileHtml.right+=that.generateSingleLineHtml(insertType,newLine.newNumber,diff.second.line,diff.second.prefix)}if(max>common){var oldSlice=oldLines.slice(common),newSlice=newLines.slice(common),tmpHtml=that.processLines(oldSlice,newSlice);fileHtml.left+=tmpHtml.left,fileHtml.right+=tmpHtml.right}}),oldLines=[],newLines=[]}fileHtml.left+=that.makeSideHtml(block.header),fileHtml.right+=that.makeSideHtml(\"\");for(var oldLines=[],newLines=[],i=0;i<block.lines.length;i++){var line=block.lines[i],prefix=line.content[0],escapedLine=utils.escape(line.content.substr(1));line.type!==diffParser.LINE_TYPE.INSERTS&&(newLines.length>0||line.type!==diffParser.LINE_TYPE.DELETES&&oldLines.length>0)&&processChangeBlock(),line.type===diffParser.LINE_TYPE.CONTEXT?(fileHtml.left+=that.generateSingleLineHtml(line.type,line.oldNumber,escapedLine,prefix),fileHtml.right+=that.generateSingleLineHtml(line.type,line.newNumber,escapedLine,prefix)):line.type!==diffParser.LINE_TYPE.INSERTS||oldLines.length?line.type===diffParser.LINE_TYPE.DELETES?oldLines.push(line):line.type===diffParser.LINE_TYPE.INSERTS&&Boolean(oldLines.length)?newLines.push(line):(console.error(\"unknown state in html side-by-side generator\"),processChangeBlock()):(fileHtml.left+=that.generateSingleLineHtml(diffParser.LINE_TYPE.CONTEXT,\"\",\"\",\"\"),fileHtml.right+=that.generateSingleLineHtml(line.type,line.newNumber,escapedLine,prefix))}processChangeBlock()}),fileHtml},SideBySidePrinter.prototype.processLines=function(oldLines,newLines){var that=this,fileHtml={};fileHtml.left=\"\",fileHtml.right=\"\";for(var maxLinesNumber=Math.max(oldLines.length,newLines.length),i=0;maxLinesNumber>i;i++){var oldContent,newContent,oldPrefix,newPrefix,oldLine=oldLines[i],newLine=newLines[i];oldLine&&(oldContent=utils.escape(oldLine.content.substr(1)),oldPrefix=oldLine.content[0]),newLine&&(newContent=utils.escape(newLine.content.substr(1)),newPrefix=newLine.content[0]),oldLine&&newLine?(fileHtml.left+=that.generateSingleLineHtml(oldLine.type,oldLine.oldNumber,oldContent,oldPrefix),fileHtml.right+=that.generateSingleLineHtml(newLine.type,newLine.newNumber,newContent,newPrefix)):oldLine?(fileHtml.left+=that.generateSingleLineHtml(oldLine.type,oldLine.oldNumber,oldContent,oldPrefix),fileHtml.right+=that.generateSingleLineHtml(diffParser.LINE_TYPE.CONTEXT,\"\",\"\",\"\")):newLine?(fileHtml.left+=that.generateSingleLineHtml(diffParser.LINE_TYPE.CONTEXT,\"\",\"\",\"\"),fileHtml.right+=that.generateSingleLineHtml(newLine.type,newLine.newNumber,newContent,newPrefix)):console.error(\"How did it get here?\")}return fileHtml},SideBySidePrinter.prototype.generateSingleLineHtml=function(type,number,content,prefix){return hoganUtils.render(genericTemplatesPath,\"line\",{type:type,lineClass:\"d2h-code-side-linenumber\",contentClass:\"d2h-code-side-line\",prefix:prefix&&utils.convertWhiteSpaceToNonBreakingSpace(prefix),content:content&&utils.convertWhiteSpaceToNonBreakingSpace(content),lineNumber:number})},SideBySidePrinter.prototype.generateEmptyDiff=function(){var fileHtml={};return fileHtml.right=\"\",fileHtml.left=hoganUtils.render(genericTemplatesPath,\"empty-diff\",{contentClass:\"d2h-code-side-line\",diffParser:diffParser}),fileHtml},module.exports.SideBySidePrinter=SideBySidePrinter}()},{\".\/diff-parser.js\":22,\".\/hoganjs-utils.js\":25,\".\/printer-utils.js\":28,\".\/rematch.js\":29,\".\/utils.js\":32}],31:[function(require,module){(function(global){!function(){global.browserTemplates||(global.browserTemplates={});var Hogan=require(\"hogan.js\");global.browserTemplates[\"file-summary-line\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<li class=\"d2h-file-list-line\">\'),t.b(\"\\n\"+i),t.b(\'    <span class=\"d2h-file-name-wrapper\">\'),t.b(\"\\n\"+i),t.b(\"      <span>\"),t.b(t.rp(\"<fileIcon0\",c,p,\"\")),t.b(\"<\/span>\"),t.b(\"\\n\"+i),t.b(\'      <a href=\"#\'),t.b(t.v(t.f(\"fileHtmlId\",c,p,0))),t.b(\'\" class=\"d2h-file-name\">\'),t.b(t.v(t.f(\"fileName\",c,p,0))),t.b(\"<\/a>\"),t.b(\"\\n\"+i),t.b(\'      <span class=\"d2h-file-stats\">\'),t.b(\"\\n\"+i),t.b(\'          <span class=\"d2h-lines-added\">\'),t.b(t.v(t.f(\"addedLines\",c,p,0))),t.b(\"<\/span>\"),t.b(\"\\n\"+i),t.b(\'          <span class=\"d2h-lines-deleted\">\'),t.b(t.v(t.f(\"deletedLines\",c,p,0))),t.b(\"<\/span>\"),t.b(\"\\n\"+i),t.b(\"      <\/span>\"),t.b(\"\\n\"+i),t.b(\"    <\/span>\"),t.b(\"\\n\"+i),t.b(\"<\/li>\"),t.fl()},partials:{\"<fileIcon0\":{name:\"fileIcon\",partials:{},subs:{}}},subs:{}}),global.browserTemplates[\"file-summary-wrapper\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<div class=\"d2h-file-list-wrapper\">\'),t.b(\"\\n\"+i),t.b(\'    <div class=\"d2h-file-list-header\">\'),t.b(\"\\n\"+i),t.b(\'        <span class=\"d2h-file-list-title\">Files changed (\'),t.b(t.v(t.f(\"filesNumber\",c,p,0))),t.b(\")<\/span>\"),t.b(\"\\n\"+i),t.b(\'        <a class=\"d2h-file-switch d2h-hide\">hide<\/a>\'),t.b(\"\\n\"+i),t.b(\'        <a class=\"d2h-file-switch d2h-show\">show<\/a>\'),t.b(\"\\n\"+i),t.b(\"    <\/div>\"),t.b(\"\\n\"+i),t.b(\'    <ol class=\"d2h-file-list\">\'),t.b(\"\\n\"+i),t.b(\"    \"),t.b(t.t(t.f(\"files\",c,p,0))),t.b(\"\\n\"+i),t.b(\"    <\/ol>\"),t.b(\"\\n\"+i),t.b(\"<\/div>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"generic-column-line-number\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\"<tr>\"),t.b(\"\\n\"+i),t.b(\'    <td class=\"\'),t.b(t.v(t.f(\"lineClass\",c,p,0))),t.b(\" \"),t.b(t.v(t.d(\"diffParser.LINE_TYPE.INFO\",c,p,0))),t.b(\'\"><\/td>\'),t.b(\"\\n\"+i),t.b(\'    <td class=\"\'),t.b(t.v(t.d(\"diffParser.LINE_TYPE.INFO\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\'        <div class=\"\'),t.b(t.v(t.f(\"contentClass\",c,p,0))),t.b(\" \"),t.b(t.v(t.d(\"diffParser.LINE_TYPE.INFO\",c,p,0))),t.b(\'\">\'),t.b(t.t(t.f(\"blockHeader\",c,p,0))),t.b(\"<\/div>\"),t.b(\"\\n\"+i),t.b(\"    <\/td>\"),t.b(\"\\n\"+i),t.b(\"<\/tr>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"generic-empty-diff\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\"<tr>\"),t.b(\"\\n\"+i),t.b(\'    <td class=\"\'),t.b(t.v(t.d(\"diffParser.LINE_TYPE.INFO\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\'        <div class=\"\'),t.b(t.v(t.f(\"contentClass\",c,p,0))),t.b(\" \"),t.b(t.v(t.d(\"diffParser.LINE_TYPE.INFO\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\"            File without changes\"),t.b(\"\\n\"+i),t.b(\"        <\/div>\"),t.b(\"\\n\"+i),t.b(\"    <\/td>\"),t.b(\"\\n\"+i),t.b(\"<\/tr>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"generic-file-path\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<span class=\"d2h-file-name-wrapper\">\'),t.b(\"\\n\"+i),t.b(\'    <span class=\"d2h-icon-wrapper\">\'),t.b(t.rp(\"<fileIcon0\",c,p,\"\")),t.b(\"<\/span>\"),t.b(\"\\n\"+i),t.b(\'    <span class=\"d2h-file-name\">\'),t.b(t.v(t.f(\"fileDiffName\",c,p,0))),t.b(\"<\/span>\"),t.b(\"\\n\"+i),t.b(t.rp(\"<fileTag1\",c,p,\"    \")),t.b(\"<\/span>\"),t.fl()},partials:{\"<fileIcon0\":{name:\"fileIcon\",partials:{},subs:{}},\"<fileTag1\":{name:\"fileTag\",partials:{},subs:{}}},subs:{}}),global.browserTemplates[\"generic-line\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\"<tr>\"),t.b(\"\\n\"+i),t.b(\'    <td class=\"\'),t.b(t.v(t.f(\"lineClass\",c,p,0))),t.b(\" \"),t.b(t.v(t.f(\"type\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\"      \"),t.b(t.t(t.f(\"lineNumber\",c,p,0))),t.b(\"\\n\"+i),t.b(\"    <\/td>\"),t.b(\"\\n\"+i),t.b(\'    <td class=\"\'),t.b(t.v(t.f(\"type\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\'        <div class=\"\'),t.b(t.v(t.f(\"contentClass\",c,p,0))),t.b(\" \"),t.b(t.v(t.f(\"type\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.s(t.f(\"prefix\",c,p,1),c,p,0,171,247,\"{{ }}\")&&(t.rs(c,p,function(c,p,t){t.b(\'            <span class=\"d2h-code-line-prefix\">\'),t.b(t.t(t.f(\"prefix\",c,p,0))),t.b(\"<\/span>\"),t.b(\"\\n\"+i)}),c.pop()),t.s(t.f(\"content\",c,p,1),c,p,0,279,353,\"{{ }}\")&&(t.rs(c,p,function(c,p,t){t.b(\'            <span class=\"d2h-code-line-ctn\">\'),t.b(t.t(t.f(\"content\",c,p,0))),t.b(\"<\/span>\"),t.b(\"\\n\"+i)}),c.pop()),t.b(\"        <\/div>\"),t.b(\"\\n\"+i),t.b(\"    <\/td>\"),t.b(\"\\n\"+i),t.b(\"<\/tr>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"generic-wrapper\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<div class=\"d2h-wrapper\">\'),t.b(\"\\n\"+i),t.b(\"    \"),t.b(t.t(t.f(\"content\",c,p,0))),t.b(\"\\n\"+i),t.b(\"<\/div>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"icon-file-added\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<svg aria-hidden=\"true\" class=\"d2h-icon d2h-added\" height=\"16\" title=\"added\" version=\"1.1\" viewBox=\"0 0 14 16\"\'),t.b(\"\\n\"+i),t.b(\'     width=\"14\">\'),t.b(\"\\n\"+i),t.b(\'    <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM6 9H3V7h3V4h2v3h3v2H8v3H6V9z\"><\/path>\'),t.b(\"\\n\"+i),t.b(\"<\/svg>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"icon-file-changed\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<svg aria-hidden=\"true\" class=\"d2h-icon d2h-changed\" height=\"16\" title=\"modified\" version=\"1.1\"\'),t.b(\"\\n\"+i),t.b(\'     viewBox=\"0 0 14 16\" width=\"14\">\'),t.b(\"\\n\"+i),t.b(\'    <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z\"><\/path>\'),t.b(\"\\n\"+i),t.b(\"<\/svg>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"icon-file-deleted\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<svg aria-hidden=\"true\" class=\"d2h-icon d2h-deleted\" height=\"16\" title=\"removed\" version=\"1.1\"\'),t.b(\"\\n\"+i),t.b(\'     viewBox=\"0 0 14 16\" width=\"14\">\'),t.b(\"\\n\"+i),t.b(\'    <path d=\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM11 9H3V7h8v2z\"><\/path>\'),t.b(\"\\n\"+i),t.b(\"<\/svg>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"icon-file-renamed\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<svg aria-hidden=\"true\" class=\"d2h-icon d2h-moved\" height=\"16\" title=\"renamed\" version=\"1.1\"\'),t.b(\"\\n\"+i),t.b(\'     viewBox=\"0 0 14 16\" width=\"14\">\'),t.b(\"\\n\"+i),t.b(\'    <path d=\"M6 9H3V7h3V4l5 4-5 4V9z m8-7v12c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h12c0.55 0 1 0.45 1 1z m-1 0H1v12h12V2z\"><\/path>\'),t.b(\"\\n\"+i),t.b(\"<\/svg>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"icon-file\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<svg aria-hidden=\"true\" class=\"d2h-icon\" height=\"16\" version=\"1.1\" viewBox=\"0 0 12 16\" width=\"12\">\'),t.b(\"\\n\"+i),t.b(\'    <path d=\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\"><\/path>\'),t.b(\"\\n\"+i),t.b(\"<\/svg>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"line-by-line-file-diff\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<div id=\"\'),t.b(t.v(t.f(\"fileHtmlId\",c,p,0))),t.b(\'\" class=\"d2h-file-wrapper\" data-lang=\"\'),t.b(t.v(t.d(\"file.language\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\'    <div class=\"d2h-file-header\">\'),t.b(\"\\n\"+i),t.b(\"    \"),t.b(t.t(t.f(\"filePath\",c,p,0))),t.b(\"\\n\"+i),t.b(\"    <\/div>\"),t.b(\"\\n\"+i),t.b(\'    <div class=\"d2h-file-diff\">\'),t.b(\"\\n\"+i),t.b(\'        <div class=\"d2h-code-wrapper\">\'),t.b(\"\\n\"+i),t.b(\'            <table class=\"d2h-diff-table\">\'),t.b(\"\\n\"+i),t.b(\'                <tbody class=\"d2h-diff-tbody\">\'),t.b(\"\\n\"+i),t.b(\"                \"),t.b(t.t(t.f(\"diffs\",c,p,0))),t.b(\"\\n\"+i),t.b(\"                <\/tbody>\"),t.b(\"\\n\"+i),t.b(\"            <\/table>\"),t.b(\"\\n\"+i),t.b(\"        <\/div>\"),t.b(\"\\n\"+i),t.b(\"    <\/div>\"),t.b(\"\\n\"+i),t.b(\"<\/div>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"line-by-line-numbers\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<div class=\"line-num1\">\'),t.b(t.v(t.f(\"oldNumber\",c,p,0))),t.b(\"<\/div>\"),t.b(\"\\n\"+i),t.b(\'<div class=\"line-num2\">\'),t.b(t.v(t.f(\"newNumber\",c,p,0))),t.b(\"<\/div>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"side-by-side-file-diff\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<div id=\"\'),t.b(t.v(t.f(\"fileHtmlId\",c,p,0))),t.b(\'\" class=\"d2h-file-wrapper\" data-lang=\"\'),t.b(t.v(t.d(\"file.language\",c,p,0))),t.b(\'\">\'),t.b(\"\\n\"+i),t.b(\'    <div class=\"d2h-file-header\">\'),t.b(\"\\n\"+i),t.b(\"      \"),t.b(t.t(t.f(\"filePath\",c,p,0))),t.b(\"\\n\"+i),t.b(\"    <\/div>\"),t.b(\"\\n\"+i),t.b(\'    <div class=\"d2h-files-diff\">\'),t.b(\"\\n\"+i),t.b(\'        <div class=\"d2h-file-side-diff\">\'),t.b(\"\\n\"+i),t.b(\'            <div class=\"d2h-code-wrapper\">\'),t.b(\"\\n\"+i),t.b(\'                <table class=\"d2h-diff-table\">\'),t.b(\"\\n\"+i),t.b(\'                    <tbody class=\"d2h-diff-tbody\">\'),t.b(\"\\n\"+i),t.b(\"                    \"),t.b(t.t(t.d(\"diffs.left\",c,p,0))),t.b(\"\\n\"+i),t.b(\"                    <\/tbody>\"),t.b(\"\\n\"+i),t.b(\"                <\/table>\"),t.b(\"\\n\"+i),t.b(\"            <\/div>\"),t.b(\"\\n\"+i),t.b(\"        <\/div>\"),t.b(\"\\n\"+i),t.b(\'        <div class=\"d2h-file-side-diff\">\'),t.b(\"\\n\"+i),t.b(\'            <div class=\"d2h-code-wrapper\">\'),t.b(\"\\n\"+i),t.b(\'                <table class=\"d2h-diff-table\">\'),t.b(\"\\n\"+i),t.b(\'                    <tbody class=\"d2h-diff-tbody\">\'),t.b(\"\\n\"+i),t.b(\"                    \"),t.b(t.t(t.d(\"diffs.right\",c,p,0))),t.b(\"\\n\"+i),t.b(\"                    <\/tbody>\"),t.b(\"\\n\"+i),t.b(\"                <\/table>\"),t.b(\"\\n\"+i),t.b(\"            <\/div>\"),t.b(\"\\n\"+i),t.b(\"        <\/div>\"),t.b(\"\\n\"+i),t.b(\"    <\/div>\"),t.b(\"\\n\"+i),t.b(\"<\/div>\"),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"tag-file-added\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<span class=\"d2h-tag d2h-added d2h-added-tag\">ADDED<\/span>\'),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"tag-file-changed\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<span class=\"d2h-tag d2h-changed d2h-changed-tag\">CHANGED<\/span>\'),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"tag-file-deleted\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<span class=\"d2h-tag d2h-deleted d2h-deleted-tag\">DELETED<\/span>\'),t.fl()},partials:{},subs:{}}),global.browserTemplates[\"tag-file-renamed\"]=new Hogan.Template({code:function(c,p,i){var t=this;return t.b(i=i||\"\"),t.b(\'<span class=\"d2h-tag d2h-moved d2h-moved-tag\">RENAMED<\/span>\'),t.fl()},partials:{},subs:{}}),module.exports=global.browserTemplates}()}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"hogan.js\":20}],32:[function(require,module){!function(){function Utils(){}Utils.prototype.convertWhiteSpaceToNonBreakingSpace=function(str){return str.slice(0).replace(\/ \/g,\"&nbsp;\")},Utils.prototype.escape=function(str){return str.slice(0).replace(\/&\/g,\"&amp;\").replace(\/<\/g,\"&lt;\").replace(\/>\/g,\"&gt;\").replace(\/\\t\/g,\"    \")},Utils.prototype.startsWith=function(str,start){if(\"object\"==typeof start){var result=!1;return start.forEach(function(s){0===str.indexOf(s)&&(result=!0)}),result}return 0===str.indexOf(start)},Utils.prototype.valueOrEmpty=function(value){return value?value:\"\"},module.exports.Utils=new Utils}()},{}]},{},[23]);\n\\ No newline at end of file\n+},Hogan.wrapMain=function(code){return\'var t=this;t.b(i=i||\"\");\'+code+\"return t.fl();\"},Hogan.template=Hogan.Template,Hogan.makeTemplate=function(codeObj,text,options){var template=this.makePartials(codeObj);return template.code=new Function(\"c\",\"p\",\"i\",this.wrapMain(codeObj.code)),new this.template(template,text,this,options)},Hogan.makePartials=function(codeObj){var key,template={subs:{},partials:codeObj.partials,name:codeObj.name};for(key in template.partials)template.partials[key]=this.makePartials(template.partials[key]);for(key in codeObj.subs)template.subs[key]=new Function(\"c\",\"p\",\"t\",\"i\",codeObj.subs[key]);return template},Hogan.codegen={\"#\":function(node,context){context.code+=\"if(t.s(t.\"+chooseMethod(node.n)+\'(\"\'+esc(node.n)+\'\",c,p,1),c,p,0,\'+node.i+\",\"+node.end+\',\"\'+node.otag+\" \"+node.ctag+\'\")){t.rs(c,p,function(c,p,t){\',Hogan.walk(node.nodes,context),context.code+=\"});c.pop();}\"},\"^\":function(node,context){context.code+=\"if(!t.s(t.\"+chooseMethod(node.n)+\'(\"\'+esc(node.n)+\'\",c,p,1),c,p,1,0,0,\"\")){\',Hogan.walk(node.nodes,context),context.code+=\"};\"},\">\":createPartial,\"<\":function(node,context){var ctx={partials:{},code:\"\",subs:{},inPartial:!0};Hogan.walk(node.nodes,ctx);var template=context.partials[createPartial(node,context)];template.subs=ctx.subs,template.partials=ctx.partials},$:function(node,context){var ctx={subs:{},code:\"\",partials:context.partials,prefix:node.n};Hogan.walk(node.nodes,ctx),";

    $(document).ready(function() {
      var diff2htmlUi = new Diff2HtmlUI({diff: lineDiffExample});

      diff2htmlUi.draw('#line-by-line', {inputFormat: 'json', showFiles: true, matching: 'lines'});
      diff2htmlUi.fileListCloseable('#line-by-line', false);
      diff2htmlUi.highlightCode('#line-by-line');

      diff2htmlUi.draw('#side-by-side', {
        inputFormat: 'json',
        showFiles: true,
        matching: 'lines',
        outputFormat: 'side-by-side',
        synchronisedScroll: true
      });
      diff2htmlUi.fileListCloseable('#side-by-side', false);
      diff2htmlUi.highlightCode('#side-by-side');
    });
  </script>

Do you have any idea?

Here is firefox asking to interrupt the slow page:

html2diff-issue

and here is the rendered diff after 60 secs on firefox:

html2diff-issue2

Space in file name

If a file in the diff has a space in its name, space and the rest is truncated in the HTML.

Allow line breaks in side-by-side view

Allow line breaks in side-by-side view to see the code without the need to scroll horizontally.

Check https://github.com/mohanapreeya/diff2html for an example.


Thank for a quick response on #97 and we do have word wrap working in default view but not in side by side view. Wordwrap view has always been challenging in side by side view but I figure I would use this time to describe the problem.

Side by side view with wordwrap is challenging because when word is wrapped in one table, that height needs to be applied to another table. For example, in below right table's words are wrapped and caused increase in row height but it cannot be easily be applied to left table as they are separate table.

screen shot 2016-09-11 at 15 06 32

Will it be easy to place them in a same table so we can easily do this without JS? I feel like this will not be a trivial change and I think this maybe not be a critical issue.

word-to-word highlight for multiple lines change

Hi, thanks for this nice library. I found something that is different from the GitHub style.
It's about word-to-word highlight (BTW, the README says char-to-char, which actually is word-to-word, isn't it)

If you have multiple lines changed, this doesn't work.
The example input is the following:

diff --git a/foo.js b/foo.js

---
+++
@@ -1,4 +1,5 @@
+zero
 one
-two word
-three word
+to word
+tree word
 four

It would be so nice if this is supported.

Rolling load

Hi, as I was working on FredrikNoren/ungit#514 I came across couple of features that could be added in.

One of the problem we saw is that sometimes git diff for a single file is rather large and in such cases loading diff for those files is rather resource consumption heavy. What we did to solve this issue was implementing rolling load that will limit the display of diff to certain # of lines and provide a button to load more if users is required.

I agree that this is a rare edge case but hopefully I can send you a pull request soon for you to review.

TypeScript Definitions?

Would it be possible to write a .d.ts file to describe this module, so it can be used with TypeScript?

git diff parsing error when text starts with "-"

Example data

diff --git a/coverage.init b/coverage.init
index fc56817..e8e7e49 100644
--- a/coverage.init
+++ b/coverage.init
@@ -19,7 +19,7 @@
 -opt "\-nostart"

 # skip stopenv
--do "runbvt,stopenv,getlogs,pullcoveragedata"
+-do "runbvt,getlogs,pullcoveragedata"

 ##########################################
 # logs files to bring back to base

diff2html false positive deleted file parsing error

Below code shows --> line as a deleted line although it is not deleted.

I think regex should be fixed to ^-

m = "diff --git a/a.xml b/b.xml"
+ "\nindex e54317e..82a9a56 100644"
+ "\n--- a/a.xml"
+ "\n+++ b/b.xml"
+ "\n@@ -242,4 +242,6 @@ need to create a new job for native server java api and move these tests to a ne"
+ "\n                </packages>"
+ "\n        </test>"
+ "\n -->"
+ "\n+"
+ "\n+";

var diff2html = require('diff2html').Diff2Html;

console.log(diff2html.getJsonFromDiff(m));

Parse valid unidiffs

This is a valid unidiff

--- a/sample
+++ b/sample
@@ -11 @@
-test
+test1r

but diff2html only returns

<div class="d2h-wrapper">

</div>

When I add diff to the beginning of the unidiff, however, it works:

diff--- a/sample
+++ b/sample
@@ -11 @@
-test
+test1r

Add opacity to the context lines

We should be able to have an option to configure opacity for the context lines of the diff, so we can focus more on the changes.

Problem parsing diff within diff

parsing below git diff will result in var text = .... line being missing. I think dff2html parses correctly when I bring down the character count on that line to below 100.

diff --git a/test.js b/test.js
new file mode 100644
index 0000000..e1e22ec
--- /dev/null
+++ b/test.js
@@ -0,0 +1,6 @@
+var parser = require('./source/git-parser');
+
+var text = 'diff --git a/components/app/app.html b/components/app/app.html\nindex ecb7a95..027bd9b 100644\n--- a/components/app/app.html\n+++ b/components/app/app.html\n@@ -52,0 +53,3 @@\n+\n+\n+\n@@ -56,0 +60,3 @@\n+\n+\n+\n'
+var patchLineList = [ false, false, false, false ];
+
+console.log(parser.parsePatchDiffResult(text, patchLineList));

how to properly set files changed as expanded by default

for instances where i'm more interested in the summary of files changed, i would like to have this expanded by default.

i thought i'd be able to do it by setting the url, given that gets changed, but it gets changed to something like 'diff.html#d2h-show-hfr' and 'diff.html#d2h-hide-pvi'

i'm confused as to what the '-hfr' and '-pvi' do, they are not static between generations, they seem random, so it isn't something i could add to my url that i give out

is it possible to easily get functionality like what i want?

Allow files to be collapsable

Allow files to be collapsible.

Ideally this could be just CSS to avoid Javascript usage.
We could then allow an option to choose if the files start open or collapsed.


If enabled then the diffs will start as collapsed when there is more than one file.
You would then be able to click the header to toggle the collapse state of the different files.

Overlapping text in 2.0.6

Hello,

The changes in 2.0.6 seem to cause a me to get some overlapping text in firefox and chrome on windows. It mostly it seems to affect comments, as if they're not given their own row or something. I've tried to attach a screenshot of the issue here:

overlap

A downgrade to 2.0.5 fixes the overlap.

I'm not sure how to provide much better detail about the issue so please let me know if there's more specifics I can provide.

If I have some time tomorrow I will try to dig into the css to figure out which part specifically causes the issue. At the very least, I'll try to get it to happen with a diff I'm more comfortable sharing and upload an actual test case, for now this is the file I'm using, but with a real diff in the string:

<html><head><meta charset='UTF-8'><title>diff h947920</title><body>
    <form method="GET" >
    <input type="hidden" value="113262" name="ID"/>
    <input type="hidden" value="1" name="CLEAR"/>
    <label for="NOCOMBINE">Expand revs</label>
    <input type="checkbox"  id="NOCOMBINE" name="NOCOMBINE" alt="Combines diffs of multiple revisions into a single diff, but not quite as fancy as revdiff"/>
    <select name="MODE"><option value="side-by-side" selected>side-by-side</option><option value="line-by-line" >line-by-line</option></select>
    <span class="ui-spinner ui-corner-all ui-widget ui-widget-content"><input type="text" class="ui-spinner-input" name="SEARCH" placeholder="h# || changelist ids" value="h947920" size="50" /></span>
    <input type="text" name="CONTEXT" id="CONTEXT" placeholder="ctxt" value="" size="3" />
    <input type="submit" value="Diff!"/>
    </form>
    <link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.0/themes/base/jquery-ui.min.css" />
    <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <script>
    $(":checkbox").checkboxradio().tooltip();
    $("select").selectmenu();
    $(":submit").button();
    $("#CONTEXT").spinner({
        min: 0,
    });
    </script>
Changelists: 2472171 2472172 2472216<br />
        <div id='diff-div'></div>
        <link rel="stylesheet" type='text/css' href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/styles/github.min.css">
        <link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.0.6/diff2html.min.css' />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/highlight.min.js"></script>
        <script src='https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.0.6/diff2html.js' type='text/javascript'></script>
        <script src='https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.0.6/diff2html-ui.js' type='text/javascript'></script>
        <script type='text/javascript'>
            var diff2htmlUI = new Diff2HtmlUI({ diff: "my diff here" });
            diff2htmlUI.draw('#diff-div', {
                inputFormat: 'json',
                showFiles: true,
                matching: 'lines',
                outputFormat: 'side-by-side',
                synchronisedScroll: true
            });
            diff2htmlUI.highlightCode('#diff-div');
            diff2htmlUI.fileListCloseable('#diff-div', true);
        </script>
    </body></html>

.d2h-code-side-line del/ins "display: inline-block" hiding lines

I'm not sure what the best fix would be, but deleting "display: inline-block" from .d2h-code-side-line (etc?) del/ins lets long del/ins blocks sit on the same line as the text they should be on the same line with.

Without doing this (not sure if it matters, but it was with a 1 line only diff), the non del/ins block text was on its own line, and the del/ins block was on a new line down, but the containing divs did not grow to match this, staying the same 1 line size, making the del/ins block completely invisible to the viewer.

Absolutely awesome tool though!

Line breaks instead of horizontal scrolling

Hi,

Is it possible to deactivate horizontal scrolling, and instead have line breaks in the diff view, the same way it is done on GitHub?

Here is an example:

Line breaks instead of horizontal scrolling

That would be sweet!

Thanks,
Lionel

Separate diff2json parser into a separate project?

I've been thinking that some people might find super useful to parse diff output into a json. We already have this in our project, so maybe it will be great to separate it into it's own diff2json project, and use that as an external dependency in diff2html.

This will simplify diff2html project itself and will decouple the parser, so can be reusable.

It shouldn't be too hard to do this.

Is there a way to modify the templates / HTML?

We are using your awesome project to display a diff before importing files into a webapp. What we're hoping to achieve is having a checkbox next to each filename title to select whether to include that file in the import.

The first thought I had was to add checkboxes with JS after but it would be useful to have more details on the file and build the HTML at once. I noticed there are templates built with Hogan JS but I don't see how they could be changed/overridden without forking this project and building our own version.

Any thoughts would be great, thanks.

Compare two strings of html

Looking at the API it seems there's only one input option, what format should this input be to compare two strings?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.