Diff: Added support for syntax highlighting inside diff blocks (#1889)

This adds support for syntax highlighting inside diff blocks via a new plugin called: Diff Highlight.
This commit is contained in:
Michael Schmidt 2019-07-22 01:27:48 +02:00 committed by GitHub
parent c8844286a8
commit e7702ae110
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 263 additions and 27 deletions

File diff suppressed because one or more lines are too long

View File

@ -1078,6 +1078,11 @@
"owner": "mAAdhaTTah",
"require": "toolbar",
"noCSS": true
},
"diff-highlight": {
"title": "Diff Highlight",
"owner": "RunDevelopment",
"require": "diff"
}
}
}

View File

@ -1,20 +1,54 @@
Prism.languages.diff = {
'coord': [
// Match all kinds of coord lines (prefixed by "+++", "---" or "***").
/^(?:\*{3}|-{3}|\+{3}).*$/m,
// Match "@@ ... @@" coord lines in unified diff.
/^@@.*@@$/m,
// Match coord lines in normal diff (starts with a number).
/^\d+.*$/m
],
(function (Prism) {
// Match inserted and deleted lines. Support both +/- and >/< styles.
'deleted': /^[-<].*$/m,
'inserted': /^[+>].*$/m,
Prism.languages.diff = {
'coord': [
// Match all kinds of coord lines (prefixed by "+++", "---" or "***").
/^(?:\*{3}|-{3}|\+{3}).*$/m,
// Match "@@ ... @@" coord lines in unified diff.
/^@@.*@@$/m,
// Match coord lines in normal diff (starts with a number).
/^\d+.*$/m
]
// Match "different" lines (prefixed with "!") in context diff.
'diff': {
'pattern': /^!(?!!).+$/m,
'alias': 'important'
}
};
// deleted, inserted, unchanged, diff
};
/**
* A map from the name of a block to its line prefix.
*
* @type {Object<string, string>}
*/
var PREFIXES = {
'deleted-sign': '-',
'deleted-arrow': '<',
'inserted-sign': '+',
'inserted-arrow': '>',
'unchanged': ' ',
'diff': '!',
};
// add a token for each prefix
Object.keys(PREFIXES).forEach(function (name) {
var prefix = PREFIXES[name];
var alias = [];
if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"
alias.push(/\w+/.exec(name)[0]);
}
if (name === "diff") {
alias.push("bold");
}
Prism.languages.diff[name] = {
// pattern: /^(?:[_].*(?:\r\n?|\n|(?![\s\S])))+/m
pattern: RegExp('^(?:[' + prefix + '].*(?:\r\n?|\n|(?![\\s\\S])))+', 'm'),
alias: alias
};
});
// make prefixes available to Diff plugin
Object.defineProperty(Prism.languages.diff, 'PREFIXES', {
value: PREFIXES
});
}(Prism));

View File

