238 lines
6.5 KiB
TypeScript
238 lines
6.5 KiB
TypeScript
/**
|
||
* 代码高亮组件
|
||
*
|
||
* 功能说明:
|
||
* - 使用 highlight.js 提供专业的代码语法高亮
|
||
* - 支持多种编程语言(Verilog, JavaScript, Python 等)
|
||
* - 提供行内代码和代码块的不同样式
|
||
* - 自动检测语言类型
|
||
*/
|
||
|
||
/**
|
||
* 获取 highlight.js 的 CDN 链接
|
||
*/
|
||
export function getHighlightJsLinks(): string {
|
||
return `
|
||
<!-- Highlight.js CSS (VS Code Dark+ 主题) -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css">
|
||
<!-- Highlight.js 核心库 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||
<!-- Verilog 语言支持 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/verilog.min.js"></script>
|
||
`;
|
||
}
|
||
|
||
/**
|
||
* 获取代码高亮的样式
|
||
*/
|
||
export function getCodeHighlightStyles(): string {
|
||
return `
|
||
/* 代码块基础样式 */
|
||
.segment-text pre {
|
||
background: var(--vscode-textCodeBlock-background);
|
||
border: 1px solid var(--vscode-panel-border);
|
||
border-radius: 6px;
|
||
padding: 12px;
|
||
overflow-x: auto;
|
||
margin: 12px 0;
|
||
position: relative;
|
||
white-space: pre;
|
||
}
|
||
|
||
.segment-text pre code {
|
||
background: transparent !important;
|
||
padding: 0;
|
||
border: none;
|
||
display: block;
|
||
line-height: 1.5;
|
||
white-space: pre;
|
||
font-family: 'Courier New', Consolas, 'Monaco', monospace;
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
/* 行内代码样式 */
|
||
.segment-text code:not(pre code) {
|
||
background: var(--vscode-textCodeBlock-background);
|
||
padding: 2px 6px;
|
||
border-radius: 3px;
|
||
color: var(--vscode-textPreformat-foreground);
|
||
border: 1px solid var(--vscode-panel-border);
|
||
font-family: 'Courier New', Consolas, 'Monaco', monospace;
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
/* 覆盖 highlight.js 的背景色,使用 VSCode 主题色 */
|
||
.segment-text pre code.hljs {
|
||
background: transparent !important;
|
||
padding: 0 !important;
|
||
}
|
||
|
||
/* 代码块语言标签 */
|
||
.code-block-wrapper {
|
||
position: relative;
|
||
margin: -20px 0;
|
||
}
|
||
|
||
.code-language-label {
|
||
position: absolute;
|
||
top: 8px;
|
||
right: 8px;
|
||
background: var(--vscode-badge-background);
|
||
color: var(--vscode-badge-foreground);
|
||
padding: 2px 8px;
|
||
border-radius: 3px;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
text-transform: uppercase;
|
||
opacity: 0.8;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* 代码块复制按钮 */
|
||
.code-copy-btn {
|
||
position: absolute;
|
||
top: 8px;
|
||
right: 8px;
|
||
background: var(--vscode-button-secondaryBackground);
|
||
color: var(--vscode-button-secondaryForeground);
|
||
border: 1px solid var(--vscode-button-border);
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
font-size: 11px;
|
||
cursor: pointer;
|
||
opacity: 0;
|
||
transition: opacity 0.2s ease;
|
||
z-index: 2;
|
||
}
|
||
|
||
.code-block-wrapper:hover .code-copy-btn {
|
||
opacity: 1;
|
||
}
|
||
|
||
.code-copy-btn:hover {
|
||
background: var(--vscode-button-secondaryHoverBackground);
|
||
}
|
||
|
||
.code-copy-btn.copied {
|
||
background: var(--vscode-button-background);
|
||
color: var(--vscode-button-foreground);
|
||
}
|
||
|
||
/* 代码块滚动条样式 */
|
||
.segment-text pre::-webkit-scrollbar {
|
||
height: 8px;
|
||
}
|
||
|
||
.segment-text pre::-webkit-scrollbar-track {
|
||
background: var(--vscode-scrollbarSlider-background);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.segment-text pre::-webkit-scrollbar-thumb {
|
||
background: var(--vscode-scrollbarSlider-hoverBackground);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.segment-text pre::-webkit-scrollbar-thumb:hover {
|
||
background: var(--vscode-scrollbarSlider-activeBackground);
|
||
}
|
||
`;
|
||
}
|
||
|
||
/**
|
||
* 获取代码高亮的脚本
|
||
*/
|
||
export function getCodeHighlightScript(): string {
|
||
return `
|
||
/**
|
||
* 使用 highlight.js 进行代码高亮
|
||
*/
|
||
function highlightCodeBlocks() {
|
||
// 等待 highlight.js 加载完成
|
||
if (typeof hljs === 'undefined') {
|
||
setTimeout(highlightCodeBlocks, 100);
|
||
return;
|
||
}
|
||
|
||
const codeBlocks = document.querySelectorAll('.segment-text pre code:not(.hljs)');
|
||
codeBlocks.forEach((block) => {
|
||
hljs.highlightElement(block);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 为代码块添加复制按钮
|
||
*/
|
||
function enhanceCodeBlocks() {
|
||
const codeBlocks = document.querySelectorAll('.segment-text pre code');
|
||
|
||
codeBlocks.forEach((codeElement) => {
|
||
const preElement = codeElement.parentElement;
|
||
if (!preElement || preElement.classList.contains('enhanced')) {
|
||
return;
|
||
}
|
||
|
||
// 标记为已增强,避免重复处理
|
||
preElement.classList.add('enhanced');
|
||
|
||
// 应用语法高亮
|
||
if (typeof hljs !== 'undefined' && !codeElement.classList.contains('hljs')) {
|
||
hljs.highlightElement(codeElement);
|
||
}
|
||
|
||
// 创建包装器
|
||
const wrapper = document.createElement('div');
|
||
wrapper.className = 'code-block-wrapper';
|
||
preElement.parentNode.insertBefore(wrapper, preElement);
|
||
wrapper.appendChild(preElement);
|
||
|
||
// 添加复制按钮
|
||
const copyBtn = document.createElement('button');
|
||
copyBtn.className = 'code-copy-btn';
|
||
copyBtn.textContent = '复制';
|
||
copyBtn.onclick = function() {
|
||
const code = codeElement.textContent;
|
||
navigator.clipboard.writeText(code).then(() => {
|
||
copyBtn.textContent = '已复制';
|
||
copyBtn.classList.add('copied');
|
||
setTimeout(() => {
|
||
copyBtn.textContent = '复制';
|
||
copyBtn.classList.remove('copied');
|
||
}, 2000);
|
||
});
|
||
};
|
||
wrapper.appendChild(copyBtn);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 监听 DOM 变化,自动增强新添加的代码块
|
||
*/
|
||
function observeCodeBlocks() {
|
||
const observer = new MutationObserver((mutations) => {
|
||
mutations.forEach((mutation) => {
|
||
if (mutation.addedNodes.length > 0) {
|
||
enhanceCodeBlocks();
|
||
}
|
||
});
|
||
});
|
||
|
||
observer.observe(document.getElementById('messages'), {
|
||
childList: true,
|
||
subtree: true
|
||
});
|
||
}
|
||
|
||
// 初始化代码块增强
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
enhanceCodeBlocks();
|
||
observeCodeBlocks();
|
||
});
|
||
} else {
|
||
enhanceCodeBlocks();
|
||
observeCodeBlocks();
|
||
}
|
||
`;
|
||
}
|