mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-19 23:37:15 +08:00
refactor(editor): remove code block service (#11010)
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
7
blocksuite/affine/blocks/block-code/src/code-keymap.ts
Normal file
7
blocksuite/affine/blocks/block-code/src/code-keymap.ts
Normal 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,
|
||||||
|
});
|
||||||
@@ -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(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user