Last active
March 21, 2026 16:04
-
-
Save orange030/fae181fd79c73cc19a3f4c7a9b22032b to your computer and use it in GitHub Desktop.
为ChatGPT提供GDScript代码高亮的油猴脚本
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name ChatGPT GDScript Syntax Highlighter | |
| // @name:zh-CN ChatGPT GDScript 代码高亮 | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.1 | |
| // @description Highlights GDScript code in the ChatGPT web interface using Prism.js. | |
| // @description:zh-CN 为 ChatGPT 网页版的 GDScript 代码片段提供语法高亮,自动适配暗色/亮色主题,基于 Prism.js。 | |
| // @author Anonymous | |
| // @match https://chatgpt.com/* | |
| // @require https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js | |
| // @require https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-gdscript.min.js | |
| // @grant GM_addStyle | |
| // @run-at document-end | |
| // @license MIT | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| if (typeof Prism === 'undefined') { | |
| console.error('❌ [GDScript Highlighter] 核心库 Prism.js 未加载。'); | |
| return; | |
| } | |
| // 1. 创建 TrustedHTML 策略 (应对潜在的 CSP 限制) | |
| let ttPolicy; | |
| if (window.trustedTypes && window.trustedTypes.createPolicy) { | |
| try { | |
| const policyName = 'gdscript-policy-gpt-' + Math.random().toString(36).substring(2, 9); | |
| ttPolicy = window.trustedTypes.createPolicy(policyName, { | |
| createHTML: (string) => string | |
| }); | |
| } catch (e) { | |
| console.error('❌ [GDScript Highlighter] TrustedTypes 策略创建失败:', e); | |
| } | |
| } | |
| // 2. 实时检测 ChatGPT 网页的实际主题模式 | |
| function updateThemeMode() { | |
| const textColor = window.getComputedStyle(document.body).color; | |
| const match = textColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); | |
| let isDarkMode = true; | |
| if (match) { | |
| const r = parseInt(match[1], 10); | |
| const g = parseInt(match[2], 10); | |
| const b = parseInt(match[3], 10); | |
| // 通过 RGB 计算视觉亮度 (Luma) | |
| const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; | |
| isDarkMode = luma > 128; // 亮度大于 128 (文字发白),即为暗色背景 | |
| } | |
| document.documentElement.setAttribute('data-gds-theme', isDarkMode ? 'dark' : 'light'); | |
| } | |
| const themeObserver = new MutationObserver((mutations) => { | |
| for (let m of mutations) { | |
| if (m.type === 'attributes' && (m.attributeName === 'class' || m.attributeName === 'style' || m.attributeName === 'data-theme')) { | |
| updateThemeMode(); | |
| break; | |
| } | |
| } | |
| }); | |
| // ChatGPT 的主题通常挂载在 html class 上(例如 "light" 或 "dark") | |
| themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'style', 'data-theme'] }); | |
| themeObserver.observe(document.body, { attributes: true, attributeFilter: ['class', 'style'] }); | |
| updateThemeMode(); | |
| // 3. 注入统一的高亮样式 (兼容 ChatGPT 的 div 容器) | |
| GM_addStyle(` | |
| .gdscript-injected { | |
| background: transparent !important; | |
| text-shadow: none !important; | |
| font-family: inherit !important; | |
| tab-size: 4 !important; | |
| } | |
| /* ====== 浅色主题 ====== */ | |
| html[data-gds-theme="light"] .gdscript-injected { color: #24292e !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.comment { color: #6a737d !important; font-style: italic !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.punctuation { color: #24292e !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.keyword { color: #d73a49 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.function { color: #6f42c1 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.string { color: #032f62 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.number { color: #005cc5 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.class-name, | |
| html[data-gds-theme="light"] .gdscript-injected .token.builtin { color: #e36209 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.operator { color: #d73a49 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.boolean, | |
| html[data-gds-theme="light"] .gdscript-injected .token.property, | |
| html[data-gds-theme="light"] .gdscript-injected .token.constant { color: #005cc5 !important; } | |
| html[data-gds-theme="light"] .gdscript-injected .token.variable { color: #e36209 !important; } | |
| /* ====== 深色主题 ====== */ | |
| html[data-gds-theme="dark"] .gdscript-injected { color: #d4d4d4 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.comment { color: #6a9955 !important; font-style: italic !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.punctuation { color: #d4d4d4 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.keyword { color: #569cd6 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.function { color: #dcdcaa !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.string { color: #ce9178 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.number { color: #b5cea8 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.class-name, | |
| html[data-gds-theme="dark"] .gdscript-injected .token.builtin { color: #4ec9b0 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.operator { color: #d4d4d4 !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.boolean, | |
| html[data-gds-theme="dark"] .gdscript-injected .token.property, | |
| html[data-gds-theme="dark"] .gdscript-injected .token.variable { color: #9cdcfe !important; } | |
| html[data-gds-theme="dark"] .gdscript-injected .token.constant { color: #4fc1ff !important; } | |
| `); | |
| // 4. 执行 GDScript 识别与渲染 (适配 ChatGPT 结构) | |
| function highlightGDScript() { | |
| const pres = document.querySelectorAll('pre'); | |
| pres.forEach(pre => { | |
| // 查找顶部标题栏区域,ChatGPT 通常在这里标明语言 | |
| const header = pre.querySelector('.bg-token-bg-elevated-secondary'); | |
| // 验证是否包含 gdscript 标识 | |
| if (header && header.textContent.toLowerCase().includes('gdscript')) { | |
| // ChatGPT 代码正文放置在 .cm-content 内 | |
| const contentDiv = pre.querySelector('.cm-content'); | |
| if (contentDiv) { | |
| // 使用 innerText 可以自然提取出带 \n 的纯文本 | |
| const rawText = contentDiv.innerText; | |
| // 避免打断流式输出 | |
| if (contentDiv.dataset.rawText === rawText) return; | |
| contentDiv.dataset.rawText = rawText; | |
| contentDiv.classList.add('gdscript-injected', 'language-gdscript'); | |
| // 利用 Prism.js 生成标准高亮 HTML | |
| const highlightedHTML = Prism.highlight(rawText, Prism.languages.gdscript, 'gdscript'); | |
| // 核心适配:将 \n 转换回 <br>,以兼容 ChatGPT 的 CodeMirror div 结构 | |
| const finalHTML = highlightedHTML.replace(/\n/g, '<br>'); | |
| if (ttPolicy) { | |
| contentDiv.innerHTML = ttPolicy.createHTML(finalHTML); | |
| } else { | |
| contentDiv.innerHTML = finalHTML; | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // 5. 监听页面变化,适配流式输出 | |
| let debounceTimer = null; | |
| const domObserver = new MutationObserver(() => { | |
| clearTimeout(debounceTimer); | |
| debounceTimer = setTimeout(highlightGDScript, 300); | |
| }); | |
| domObserver.observe(document.body, { childList: true, subtree: true, characterData: true }); | |
| // 初始化执行 | |
| setTimeout(highlightGDScript, 500); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment