Private
Public Access
1
0

新增:Markdown 本地文件链接支持 + Shell 语法高亮

Markdown 预览增强:
- 支持点击本地文件链接(相对路径)打开对应文件
- 支持链接文本中的加粗/斜体等内联语法
- 锚点链接保持页面内跳转,外部链接新窗口打开

代码高亮增强:
- 添加 sh/bash/shell 语言别名映射
- 安装 @codemirror/legacy-modes 支持 .sh 文件语法高亮
This commit is contained in:
2026-02-27 18:09:27 +08:00
parent a6f99e0c49
commit c5e6ff3ba6
7 changed files with 268 additions and 73 deletions

View File

@@ -1,9 +1,26 @@
import { marked } from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/lib/common'
// 额外导入 common 包不包含的语言
import 'highlight.js/lib/languages/bash'
import 'highlight.js/lib/languages/go'
import 'highlight.js/styles/github-dark.css'
import 'highlight.js/styles/github.css'
// 语言别名映射sh -> bash 等)
const languageAliases: Record<string, string> = {
'sh': 'bash',
'shell': 'bash',
'zsh': 'bash',
'ksh': 'bash',
'ts': 'typescript',
'js': 'javascript',
'py': 'python',
'rb': 'ruby',
'yml': 'yaml',
'md': 'markdown'
}
let mermaidInstance: typeof import('mermaid').default | null = null
async function loadMermaid() {
@@ -30,7 +47,15 @@ renderer.code = function(token: any) {
return `<pre class="mermaid">${token.text}</pre>`
}
const lang = hljs.getLanguage(token.lang) ? token.lang : 'plaintext'
// 获取语言,支持别名
let lang = token.lang || 'plaintext'
lang = languageAliases[lang] || lang
// 检查语言是否支持
if (!hljs.getLanguage(lang)) {
lang = 'plaintext'
}
const highlighted = hljs.highlight(token.text, { language: lang }).value
return `<pre><code class="hljs language-${lang}" data-theme="auto">${highlighted}</code></pre>`
}
@@ -53,6 +78,40 @@ renderer.heading = function(token: any) {
</h${depth}>`
}
// 判断是否为本地文件链接(相对路径或本地绝对路径)
const isLocalFileLink = (href: string): boolean => {
if (!href) return false
// 排除 http/https/ftp/mailto 等外部链接
if (/^(https?|ftp|mailto|tel|data):/i.test(href)) return false
// 排除锚点链接
if (href.startsWith('#')) return false
// 相对路径或本地路径(如 ./file.md, ../file.md, /path/to/file, C:\path\file
return true
}
// 自定义链接渲染器 - 支持本地文件链接
renderer.link = function(token: any) {
const href = token.href || ''
// 解析链接文本中的内联元素(如加粗、斜体等)
const text = this.parser.parseInline(token.tokens) || token.text || ''
const title = token.title || ''
const titleAttr = title ? ` title="${title}"` : ''
// 锚点链接 - 保持原样,页面内跳转
if (href.startsWith('#')) {
return `<a href="${href}"${titleAttr}>${text}</a>`
}
// 判断是否为本地文件链接
if (isLocalFileLink(href)) {
return `<a href="javascript:void(0)" data-local-link="${href}" class="local-file-link"${titleAttr}>${text}</a>`
}
// 外部链接使用默认行为
return `<a href="${href}" target="_blank" rel="noopener noreferrer"${titleAttr}>${text}</a>`
}
marked.use({ renderer, breaks: true, gfm: true })
export { marked }