您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Renders Cursor Rules (*.mdc) markdown on GitHub into actual Markdown locally, using the marked library.
当前为
- // ==UserScript==
- // @name Cursor Rule Markdown Renderer for GitHub
- // @namespace http://tampermonkey.net/
- // @version 2025-05-27
- // @description Renders Cursor Rules (*.mdc) markdown on GitHub into actual Markdown locally, using the marked library.
- // @author Texarkanine
- // @match https://github.com/*
- // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANAAAACACAMAAABN9BexAAABRFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8NAl4NAAAAanRSTlMAAQIDBQcICQsMDg8SGBsfJSo2ODk6Ozw9P0FCREpQUVJTVFpfYWZnbHN0dXZ3eHl7gIKDhYaIiYqLjJiZnqCkp6ipr7CxsrO0vr/BwsPGx8nR1dfY2eDh4uPk5+jp7PHy8/T19vj5+v3+PVg6RwAAAAFiS0dEa1JlpZgAAAPiSURBVHja7d1rWxJBGAbgB3ABK+mgIZqVaUHhqXMQlNnJU6FFWYJWaB6Y//8D+iDsidnd2WXXeOea9xN+4IL7kn3mmUEB6E4iV96sHzByc1DfLI8nYJ/Uwj4jPPvzKatnZpcRn90ZEyf2qM3IT/t5vOuJv2VSzEpX9IxJMk86109bFlB7GgCSP5k000gBWGQSzRyQ2JcJtBdHzvTj+4k0yE164qOJkMVL44dFEJ0lw1DGhvH7AdlZ1RHr+K7fnqALmtQR39DSb6fpgoZ1RAvGyw+Ex6RQIAVSIAVSIAVSIAVSIAVSoP8D4h1E5MUeo8C7r6/n5uNufYFOciKesSMyINbMeD+tkQajA2JbmtcDDH1ilEDstdcDVBktkFcwFBg1kHsw8ANhoEGuweAQCIMNcgkGp0AYcJBzMFQZTZBTMBQYVRA/GJwDYeBB3GBwCYTBB3GCwS0QCIB6g6HKaIPswVBg1EHWYHAPBBIgSzB4BAINkCkYvAKBCMgIhiqTA9QNhgKTBXQWDN6BQAbEmhmhQKADYluaSCAQArFqlckFEh4FUiAFYkwwACpkQGIRXdPIgIQW0WYGdEAY9aw5JzlQAuGuSGGlBPLaKlRADeQeDDVN8JmVgy8ApXBBrsHQ2ZYLgGKvgnqWYyGDXIKhe3Ai8tpJvAvmWRtC2CDnYMj7uRhSn4N4ttMIH+QUDBV/V/fFL/49Xy8hChA/GGqaz7jK7Pj1NC4jEhA3GEzndKL5e8Xn/8f8uoqIQJxgMJ+kCi8o11p+PH+ziAzUGwz5QCvk1LG45+QmIgTZg6EScMmfPRX1tO8hUpA1GGpa0A5zXxRURLQgSzDY3tHzVcoES1AJUYNMwWB/z9UXSKwE2QpPJCAjGPJ91WaREmQvPNGAusFQ6XMf4F2CttM4F9BZMNS0fjc2XiWot/BEBMJIg/sWv++dmnsJ4hSeqEAYPeL9EYb/radbCeIVnshAyOfD2UuPHTp5DsdwnqDQDgecShC/8BAAOZQgh8JDAcQvQUXQBfFKUAmUQb0lyLHw0AD1lCDnwkMEZCtB22lQB1lKkFvhIQMylSDXwkMHpJcg98JDCNQ5CeKe8NAEYerYu/CQAmH21LPw0AKhWET4ICqjQAqkQAqkQAqkQAqkQAqkQOcA+qPfHKbruaAjfsv3oZMb+u0PdEFrOmLdfDa+RNXz0DC8wLhpx786SfA6Gr6xZiJcl+zDj5txYF4m0AMAyR/yeHZTAHBHno94v312WT2VBfS4kxPxFTk8b/QvfogtyPVFFgCmySfDzi3r8pSc2yO9/hSTPStuPFvaqLfoWVr19VLWeLX9A7BB7+nmPT+tAAAAAElFTkSuQmCC
- // @grant GM_addStyle
- // @require https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.7/marked.min.js
- // ==/UserScript==
- (function() {
- 'use strict';
- // Set to true to enable debug logging
- const DEBUG = false;
- // GitHub uses these specific selectors for file content display
- const CONTENT_SECTION = 'section';
- const MARKDOWN_SOURCE = '#read-only-cursor-text-area';
- // Only process .mdc files on GitHub
- const MDC_FILE_REGEX = /^https:\/\/github\.com\/.*\.mdc$/;
- // Cursor rules have YAML frontmatter that needs special handling
- const YAML_FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
- // GitHub-compatible markdown styles using GitHub's CSS variables for theme compatibility
- const MARKDOWN_CSS = `
- .markdown-body {
- box-sizing: border-box;
- min-width: 200px;
- max-width: 980px;
- margin: 0 auto;
- padding: 45px;
- background: var(--color-canvas-default, #fff);
- color: var(--color-fg-default, #24292f);
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
- font-size: 16px;
- line-height: 1.5;
- word-wrap: break-word;
- }
- .markdown-body h1, .markdown-body h2, .markdown-body h3,
- .markdown-body h4, .markdown-body h5, .markdown-body h6 {
- margin-top: 24px;
- margin-bottom: 16px;
- font-weight: 600;
- line-height: 1.25;
- }
- .markdown-body p {
- margin-top: 0;
- margin-bottom: 10px;
- }
- .markdown-body pre {
- background-color: #f6f8fa;
- padding: 16px;
- overflow: auto;
- border-radius: 6px;
- }
- .markdown-body code {
- background-color: #f6f8fa;
- padding: 0.2em 0.4em;
- border-radius: 6px;
- font-size: 85%;
- }
- .markdown-body blockquote {
- padding: 0 1em;
- color: #6a737d;
- border-left: 0.25em solid #dfe2e5;
- }
- .markdown-body ul, .markdown-body ol {
- padding-left: 2em;
- }
- .markdown-body table {
- border-collapse: collapse;
- display: block;
- width: 100%;
- overflow: auto;
- }
- .markdown-body th, .markdown-body td {
- border: 1px solid #dfe2e5;
- padding: 6px 13px;
- }
- `;
- let cssInjected = false;
- /**
- * Processes .mdc content by wrapping YAML frontmatter in code blocks.
- * This is necessary because cursor rules use YAML frontmatter that should
- * be displayed as code rather than parsed as markdown.
- */
- function processContent(rawContent) {
- const match = rawContent.match(YAML_FRONTMATTER_REGEX);
- if (match) {
- const [, yamlContent, markdownContent] = match;
- return `\`\`\`yaml\n${yamlContent}\n\`\`\`\n\n${markdownContent}`;
- }
- return rawContent;
- }
- /**
- * Injects GitHub-compatible markdown styles.
- * Uses GitHub's CSS variables to match the current theme automatically.
- */
- function injectStyles() {
- if (cssInjected) return;
- GM_addStyle(MARKDOWN_CSS);
- cssInjected = true;
- }
- /**
- * Renders the markdown content by replacing the section content.
- * Preserves the original textarea as hidden for potential future reference.
- */
- function renderMarkdown() {
- const section = document.querySelector(CONTENT_SECTION);
- const textarea = document.querySelector(MARKDOWN_SOURCE);
- if (!section || !textarea) {
- return false;
- }
- const rawContent = textarea.textContent;
- if (!rawContent) {
- return false;
- }
- // Process content and render markdown
- const processedContent = processContent(rawContent);
- const markdownDiv = document.createElement('div');
- markdownDiv.className = 'markdown-body';
- markdownDiv.innerHTML = marked.parse(processedContent);
- // Replace section content while preserving the original textarea
- section.innerHTML = '';
- textarea.style.display = 'none'; // Keep textarea but hide it
- section.appendChild(textarea);
- section.appendChild(markdownDiv);
- injectStyles();
- return true;
- }
- let contentObserver = null;
- let lastContent = '';
- /**
- * Sets up observation of the textarea content changes.
- * This ensures we only render when the actual content changes, not stale content.
- */
- function observeContentChanges() {
- // Clean up any existing observer
- if (contentObserver) {
- contentObserver.disconnect();
- contentObserver = null;
- }
- const textarea = document.querySelector(MARKDOWN_SOURCE);
- if (!textarea) {
- return false;
- }
- // Check if content is different from last render
- const currentContent = textarea.textContent;
- if (currentContent && currentContent !== lastContent) {
- lastContent = currentContent;
- if (renderMarkdown()) {
- DEBUG && console.log('[mdc-render] Successfully rendered markdown');
- }
- }
- // Set up observer for future content changes
- contentObserver = new MutationObserver(() => {
- const newContent = textarea.textContent;
- if (newContent && newContent !== lastContent) {
- lastContent = newContent;
- if (renderMarkdown()) {
- DEBUG && console.log('[mdc-render] Content changed, re-rendered markdown');
- }
- }
- });
- // Observe changes to the textarea's text content
- contentObserver.observe(textarea, {
- childList: true,
- subtree: true,
- characterData: true
- });
- return true;
- }
- /**
- * Waits for the textarea to appear, then sets up content observation.
- * GitHub loads content asynchronously, so we need to wait for the textarea.
- */
- function waitForTextareaAndObserve() {
- let attempts = 0;
- const maxAttempts = 100; // 10 seconds at 100ms intervals
- const checkInterval = setInterval(() => {
- attempts++;
- if (observeContentChanges()) {
- clearInterval(checkInterval);
- DEBUG && console.log('[mdc-render] Set up content observation');
- } else if (attempts >= maxAttempts) {
- clearInterval(checkInterval);
- DEBUG && console.log('[mdc-render] Timeout waiting for textarea');
- }
- }, 100);
- }
- /**
- * Handles URL changes to detect navigation to .mdc files.
- * GitHub is a SPA, so we need to monitor URL changes via DOM mutations.
- */
- function handleUrlChange() {
- if (MDC_FILE_REGEX.test(location.href)) {
- DEBUG && console.log('[mdc-render] MDC file detected:', location.href);
- waitForTextareaAndObserve();
- }
- }
- // Initialize: handle current page and set up URL change detection
- let currentUrl = location.href;
- handleUrlChange();
- // Monitor for URL changes in GitHub's SPA
- new MutationObserver(() => {
- if (location.href !== currentUrl) {
- currentUrl = location.href;
- handleUrlChange();
- }
- }).observe(document, { subtree: true, childList: true });
- })();