Go.dev Code Highlight

Golang code highlighter

As of 2023-12-19. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Go.dev Code Highlight
// @version      1.1.5
// @description  Golang code highlighter
// @author       Anton Vi
// @match        https://*.go.dev/*
// @resource     IMPORTED_CSS  https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @license      GNU GPLv3
// @namespace GolangDevNamespace
// ==/UserScript==

(function() {

    'use strict';

    document.addEventListener('readystatechange', (e) => {
        if (e.target.readyState === 'complete') {
            resetBlogCss();
            start();
        }
    })


})();

function resetBlogCss() {
    // reset styles for go dev blog
    let css = `#blog pre, #content .code, #content .playground {
        background: black; 
        font-family: Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;
        font-size: 1rem;
    }`;
    GM_addStyle(css);

}

function start() {
    // create Prisma object
    window.Prism = window.Prism || {};
    // no highlight on auto
    Prism.manual = true;

    // add highlight styles css
    const my_css = GM_getResourceText("IMPORTED_CSS");
    GM_addStyle(my_css);

    // start prism
    initPrismCore();

    // add languages syntax
    addClikeSyntax();
    addGoSyntax();


    // loop pre-s and add code child elements for highlight
    let pre_s = document.getElementsByTagName('pre');
    for (let el of pre_s) {
        // skip pre element for ==Output== code run in documentation
        if (el.getElementsByClassName('Documentation-exampleOutputLabel').length > 0) {
            continue;
        }


        if (!el.getElementsByTagName('code').length > 0) {
            let text = el.innerHTML;
            el.innerHTML = '';

            let code = document.createElement('code');
            code.innerHTML = text;
            code.className = 'language-go';
            el.appendChild(code);
        }

    }


    // get examples in go library doc
    let divS = document.getElementsByClassName('Documentation-exampleDetailsBody');
    for (divEl of divS) {
        let outputPre = divEl.getElementsByTagName('pre')[0];
        outputPre.className = 'language-go';


        let textareaBlock = divEl.querySelector('textarea.Documentation-exampleCode.code');
        textareaBlock.style.display = 'none';
        // textareaBlock.remove();
        divEl.insertAdjacentHTML('afterbegin', '<pre class="language-go"><code>' + textareaBlock.value + '</code></pre>');


    }


    // start highlight syntax
    Prism.highlightAll();

}