@ -1 +1 @@
Prism.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d+.*$/m],deleted:/^[-<].*$/m,inserted:/^[+>].*$/m,diff:{pattern:/^!(?!!).+$/m,alias:"important"}};
!function(d){d.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d+.*$/m]};var r={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(r).forEach(function(e){var n=r[e],a=[];/^\w+$/.test(e)||a.push(/\w+/.exec(e)[0]),"diff"===e&&a.push("bold"),d.languages.diff[e]={pattern:RegExp("^(?:["+n+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a}}),Object.defineProperty(d.languages.diff,"PREFIXES",{value:r})}(Prism);

View File

@ -30,4 +30,4 @@
headers: "src/*.h"
- qt: core
+ qt: core gui
public_headers: "src/*.h"</code></pre>
public_headers: "src/*.h"</code></pre>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.png" />
<title>Data-URI Highlight ▲ Prism plugins</title>
<base href="../.." />
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
<link rel="stylesheet" href="plugins/diff-highlight/prism-diff-highlight.css" data-noprefix />
<script src="scripts/prefixfree.min.js"></script>
<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
<script src="https://www.google-analytics.com/ga.js" async></script>
</head>
<body class="language-none">
<header>
<div class="intro" data-src="templates/header-plugins.html" data-type="text/html"></div>
<h2>Diff Highlight</h2>
<p>Highlights the code inside diff blocks.</p>
</header>
<section>
<h1>How to use</h1>
<p>Replace the <code>language-diff</code> of your code block with a <code>language-diff-xxxx</code> class to enable syntax highlighting for diff blocks.</p>
<p>Optional:<br>
You can add the <code>diff-highlight</code> class to your code block to indicate changes using the background color of a line rather than the color of the text.</p>
</section>
<section>
<h1>Example</h1>
<p>Using <code>class="language-diff"</code>:</p>
<pre><code class="language-diff">@@ -4,6 +4,5 @@
- let foo = bar.baz([1, 2, 3]);
- foo = foo + 1;
+ const foo = bar.baz([1, 2, 3]) + 1;
console.log(`foo: ${foo}`);</code></pre>
<p>Using <code>class="language-diff diff-highlight"</code>:</p>
<pre><code class="language-diff diff-highlight">@@ -4,6 +4,5 @@
- let foo = bar.baz([1, 2, 3]);
- foo = foo + 1;
+ const foo = bar.baz([1, 2, 3]) + 1;
console.log(`foo: ${foo}`);</code></pre>
<p>Using <code>class="language-diff-javascript"</code>:</p>
<pre><code class="language-diff-javascript">@@ -4,6 +4,5 @@
- let foo = bar.baz([1, 2, 3]);
- foo = foo + 1;
+ const foo = bar.baz([1, 2, 3]) + 1;
console.log(`foo: ${foo}`);</code></pre>
<p>Using <code>class="language-diff-javascript diff-highlight"</code>:</p>
<pre><code class="language-diff-javascript diff-highlight">@@ -4,6 +4,5 @@
- let foo = bar.baz([1, 2, 3]);
- foo = foo + 1;
+ const foo = bar.baz([1, 2, 3]) + 1;
console.log(`foo: ${foo}`);</code></pre>
</section>
<footer data-src="templates/footer.html" data-type="text/html"></footer>
<script src="prism.js"></script>
<script src="components/prism-diff.js"></script>
<script src="plugins/diff-highlight/prism-diff-highlight.js"></script>
<script src="scripts/utopia.js"></script>
<script src="components.js"></script>
<script src="scripts/code.js"></script>
</body>
</html>

View File

@ -0,0 +1,13 @@
pre.diff-highlight > code .token.deleted:not(.prefix),
pre > code.diff-highlight .token.deleted:not(.prefix) {
background-color: rgba(255, 0, 0, .1);
color: inherit;
display: block;
}
pre.diff-highlight > code .token.inserted:not(.prefix),
pre > code.diff-highlight .token.inserted:not(.prefix) {
background-color: rgba(0, 255, 128, .1);
color: inherit;
display: block;
}

View File

@ -0,0 +1,83 @@
(function () {
if (typeof Prism === 'undefined' || !Prism.languages['diff']) {
return;
}
var LANGUAGE_REGEX = /diff-([\w-]+)/i;
var HTML_TAG = /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/gi;
//this will match a line plus the line break while ignoring the line breaks HTML tags may contain.
var HTML_LINE = RegExp(/(?:__|[^\r\n<])*(?:\r\n?|\n|(?:__|[^\r\n<])(?![^\r\n]))/.source.replace(/__/g, HTML_TAG.source), 'gi');
var PREFIXES = Prism.languages.diff.PREFIXES;
Prism.hooks.add('before-sanity-check', function (env) {
var lang = env.language;
if (LANGUAGE_REGEX.test(lang) && !env.grammar) {
env.grammar = Prism.languages[lang] = Prism.languages['diff'];
}
});
Prism.hooks.add('before-tokenize', function (env) {
var lang = env.language;
if (LANGUAGE_REGEX.test(lang) && !Prism.languages[lang]) {
Prism.languages[lang] = Prism.languages['diff'];
}
});
Prism.hooks.add('wrap', function (env) {
var diffLanguage, diffGrammar;
if (env.language !== 'diff') {
var langMatch = LANGUAGE_REGEX.exec(env.language);
if (!langMatch) {
return; // not a language specific diff
}
diffLanguage = langMatch[1];
diffGrammar = Prism.languages[diffLanguage];
}
// one of the diff tokens without any nested tokens
if (env.type in PREFIXES) {
/** @type {string} */
var content = env.content.replace(HTML_TAG, ''); // remove all HTML tags
/** @type {string} */
var decoded = content.replace(/&lt;/g, '<').replace(/&amp;/g, '&');
// remove any one-character prefix
var code = decoded.replace(/(^|[\r\n])./g, '$1');
// highlight, if possible
var highlighted;
if (diffGrammar) {
highlighted = Prism.highlight(code, diffGrammar, diffLanguage);
} else {
highlighted = Prism.util.encode(code);
}
// get the HTML source of the prefix token
var prefixToken = new Prism.Token('prefix', PREFIXES[env.type], [/\w+/.exec(env.type)[0]]);
var prefix = Prism.Token.stringify(prefixToken, env.language);
// add prefix
var lines = [], m;
HTML_LINE.lastIndex = 0;
while (m = HTML_LINE.exec(highlighted)) {
lines.push(prefix + m[0]);
}
if (/(?:^|[\r\n]).$/.test(decoded)) {
// because both "+a\n+" and "+a\n" will map to "a\n" after the line prefixes are removed
lines.push(prefix);
}
env.content = lines.join('');
if (diffGrammar) {
env.classes.push('language-' + diffLanguage);
}
}
});
}());

View File

@ -0,0 +1 @@
!function(){if("undefined"!=typeof Prism&&Prism.languages.diff){var o=/diff-([\w-]+)/i,m=/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/gi,c=RegExp("(?:__|[^\r\\n<])*(?:\r\\n?|\n|(?:__|[^\r\\n<])(?![^\r\\n]))".replace(/__/g,m.source),"gi"),d=Prism.languages.diff.PREFIXES;Prism.hooks.add("before-sanity-check",function(e){var a=e.language;o.test(a)&&!e.grammar&&(e.grammar=Prism.languages[a]=Prism.languages.diff)}),Prism.hooks.add("before-tokenize",function(e){var a=e.language;o.test(a)&&!Prism.languages[a]&&(Prism.languages[a]=Prism.languages.diff)}),Prism.hooks.add("wrap",function(e){var a,s;if("diff"!==e.language){var r=o.exec(e.language);if(!r)return;a=r[1],s=Prism.languages[a]}if(e.type in d){var n,i=e.content.replace(m,"").replace(/&lt;/g,"<").replace(/&amp;/g,"&"),g=i.replace(/(^|[\r\n])./g,"$1");n=s?Prism.highlight(g,s,a):Prism.util.encode(g);var f,t=new Prism.Token("prefix",d[e.type],[/\w+/.exec(e.type)[0]]),u=Prism.Token.stringify(t,e.language),l=[];for(c.lastIndex=0;f=c.exec(n);)l.push(u+f[0]);/(?:^|[\r\n]).$/.test(i)&&l.push(u),e.content=l.join(""),s&&e.classes.push("language-"+a)}})}}();

View File

@ -1,5 +1,7 @@
! qt: core
unchanged
- qt: core
+ qt: core gui
@ -9,13 +11,14 @@
----------------------------------------------------
[
["diff", "! qt: core"],
["deleted", "- qt: core"],
["inserted", "+ qt: core gui"],
["deleted", "< qt: core"],
["inserted", "> qt: core quick"]
["diff", "! qt: core\r\n"],
["unchanged", " unchanged\r\n"],
["deleted-sign", "- qt: core\r\n"],
["inserted-sign", "+ qt: core gui\r\n"],
["deleted-arrow", "< qt: core\r\n"],
["inserted-arrow", "> qt: core quick"]
]
----------------------------------------------------
Checks for deleted, inserted and different lines.
Checks for deleted, inserted and different lines.

View File

@ -115,3 +115,16 @@ code[class*="language-"] {
.token.deleted {
color: red;
}
/* Plugin styles: Diff Highlight */
pre.diff-highlight.diff-highlight > code .token.deleted:not(.prefix),
pre > code.diff-highlight.diff-highlight .token.deleted:not(.prefix) {
background-color: rgba(255, 0, 0, .3);
display: inline;
}
pre.diff-highlight.diff-highlight > code .token.inserted:not(.prefix),
pre > code.diff-highlight.diff-highlight .token.inserted:not(.prefix) {
background-color: rgba(0, 255, 128, .3);
display: inline;
}