refactor(editor): extensionalize plain text adapter (#9330)
This commit is contained in:
@@ -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,
|
||||
];
|
||||
|
||||
4
blocksuite/affine/block-surface/src/adapters/index.ts
Normal file
4
blocksuite/affine/block-surface/src/adapters/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
EdgelessSurfaceBlockAdapterExtensions,
|
||||
SurfaceBlockAdapterExtensions,
|
||||
} from './extension.js';
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 };
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<TextBuffer>;
|
||||
export type ElementToPlainTextAdapterMatcher = ElementModelMatcher<TextBuffer>;
|
||||
|
||||
export const ElementToPlainTextAdapterMatcherIdentifier =
|
||||
createIdentifier<ElementToPlainTextAdapterMatcher>(
|
||||
'elementToPlainTextAdapterMatcher'
|
||||
);
|
||||
|
||||
export function ElementToPlainTextAdapterExtension(
|
||||
matcher: ElementToPlainTextAdapterMatcher
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<ElementToPlainTextAdapterMatcher>;
|
||||
} {
|
||||
const identifier = ElementToPlainTextAdapterMatcherIdentifier(matcher.name);
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(identifier, () => matcher);
|
||||
},
|
||||
identifier,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -42,9 +42,13 @@ export {
|
||||
BlockPlainTextAdapterExtension,
|
||||
type BlockPlainTextAdapterMatcher,
|
||||
BlockPlainTextAdapterMatcherIdentifier,
|
||||
InlineDeltaToPlainTextAdapterExtension,
|
||||
type InlineDeltaToPlainTextAdapterMatcher,
|
||||
InlineDeltaToPlainTextAdapterMatcherIdentifier,
|
||||
type PlainText,
|
||||
PlainTextAdapter,
|
||||
PlainTextAdapterFactoryExtension,
|
||||
PlainTextAdapterFactoryIdentifier,
|
||||
PlainTextDeltaConverter,
|
||||
} from './plain-text';
|
||||
export {
|
||||
|
||||
@@ -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<InlineDeltaToPlainTextAdapterMatcher>;
|
||||
} {
|
||||
const identifier = InlineDeltaToPlainTextAdapterMatcherIdentifier(
|
||||
matcher.name
|
||||
);
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(identifier, () => matcher);
|
||||
},
|
||||
identifier,
|
||||
};
|
||||
}
|
||||
|
||||
export type PlainTextASTToDeltaMatcher = ASTToDeltaMatcher<string>;
|
||||
|
||||
export class PlainTextDeltaConverter extends DeltaASTConverter<
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './block-adapter.js';
|
||||
export * from './delta-converter.js';
|
||||
export * from './type.js';
|
||||
export * from './plain-text.js';
|
||||
|
||||
331
blocksuite/affine/shared/src/adapters/plain-text/plain-text.ts
Normal file
331
blocksuite/affine/shared/src/adapters/plain-text/plain-text.ts
Normal file
@@ -0,0 +1,331 @@
|
||||
import {
|
||||
DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
NoteDisplayMode,
|
||||
} from '@blocksuite/affine-model';
|
||||
import type { ExtensionType } from '@blocksuite/block-std';
|
||||
import type { ServiceProvider } from '@blocksuite/global/di';
|
||||
import {
|
||||
type AssetsManager,
|
||||
ASTWalker,
|
||||
BaseAdapter,
|
||||
type BlockSnapshot,
|
||||
BlockSnapshotSchema,
|
||||
type DocSnapshot,
|
||||
type FromBlockSnapshotPayload,
|
||||
type FromBlockSnapshotResult,
|
||||
type FromDocSnapshotPayload,
|
||||
type FromDocSnapshotResult,
|
||||
type FromSliceSnapshotPayload,
|
||||
type FromSliceSnapshotResult,
|
||||
type Job,
|
||||
nanoid,
|
||||
type SliceSnapshot,
|
||||
type ToBlockSnapshotPayload,
|
||||
type ToDocSnapshotPayload,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
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;
|
||||
assets?: AssetsManager;
|
||||
blockVersions: Record<string, number>;
|
||||
workspaceId: string;
|
||||
pageId: string;
|
||||
};
|
||||
|
||||
export class PlainTextAdapter extends BaseAdapter<PlainText> {
|
||||
deltaConverter: PlainTextDeltaConverter;
|
||||
|
||||
readonly blockMatchers: BlockPlainTextAdapterMatcher[];
|
||||
|
||||
constructor(
|
||||
job: Job,
|
||||
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,
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
private async _traverseSnapshot(
|
||||
snapshot: BlockSnapshot
|
||||
): Promise<{ plaintext: string }> {
|
||||
const textBuffer: TextBuffer = {
|
||||
content: '',
|
||||
};
|
||||
const walker = new ASTWalker<BlockSnapshot, TextBuffer>();
|
||||
walker.setONodeTypeGuard(
|
||||
(node): node is BlockSnapshot =>
|
||||
BlockSnapshotSchema.safeParse(node).success
|
||||
);
|
||||
walker.setEnter(async (o, context) => {
|
||||
for (const matcher of this.blockMatchers) {
|
||||
if (matcher.fromMatch(o)) {
|
||||
const adapterContext: AdapterContext<BlockSnapshot, TextBuffer> = {
|
||||
walker,
|
||||
walkerContext: context,
|
||||
configs: this.configs,
|
||||
job: this.job,
|
||||
deltaConverter: this.deltaConverter,
|
||||
provider: this.provider,
|
||||
textBuffer,
|
||||
};
|
||||
await matcher.fromBlockSnapshot.enter?.(o, adapterContext);
|
||||
}
|
||||
}
|
||||
});
|
||||
walker.setLeave(async (o, context) => {
|
||||
for (const matcher of this.blockMatchers) {
|
||||
if (matcher.fromMatch(o)) {
|
||||
const adapterContext: AdapterContext<BlockSnapshot, TextBuffer> = {
|
||||
walker,
|
||||
walkerContext: context,
|
||||
configs: this.configs,
|
||||
job: this.job,
|
||||
deltaConverter: this.deltaConverter,
|
||||
provider: this.provider,
|
||||
textBuffer,
|
||||
};
|
||||
await matcher.fromBlockSnapshot.leave?.(o, adapterContext);
|
||||
}
|
||||
}
|
||||
});
|
||||
await walker.walkONode(snapshot);
|
||||
return {
|
||||
plaintext: textBuffer.content,
|
||||
};
|
||||
}
|
||||
|
||||
async fromBlockSnapshot({
|
||||
snapshot,
|
||||
}: FromBlockSnapshotPayload): Promise<FromBlockSnapshotResult<PlainText>> {
|
||||
const { plaintext } = await this._traverseSnapshot(snapshot);
|
||||
return {
|
||||
file: plaintext,
|
||||
assetsIds: [],
|
||||
};
|
||||
}
|
||||
|
||||
async fromDocSnapshot({
|
||||
snapshot,
|
||||
assets,
|
||||
}: FromDocSnapshotPayload): Promise<FromDocSnapshotResult<PlainText>> {
|
||||
let buffer = '';
|
||||
if (snapshot.meta.title) {
|
||||
buffer += `${snapshot.meta.title}\n\n`;
|
||||
}
|
||||
const { file, assetsIds } = await this.fromBlockSnapshot({
|
||||
snapshot: snapshot.blocks,
|
||||
assets,
|
||||
});
|
||||
buffer += file;
|
||||
return {
|
||||
file: buffer,
|
||||
assetsIds,
|
||||
};
|
||||
}
|
||||
|
||||
async fromSliceSnapshot({
|
||||
snapshot,
|
||||
}: FromSliceSnapshotPayload): Promise<FromSliceSnapshotResult<PlainText>> {
|
||||
let buffer = '';
|
||||
const sliceAssetsIds: string[] = [];
|
||||
for (const contentSlice of snapshot.content) {
|
||||
const { plaintext } = await this._traverseSnapshot(contentSlice);
|
||||
buffer += plaintext;
|
||||
}
|
||||
const plaintext =
|
||||
buffer.match(/\n/g)?.length === 1 ? buffer.trimEnd() : buffer;
|
||||
return {
|
||||
file: plaintext,
|
||||
assetsIds: sliceAssetsIds,
|
||||
};
|
||||
}
|
||||
|
||||
toBlockSnapshot(payload: ToBlockSnapshotPayload<PlainText>): BlockSnapshot {
|
||||
payload.file = payload.file.replaceAll('\r', '');
|
||||
return {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:note',
|
||||
props: {
|
||||
xywh: '[0,0,800,95]',
|
||||
background: DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
index: 'a0',
|
||||
hidden: false,
|
||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||
},
|
||||
children: payload.file.split('\n').map((line): BlockSnapshot => {
|
||||
return {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:paragraph',
|
||||
props: {
|
||||
type: 'text',
|
||||
text: {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: line,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
toDocSnapshot(payload: ToDocSnapshotPayload<PlainText>): DocSnapshot {
|
||||
payload.file = payload.file.replaceAll('\r', '');
|
||||
return {
|
||||
type: 'page',
|
||||
meta: {
|
||||
id: nanoid(),
|
||||
title: 'Untitled',
|
||||
createDate: Date.now(),
|
||||
tags: [],
|
||||
},
|
||||
blocks: {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:page',
|
||||
props: {
|
||||
title: {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: 'Untitled',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:surface',
|
||||
props: {
|
||||
elements: {},
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:note',
|
||||
props: {
|
||||
xywh: '[0,0,800,95]',
|
||||
background: DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
index: 'a0',
|
||||
hidden: false,
|
||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||
},
|
||||
children: payload.file.split('\n').map((line): BlockSnapshot => {
|
||||
return {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:paragraph',
|
||||
props: {
|
||||
type: 'text',
|
||||
text: {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: line,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
toSliceSnapshot(
|
||||
payload: PlainTextToSliceSnapshotPayload
|
||||
): SliceSnapshot | null {
|
||||
if (payload.file.trim().length === 0) {
|
||||
return null;
|
||||
}
|
||||
payload.file = payload.file.replaceAll('\r', '');
|
||||
const contentSlice = {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:note',
|
||||
props: {
|
||||
xywh: '[0,0,800,95]',
|
||||
background: DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
index: 'a0',
|
||||
hidden: false,
|
||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||
},
|
||||
children: payload.file.split('\n').map((line): BlockSnapshot => {
|
||||
return {
|
||||
type: 'block',
|
||||
id: nanoid(),
|
||||
flavour: 'affine:paragraph',
|
||||
props: {
|
||||
type: 'text',
|
||||
text: {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: line,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
}),
|
||||
} as BlockSnapshot;
|
||||
return {
|
||||
type: 'slice',
|
||||
content: [contentSlice],
|
||||
workspaceId: payload.workspaceId,
|
||||
pageId: payload.pageId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const PlainTextAdapterFactoryIdentifier =
|
||||
AdapterFactoryIdentifier('PlainText');
|
||||
|
||||
export const PlainTextAdapterFactoryExtension: ExtensionType = {
|
||||
setup: di => {
|
||||
di.addImpl(PlainTextAdapterFactoryIdentifier, provider => ({
|
||||
get: (job: Job) => new PlainTextAdapter(job, provider),
|
||||
}));
|
||||
},
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export type PlainText = string;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user