Skip to content

Instantly share code, notes, and snippets.

@petrosh
Forked from glebm/RenderWhitespace.md
Created September 7, 2017 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petrosh/5798aa3d5ec580fc5cbdce28dab6e7a0 to your computer and use it in GitHub Desktop.
Save petrosh/5798aa3d5ec580fc5cbdce28dab6e7a0 to your computer and use it in GitHub Desktop.
Render whitespace on GitHub

Are they tabs? Are they spaces? How many? Never wonder again!

Copy-paste the file below into the console to see the whitespace like this:

whitespace

Also available as a bookmarklet:

javascript:(function()%7Bfunction%20e(e%2Co%2Cr)%7Bconst%20c%3De.nodeValue.split(%22%5Ct%22).map(e%3D%3Ee.split(%22%20%22))%3Bif(1%3D%3D%3Dc.length%26%261%3D%3D%3Dc%5B0%5D.length)return%3Bconst%20a%3De.parentNode%2Cd%3Dt%3D%3E%7Ba.insertBefore(t%2Ce)%7D%3Bn(c%2Ce%3D%3E1%3D%3D%3De.length%26%26%22%22%3D%3D%3De%5B0%5D%2Ce%3D%3Ed(t(o.repeat(e)))%2Ce%3D%3En(e%2Ce%3D%3E%22%22%3D%3D%3De%2Ce%3D%3Ed(t(r.repeat(e)))%2Ce%3D%3Ed(document.createTextNode(e))))%2Ca.removeChild(e)%7Dfunction%20t(e)%7Bconst%20t%3Ddocument.createElement(%22span%22)%3Breturn%20t.textContent%3De%2Ct.style.opacity%3Dc%2Ct%7Dfunction%20n(e%2Ct%2Cn%2Co)%7Bconst%20r%3De.length%3Be.reduce((e%2Cc%2Ca)%3D%3E%7Bconst%20d%3Dt(c)%3Breturn%20d%26%26a!%3D%3Dr-1%3Fe%2B1%3A(e%3E0%26%26n(e)%2Cd%7C%7Co(c)%2C1)%7D%2C0)%7Dvar%20o%3D%22%C2%B7%22%2Cr%3D%22%E2%86%92%22%2Cc%3D.8%3B!function()%7Bfor(const%20t%20of%20document.querySelectorAll(%22table%5Bdata-tab-size%5D%22))%7Bconst%20n%3Dr.padEnd(%2Bt.dataset.tabSize)%2Cc%3Ddocument.createTreeWalker(t%2CNodeFilter.SHOW_TEXT%2C%7BacceptNode(e)%7Blet%20t%3De.parentNode%3Bfor(%3B%22TABLE%22!%3Dt.nodeName%3B)%7Bif(t.classList.contains(%22blob-code-inner%22))return%20t.firstChild!%3D%3De%7C%7C%22%20%22!%3D%3De.nodeValue%3FNodeFilter.FILTER_ACCEPT%3ANodeFilter.FILTER_SKIP%3Bt%3Dt.parentNode%7Dreturn%20NodeFilter.FILTER_SKIP%7D%7D)%2Ca%3D%5B%5D%3Bfor(%3Bc.nextNode()%3B)a.push(c.currentNode)%3Bfor(const%20t%20of%20a)e(t%2Cn%2Co)%7D%7D()%7D)()

And as a userscript:

https://openuserjs.org/scripts/glebm/Render_Whitespace_on_GitHub

https://greasyfork.org/en/scripts/32986-render-whitespace-on-github

/* The MIT License (c) 2017 Gleb Mazovetskiy */
var SPACE = '·';
var TAB = '→';
var WHITESPACE_OPACITY = 0.78;
var ROOT_SELECTOR = 'table[data-tab-size]';
var NODE_FILTER = {
acceptNode(node) {
let parent = node.parentNode;
while (parent.nodeName != 'TABLE') {
if (parent.classList.contains('blob-code-inner')) {
return !(parent.firstChild === node && node.nodeValue === ' ') ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
parent = parent.parentNode;
}
return NodeFilter.FILTER_SKIP;
}
};
function showWhitespace() {
for (const root of document.querySelectorAll(ROOT_SELECTOR)) {
const tab = TAB.padEnd(+root.dataset.tabSize);
const treeWalker =
document.createTreeWalker(root, NodeFilter.SHOW_TEXT, NODE_FILTER);
const nodes = [];
while (treeWalker.nextNode()) nodes.push(treeWalker.currentNode);
for (const node of nodes) replaceWhitespace(node, tab, SPACE);
}
}
function replaceWhitespace(node, tab, space) {
const tabParts = node.nodeValue.split('\t');
const tabSpaceParts = tabParts.map(s => s.split(' '));
if (tabSpaceParts.length === 1 && tabSpaceParts[0].length === 1) return;
const parent = node.parentNode;
const insert = (newNode) => {
parent.insertBefore(newNode, node);
};
insertParts(tabSpaceParts,
spaceParts => spaceParts.length === 1 && spaceParts[0] === '',
n => insert(createWhitespaceNode(tab.repeat(n))),
spaceParts =>
insertParts(spaceParts,
text => text === '',
n => insert(createWhitespaceNode(space.repeat(n))),
text => insert(document.createTextNode(text))));
parent.removeChild(node);
}
function createWhitespaceNode(text) {
const node = document.createElement('span');
node.textContent = text;
node.style.opacity = WHITESPACE_OPACITY;
return node;
}
function insertParts(parts, isConsecutiveFn, addInterFn, addPartFn) {
const n = parts.length;
parts.reduce((consecutive, part, i) => {
const isConsecutive = isConsecutiveFn(part);
if (isConsecutive) {
if (i !== n - 1) return consecutive + 1;
}
if (consecutive > 0) addInterFn(consecutive);
if (!isConsecutive) addPartFn(part);
return 1;
}, 0);
}
showWhitespace();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment