您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Replace Pastebin code blocks in markdown mode with Shiki syntax highlighting and copy button
// ==UserScript== // @name Pastebin Shiki Highlighter Codeblocks for Markdown // @namespace https://pastebin.com/ // @version 1.4.0 // @description Replace Pastebin code blocks in markdown mode with Shiki syntax highlighting and copy button // @match https://pastebin.com/* // @author BourbonCrow // @icon https://raw.githubusercontent.com/shikijs/shiki/main/docs/public/logo.svg // @grant GM_addStyle // @run-at document-start // @license MIT // ==/UserScript== (function () { "use strict"; // Hide raw markdown code instantly — only original (non-shiki) <pre><code> blocks if (typeof GM_addStyle === "function") { GM_addStyle(` /* Only hide the site's original code nodes; do NOT hide pre.shiki generated content */ .source.markdown pre:not(.shiki) > code, .source.markdown code[class^="language-"]:not(.shiki) { display: none !important; } `); } function getHeaderHeight() { const header = document.querySelector(".header"); return header ? header.offsetHeight || 0 : 0; } function init() { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); return; } // Load Devicons CSS (optional icons) const devicons = document.createElement("link"); devicons.rel = "stylesheet"; devicons.href = "https://cdn.jsdelivr.net/gh/devicons/devicon/devicon.min.css"; document.head.appendChild(devicons); // Inject ESM module into the page so it runs in page context const script = document.createElement("script"); script.type = "module"; script.innerHTML = ` const SHOW_DEVICONS = true; import { codeToHtml } from 'https://esm.sh/shiki'; // --- inline language table (display, optional aliases, optional devicon) --- const languages = { abap: { display: "ABAP" }, actionscript: { display: "ActionScript", aliases: ["actionscript-3"] }, ada: { display: "Ada" }, "angular-html": { display: "Angular HTML" }, "angular-ts": { display:"Angular TypeScript" }, apache: { display: "Apache Conf" }, ansi: { display: "ANSI" }, apex: { display: "Apex" }, apl: { display: "APL" }, applescript: { display: "AppleScript" }, ara: { display: "Ara" }, asciidoc: { display: "AsciiDoc", aliases: ["adoc"] }, asm: { display: "Assembly" }, astro: { display: "Astro" }, awk: { display: "AWK" }, ballerina: { display: "Ballerina" }, bat: { display: "Batch File", aliases: ["batch"] }, beancount: { display: "Beancount" }, berry: { display: "Berry", aliases: ["be"] }, bibtex: { display: "BibTeX" }, bicep: { display: "Bicep" }, blade: { display: "Blade" }, bsl: { display: "1C (Enterprise)", aliases: ["1c"] }, c: { display: "C", devicon: "c-plain" }, cadence: { display: "Cadence", aliases: ["cdc"] }, cairo: { display: "Cairo" }, clarity: { display: "Clarity" }, clojure: { display: "Clojure", aliases: ["clj"], devicon: "clojure-line" }, cmake: { display: "CMake" }, cobol: { display: "COBOL" }, codeowners: { display: "CODEOWNERS" }, codeql: { display: "CodeQL", aliases: ["ql"] }, coffee: { display: "CoffeeScript", aliases: ["coffeescript"], devicon: "coffeescript-original" }, "common-lisp": { display: "Common Lisp", aliases: ["lisp"] }, coq: { display: "Coq" }, cpp: { display: "C++", aliases: ["c++"], devicon: "cplusplus-plain" }, crystal: { display: "Crystal" }, csharp: { display: "C#", aliases: ["cs","c#"], devicon: "csharp-plain" }, css: { display: "CSS", devicon: "css3-plain" }, csv: { display: "CSV" }, cue: { display: "CUE" }, cypher: { display:"Cypher", aliases: ["cql"] }, d: { display:"D" }, dart: { display: "Dart" }, dax: { display: "DAX" }, desktop: { display: "Desktop" }, diff: { display: "Diff" }, docker: { display: "Dockerfile", aliases: ["dockerfile"], devicon: "docker-plain" }, dotenv: { display: "dotEnv" }, "dream-maker": { display: "Dream Maker" }, edge: { display:"Edge" }, elixir: { display: "Elixir", devicon: "elixir-plain" }, elm: { display: "Elm", devicon: "elm-plain" }, "emacs-lisp": { display: "Emacs Lisp", aliases: ["elisp"] }, erb: { display: "ERB" }, erlang: { display: "Erlang", aliases: ["erl"], devicon: "erlang-plain" }, fennel: { display: "Fennel" }, fish: { display: "Fish" }, fluent: { display: "Fluent", aliases: ["ftl"] }, "fortran-fixed-form": { display: "Fortran (Fixed Form)", aliases: ["f77"] }, "fortran-free-form": { display: "Fortran (Free Form)", aliases: ["f90","f95","f03","f08","f18"] }, fsharp: { display: "F#", aliases: ["fs","f#"], devicon: "fsharp-plain" }, gdresource: { display: "GDResource" }, gdscript: { display: "GDScript" }, gdshader: { display: "GDShader" }, genie: { display: "Genie" }, gherkin: { display: "Gherkin" }, "git-commit": { display: "Git Commit Message" }, "git-rebase": { display: "Git Rebase Message" }, gleam: { display:"Gleam" }, "glimmer-js": { display: "Glimmer JS", aliases: ["gjs"] }, "glimmer-ts": { display: "Glimmer TS", aliases: ["gts"] }, glsl: { display: "GLSL" }, gnuplot: { display: "Gnuplot" }, go: { display: "Go", devicon: "go-plain" }, graphql: { display: "GraphQL", aliases: ["gql"] }, groovy: { display: "Groovy", devicon: "groovy-plain" }, hack: { display: "Hack" }, haml: { display: "Ruby Haml" }, handlebars: { display: "Handlebars", aliases: ["hbs"], devicon: "handlebars-plain" }, haskell: { display: "Haskell", aliases: ["hs"], devicon: "haskell-plain" }, haxe: { display: "Haxe" }, hcl: { display: "HashiCorp HCL" }, hjson: { display:"Hjson" }, hlsl: { display: "HLSL" }, html: { display: "HTML", devicon: "html5-plain" }, "html-derivative": { display: "HTML (Derivative)" }, http: { display: "HTTP" }, hxml: { display: "HXML" }, hy: { display: "Hy" }, imba: { display: "Imba" }, ini: { display: "INI", aliases: ["properties"] }, java: { display: "Java", devicon: "java-plain" }, javascript: { display: "JavaScript", aliases: ["js"], devicon: "javascript-plain" }, jinja: { display: "Jinja" }, jison: { display: "Jison" }, json: { display: "JSON", devicon: "json-plain" }, json5: { display: "JSON5" }, jsonc: { display: "JSON with Comments" }, jsonl: { display: "JSON Lines" }, jsonnet: { display: "Jsonnet" }, jssm: { display: "JSSM", aliases: ["fsl"] }, jsx: { display: "JSX", devicon: "react-original" }, julia: { display: "Julia", aliases: ["jl"] }, kotlin: { display: "Kotlin", aliases: ["kt","kts"], devicon: "kotlin-plain" }, kusto: { display: "Kusto", aliases: ["kql"] }, latex: { display: "LaTeX", devicon: "latex-original" }, lean: { display: "Lean 4", aliases: ["lean4"] }, less: { display:"Less", devicon: "less-plain-wordmark" }, liquid: { display: "Liquid" }, llvm: { display: "LLVM IR" }, log: { display :"Log file" }, logo: { display: "Logo" }, lua: { display: "Lua", devicon: "lua-plain" }, luau: { display: "Luau" }, make: { display: "Makefile", aliases: ["makefile"] }, markdown: { display: "Markdown", aliases: ["md"], devicon: "markdown-original" }, marko: { display: "Marko" }, matlab: { display: "MATLAB", devicon: "matlab-plain" }, mdc: { display: "MDC" }, mdx: { display: "MDX" }, mermaid: { display: "Mermaid", aliases: ["mmd"] }, mipsasm: { display: "MIPS Assembly", aliases: ["mips"] }, mojo: { display: "Mojo" }, move: { display: "Move" }, narrat: { display: "Narrat Language", aliases: ["nar"] }, nextflow:{display:"Nextflow",aliases:["nf"]}, nginx: { display: "Nginx" }, nim: { display: "Nim" }, nix: { display: "Nix" }, nushell: {display: "nushell", aliases: ["nu"] }, "objective-c": { display: "Objective-C", aliases: ["objc"], devicon: "objectivec-plain" }, "objective-cpp": { display: "Objective-C++" }, ocaml: { display: "OCaml", devicon: "ocaml-plain" }, pascal: { display: "Pascal" }, perl: { display: "Perl" }, php: { display: "PHP", devicon: "php-plain" }, plsql: { display: "PL/SQL" }, po: { display: "Gettext PO", aliases: ["pot","potx"] }, polar: { display: "Polar" }, postcss: { display: "PostCSS" }, powerquery: { display: "PowerQuery" }, powershell: {display: "PowerShell", aliases:["ps","ps1"], devicon: "powershell-plain" }, prisma: { display: "Prisma" }, prolog: { display: "Prolog" }, proto: { display: "Protocol Buffer 3", aliases: ["protobuf"] }, pug: { display: "Pug", aliases:["jade"] }, puppet: { display: "Puppet" }, purescript: { display: "PureScript" }, python: { display: "Python", aliases: ["py"], devicon: "python-plain" }, qml: { display: "QML" }, qmldir: { display: "QML Directory" }, qss: { display: "Qt Style Sheets" }, r: { display: "R", devicon: "r-original" }, racket: { display: "Racket" }, raku: { display: "Raku", aliases: ["perl6"] }, razor: { display: "ASP.NET Razor", aliases: ["cshtml"], devicon: "dot-net-plain" }, reg: { display: "Windows Registry Script" }, regexp: { display: "RegExp", aliases: ["regex"] }, rel: { display: "Rel" }, riscv: { display: "RISC-V" }, rst: { display: "reStructuredText" }, ruby: { display: "Ruby", aliases: ["rb"], devicon: "ruby-plain" }, rust: { display: "Rust", aliases: ["rs"], devicon: "rust-plain" }, sas: { display: "SAS", devicon: "sass-original" }, sass: { display: "Sass" }, scala: { display: "Scala", devicon: "scala-plain" }, scheme: { display: "Scheme" }, scss: { display: "SCSS", devicon: "sass-original" }, sdbl: { display: "1C (Query)", aliases: ["1c-query"] }, shaderlab: { display: "ShaderLab", aliases: ["shader"] }, shellscript: { display: "Shell", aliases: ["bash","sh","zsh"], devicon: "bash-plain" }, shellsession: { display: "Shell Session", aliases: ["console"] }, smalltalk: { display: "Smalltalk" }, solidity: { display: "Solidity" }, soy: { display: "Closure Templates", aliases: ["closure-templates"] }, sparql: { display: "SPARQL" }, splunk: { display: "Splunk Query Language", aliases: ["spl"] }, sql: { display: "SQL", devicon: "azuresqldatabase-plain" }, "ssh-config": { display: "SSH Config" }, stata: { display: "Stata" }, stylus: { display: "Stylus", aliases: ["styl"], devicon: "stylus-original" }, svelte: { display: "Svelte" }, swift: { display: "Swift", devicon: "swift-plain" }, "system-verilog": { display: "SystemVerilog" }, systemd: { display: "Systemd Units" }, talonscript: { display: "TalonScript", aliases: ["talon"] }, tasl: { display: "Tasl" }, tcl: { display: "Tcl" }, templ: { display: "Templ" }, terraform: { display: "Terraform", aliases: ["tf","tfvars"] }, tex: { display: "TeX" }, toml: { display: "TOML" }, "ts-tags": { display: "TypeScript with Tags", aliases: ["lit"], devicon: "typescript-plain" }, tsv: { display: "TSV" }, tsx: { display: "TSX", devicon: "react-original" }, turtle: { display: "Turtle" }, twig: { display: "Twig" }, typescript: { display: "TypeScript", aliases: ["ts"], devicon: "typescript-plain" }, typespec: {display: "TypeSpec", aliases: ["tsp"] }, typst: { display: "Typst", aliases: ["typ"] }, v: { display: "V" }, vala: { display: "Vala" }, vb: { display: "Visual Basic", aliases: ["cmd"], devicon: "dot-net-plain" }, verilog: { display: "Verilog" }, vhdl: { display: "VHDL" }, viml: { display: "Vim Script", aliases: ["vim","vimscript"], devicon:"vim-plain" }, vue: { display: "Vue", devicon: "vuejs-plain" }, "vue-html": { display: "Vue HTML", devicon: "vuejs-plain" }, "vue-vine": { display: "Vue Vine" }, vyper: { display: "Vyper", aliases:["vy"] }, wasm: { display: "WebAssembly" }, wenyan: { display: "Wenyan", aliases:["文言"] }, wgsl: { display: "WGSL" }, wikitext: { display: "Wikitext", aliases: ["mediawiki","wiki"] }, wit: { display: "WebAssembly Interface Types" }, wolfram: { display: "Wolfram", aliases: ["wl"] }, xml: { display: "XML" }, xsl: { display: "XSL" }, yaml: { display: "YAML", aliases: ["yml"] }, zenscript: { display: "ZenScript" }, zig: { display: "Zig" }, plaintext: { display: "Plain Text", aliases: ["text","txt"] } }; // Build alias lookup (aliases optional) const aliasMap = {}; for (const [id, data] of Object.entries(languages)) { if (Array.isArray(data.aliases)) { for (const alias of data.aliases) { aliasMap[alias.toLowerCase()] = id; } } } function resolveLang(lang) { if (!lang) return { name: "Plain Text", devicon: null }; const key = lang.toLowerCase(); const canonicalId = languages[key] ? key : (aliasMap[key] || "plaintext"); const data = languages[canonicalId] || { display: "Plain Text" }; return { name: data.display, devicon: data.devicon || null }; } async function highlight() { const markdownSource = document.querySelector(".source.markdown"); if (!markdownSource) return; // Grab all pre > code blocks (with or without language class) const codeBlocks = markdownSource.querySelectorAll("pre > code"); for (const block of codeBlocks) { try { const rawCode = block.textContent; // detect language from class, fallback to plaintext const match = block.className.match(/language-([^\\s]+)/); const lang = match ? match[1] : "plaintext"; const { name, devicon } = resolveLang(lang); // Render with shiki const html = await codeToHtml(rawCode, { lang, theme: "github-dark" }); // Wrap and replace const wrapper = document.createElement("div"); wrapper.className = "shiki-wrapper"; wrapper.innerHTML = \` <div class="shiki-header"> \${SHOW_DEVICONS && devicon ? \`<i class="devicon-\${devicon}"></i>\` : ""} <span class="shiki-lang">\${name}</span> <button class="shiki-copy">Copy code</button> </div> \${html} \`; const pre = block.closest("pre") || block.parentElement; pre.replaceWith(wrapper); // Floating copy button logic const copyBtn = wrapper.querySelector(".shiki-copy"); function updatePosition() { const headerHeight = (${getHeaderHeight.toString()})(); const wrapperRect = wrapper.getBoundingClientRect(); const btnHeight = copyBtn.offsetHeight; const margin = 7; const shouldFloat = wrapperRect.top < headerHeight + margin && wrapperRect.bottom > headerHeight + btnHeight + margin; if (shouldFloat) { if (!copyBtn.classList.contains("floating")) { copyBtn.classList.add("floating"); copyBtn.style.position = "fixed"; copyBtn.style.zIndex = "999"; } const targetTop = Math.min( Math.max(headerHeight + margin, wrapperRect.top + margin), wrapperRect.bottom - btnHeight - margin ); const targetRight = window.innerWidth - wrapperRect.right + 8; copyBtn.style.top = targetTop + "px"; copyBtn.style.right = targetRight + "px"; copyBtn.style.left = "auto"; } else { if (copyBtn.classList.contains("floating")) { copyBtn.classList.remove("floating"); copyBtn.style.position = "absolute"; copyBtn.style.zIndex = "1"; } copyBtn.style.top = margin + "px"; copyBtn.style.right = "8px"; copyBtn.style.left = "auto"; } } // Throttle with rAF let ticking = false; const requestTick = () => { if (!ticking) { requestAnimationFrame(() => { updatePosition(); ticking = false; }); ticking = true; } }; window.addEventListener("scroll", requestTick, { passive: true }); window.addEventListener("resize", requestTick, { passive: true }); // initial setTimeout(updatePosition, 100); } catch (err) { console.warn("Highlight failed:", err); } } } // Start highlighting highlight(); // Copy button handler (module scope) document.addEventListener("click", (e) => { const btn = e.target.closest && e.target.closest(".shiki-copy"); if (!btn) return; const code = btn.closest(".shiki-wrapper").querySelector("code").innerText; navigator.clipboard.writeText(code).then(() => { const prev = btn.textContent; btn.textContent = "Copied!"; setTimeout(() => (btn.textContent = prev || "Copy code"), 1500); }).catch(() => { // fallback: still try to show UI btn.textContent = "Copied!"; setTimeout(() => (btn.textContent = "Copy code"), 1500); }); }); `; document.head.appendChild(script); // Styles for wrapper and header (generated content) GM_addStyle(` .shiki-wrapper { margin: 1em 0; border: 1px solid #171717; border-radius: 8px; overflow: hidden; background: #171717; position: relative; } .shiki-header { display: flex; align-items: center; gap: 8px; background: #171717; color: #ccc; font-size: 12px; font-family: sans-serif; padding: 0.3em 1.5em; position: relative; } .shiki-header .shiki-lang { user-select: none; font-weight: bold; color: #bbb; flex: 1; } .shiki-header i[class^="devicon-"] { font-size: 14px; margin-right: 2px; color: #bbb; } .shiki-header .shiki-copy { background: #171717; border-radius: 3px; border: none; color: #bbb; cursor: pointer; font-size: 12px; font-weight: bold; padding: 1px 10px; position: absolute; top: 7px; right: 8px; z-index: 1; } .shiki-header .shiki-copy:hover { color: white; } pre.shiki { margin: 0; padding: 1em; overflow-x: auto; font-size: 14px; line-height: 1.5; border: 1px solid #171717; background: none !important; } pre.shiki code { background: none !important; } `); } init(); })();