Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Whitespace normalizer plugin #847

Merged
merged 2 commits into from
Feb 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions components.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ var components = {
"command-line": {
"title": "Command Line",
"owner": "chriswells0"
},
"normalize-whitespace": {
"title": "Normalize Whitespace",
"owner": "zeitgeist87",
"noCSS": true
}
}
};
29 changes: 29 additions & 0 deletions plugins/normalize-whitespace/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<body data-prism data-remove-trailing="true">
<section id="main" class="language-javascript" data-right-trim="true">

<pre>

<code data-left-trim="true">


var example = {
foo: true,

bar: false
};


</code>

</pre>

</section>
<script src="plugins/normalize-whitespace/prism-normalize-whitespace.js"></script>
<script type="text/javascript">
Prism.plugins.NormalizeWhitespace.setDefaults({
'remove-trailing': false,
'left-trim': false,
'right-trim': false
});
</script>
</body>
101 changes: 101 additions & 0 deletions plugins/normalize-whitespace/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="utf-8" />
<link rel="shortcut icon" href="favicon.png" />
<title>Normalize Whitespace ▲ Prism plugins</title>
<base href="../.." />
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
<script src="prefixfree.min.js"></script>

<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
<script src="http://www.google-analytics.com/ga.js" async></script>
</head>
<body>

<header>
<div class="intro" data-src="templates/header-plugins.html" data-type="text/html"></div>

<h2>Normalize Whitespace</h2>
<p>Supports multiple operations to normalize whitespace in code blocks.</p>
</header>

<section class="language-markup">
<h1>How to use</h1>

<p>Obviously, this is supposed to work only for code blocks (<code>&lt;pre>&lt;code></code>) and not for inline code.</p>
<p>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.</p>

<p>The plugin uses the <a href="plugins/parse-settings/">Parse Settings</a> plugin to get its settings.
The default settings can be overridden with the <code class="language-javascript">setDefaults()</code> method
like so:</p>

<pre class="language-javascript"><code>
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*/
});
</code></pre>

<p>It is also possible to change the default settings with <code>data-*</code>-attributes.</p>

<pre><code>&lt;code data-left-trim="false">...&lt;/code></code></pre>

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

<pre><code>&lt;code class="no-whitespace-normalization"
data-whitespace-normalization="false">
...
&lt;/code></code></pre>
</section>

<section class="language-markup">
<h1>Examples</h1>

<p>The following example shows some of the possible ways of configuring this plugin:</p>

<pre data-src="plugins/normalize-whitespace/demo.html"></pre>

<p>The result looks like this:</p>

<pre class="language-javascript">

<code>


var example = {
foo: true,

bar: false
};


</code>

</pre>

</section>

<footer data-src="templates/footer.html" data-type="text/html"></footer>

<script src="prism.js"></script>
<script src="plugins/parse-settings/prism-parse-settings.js"></script>
<script src="plugins/normalize-whitespace/prism-normalize-whitespace.js"></script>
<script src="utopia.js"></script>
<script src="components.js"></script>
<script src="code.js"></script>


</body>
</html>
162 changes: 162 additions & 0 deletions plugins/normalize-whitespace/prism-normalize-whitespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
(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();
});
}

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);
},
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') + '$&');
},
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');
}
};

Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({
'remove-trailing': true,
'remove-indent': true,
'left-trim': true,
'right-trim': true,
/*'break-lines': 80,
'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 <pre> tag into the <code> 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);
});

}());

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion plugins/remove-initial-line-feed/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ <h2>Remove initial line feed</h2>
</header>

<section class="language-markup">
<h1>How to use</h1>
<h1>How to use (DEPRECATED)</h1>

<p>This plugin will be removed in the future. Please use the general purpose <a href="plugins/normalize-whitespace/">Normalize Whitespace</a> plugin instead.</p>
<p>Obviously, this is supposed to work only for code blocks (<code>&lt;pre>&lt;code></code>) and not for inline code.</p>
<p>With this plugin included, any initial line feed will be removed by default.</p>
<p>To bypass this behaviour, you may add the class <strong>keep-initial-line-feed</strong> to your desired <code>&lt;pre></code>.</p>
Expand Down