feat(editor): Shiki highlighting for code files in PlanView and SkillsPage
Reuse the file-editor Shiki extension for the PlanView and SkillsPage editors, gated to non-markdown files. Markdown sources keep the lezer highlighter (its markdown-aware styling is better for editing and there's no Shiki view to match). - PlanView: code files opened through it get Shiki colors; plan .md stays lezer. - SkillsPage: code supporting files get Shiki colors; SKILL.md stays lezer.
This commit is contained in:
@@ -35,6 +35,9 @@ import {
|
|||||||
import { useI18n } from '@/lib/i18n';
|
import { useI18n } from '@/lib/i18n';
|
||||||
import { languageByExtension } from '@/lib/codemirror/languageByExtension';
|
import { languageByExtension } from '@/lib/codemirror/languageByExtension';
|
||||||
import { createFlexokiCodeMirrorTheme } from '@/lib/codemirror/flexokiTheme';
|
import { createFlexokiCodeMirrorTheme } from '@/lib/codemirror/flexokiTheme';
|
||||||
|
import { shikiHighlightExtension } from '@/lib/codemirror/shikiHighlight';
|
||||||
|
import { getResolvedShikiTheme } from '@/lib/shiki/appThemeRegistry';
|
||||||
|
import { getLanguageFromExtension } from '@/lib/toolHelpers';
|
||||||
import { useThemeSystem } from '@/contexts/useThemeSystem';
|
import { useThemeSystem } from '@/contexts/useThemeSystem';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
@@ -253,11 +256,21 @@ const SkillsInstalledPage: React.FC = () => {
|
|||||||
|
|
||||||
const supportingFileEditorExtensions = React.useMemo<Extension[]>(() => {
|
const supportingFileEditorExtensions = React.useMemo<Extension[]>(() => {
|
||||||
const filePath = newFileName.trim() || 'supporting-file.md';
|
const filePath = newFileName.trim() || 'supporting-file.md';
|
||||||
const extensions: Extension[] = [createFlexokiCodeMirrorTheme(currentTheme)];
|
// Shiki token colors for code supporting files; markdown stays on lezer.
|
||||||
|
const shikiLanguage = getLanguageFromExtension(filePath);
|
||||||
|
const useShiki = Boolean(shikiLanguage) && shikiLanguage !== 'markdown';
|
||||||
|
const extensions: Extension[] = [createFlexokiCodeMirrorTheme(currentTheme, useShiki ? { syntaxColors: false } : undefined)];
|
||||||
const languageExtension = languageByExtension(filePath);
|
const languageExtension = languageByExtension(filePath);
|
||||||
if (languageExtension) {
|
if (languageExtension) {
|
||||||
extensions.push(languageExtension);
|
extensions.push(languageExtension);
|
||||||
}
|
}
|
||||||
|
if (useShiki && shikiLanguage) {
|
||||||
|
extensions.push(shikiHighlightExtension({
|
||||||
|
language: shikiLanguage,
|
||||||
|
themeName: currentTheme.metadata.id,
|
||||||
|
theme: getResolvedShikiTheme(currentTheme),
|
||||||
|
}));
|
||||||
|
}
|
||||||
extensions.push(EditorView.lineWrapping);
|
extensions.push(EditorView.lineWrapping);
|
||||||
return extensions;
|
return extensions;
|
||||||
}, [currentTheme, newFileName]);
|
}, [currentTheme, newFileName]);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import { getLanguageFromExtension } from '@/lib/toolHelpers';
|
|||||||
import { useDeviceInfo } from '@/lib/device';
|
import { useDeviceInfo } from '@/lib/device';
|
||||||
import { useThemeSystem } from '@/contexts/useThemeSystem';
|
import { useThemeSystem } from '@/contexts/useThemeSystem';
|
||||||
import { createFlexokiCodeMirrorTheme } from '@/lib/codemirror/flexokiTheme';
|
import { createFlexokiCodeMirrorTheme } from '@/lib/codemirror/flexokiTheme';
|
||||||
|
import { shikiHighlightExtension } from '@/lib/codemirror/shikiHighlight';
|
||||||
|
import { getResolvedShikiTheme } from '@/lib/shiki/appThemeRegistry';
|
||||||
import { languageByExtension } from '@/lib/codemirror/languageByExtension';
|
import { languageByExtension } from '@/lib/codemirror/languageByExtension';
|
||||||
import { useSessionUIStore } from '@/sync/session-ui-store';
|
import { useSessionUIStore } from '@/sync/session-ui-store';
|
||||||
import { useSessions } from '@/sync/sync-context';
|
import { useSessions } from '@/sync/sync-context';
|
||||||
@@ -344,11 +346,22 @@ export const PlanView: React.FC<PlanViewProps> = ({ targetPath = null }) => {
|
|||||||
}, [cancel, commentText, editingDraftId, isMobile, lineSelection]);
|
}, [cancel, commentText, editingDraftId, isMobile, lineSelection]);
|
||||||
|
|
||||||
const editorExtensions = React.useMemo(() => {
|
const editorExtensions = React.useMemo(() => {
|
||||||
const extensions = [createFlexokiCodeMirrorTheme(currentTheme)];
|
// Shiki token colors only for code files; markdown keeps the lezer
|
||||||
|
// highlighter (markdown-aware bold headings etc., and no Shiki view to match).
|
||||||
|
const shikiLanguage = resolvedPath ? getLanguageFromExtension(resolvedPath) : null;
|
||||||
|
const useShiki = Boolean(shikiLanguage) && shikiLanguage !== 'markdown';
|
||||||
|
const extensions = [createFlexokiCodeMirrorTheme(currentTheme, useShiki ? { syntaxColors: false } : undefined)];
|
||||||
const language = languageByExtension(resolvedPath || 'plan.md');
|
const language = languageByExtension(resolvedPath || 'plan.md');
|
||||||
if (language) {
|
if (language) {
|
||||||
extensions.push(language);
|
extensions.push(language);
|
||||||
}
|
}
|
||||||
|
if (useShiki && shikiLanguage) {
|
||||||
|
extensions.push(shikiHighlightExtension({
|
||||||
|
language: shikiLanguage,
|
||||||
|
themeName: currentTheme.metadata.id,
|
||||||
|
theme: getResolvedShikiTheme(currentTheme),
|
||||||
|
}));
|
||||||
|
}
|
||||||
extensions.push(EditorView.lineWrapping);
|
extensions.push(EditorView.lineWrapping);
|
||||||
return extensions;
|
return extensions;
|
||||||
}, [currentTheme, resolvedPath]);
|
}, [currentTheme, resolvedPath]);
|
||||||
|
|||||||
Reference in New Issue
Block a user