refactor(editor): remove code block service (#11010)

This commit is contained in:
Saul-Mirone
2025-03-19 13:38:10 +00:00
parent 1c6a876e6a
commit ee65d66d67
5 changed files with 55 additions and 53 deletions

View File

@@ -1,10 +1,8 @@
import { CodeBlockSchema, ColorScheme } from '@blocksuite/affine-model'; import { ColorScheme } from '@blocksuite/affine-model';
import { textKeymap } from '@blocksuite/affine-rich-text';
import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { BlockService } from '@blocksuite/block-std'; import { LifeCycleWatcher } from '@blocksuite/block-std';
import { type Signal, signal } from '@preact/signals-core'; import { type Signal, signal } from '@preact/signals-core';
import { import {
bundledLanguagesInfo,
createHighlighterCore, createHighlighterCore,
createOnigurumaEngine, createOnigurumaEngine,
type HighlighterCore, type HighlighterCore,
@@ -18,8 +16,8 @@ import {
CODE_BLOCK_DEFAULT_LIGHT_THEME, CODE_BLOCK_DEFAULT_LIGHT_THEME,
} from './highlight/const.js'; } from './highlight/const.js';
export class CodeBlockService extends BlockService { export class CodeBlockHighlighter extends LifeCycleWatcher {
static override readonly flavour = CodeBlockSchema.model.flavour; static override key = 'code-block-highlighter';
private _darkThemeKey: string | undefined; private _darkThemeKey: string | undefined;
@@ -27,13 +25,6 @@ export class CodeBlockService extends BlockService {
highlighter$: Signal<HighlighterCore | null> = signal(null); highlighter$: Signal<HighlighterCore | null> = signal(null);
get langs() {
return (
this.std.getOptional(CodeBlockConfigExtension.identifier)?.langs ??
bundledLanguagesInfo
);
}
get themeKey() { get themeKey() {
const theme = this.std.get(ThemeProvider).theme$.value; const theme = this.std.get(ThemeProvider).theme$.value;
return theme === ColorScheme.Dark return theme === ColorScheme.Dark
@@ -41,35 +32,31 @@ export class CodeBlockService extends BlockService {
: this._lightThemeKey; : this._lightThemeKey;
} }
private readonly _loadTheme = async (
highlighter: HighlighterCore
): Promise<void> => {
const config = this.std.getOptional(CodeBlockConfigExtension.identifier);
const darkTheme = config?.theme?.dark ?? CODE_BLOCK_DEFAULT_DARK_THEME;
const lightTheme = config?.theme?.light ?? CODE_BLOCK_DEFAULT_LIGHT_THEME;
this._darkThemeKey = (await normalizeGetter(darkTheme)).name;
this._lightThemeKey = (await normalizeGetter(lightTheme)).name;
await highlighter.loadTheme(darkTheme, lightTheme);
this.highlighter$.value = highlighter;
};
override mounted(): void { override mounted(): void {
super.mounted(); super.mounted();
this.bindHotKey(textKeymap(this.std));
createHighlighterCore({ createHighlighterCore({
engine: createOnigurumaEngine(() => getWasm), engine: createOnigurumaEngine(() => getWasm),
}) })
.then(async highlighter => { .then(this._loadTheme)
const config = this.std.getOptional(
CodeBlockConfigExtension.identifier
);
const darkTheme = config?.theme?.dark ?? CODE_BLOCK_DEFAULT_DARK_THEME;
const lightTheme =
config?.theme?.light ?? CODE_BLOCK_DEFAULT_LIGHT_THEME;
this._darkThemeKey = (await normalizeGetter(darkTheme)).name;
this._lightThemeKey = (await normalizeGetter(lightTheme)).name;
await highlighter.loadTheme(darkTheme, lightTheme);
this.highlighter$.value = highlighter;
this.disposables.add(() => {
highlighter.dispose();
});
})
.catch(console.error); .catch(console.error);
} }
override unmounted(): void {
this.highlighter$.value?.dispose();
}
} }
/** /**

View File

@@ -12,7 +12,8 @@ import {
CodeBlockInlineManagerExtension, CodeBlockInlineManagerExtension,
CodeBlockUnitSpecExtension, CodeBlockUnitSpecExtension,
} from './code-block-inline.js'; } from './code-block-inline.js';
import { CodeBlockService } from './code-block-service.js'; import { CodeBlockHighlighter } from './code-block-service.js';
import { CodeKeymapExtension } from './code-keymap.js';
import { AFFINE_CODE_TOOLBAR_WIDGET } from './code-toolbar/index.js'; import { AFFINE_CODE_TOOLBAR_WIDGET } from './code-toolbar/index.js';
import { codeSlashMenuConfig } from './configs/slash-menu.js'; import { codeSlashMenuConfig } from './configs/slash-menu.js';
@@ -24,11 +25,12 @@ export const codeToolbarWidget = WidgetViewExtension(
export const CodeBlockSpec: ExtensionType[] = [ export const CodeBlockSpec: ExtensionType[] = [
FlavourExtension('affine:code'), FlavourExtension('affine:code'),
CodeBlockService, CodeBlockHighlighter,
BlockViewExtension('affine:code', literal`affine-code`), BlockViewExtension('affine:code', literal`affine-code`),
codeToolbarWidget, codeToolbarWidget,
CodeBlockInlineManagerExtension, CodeBlockInlineManagerExtension,
CodeBlockUnitSpecExtension, CodeBlockUnitSpecExtension,
CodeBlockAdapterExtensions, CodeBlockAdapterExtensions,
SlashMenuConfigExtension('affine:code', codeSlashMenuConfig), SlashMenuConfigExtension('affine:code', codeSlashMenuConfig),
CodeKeymapExtension,
].flat(); ].flat();

View File

@@ -26,18 +26,15 @@ import { computed, effect, type Signal, signal } from '@preact/signals-core';
import { html, nothing, type TemplateResult } from 'lit'; import { html, nothing, type TemplateResult } from 'lit';
import { query } from 'lit/decorators.js'; import { query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js'; import { classMap } from 'lit/directives/class-map.js';
import type { ThemedToken } from 'shiki'; import { bundledLanguagesInfo, type ThemedToken } from 'shiki';
import { CodeClipboardController } from './clipboard/index.js'; import { CodeClipboardController } from './clipboard/index.js';
import { CodeBlockConfigExtension } from './code-block-config.js'; import { CodeBlockConfigExtension } from './code-block-config.js';
import { CodeBlockInlineManagerExtension } from './code-block-inline.js'; import { CodeBlockInlineManagerExtension } from './code-block-inline.js';
import type { CodeBlockService } from './code-block-service.js'; import { CodeBlockHighlighter } from './code-block-service.js';
import { codeBlockStyles } from './styles.js'; import { codeBlockStyles } from './styles.js';
export class CodeBlockComponent extends CaptionedBlockComponent< export class CodeBlockComponent extends CaptionedBlockComponent<CodeBlockModel> {
CodeBlockModel,
CodeBlockService
> {
static override styles = codeBlockStyles; static override styles = codeBlockStyles;
private _inlineRangeProvider: InlineRangeProvider | null = null; private _inlineRangeProvider: InlineRangeProvider | null = null;
@@ -52,7 +49,7 @@ export class CodeBlockComponent extends CaptionedBlockComponent<
return 'Plain Text'; return 'Plain Text';
} }
const matchedInfo = this.service.langs.find(info => info.id === lang); const matchedInfo = this.langs.find(info => info.id === lang);
return matchedInfo ? matchedInfo.name : 'Plain Text'; return matchedInfo ? matchedInfo.name : 'Plain Text';
}); });
@@ -75,6 +72,17 @@ export class CodeBlockComponent extends CaptionedBlockComponent<
return this.doc.readonly; return this.doc.readonly;
} }
get langs() {
return (
this.std.getOptional(CodeBlockConfigExtension.identifier)?.langs ??
bundledLanguagesInfo
);
}
get highlighter() {
return this.std.get(CodeBlockHighlighter);
}
override get topContenteditableElement() { override get topContenteditableElement() {
if (this.std.get(DocModeProvider).getEditorMode() === 'edgeless') { if (this.std.get(DocModeProvider).getEditorMode() === 'edgeless') {
return this.closest<BlockComponent>(NOTE_SELECTOR); return this.closest<BlockComponent>(NOTE_SELECTOR);
@@ -89,7 +97,7 @@ export class CodeBlockComponent extends CaptionedBlockComponent<
return; return;
} }
const matchedInfo = this.service.langs.find( const matchedInfo = this.langs.find(
info => info =>
info.id === modelLang || info.id === modelLang ||
info.name === modelLang || info.name === modelLang ||
@@ -101,8 +109,8 @@ export class CodeBlockComponent extends CaptionedBlockComponent<
const langImport = matchedInfo.import; const langImport = matchedInfo.import;
const lang = matchedInfo.id; const lang = matchedInfo.id;
const highlighter = this.service.highlighter$.value; const highlighter = this.highlighter.highlighter$.value;
const theme = this.service.themeKey; const theme = this.highlighter.themeKey;
if (!theme || !highlighter) { if (!theme || !highlighter) {
this.highlightTokens$.value = []; this.highlightTokens$.value = [];
return; return;

View File

@@ -0,0 +1,7 @@
import { CodeBlockSchema } from '@blocksuite/affine-model';
import { textKeymap } from '@blocksuite/affine-rich-text';
import { KeymapExtension } from '@blocksuite/block-std';
export const CodeKeymapExtension = KeymapExtension(textKeymap, {
flavour: CodeBlockSchema.model.flavour,
});

View File

@@ -104,13 +104,11 @@ export class LanguageListButton extends WithDisposable(
if (langList) { if (langList) {
this._sortedBundledLanguages = JSON.parse(langList); this._sortedBundledLanguages = JSON.parse(langList);
} else { } else {
this._sortedBundledLanguages = this.blockComponent.service.langs.map( this._sortedBundledLanguages = this.blockComponent.langs.map(lang => ({
lang => ({ label: lang.name,
label: lang.name, name: lang.id,
name: lang.id, aliases: lang.aliases,
aliases: lang.aliases, }));
})
);
} }
this.disposables.add(() => { this.disposables.add(() => {