function initPrismCore() {
    var _self = "undefined" != typeof window ? window : "undefined" != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope ? self : {},
        Prism = function(e) {
            var n = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,
                t = 0,
                r = {},
                a = {
                    manual: e.Prism && e.Prism.manual,
                    disableWorkerMessageHandler: e.Prism && e.Prism.disableWorkerMessageHandler,
                    util: {
                        encode: function e(n) { return n instanceof i ? new i(n.type, e(n.content), n.alias) : Array.isArray(n) ? n.map(e) : n.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/\u00a0/g, " ") },
                        type: function(e) { return Object.prototype.toString.call(e).slice(8, -1) },
                        objId: function(e) { return e.__id || Object.defineProperty(e, "__id", { value: ++t }), e.__id },
                        clone: function e(n, t) {
                            var r, i;
                            switch (t = t || {}, a.util.type(n)) {
                                case "Object":
                                    if (i = a.util.objId(n), t[i]) return t[i];
                                    for (var l in r = {}, t[i] = r, n) n.hasOwnProperty(l) && (r[l] = e(n[l], t));
                                    return r;
                                case "Array":
                                    return i = a.util.objId(n), t[i] ? t[i] : (r = [], t[i] = r, n.forEach((function(n, a) { r[a] = e(n, t) })), r);
                                default:
                                    return n
                            }
                        },
                        getLanguage: function(e) {
                            for (; e;) {
                                var t = n.exec(e.className);
                                if (t) return t[1].toLowerCase();
                                e = e.parentElement
                            }
                            return "none"
                        },
                        setLanguage: function(e, t) { e.className = e.className.replace(RegExp(n, "gi"), ""), e.classList.add("language-" + t) },
                        currentScript: function() {
                            if ("undefined" == typeof document) return null;
                            if ("currentScript" in document) return document.currentScript;
                            try { throw new Error } catch (r) {
                                var e = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(r.stack) || [])[1];
                                if (e) {
                                    var n = document.getElementsByTagName("script");
                                    for (var t in n)
                                        if (n[t].src == e) return n[t]
                                }
                                return null
                            }
                        },
                        isActive: function(e, n, t) {
                            for (var r = "no-" + n; e;) {
                                var a = e.classList;
                                if (a.contains(n)) return !0;
                                if (a.contains(r)) return !1;
                                e = e.parentElement
                            }
                            return !!t
                        }
                    },
                    languages: {
                        plain: r,
                        plaintext: r,
                        text: r,
                        txt: r,
                        extend: function(e, n) { var t = a.util.clone(a.languages[e]); for (var r in n) t[r] = n[r]; return t },
                        insertBefore: function(e, n, t, r) {
                            var i = (r = r || a.languages)[e],
                                l = {};
                            for (var o in i)
                                if (i.hasOwnProperty(o)) {
                                    if (o == n)
                                        for (var s in t) t.hasOwnProperty(s) && (l[s] = t[s]);
                                    t.hasOwnProperty(o) || (l[o] = i[o])
                                } var u = r[e];
                            return r[e] = l, a.languages.DFS(a.languages, (function(n, t) { t === u && n != e && (this[n] = l) })), l
                        },
                        DFS: function e(n, t, r, i) {
                            i = i || {};
                            var l = a.util.objId;
                            for (var o in n)
                                if (n.hasOwnProperty(o)) {
                                    t.call(n, o, n[o], r || o);
                                    var s = n[o],
                                        u = a.util.type(s);
                                    "Object" !== u || i[l(s)] ? "Array" !== u || i[l(s)] || (i[l(s)] = !0, e(s, t, o, i)) : (i[l(s)] = !0, e(s, t, null, i))
                                }
                        }
                    },
                    plugins: {},
                    highlightAll: function(e, n) { a.highlightAllUnder(document, e, n) },
                    highlightAllUnder: function(e, n, t) {
                        var r = { callback: t, container: e, selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' };
                        a.hooks.run("before-highlightall", r), r.elements = Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)), a.hooks.run("before-all-elements-highlight", r);
                        for (var i, l = 0; i = r.elements[l++];) a.highlightElement(i, !0 === n, r.callback)
                    },
                    highlightElement: function(n, t, r) {
                        var i = a.util.getLanguage(n),
                            l = a.languages[i];
                        a.util.setLanguage(n, i);
                        var o = n.parentElement;
                        o && "pre" === o.nodeName.toLowerCase() && a.util.setLanguage(o, i);
                        var s = { element: n, language: i, grammar: l, code: n.textContent };

                        function u(e) { s.highlightedCode = e, a.hooks.run("before-insert", s), s.element.innerHTML = s.highlightedCode, a.hooks.run("after-highlight", s), a.hooks.run("complete", s), r && r.call(s.element) }
                        if (a.hooks.run("before-sanity-check", s), (o = s.element.parentElement) && "pre" === o.nodeName.toLowerCase() && !o.hasAttribute("tabindex") && o.setAttribute("tabindex", "0"), !s.code) return a.hooks.run("complete", s), void(r && r.call(s.element));
                        if (a.hooks.run("before-highlight", s), s.grammar)
                            if (t && e.Worker) {
                                var c = new Worker(a.filename);
                                c.onmessage = function(e) { u(e.data) }, c.postMessage(JSON.stringify({ language: s.language, code: s.code, immediateClose: !0 }))
                            } else u(a.highlight(s.code, s.grammar, s.language));
                        else u(a.util.encode(s.code))
                    },
                    highlight: function(e, n, t) { var r = { code: e, grammar: n, language: t }; if (a.hooks.run("before-tokenize", r), !r.grammar) throw new Error('The language "' + r.language + '" has no grammar.'); return r.tokens = a.tokenize(r.code, r.grammar), a.hooks.run("after-tokenize", r), i.stringify(a.util.encode(r.tokens), r.language) },
                    tokenize: function(e, n) {
                        var t = n.rest;
                        if (t) {
                            for (var r in t) n[r] = t[r];
                            delete n.rest
                        }
                        var a = new s;
                        return u(a, a.head, e), o(e, a, n, a.head, 0),
                            function(e) { for (var n = [], t = e.head.next; t !== e.tail;) n.push(t.value), t = t.next; return n }(a)
                    },
                    hooks: {
                        all: {},
                        add: function(e, n) {
                            var t = a.hooks.all;
                            t[e] = t[e] || [], t[e].push(n)
                        },
                        run: function(e, n) {
                            var t = a.hooks.all[e];
                            if (t && t.length)
                                for (var r, i = 0; r = t[i++];) r(n)
                        }
                    },
                    Token: i
                };

            function i(e, n, t, r) { this.type = e, this.content = n, this.alias = t, this.length = 0 | (r || "").length }

            function l(e, n, t, r) {
                e.lastIndex = n;
                var a = e.exec(t);
                if (a && r && a[1]) {
                    var i = a[1].length;
                    a.index += i, a[0] = a[0].slice(i)
                }
                return a
            }

            function o(e, n, t, r, s, g) {
                for (var f in t)
                    if (t.hasOwnProperty(f) && t[f]) {
                        var h = t[f];
                        h = Array.isArray(h) ? h : [h];
                        for (var d = 0; d < h.length; ++d) {
                            if (g && g.cause == f + "," + d) return;
                            var v = h[d],
                                p = v.inside,
                                m = !!v.lookbehind,
                                y = !!v.greedy,
                                k = v.alias;
                            if (y && !v.pattern.global) {
                                var x = v.pattern.toString().match(/[imsuy]*$/)[0];
                                v.pattern = RegExp(v.pattern.source, x + "g")
                            }
                            for (var b = v.pattern || v, w = r.next, A = s; w !== n.tail && !(g && A >= g.reach); A += w.value.length, w = w.next) {
                                var E = w.value;
                                if (n.length > e.length) return;
                                if (!(E instanceof i)) {
                                    var P, L = 1;
                                    if (y) {
                                        if (!(P = l(b, A, e, m)) || P.index >= e.length) break;
                                        var S = P.index,
                                            O = P.index + P[0].length,
                                            j = A;
                                        for (j += w.value.length; S >= j;) j += (w = w.next).value.length;
                                        if (A = j -= w.value.length, w.value instanceof i) continue;
                                        for (var C = w; C !== n.tail && (j < O || "string" == typeof C.value); C = C.next) L++, j += C.value.length;
                                        L--, E = e.slice(A, j), P.index -= A
                                    } else if (!(P = l(b, 0, E, m))) continue;
                                    S = P.index;
                                    var N = P[0],
                                        _ = E.slice(0, S),
                                        M = E.slice(S + N.length),
                                        W = A + E.length;
                                    g && W > g.reach && (g.reach = W);
                                    var z = w.prev;
                                    if (_ && (z = u(n, z, _), A += _.length), c(n, z, L), w = u(n, z, new i(f, p ? a.tokenize(N, p) : N, k, N)), M && u(n, w, M), L > 1) {
                                        var I = { cause: f + "," + d, reach: W };
                                        o(e, n, t, w.prev, A, I), g && I.reach > g.reach && (g.reach = I.reach)
                                    }
                                }
                            }
                        }
                    }
            }

            function s() {
                var e = { value: null, prev: null, next: null },
                    n = { value: null, prev: e, next: null };
                e.next = n, this.head = e, this.tail = n, this.length = 0
            }

            function u(e, n, t) {
                var r = n.next,
                    a = { value: t, prev: n, next: r };
                return n.next = a, r.prev = a, e.length++, a
            }

            function c(e, n, t) {
                for (var r = n.next, a = 0; a < t && r !== e.tail; a++) r = r.next;
                n.next = r, r.prev = n, e.length -= a
            }
            if (e.Prism = a, i.stringify = function e(n, t) {
                    if ("string" == typeof n) return n;
                    if (Array.isArray(n)) { var r = ""; return n.forEach((function(n) { r += e(n, t) })), r }
                    var i = { type: n.type, content: e(n.content, t), tag: "span", classes: ["token", n.type], attributes: {}, language: t },
                        l = n.alias;
                    l && (Array.isArray(l) ? Array.prototype.push.apply(i.classes, l) : i.classes.push(l)), a.hooks.run("wrap", i);
                    var o = "";
                    for (var s in i.attributes) o += " " + s + '="' + (i.attributes[s] || "").replace(/"/g, "&quot;") + '"';
                    return "<" + i.tag + ' class="' + i.classes.join(" ") + '"' + o + ">" + i.content + "</" + i.tag + ">"
                }, !e.document) return e.addEventListener ? (a.disableWorkerMessageHandler || e.addEventListener("message", (function(n) {
                var t = JSON.parse(n.data),
                    r = t.language,
                    i = t.code,
                    l = t.immediateClose;
                e.postMessage(a.highlight(i, a.languages[r], r)), l && e.close()
            }), !1), a) : a;
            var g = a.util.currentScript();

            function f() { a.manual || a.highlightAll() }
            if (g && (a.filename = g.src, g.hasAttribute("data-manual") && (a.manual = !0)), !a.manual) { var h = document.readyState; "loading" === h || "interactive" === h && g && g.defer ? document.addEventListener("DOMContentLoaded", f) : window.requestAnimationFrame ? window.requestAnimationFrame(f) : window.setTimeout(f, 16) }
            return a
        }(_self);
    "undefined" != typeof module && module.exports && (module.exports = Prism), "undefined" != typeof global && (global.Prism = Prism);
}

function addClikeSyntax() {
    Prism.languages.clike = {
        comment: [{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0, greedy: !0 },
            { pattern: /(^|[^\\:])\/\/.*/, lookbehind: !0, greedy: !0 }
        ],
        string: { pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: !0 },
        "class-name": { pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, lookbehind: !0, inside: { punctuation: /[.\\]/ } },
        keyword: /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
        boolean: /\b(?:false|true)\b/,
        function: /\b\w+(?=\()/,
        number: /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
        operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
        punctuation: /[{}[\];(),.:]/
    };
}

function addGoSyntax() {
    Prism.languages.go = Prism.languages
        .extend("clike", {
            string: { pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/, lookbehind: !0, greedy: !0 },
            keyword: /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,
            boolean: /\b(?:_|false|iota|nil|true)\b/,
            number: [/\b0(?:b[01_]+|o[0-7_]+)i?\b/i, /\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i, /(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],
            operator: /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,
            builtin: /\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/
        }),
        Prism.languages.insertBefore("go", "string", { char: { pattern: /'(?:\\.|[^'\\\r\n]){0,10}'/, greedy: !0 } }), delete Prism.languages.go["class-name"];
}