fix(editor): 保留完整代码语言列表与兼容高亮
This commit is contained in:
@@ -56,6 +56,12 @@ describe('VisualMarkdownEditor formatting toolbars', () => {
|
|||||||
const config = editor.action(ctx => ctx.get(codeBlockConfig.key))
|
const config = editor.action(ctx => ctx.get(codeBlockConfig.key))
|
||||||
const matching = config.languages.filter(item => item.alias.includes('python'))
|
const matching = config.languages.filter(item => item.alias.includes('python'))
|
||||||
expect(matching).toHaveLength(1)
|
expect(matching).toHaveLength(1)
|
||||||
|
for (const name of ['Java', 'Go', 'Rust']) {
|
||||||
|
const language = config.languages.find(item => item.name === name)
|
||||||
|
expect(language, `${name} remains available`).toBeDefined()
|
||||||
|
const support = await language!.load()
|
||||||
|
expect(support.language.parser.parse('class Example {}').length).toBe(16)
|
||||||
|
}
|
||||||
const cm = new CodeMirror({ doc: 'print("Hello")', extensions: [...config.extensions, await matching[0]!.load()] })
|
const cm = new CodeMirror({ doc: 'print("Hello")', extensions: [...config.extensions, await matching[0]!.load()] })
|
||||||
try {
|
try {
|
||||||
const string = [...cm.dom.querySelectorAll<HTMLElement>('.shiki-token')].find(el => el.textContent?.includes('Hello'))
|
const string = [...cm.dom.querySelectorAll<HTMLElement>('.shiki-token')].find(el => el.textContent?.includes('Hello'))
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ onMounted(async () => {
|
|||||||
// Replace both AFTER feature configuration to avoid default grammar collisions.
|
// Replace both AFTER feature configuration to avoid default grammar collisions.
|
||||||
crepe.editor.config(ctx => ctx.update(codeBlockConfig.key, config => ({
|
crepe.editor.config(ctx => ctx.update(codeBlockConfig.key, config => ({
|
||||||
...config,
|
...config,
|
||||||
languages: shikiLanguages(themeStore.resolvedCodeBlockTheme),
|
languages: shikiLanguages(themeStore.resolvedCodeBlockTheme, config.languages),
|
||||||
extensions: [basicSetup, keymap.of([indentWithTab]), shikiEditorTheme(themeStore.resolvedCodeBlockTheme)],
|
extensions: [basicSetup, keymap.of([indentWithTab]), shikiEditorTheme(themeStore.resolvedCodeBlockTheme)],
|
||||||
})))
|
})))
|
||||||
crepe.editor.use(fontSizeMarkdownPlugin)
|
crepe.editor.use(fontSizeMarkdownPlugin)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// @vitest-environment happy-dom
|
// @vitest-environment happy-dom
|
||||||
import { afterEach, expect, it } from 'vitest'
|
import { afterEach, expect, it } from 'vitest'
|
||||||
import { Compartment } from '@codemirror/state'
|
import { Compartment } from '@codemirror/state'
|
||||||
|
import { LanguageDescription } from '@codemirror/language'
|
||||||
import { EditorView } from '@codemirror/view'
|
import { EditorView } from '@codemirror/view'
|
||||||
import { shikiLanguage, shikiLanguages } from './shikiCodeMirror'
|
import { shikiLanguage, shikiLanguages } from './shikiCodeMirror'
|
||||||
import { getCodeTokenizer } from '@/utils/markdown'
|
import { getCodeTokenizer } from '@/utils/markdown'
|
||||||
@@ -41,3 +42,16 @@ it('offers fenced-code aliases and retains the LaTeX selector', () => {
|
|||||||
expect(languages.find(item => item.name === 'Python')?.alias).toContain('py')
|
expect(languages.find(item => item.name === 'Python')?.alias).toContain('py')
|
||||||
expect(languages.find(item => item.name === 'LaTeX')?.alias).toContain('latex')
|
expect(languages.find(item => item.name === 'LaTeX')?.alias).toContain('latex')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('preserves original loaders and metadata while replacing supported languages', async () => {
|
||||||
|
const originalPython = LanguageDescription.of({ name: 'Python', alias: ['py', 'custom-python'], extensions: ['py'], filename: /^SConstruct$/, load: () => shikiLanguage('text', 'github-light') })
|
||||||
|
const originalRust = LanguageDescription.of({ name: 'Rust', alias: ['rs'], extensions: ['rs'], load: () => shikiLanguage('text', 'github-light') })
|
||||||
|
const languages = shikiLanguages('github-dark', [originalPython, originalRust])
|
||||||
|
expect(languages.find(item => item.name === 'Rust')).toBe(originalRust)
|
||||||
|
const python = languages.find(item => item.name === 'Python')!
|
||||||
|
expect(languages.filter(item => item.alias.includes('python'))).toHaveLength(1)
|
||||||
|
expect(python.alias).toContain('custom-python')
|
||||||
|
expect(python.extensions).toEqual(['py'])
|
||||||
|
expect(python.filename).toBe(originalPython.filename)
|
||||||
|
expect(await python.load()).not.toBe(await originalPython.load())
|
||||||
|
})
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ export async function shikiLanguage(language: string, theme: CodeTheme): Promise
|
|||||||
return new LanguageSupport(parser, highlights)
|
return new LanguageSupport(parser, highlights)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shikiLanguages(theme: CodeTheme): LanguageDescription[] {
|
export function shikiLanguages(theme: CodeTheme, originalLanguages: readonly LanguageDescription[] = []): LanguageDescription[] {
|
||||||
return [
|
const overrides = [
|
||||||
{ name: 'C', alias: ['c'] },
|
{ name: 'C', alias: ['c'] },
|
||||||
{ name: 'C++', alias: ['cpp', 'c++'] },
|
{ name: 'C++', alias: ['cpp', 'c++'] },
|
||||||
{ name: 'Python', alias: ['python', 'py'] },
|
{ name: 'Python', alias: ['python', 'py'] },
|
||||||
@@ -57,6 +57,22 @@ export function shikiLanguages(theme: CodeTheme): LanguageDescription[] {
|
|||||||
].map(({ name, alias }) => LanguageDescription.of({
|
].map(({ name, alias }) => LanguageDescription.of({
|
||||||
name, alias, load: () => shikiLanguage(alias[0]!, theme),
|
name, alias, load: () => shikiLanguage(alias[0]!, theme),
|
||||||
}))
|
}))
|
||||||
|
// Keep Crepe's full registry and lazy loaders for languages without Shiki grammars.
|
||||||
|
const remaining = new Map(overrides.map(language => [language.name.toLowerCase(), language]))
|
||||||
|
const languages = originalLanguages.map(original => {
|
||||||
|
const key = original.name.toLowerCase()
|
||||||
|
const replacement = remaining.get(key)
|
||||||
|
if (!replacement) return original
|
||||||
|
remaining.delete(key)
|
||||||
|
return LanguageDescription.of({
|
||||||
|
name: original.name,
|
||||||
|
alias: [...new Set([...original.alias, ...replacement.alias])],
|
||||||
|
extensions: original.extensions,
|
||||||
|
filename: original.filename,
|
||||||
|
load: () => replacement.load(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return [...languages, ...remaining.values()]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shikiEditorTheme(theme: CodeTheme) {
|
export function shikiEditorTheme(theme: CodeTheme) {
|
||||||
|
|||||||
Reference in New Issue
Block a user