From cadb9211a6fdad3015d270dc0be1b7993cc948a7 Mon Sep 17 00:00:00 2001 From: donteatfriedrice Date: Thu, 26 Dec 2024 07:27:07 +0000 Subject: [PATCH] refactor(editor): extensionalize plain text adapter (#9330) --- .../block-surface/src/adapters/extension.ts | 3 + .../block-surface/src/adapters/index.ts | 4 ++ .../element-adapter/elements/brush.ts | 8 +-- .../element-adapter/elements/connector.ts | 8 +-- .../element-adapter/elements/group.ts | 8 +-- .../element-adapter/elements/index.ts | 2 +- .../element-adapter/elements/mindmap.ts | 8 +-- .../element-adapter/elements/shape.ts | 8 +-- .../element-adapter/elements/text.ts | 7 ++- .../plain-text/element-adapter/index.ts | 5 +- .../plain-text/element-adapter/type.ts | 27 ++++++++- .../src/adapters/plain-text/plain-text.ts | 15 ++++- blocksuite/affine/block-surface/src/index.ts | 4 ++ .../affine/shared/src/adapters/index.ts | 4 ++ .../adapters/plain-text/delta-converter.ts | 22 ++++++- .../shared/src/adapters/plain-text/index.ts | 2 +- .../src}/adapters/plain-text/plain-text.ts | 48 +++++++++------ .../shared/src/adapters/plain-text/type.ts | 1 - .../shared/src/adapters/types/adapter.ts | 3 +- .../adapters/plain-text.unit.spec.ts | 40 +++++++++---- .../blocks/src/_common/adapters/extension.ts | 8 ++- .../blocks/src/_common/adapters/index.ts | 1 - .../adapters/plain-text/block-matcher.ts | 59 +++++++++---------- .../delta-converter/inline-delta.ts | 36 +++++------ .../blocks/src/code-block/clipboard/index.ts | 6 +- blocksuite/blocks/src/index.ts | 3 + .../presets/_common/utils/markdown-utils.ts | 6 +- 27 files changed, 226 insertions(+), 120 deletions(-) create mode 100644 blocksuite/affine/block-surface/src/adapters/index.ts rename blocksuite/{blocks/src/_common => affine/shared/src}/adapters/plain-text/plain-text.ts (91%) delete mode 100644 blocksuite/affine/shared/src/adapters/plain-text/type.ts diff --git a/blocksuite/affine/block-surface/src/adapters/extension.ts b/blocksuite/affine/block-surface/src/adapters/extension.ts index 46f2de881f395..9c0fd0dec0b4b 100644 --- a/blocksuite/affine/block-surface/src/adapters/extension.ts +++ b/blocksuite/affine/block-surface/src/adapters/extension.ts @@ -2,17 +2,20 @@ import { EdgelessSurfaceBlockMarkdownAdapterExtension, SurfaceBlockMarkdownAdapterExtension, } from './markdown/markdown.js'; +import { elementToPlainTextAdapterMatchers } from './plain-text/element-adapter/elements/index.js'; import { EdgelessSurfaceBlockPlainTextAdapterExtension, SurfaceBlockPlainTextAdapterExtension, } from './plain-text/plain-text.js'; export const SurfaceBlockAdapterExtensions = [ + ...elementToPlainTextAdapterMatchers, SurfaceBlockPlainTextAdapterExtension, SurfaceBlockMarkdownAdapterExtension, ]; export const EdgelessSurfaceBlockAdapterExtensions = [ + ...elementToPlainTextAdapterMatchers, EdgelessSurfaceBlockPlainTextAdapterExtension, EdgelessSurfaceBlockMarkdownAdapterExtension, ]; diff --git a/blocksuite/affine/block-surface/src/adapters/index.ts b/blocksuite/affine/block-surface/src/adapters/index.ts new file mode 100644 index 0000000000000..8e431f3cd8acb --- /dev/null +++ b/blocksuite/affine/block-surface/src/adapters/index.ts @@ -0,0 +1,4 @@ +export { + EdgelessSurfaceBlockAdapterExtensions, + SurfaceBlockAdapterExtensions, +} from './extension.js'; diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/brush.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/brush.ts index 68fb545d8020c..45101b294ffb5 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/brush.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/brush.ts @@ -1,11 +1,11 @@ -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const brushToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = - { +export const brushToPlainTextAdapterMatcher = + ElementToPlainTextAdapterExtension({ name: 'brush', match: elementModel => elementModel.type === 'brush', toAST: () => { const content = `Brush Stroke`; return { content }; }, - }; + }); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/connector.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/connector.ts index 2ef58fc4cfe9a..e7767cfabc5a5 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/connector.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/connector.ts @@ -1,8 +1,8 @@ import { getConnectorText } from '../../../utils/text.js'; -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const connectorToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = - { +export const connectorToPlainTextAdapterMatcher = + ElementToPlainTextAdapterExtension({ name: 'connector', match: elementModel => elementModel.type === 'connector', toAST: elementModel => { @@ -10,4 +10,4 @@ export const connectorToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterM const content = `Connector, with text label "${text}"`; return { content }; }, - }; + }); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/group.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/group.ts index 40b8263b83760..d7c12e2fe8edc 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/group.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/group.ts @@ -1,8 +1,8 @@ import { getGroupTitle } from '../../../utils/text.js'; -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const groupToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = - { +export const groupToPlainTextAdapterMatcher = + ElementToPlainTextAdapterExtension({ name: 'group', match: elementModel => elementModel.type === 'group', toAST: elementModel => { @@ -10,4 +10,4 @@ export const groupToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatch const content = `Group, with title "${title}"`; return { content }; }, - }; + }); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/index.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/index.ts index 10c454c9246dd..9197a0deb2de3 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/index.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/index.ts @@ -5,7 +5,7 @@ import { mindmapToPlainTextAdapterMatcher } from './mindmap.js'; import { shapeToPlainTextAdapterMatcher } from './shape.js'; import { textToPlainTextAdapterMatcher } from './text.js'; -export const elementModelToPlainTextAdapterMatchers = [ +export const elementToPlainTextAdapterMatchers = [ groupToPlainTextAdapterMatcher, shapeToPlainTextAdapterMatcher, connectorToPlainTextAdapterMatcher, diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/mindmap.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/mindmap.ts index 7f1479d96bbc2..71f88ee106a77 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/mindmap.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/mindmap.ts @@ -1,12 +1,12 @@ import { getMindMapTreeText } from '../../../utils/text.js'; -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const mindmapToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = - { +export const mindmapToPlainTextAdapterMatcher = + ElementToPlainTextAdapterExtension({ name: 'mindmap', match: elementModel => elementModel.type === 'mindmap', toAST: (elementModel, context) => { const mindMapContent = getMindMapTreeText(elementModel, context.elements); return { content: mindMapContent }; }, - }; + }); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/shape.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/shape.ts index 806cff8f055aa..2e465aa9fcfa3 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/shape.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/shape.ts @@ -1,9 +1,9 @@ import type { MindMapTreeNode } from '../../../types/mindmap.js'; import { getShapeText, getShapeType } from '../../../utils/text.js'; -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const shapeToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = - { +export const shapeToPlainTextAdapterMatcher = + ElementToPlainTextAdapterExtension({ name: 'shape', match: elementModel => elementModel.type === 'shape', toAST: (elementModel, context) => { @@ -31,4 +31,4 @@ export const shapeToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatch content = `${shapeType}, with text label "${text}"`; return { content }; }, - }; + }); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/text.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/text.ts index 81bb2156f4e39..17d58244d6caa 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/text.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/elements/text.ts @@ -1,7 +1,7 @@ import { getTextElementText } from '../../../utils/text.js'; -import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; +import { ElementToPlainTextAdapterExtension } from '../type.js'; -export const textToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = +export const textToPlainTextAdapterMatcher = ElementToPlainTextAdapterExtension( { name: 'text', match: elementModel => elementModel.type === 'text', @@ -9,4 +9,5 @@ export const textToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatche const content = getTextElementText(elementModel); return { content }; }, - }; + } +); diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/index.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/index.ts index c2a3fba964aec..71689cac27859 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/index.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/index.ts @@ -4,15 +4,14 @@ import { ElementModelAdapter, type ElementModelAdapterContext, } from '../../type.js'; -import { elementModelToPlainTextAdapterMatchers } from './elements/index.js'; -import type { ElementModelToPlainTextAdapterMatcher } from './type.js'; +import type { ElementToPlainTextAdapterMatcher } from './type.js'; export class PlainTextElementModelAdapter extends ElementModelAdapter< string, TextBuffer > { constructor( - readonly elementModelMatchers: ElementModelToPlainTextAdapterMatcher[] = elementModelToPlainTextAdapterMatchers + readonly elementModelMatchers: ElementToPlainTextAdapterMatcher[] ) { super(); } diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/type.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/type.ts index 274de33ef2f2c..0e23f46acb9b1 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/type.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/element-adapter/type.ts @@ -1,6 +1,29 @@ import type { TextBuffer } from '@blocksuite/affine-shared/adapters'; +import type { ExtensionType } from '@blocksuite/block-std'; +import { + createIdentifier, + type ServiceIdentifier, +} from '@blocksuite/global/di'; import type { ElementModelMatcher } from '../../type.js'; -export type ElementModelToPlainTextAdapterMatcher = - ElementModelMatcher; +export type ElementToPlainTextAdapterMatcher = ElementModelMatcher; + +export const ElementToPlainTextAdapterMatcherIdentifier = + createIdentifier( + 'elementToPlainTextAdapterMatcher' + ); + +export function ElementToPlainTextAdapterExtension( + matcher: ElementToPlainTextAdapterMatcher +): ExtensionType & { + identifier: ServiceIdentifier; +} { + const identifier = ElementToPlainTextAdapterMatcherIdentifier(matcher.name); + return { + setup: di => { + di.addImpl(identifier, () => matcher); + }, + identifier, + }; +} diff --git a/blocksuite/affine/block-surface/src/adapters/plain-text/plain-text.ts b/blocksuite/affine/block-surface/src/adapters/plain-text/plain-text.ts index 16f32ca80d04d..2e71035faca07 100644 --- a/blocksuite/affine/block-surface/src/adapters/plain-text/plain-text.ts +++ b/blocksuite/affine/block-surface/src/adapters/plain-text/plain-text.ts @@ -5,6 +5,7 @@ import { import { getMindMapNodeMap } from '../utils/mindmap.js'; import { PlainTextElementModelAdapter } from './element-adapter/index.js'; +import { ElementToPlainTextAdapterMatcherIdentifier } from './element-adapter/type.js'; export const surfaceBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = { @@ -30,8 +31,18 @@ export const edgelessSurfaceBlockPlainTextAdapterMatcher: BlockPlainTextAdapterM toBlockSnapshot: {}, fromBlockSnapshot: { enter: (o, context) => { - const { walkerContext } = context; - const plainTextElementModelAdapter = new PlainTextElementModelAdapter(); + const { walkerContext, provider } = context; + if (!provider) { + context.walkerContext.skipAllChildren(); + return; + } + + const elementModelMatchers = Array.from( + provider.getAll(ElementToPlainTextAdapterMatcherIdentifier).values() + ); + const plainTextElementModelAdapter = new PlainTextElementModelAdapter( + elementModelMatchers + ); if ('elements' in o.node.props) { const elements = o.node.props.elements as Record< string, diff --git a/blocksuite/affine/block-surface/src/index.ts b/blocksuite/affine/block-surface/src/index.ts index a73cec0145c8f..4818187325f68 100644 --- a/blocksuite/affine/block-surface/src/index.ts +++ b/blocksuite/affine/block-surface/src/index.ts @@ -44,6 +44,10 @@ import { isSameFontFamily, wrapFontFamily, } from './utils/font.js'; +export { + EdgelessSurfaceBlockAdapterExtensions, + SurfaceBlockAdapterExtensions, +} from './adapters/index.js'; export type { SurfaceContext } from './surface-block.js'; export { SurfaceBlockComponent } from './surface-block.js'; export { SurfaceBlockModel, SurfaceBlockSchema } from './surface-model.js'; diff --git a/blocksuite/affine/shared/src/adapters/index.ts b/blocksuite/affine/shared/src/adapters/index.ts index 7c3432101d442..50edecbbf6ed3 100644 --- a/blocksuite/affine/shared/src/adapters/index.ts +++ b/blocksuite/affine/shared/src/adapters/index.ts @@ -42,9 +42,13 @@ export { BlockPlainTextAdapterExtension, type BlockPlainTextAdapterMatcher, BlockPlainTextAdapterMatcherIdentifier, + InlineDeltaToPlainTextAdapterExtension, type InlineDeltaToPlainTextAdapterMatcher, InlineDeltaToPlainTextAdapterMatcherIdentifier, type PlainText, + PlainTextAdapter, + PlainTextAdapterFactoryExtension, + PlainTextAdapterFactoryIdentifier, PlainTextDeltaConverter, } from './plain-text'; export { diff --git a/blocksuite/affine/shared/src/adapters/plain-text/delta-converter.ts b/blocksuite/affine/shared/src/adapters/plain-text/delta-converter.ts index 18be18a8d5992..5ede6bbeaf4ce 100644 --- a/blocksuite/affine/shared/src/adapters/plain-text/delta-converter.ts +++ b/blocksuite/affine/shared/src/adapters/plain-text/delta-converter.ts @@ -1,4 +1,8 @@ -import { createIdentifier } from '@blocksuite/global/di'; +import type { ExtensionType } from '@blocksuite/block-std'; +import { + createIdentifier, + type ServiceIdentifier, +} from '@blocksuite/global/di'; import type { DeltaInsert } from '@blocksuite/inline'; import type { AffineTextAttributes } from '../../types/index.js'; @@ -17,6 +21,22 @@ export const InlineDeltaToPlainTextAdapterMatcherIdentifier = 'InlineDeltaToPlainTextAdapterMatcher' ); +export function InlineDeltaToPlainTextAdapterExtension( + matcher: InlineDeltaToPlainTextAdapterMatcher +): ExtensionType & { + identifier: ServiceIdentifier; +} { + const identifier = InlineDeltaToPlainTextAdapterMatcherIdentifier( + matcher.name + ); + return { + setup: di => { + di.addImpl(identifier, () => matcher); + }, + identifier, + }; +} + export type PlainTextASTToDeltaMatcher = ASTToDeltaMatcher; export class PlainTextDeltaConverter extends DeltaASTConverter< diff --git a/blocksuite/affine/shared/src/adapters/plain-text/index.ts b/blocksuite/affine/shared/src/adapters/plain-text/index.ts index e45efaf7c7a0b..96b9c03349561 100644 --- a/blocksuite/affine/shared/src/adapters/plain-text/index.ts +++ b/blocksuite/affine/shared/src/adapters/plain-text/index.ts @@ -1,3 +1,3 @@ export * from './block-adapter.js'; export * from './delta-converter.js'; -export * from './type.js'; +export * from './plain-text.js'; diff --git a/blocksuite/blocks/src/_common/adapters/plain-text/plain-text.ts b/blocksuite/affine/shared/src/adapters/plain-text/plain-text.ts similarity index 91% rename from blocksuite/blocks/src/_common/adapters/plain-text/plain-text.ts rename to blocksuite/affine/shared/src/adapters/plain-text/plain-text.ts index 0556b6a3e83dc..87a16629c7c01 100644 --- a/blocksuite/blocks/src/_common/adapters/plain-text/plain-text.ts +++ b/blocksuite/affine/shared/src/adapters/plain-text/plain-text.ts @@ -2,16 +2,8 @@ import { DEFAULT_NOTE_BACKGROUND_COLOR, NoteDisplayMode, } from '@blocksuite/affine-model'; -import { - type AdapterContext, - AdapterFactoryIdentifier, - type BlockPlainTextAdapterMatcher, - BlockPlainTextAdapterMatcherIdentifier, - type PlainText, - PlainTextDeltaConverter, - type TextBuffer, -} from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std'; +import type { ServiceProvider } from '@blocksuite/global/di'; import { type AssetsManager, ASTWalker, @@ -32,8 +24,21 @@ import { type ToDocSnapshotPayload, } from '@blocksuite/store'; -import { defaultBlockPlainTextAdapterMatchers } from './block-matcher.js'; -import { inlineDeltaToPlainTextAdapterMatchers } from './delta-converter/inline-delta.js'; +import { + type AdapterContext, + AdapterFactoryIdentifier, + type TextBuffer, +} from '../types'; +import { + type BlockPlainTextAdapterMatcher, + BlockPlainTextAdapterMatcherIdentifier, +} from './block-adapter'; +import { + InlineDeltaToPlainTextAdapterMatcherIdentifier, + PlainTextDeltaConverter, +} from './delta-converter'; + +export type PlainText = string; type PlainTextToSliceSnapshotPayload = { file: PlainText; @@ -46,11 +51,20 @@ type PlainTextToSliceSnapshotPayload = { export class PlainTextAdapter extends BaseAdapter { deltaConverter: PlainTextDeltaConverter; + readonly blockMatchers: BlockPlainTextAdapterMatcher[]; + constructor( job: Job, - readonly blockMatchers: BlockPlainTextAdapterMatcher[] = defaultBlockPlainTextAdapterMatchers + readonly provider: ServiceProvider ) { super(job); + const blockMatchers = Array.from( + provider.getAll(BlockPlainTextAdapterMatcherIdentifier).values() + ); + const inlineDeltaToPlainTextAdapterMatchers = Array.from( + provider.getAll(InlineDeltaToPlainTextAdapterMatcherIdentifier).values() + ); + this.blockMatchers = blockMatchers; this.deltaConverter = new PlainTextDeltaConverter( job.adapterConfigs, inlineDeltaToPlainTextAdapterMatchers, @@ -78,6 +92,7 @@ export class PlainTextAdapter extends BaseAdapter<PlainText> { configs: this.configs, job: this.job, deltaConverter: this.deltaConverter, + provider: this.provider, textBuffer, }; await matcher.fromBlockSnapshot.enter?.(o, adapterContext); @@ -93,6 +108,7 @@ export class PlainTextAdapter extends BaseAdapter<PlainText> { configs: this.configs, job: this.job, deltaConverter: this.deltaConverter, + provider: this.provider, textBuffer, }; await matcher.fromBlockSnapshot.leave?.(o, adapterContext); @@ -309,13 +325,7 @@ export const PlainTextAdapterFactoryIdentifier = export const PlainTextAdapterFactoryExtension: ExtensionType = { setup: di => { di.addImpl(PlainTextAdapterFactoryIdentifier, provider => ({ - get: (job: Job) => - new PlainTextAdapter( - job, - Array.from( - provider.getAll(BlockPlainTextAdapterMatcherIdentifier).values() - ) - ), + get: (job: Job) => new PlainTextAdapter(job, provider), })); }, }; diff --git a/blocksuite/affine/shared/src/adapters/plain-text/type.ts b/blocksuite/affine/shared/src/adapters/plain-text/type.ts deleted file mode 100644 index d8cb42f07c828..0000000000000 --- a/blocksuite/affine/shared/src/adapters/plain-text/type.ts +++ /dev/null @@ -1 +0,0 @@ -export type PlainText = string; diff --git a/blocksuite/affine/shared/src/adapters/types/adapter.ts b/blocksuite/affine/shared/src/adapters/types/adapter.ts index 4a2267876b804..b82fe86efc463 100644 --- a/blocksuite/affine/shared/src/adapters/types/adapter.ts +++ b/blocksuite/affine/shared/src/adapters/types/adapter.ts @@ -1,4 +1,4 @@ -import { createIdentifier } from '@blocksuite/global/di'; +import { createIdentifier, type ServiceProvider } from '@blocksuite/global/di'; import type { BaseTextAttributes, DeltaInsert } from '@blocksuite/inline'; import { type AssetsManager, @@ -38,6 +38,7 @@ export type AdapterContext< job: Job; deltaConverter: TConverter; textBuffer: TextBuffer; + provider?: ServiceProvider; assets?: AssetsManager; pageMap?: Map<string, string>; updateAssetIds?: (assetsId: string) => void; diff --git a/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts index c7590edc49a27..bb6894f694c65 100644 --- a/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts @@ -2,6 +2,8 @@ import { DEFAULT_NOTE_BACKGROUND_COLOR, NoteDisplayMode, } from '@blocksuite/affine-model'; +import { PlainTextAdapter } from '@blocksuite/affine-shared/adapters'; +import { Container } from '@blocksuite/global/di'; import type { BlockSnapshot, DocSnapshot, @@ -9,10 +11,20 @@ import type { } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { PlainTextAdapter } from '../../_common/adapters/plain-text/plain-text.js'; +import { defaultBlockPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/block-matcher.js'; +import { inlineDeltaToPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/delta-converter/inline-delta.js'; import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js'; import { createJob } from '../utils/create-job.js'; +const container = new Container(); +[ + ...defaultBlockPlainTextAdapterMatchers, + ...inlineDeltaToPlainTextAdapterMatchers, +].forEach(ext => { + ext.setup(container); +}); +const provider = container.provider(); + describe('snapshot to plain text', () => { test('paragraph', async () => { const blockSnapshot: BlockSnapshot = { @@ -157,7 +169,7 @@ describe('snapshot to plain text', () => { }; const plainText = 'aaabbbccc\nddd\neee\nfff\nggg\n'; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -316,7 +328,7 @@ describe('snapshot to plain text', () => { const plainText = 'aaa\nbbb\nccc\nddd\neee\n'; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -386,7 +398,7 @@ describe('snapshot to plain text', () => { }; const plainText = 'aaa\n---\n'; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -449,7 +461,7 @@ describe('snapshot to plain text', () => { }; const plainText = 'import this\n'; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -568,7 +580,10 @@ describe('snapshot to plain text', () => { adapterConfigs.set('title:deadbeef', 'test'); adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); }; - const plainTextAdapter = new PlainTextAdapter(createJob([middleware])); + const plainTextAdapter = new PlainTextAdapter( + createJob([middleware]), + provider + ); const plainText = 'aaa: https://affine.pro/\ntest: https://example.com/deadbeef?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\nE=mc^2\n'; @@ -670,7 +685,7 @@ describe('snapshot to plain text', () => { ], }; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -750,7 +765,10 @@ describe('snapshot to plain text', () => { }; const plainText = 'test: https://example.com/4T5ObMgEIMII-4Bexyta1?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\n'; - const plainTextAdapter = new PlainTextAdapter(createJob([middleware])); + const plainTextAdapter = new PlainTextAdapter( + createJob([middleware]), + provider + ); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapShot, }); @@ -1146,7 +1164,7 @@ describe('snapshot to plain text', () => { await job.snapshotToDoc(syncedDocSnapshot); await job.snapshotToDoc(docSnapShot); - const mdAdapter = new PlainTextAdapter(job); + const mdAdapter = new PlainTextAdapter(job, provider); const target = await mdAdapter.fromDocSnapshot({ snapshot: docSnapShot, }); @@ -1180,7 +1198,7 @@ describe('snapshot to plain text', () => { }; const plainText = 'LaTex, with value: E=mc^2\n'; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1405,7 +1423,7 @@ describe('snapshot to plain text', () => { | Task 1 | TODO | 2023-12-15 | 1 | 65 | test1,test2 | test2: https://google.com | https://google.com | true | | Task 2 | In Progress | 2023-12-20 | | | | test1 | | | `; - const plainTextAdapter = new PlainTextAdapter(createJob()); + const plainTextAdapter = new PlainTextAdapter(createJob(), provider); const target = await plainTextAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); diff --git a/blocksuite/blocks/src/_common/adapters/extension.ts b/blocksuite/blocks/src/_common/adapters/extension.ts index 636930fbfbea4..f5291555dc757 100644 --- a/blocksuite/blocks/src/_common/adapters/extension.ts +++ b/blocksuite/blocks/src/_common/adapters/extension.ts @@ -1,4 +1,7 @@ -import { HtmlAdapterFactoryExtension } from '@blocksuite/affine-shared/adapters'; +import { + HtmlAdapterFactoryExtension, + PlainTextAdapterFactoryExtension, +} from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std'; import { AttachmentAdapterFactoryExtension } from './attachment.js'; @@ -10,12 +13,13 @@ import { MixTextAdapterFactoryExtension } from './mix-text.js'; import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js'; import { NotionHtmlAdapterFactoryExtension } from './notion-html/notion-html.js'; import { NotionTextAdapterFactoryExtension } from './notion-text.js'; -import { PlainTextAdapterFactoryExtension } from './plain-text/plain-text.js'; +import { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js'; export const AdapterFactoryExtensions: ExtensionType[] = [ ...htmlInlineToDeltaMatchers, ...inlineDeltaToHtmlAdapterMatchers, ...notionHtmlInlineToDeltaMatchers, + ...inlineDeltaToPlainTextAdapterMatchers, AttachmentAdapterFactoryExtension, ImageAdapterFactoryExtension, MarkdownAdapterFactoryExtension, diff --git a/blocksuite/blocks/src/_common/adapters/index.ts b/blocksuite/blocks/src/_common/adapters/index.ts index 410d12386b650..ff260ae46b44e 100644 --- a/blocksuite/blocks/src/_common/adapters/index.ts +++ b/blocksuite/blocks/src/_common/adapters/index.ts @@ -5,4 +5,3 @@ export * from './markdown/index.js'; export * from './mix-text.js'; export * from './notion-html/index.js'; export * from './notion-text.js'; -export * from './plain-text/plain-text.js'; diff --git a/blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts b/blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts index af7c2bfb3fe51..ba0ab860b2c7f 100644 --- a/blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts +++ b/blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts @@ -1,34 +1,33 @@ -import { bookmarkBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-bookmark'; +import { BookmarkBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-bookmark'; import { - embedFigmaBlockPlainTextAdapterMatcher, - embedGithubBlockPlainTextAdapterMatcher, - embedLinkedDocBlockPlainTextAdapterMatcher, - embedLoomBlockPlainTextAdapterMatcher, - embedSyncedDocBlockPlainTextAdapterMatcher, - embedYoutubeBlockPlainTextAdapterMatcher, + EmbedFigmaBlockPlainTextAdapterExtension, + EmbedGithubBlockPlainTextAdapterExtension, + EmbedLinkedDocBlockPlainTextAdapterExtension, + EmbedLoomBlockPlainTextAdapterExtension, + EmbedSyncedDocBlockPlainTextAdapterExtension, + EmbedYoutubeBlockPlainTextAdapterExtension, } from '@blocksuite/affine-block-embed'; -import { latexBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-latex'; -import { listBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-list'; -import { paragraphBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-paragraph'; -import type { BlockPlainTextAdapterMatcher } from '@blocksuite/affine-shared/adapters'; +import { LatexBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-latex'; +import { ListBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-list'; +import { ParagraphBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-paragraph'; +import type { ExtensionType } from '@blocksuite/block-std'; -import { codeBlockPlainTextAdapterMatcher } from '../../../code-block/adapters/plain-text.js'; -import { databaseBlockPlainTextAdapterMatcher } from '../../../database-block/adapters/plain-text.js'; -import { dividerBlockPlainTextAdapterMatcher } from '../../../divider-block/adapters/plain-text.js'; +import { CodeBlockPlainTextAdapterExtension } from '../../../code-block/adapters/plain-text.js'; +import { DatabaseBlockPlainTextAdapterExtension } from '../../../database-block/adapters/plain-text.js'; +import { DividerBlockPlainTextAdapterExtension } from '../../../divider-block/adapters/plain-text.js'; -export const defaultBlockPlainTextAdapterMatchers: BlockPlainTextAdapterMatcher[] = - [ - paragraphBlockPlainTextAdapterMatcher, - listBlockPlainTextAdapterMatcher, - dividerBlockPlainTextAdapterMatcher, - codeBlockPlainTextAdapterMatcher, - bookmarkBlockPlainTextAdapterMatcher, - embedFigmaBlockPlainTextAdapterMatcher, - embedGithubBlockPlainTextAdapterMatcher, - embedLoomBlockPlainTextAdapterMatcher, - embedYoutubeBlockPlainTextAdapterMatcher, - embedLinkedDocBlockPlainTextAdapterMatcher, - embedSyncedDocBlockPlainTextAdapterMatcher, - latexBlockPlainTextAdapterMatcher, - databaseBlockPlainTextAdapterMatcher, - ]; +export const defaultBlockPlainTextAdapterMatchers: ExtensionType[] = [ + ParagraphBlockPlainTextAdapterExtension, + ListBlockPlainTextAdapterExtension, + DividerBlockPlainTextAdapterExtension, + CodeBlockPlainTextAdapterExtension, + BookmarkBlockPlainTextAdapterExtension, + EmbedFigmaBlockPlainTextAdapterExtension, + EmbedGithubBlockPlainTextAdapterExtension, + EmbedLoomBlockPlainTextAdapterExtension, + EmbedYoutubeBlockPlainTextAdapterExtension, + EmbedLinkedDocBlockPlainTextAdapterExtension, + EmbedSyncedDocBlockPlainTextAdapterExtension, + LatexBlockPlainTextAdapterExtension, + DatabaseBlockPlainTextAdapterExtension, +]; diff --git a/blocksuite/blocks/src/_common/adapters/plain-text/delta-converter/inline-delta.ts b/blocksuite/blocks/src/_common/adapters/plain-text/delta-converter/inline-delta.ts index 9bb93626edd04..9f162fb4a7f70 100644 --- a/blocksuite/blocks/src/_common/adapters/plain-text/delta-converter/inline-delta.ts +++ b/blocksuite/blocks/src/_common/adapters/plain-text/delta-converter/inline-delta.ts @@ -1,11 +1,12 @@ import { generateDocUrl } from '@blocksuite/affine-block-embed'; -import type { - InlineDeltaToPlainTextAdapterMatcher, - TextBuffer, +import { + InlineDeltaToPlainTextAdapterExtension, + type TextBuffer, } from '@blocksuite/affine-shared/adapters'; +import type { ExtensionType } from '@blocksuite/block-std'; -export const referenceDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = - { +export const referenceDeltaMarkdownAdapterMatch = + InlineDeltaToPlainTextAdapterExtension({ name: 'reference', match: delta => !!delta.attributes?.reference, toAST: (delta, context) => { @@ -30,10 +31,10 @@ export const referenceDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMa content, }; }, - }; + }); -export const linkDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = - { +export const linkDeltaMarkdownAdapterMatch = + InlineDeltaToPlainTextAdapterExtension({ name: 'link', match: delta => !!delta.attributes?.link, toAST: delta => { @@ -51,10 +52,10 @@ export const linkDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher content, }; }, - }; + }); -export const latexDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = - { +export const latexDeltaMarkdownAdapterMatch = + InlineDeltaToPlainTextAdapterExtension({ name: 'inlineLatex', match: delta => !!delta.attributes?.latex, toAST: delta => { @@ -68,11 +69,10 @@ export const latexDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatche content: delta.attributes?.latex, }; }, - }; + }); -export const inlineDeltaToPlainTextAdapterMatchers: InlineDeltaToPlainTextAdapterMatcher[] = - [ - referenceDeltaMarkdownAdapterMatch, - linkDeltaMarkdownAdapterMatch, - latexDeltaMarkdownAdapterMatch, - ]; +export const inlineDeltaToPlainTextAdapterMatchers: ExtensionType[] = [ + referenceDeltaMarkdownAdapterMatch, + linkDeltaMarkdownAdapterMatch, + latexDeltaMarkdownAdapterMatch, +]; diff --git a/blocksuite/blocks/src/code-block/clipboard/index.ts b/blocksuite/blocks/src/code-block/clipboard/index.ts index a558a15c11ed0..39d040031e4f6 100644 --- a/blocksuite/blocks/src/code-block/clipboard/index.ts +++ b/blocksuite/blocks/src/code-block/clipboard/index.ts @@ -1,4 +1,7 @@ -import { HtmlAdapter } from '@blocksuite/affine-shared/adapters'; +import { + HtmlAdapter, + PlainTextAdapter, +} from '@blocksuite/affine-shared/adapters'; import { type BlockComponent, Clipboard, @@ -6,7 +9,6 @@ import { } from '@blocksuite/block-std'; import { assertExists, DisposableGroup } from '@blocksuite/global/utils'; -import { PlainTextAdapter } from '../../_common/adapters/index.js'; import { pasteMiddleware } from '../../root-block/clipboard/middlewares/index.js'; export class CodeClipboardController { diff --git a/blocksuite/blocks/src/index.ts b/blocksuite/blocks/src/index.ts index 9fa3f72537789..77619e3b32af4 100644 --- a/blocksuite/blocks/src/index.ts +++ b/blocksuite/blocks/src/index.ts @@ -103,6 +103,9 @@ export { HtmlAdapter, HtmlAdapterFactoryExtension, HtmlAdapterFactoryIdentifier, + PlainTextAdapter, + PlainTextAdapterFactoryExtension, + PlainTextAdapterFactoryIdentifier, } from '@blocksuite/affine-shared/adapters'; export * from '@blocksuite/affine-shared/services'; export { scrollbarStyle } from '@blocksuite/affine-shared/styles'; diff --git a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts index b67975588b90a..a38af3c06fd1c 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts @@ -86,7 +86,9 @@ export async function getContentFromSlice( } processTextInSnapshot(snapshot, host); const adapter = - type === 'markdown' ? new MarkdownAdapter(job) : new PlainTextAdapter(job); + type === 'markdown' + ? new MarkdownAdapter(job) + : new PlainTextAdapter(job, host.std.provider); const content = await adapter.fromSliceSnapshot({ snapshot, assets: job.assetsManager, @@ -104,7 +106,7 @@ export async function getPlainTextFromSlice(host: EditorHost, slice: Slice) { return ''; } processTextInSnapshot(snapshot, host); - const plainTextAdapter = new PlainTextAdapter(job); + const plainTextAdapter = new PlainTextAdapter(job, host.std.provider); const plainText = await plainTextAdapter.fromSliceSnapshot({ snapshot, assets: job.assetsManager,