Skip to content

Instantly share code, notes, and snippets.

@chadluo
Last active September 9, 2022 03:41
Show Gist options
  • Save chadluo/c526b1a32d8f985df99e2f159c37c0a4 to your computer and use it in GitHub Desktop.
Save chadluo/c526b1a32d8f985df99e2f159c37c0a4 to your computer and use it in GitHub Desktop.
Bitbucket PR syntax highlight (actually just hljs wrapper but whatever)
// ==UserScript==
// @name Bitbucket PR syntax highlight (actually just a HLJS wrapper)
// @namespace http://tampermonkey.net/
// @version 0.1
// @description use HLJS to syntax highlight Bitbucket PR. see https://highlightjs.org/usage/
// @author Chad
// @match https://bitbucket.org/*/pull-requests/*
// @icon https://www.google.com/s2/favicons?domain=bitbucket.org
// @grant GM_addStyle
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jsdiff/5.1.0/diff.min.js
// ==/UserScript==
// TODO consider switch to https://github.com/rtfpessoa/diff2html
"use strict";
const EXTENSION = /\.(\w+)$/;
(function () {
setInterval(highlight, 3000);
})();
function highlight() {
document
.querySelectorAll(
"article[data-qa='pr-diff-file-styles']:not(.highlighted)"
)
.forEach((file) => {
const label = file.ariaLabel;
const fileTypeClass = getFileTypeClass(label);
file.querySelectorAll(".code-diff").forEach((line) => {
if (fileTypeClass) {
line.classList.add(fileTypeClass);
}
// hljs.highlightElement(line); // eslint-disable-line no-undef
});
file.classList.add("highlighted");
file.querySelectorAll(".lines-wrapper").forEach((linesWrapper) => {
const before = linesWrapper.querySelector(
".line-wrapper:nth-of-type(1) .code-diff"
);
const beforeHTML = before.innerHTML;
hljs.highlightElement(before);
const after = linesWrapper.querySelector(
".line-wrapper:nth-of-type(2) .code-diff"
);
const afterHTML = after.innerHTML;
hljs.highlightElement(after);
if (
before.innerHTML.length === 0 ||
after.innerHTML.length === 0 ||
before.innerHTML === after.innerHTML
) {
return;
}
const diff = Diff.diffWords(before.innerHTML, after.innerHTML);
// console.log({before: beforeHTML, after: afterHTML, diff: diff});
if (diff.every((part) => angleBracketsMatch(part.value))) {
before.innerHTML = diff.map(renderOldTextPart).join("");
after.innerHTML = diff.map(renderNewTextPart).join("");
} else {
before.innerHTML = beforeHTML;
after.innerHTML = afterHTML;
}
});
});
document.querySelectorAll("pre.source").forEach((line) => {
hljs.highlightElement(line); // eslint-disable-line no-undef
});
}
function getFileTypeClass(label) {
if (label.endsWith(".xhtml")) {
return "jsp";
} else if (label.includes("gradlew")) {
return "bash";
} else if (label.toLowerCase().endsWith("dockerfile")) {
return "Dockerfile";
} else {
return label.match(EXTENSION)?.[1] || null;
}
}
function renderOldTextPart(part) {
return part.added
? ""
: part.removed && angleBracketsMatch(part.value)
? `<del>${part.value}</del>`
: part.value;
}
function renderNewTextPart(part) {
return part.removed
? ""
: part.added && angleBracketsMatch(part.value)
? `<ins>${part.value}</ins>`
: part.value;
}
function angleBracketsMatch(str) {
let count = 0;
for (let i = 0; i < str.length; i++) {
const c = str.charAt(i);
if (c === ">") {
count++;
} else if (c === "<") {
count--;
}
}
if (count !== 0) {
console.log("part `<>` not match", str);
}
return count === 0;
}
GM_addStyle(
"@import url('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github.min.css'); .hljs { padding: 0; background: none; overflow-y: hidden; }"
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment