From e86ec01f8924a2bd77fe8c82f28441f81c7eae21 Mon Sep 17 00:00:00 2001 From: Andreas Rohner Date: Thu, 7 Jan 2016 10:39:37 +0100 Subject: [PATCH 1/2] Add whitespace-normalizer plugin This plugin normalizes whitespace in code blocks. It can perform various operations. The user can configure them through the plugin object located at Prism.plugins.NormalizeWhitespace. Prism.plugins.NormalizeWhitespace.setDefaults({ 'remove-trailing': true, 'remove-indent': true, 'left-trim': true, 'right-trim': true, /*'indent': 2, 'remove-initial-line-feed': false, 'tabs-to-spaces': 4, 'spaces-to-tabs': 4*/ }); The plugin can be disabled for certain code blocks, by adding the class "no-whitespace-normalization" to it. There is also a HTML-interface using the parse-settings plugin. --- components.js | 5 + plugins/normalize-whitespace/demo.html | 29 ++++ plugins/normalize-whitespace/index.html | 101 ++++++++++++++ .../prism-normalize-whitespace.js | 129 ++++++++++++++++++ .../prism-normalize-whitespace.min.js | 1 + plugins/remove-initial-line-feed/index.html | 3 +- 6 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 plugins/normalize-whitespace/demo.html create mode 100644 plugins/normalize-whitespace/index.html create mode 100644 plugins/normalize-whitespace/prism-normalize-whitespace.js create mode 100644 plugins/normalize-whitespace/prism-normalize-whitespace.min.js diff --git a/components.js b/components.js index b407c14b41..6c86766bdc 100644 --- a/components.js +++ b/components.js @@ -607,6 +607,11 @@ var components = { "command-line": { "title": "Command Line", "owner": "chriswells0" + }, + "normalize-whitespace": { + "title": "Normalize Whitespace", + "owner": "zeitgeist87", + "noCSS": true } } }; diff --git a/plugins/normalize-whitespace/demo.html b/plugins/normalize-whitespace/demo.html new file mode 100644 index 0000000000..34e06f47c3 --- /dev/null +++ b/plugins/normalize-whitespace/demo.html @@ -0,0 +1,29 @@ + +
+ +
+
+	
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	
+
+
+ +
+ + + \ No newline at end of file diff --git a/plugins/normalize-whitespace/index.html b/plugins/normalize-whitespace/index.html new file mode 100644 index 0000000000..02a000f180 --- /dev/null +++ b/plugins/normalize-whitespace/index.html @@ -0,0 +1,101 @@ + + + + + + + Normalize Whitespace ▲ Prism plugins + + + + + + + + + + +
+
+ +

Normalize Whitespace

+

Supports multiple operations to normalize whitespace in code blocks.

+
+ +
+

How to use

+ +

Obviously, this is supposed to work only for code blocks (<pre><code>) and not for inline code.

+

By default the plugin trims all leading and trailing whitespace of every code block. + It also removes extra indents and trailing whitespace on every line.

+ +

The plugin uses the Parse Settings plugin to get its settings. + The default settings can be overridden with the setDefaults() method + like so:

+ +

+Prism.plugins.NormalizeWhitespace.setDefaults({
+	'remove-trailing': true,
+	'remove-indent': true,
+	'left-trim': true,
+	'right-trim': true,
+	/*'indent': 2,
+	'remove-initial-line-feed': false,
+	'tabs-to-spaces': 4,
+	'spaces-to-tabs': 4*/
+});
+
+ +

It is also possible to change the default settings with data-*-attributes.

+ +
<code data-left-trim="false">...</code>
+ +

The class no-whitespace-normalization or the corresponding + data-attribute can be used to disable the normalization for a particular + code block.

+ +
<code class="no-whitespace-normalization"
+	data-whitespace-normalization="false">
+...
+</code>
+
+ +
+

Examples

+ +

The following example shows some of the possible ways of configuring this plugin:

+ +

+
+	

The result looks like this:

+ +
+
+	
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	
+
+
+ +
+ + + + + + + + + + + + + diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.js b/plugins/normalize-whitespace/prism-normalize-whitespace.js new file mode 100644 index 0000000000..f868e11498 --- /dev/null +++ b/plugins/normalize-whitespace/prism-normalize-whitespace.js @@ -0,0 +1,129 @@ +(function() { + +if (typeof self === 'undefined' || !self.Prism || !self.document) { + return; +} + +var assign = Object.assign || function (obj1, obj2) { + for (var name in obj2) { + if (obj2.hasOwnProperty(name)) + obj1[name] = obj2[name]; + } + return obj1; +} + +function NormalizeWhitespace(defaults) { + this.defaults = assign({}, defaults); +} + +function toCamelCase(value) { + return value.replace(/-(\w)/g, function(match, firstChar) { + return firstChar.toUpperCase(); + }); +} + +NormalizeWhitespace.prototype = { + setDefaults: function (defaults) { + this.defaults = assign(this.defaults, defaults); + }, + normalize: function (input, settings) { + settings = assign(this.defaults, settings); + + for (var name in settings) { + var methodName = toCamelCase(name); + if (name !== "normalize" && methodName !== 'setDefaults' && + settings[name] && this[methodName]) { + input = this[methodName].call(this, input, settings[name]); + } + } + + return input; + }, + + /* + * Normalization methods + */ + leftTrim: function (input) { + return input.replace(/^\s+/, ''); + }, + rightTrim: function (input) { + return input.replace(/\s+$/, ''); + }, + tabsToSpaces: function (input, spaces) { + spaces = spaces|0 || 4; + return input.replace(/\t/g, new Array(++spaces).join(' ')); + }, + spacesToTabs: function (input, spaces) { + spaces = spaces|0 || 4; + return input.replace(new RegExp(' {' + spaces + '}', 'g'), '\t'); + }, + removeTrailing: function (input) { + return input.replace(/\s*?$/gm, ''); + }, + // Support for deprecated plugin remove-initial-line-feed + removeInitialLineFeed: function (input) { + return input.replace(/^(?:\r?\n|\r)/, ''); + }, + removeIndent: function (input) { + var indents = input.match(/^[^\S\n\r]*(?=\S)/gm); + + if (!indents || !indents[0].length) + return input; + + indents.sort(function(a, b){return a.length - b.length; }); + + if (!indents[0].length) + return input; + + return input.replace(new RegExp('^' + indents[0], 'gm'), ''); + }, + indent: function (input, tabs) { + return input.replace(/^[^\S\n\r]*(?=\S)/gm, new Array(++tabs).join('\t') + '$&'); + } +}; + +Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({ + 'remove-trailing': true, + 'remove-indent': true, + 'left-trim': true, + 'right-trim': true, + /*'indent': 2, + 'remove-initial-line-feed': false, + 'tabs-to-spaces': 4, + 'spaces-to-tabs': 4*/ +}); + +Prism.hooks.add('before-highlight', function (env) { + var pre = env.element.parentNode; + if (!env.code || !pre || pre.nodeName.toLowerCase() !== 'pre' || + (env.settings && env.settings['whitespace-normalization'] === false)) + return; + + var children = pre.childNodes, + before = '', + after = '', + codeFound = false; + + // Move surrounding whitespace from the
 tag into the  tag
+	for (var i = 0; i < children.length; ++i) {
+		var node = children[i];
+
+		if (node == env.element) {
+			codeFound = true;
+		} else if (node.nodeName === "#text") {
+			if (codeFound) {
+				after += node.nodeValue;
+			} else {
+				before += node.nodeValue;
+			}
+
+			pre.removeChild(node);
+			--i;
+		}
+	}
+	env.code = before + env.code + after;
+
+	env.code = Prism.plugins.NormalizeWhitespace.normalize(env.code, env.settings);
+});
+
+}());
\ No newline at end of file
diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.min.js b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js
new file mode 100644
index 0000000000..d0131cfa74
--- /dev/null
+++ b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js
@@ -0,0 +1 @@
+!function(){function e(e){this.defaults=t({},e)}function n(e){return e.replace(/-(\w)/g,function(e,n){return n.toUpperCase()})}if("undefined"!=typeof self&&self.Prism&&self.document){var t=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=t(this.defaults,e)},normalize:function(e,r){r=t(this.defaults,r);for(var i in r){var o=n(i);"normalize"!==i&&"setDefaults"!==o&&r[i]&&this[o]&&(e=this[o].call(this,e,r[i]))}return e},leftTrim:function(e){return e.replace(/^\s+/,"")},rightTrim:function(e){return e.replace(/\s+$/,"")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\t/g,new Array(++n).join(" "))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(new RegExp(" {"+n+"}","g"),"	")},removeTrailing:function(e){return e.replace(/\s*?$/gm,"")},removeInitialLineFeed:function(e){return e.replace(/^(?:\r?\n|\r)/,"")},removeIndent:function(e){var n=e.match(/^[^\S\n\r]*(?=\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(new RegExp("^"+n[0],"gm"),""):e):e},indent:function(e,n){return e.replace(/^[^\S\n\r]*(?=\S)/gm,new Array(++n).join("	")+"$&")}},Prism.plugins.NormalizeWhitespace=new e({"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.hooks.add("before-highlight",function(e){var n=e.element.parentNode;if(e.code&&n&&"pre"===n.nodeName.toLowerCase()&&(!e.settings||e.settings["whitespace-normalization"]!==!1)){for(var t=n.childNodes,r="",i="",o=!1,a=0;aRemove initial line feed
 
 
 
-

How to use

+

How to use (DEPRECATED)

+

This plugin will be removed in the future. Please use the general purpose Normalize Whitespace plugin instead.

Obviously, this is supposed to work only for code blocks (<pre><code>) and not for inline code.

With this plugin included, any initial line feed will be removed by default.

To bypass this behaviour, you may add the class keep-initial-line-feed to your desired <pre>.

From 38b7b3b6a143fb30247f4b917cb04fbc4e3d48d3 Mon Sep 17 00:00:00 2001 From: Andreas Rohner Date: Sat, 6 Feb 2016 15:49:01 +0100 Subject: [PATCH 2/2] Add support for automatic line breaks This patch adds support for automatic line breaks after a specific number of characters. The default is 80 characters, but it can be set to any number. --- .../prism-normalize-whitespace.js | 35 ++++++++++++++++++- .../prism-normalize-whitespace.min.js | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.js b/plugins/normalize-whitespace/prism-normalize-whitespace.js index f868e11498..f2df35f638 100644 --- a/plugins/normalize-whitespace/prism-normalize-whitespace.js +++ b/plugins/normalize-whitespace/prism-normalize-whitespace.js @@ -22,6 +22,15 @@ function toCamelCase(value) { }); } +function tabLen(str) { + var res = 0; + for (var i = 0; i < str.length; ++i) { + if (str.charCodeAt(i) == '\t'.charCodeAt(0)) + res += 3; + } + return str.length + res; +} + NormalizeWhitespace.prototype = { setDefaults: function (defaults) { this.defaults = assign(this.defaults, defaults); @@ -79,6 +88,29 @@ NormalizeWhitespace.prototype = { }, indent: function (input, tabs) { return input.replace(/^[^\S\n\r]*(?=\S)/gm, new Array(++tabs).join('\t') + '$&'); + }, + breakLines: function (input, characters) { + characters = (characters === true) ? 80 : characters|0 || 80; + + var lines = input.split('\n'); + for (var i = 0; i < lines.length; ++i) { + if (tabLen(lines[i]) <= characters) + continue; + + var line = lines[i].split(/(\s+)/g), + len = 0; + + for (var j = 0; j < line.length; ++j) { + var tl = tabLen(line[j]); + len += tl; + if (len > characters) { + line[j] = '\n' + line[j]; + len = tl; + } + } + lines[i] = line.join(''); + } + return lines.join('\n'); } }; @@ -87,7 +119,8 @@ Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({ 'remove-indent': true, 'left-trim': true, 'right-trim': true, - /*'indent': 2, + /*'break-lines': 80, + 'indent': 2, 'remove-initial-line-feed': false, 'tabs-to-spaces': 4, 'spaces-to-tabs': 4*/ diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.min.js b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js index d0131cfa74..11669d7dd8 100644 --- a/plugins/normalize-whitespace/prism-normalize-whitespace.min.js +++ b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js @@ -1 +1 @@ -!function(){function e(e){this.defaults=t({},e)}function n(e){return e.replace(/-(\w)/g,function(e,n){return n.toUpperCase()})}if("undefined"!=typeof self&&self.Prism&&self.document){var t=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=t(this.defaults,e)},normalize:function(e,r){r=t(this.defaults,r);for(var i in r){var o=n(i);"normalize"!==i&&"setDefaults"!==o&&r[i]&&this[o]&&(e=this[o].call(this,e,r[i]))}return e},leftTrim:function(e){return e.replace(/^\s+/,"")},rightTrim:function(e){return e.replace(/\s+$/,"")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\t/g,new Array(++n).join(" "))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(new RegExp(" {"+n+"}","g")," ")},removeTrailing:function(e){return e.replace(/\s*?$/gm,"")},removeInitialLineFeed:function(e){return e.replace(/^(?:\r?\n|\r)/,"")},removeIndent:function(e){var n=e.match(/^[^\S\n\r]*(?=\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(new RegExp("^"+n[0],"gm"),""):e):e},indent:function(e,n){return e.replace(/^[^\S\n\r]*(?=\S)/gm,new Array(++n).join(" ")+"$&")}},Prism.plugins.NormalizeWhitespace=new e({"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.hooks.add("before-highlight",function(e){var n=e.element.parentNode;if(e.code&&n&&"pre"===n.nodeName.toLowerCase()&&(!e.settings||e.settings["whitespace-normalization"]!==!1)){for(var t=n.childNodes,r="",i="",o=!1,a=0;an&&(o[s]="\n"+o[s],a=l)}t[i]=o.join("")}return t.join("\n")}},Prism.plugins.NormalizeWhitespace=new e({"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.hooks.add("before-highlight",function(e){var n=e.element.parentNode;if(e.code&&n&&"pre"===n.nodeName.toLowerCase()&&(!e.settings||e.settings["whitespace-normalization"]!==!1)){for(var r=n.childNodes,t="",i="",o=!1,a=0;a