From 30612de1adf0e8b02a404f71c7097cffca0f50f6 Mon Sep 17 00:00:00 2001 From: donteatfriedrice Date: Wed, 12 Feb 2025 09:43:52 +0000 Subject: [PATCH] fix(core): wrap code in ai chat (#10108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [BS-2540](https://linear.app/affine-design/issue/BS-2540/ai-chat-中-code-block-需要默认换行) --- blocksuite/affine/block-code/src/adapters/html.ts | 5 ++++- .../affine/block-code/src/adapters/markdown.ts | 5 ++++- .../affine/block-code/src/adapters/notion-html.ts | 5 ++++- .../affine/shared/src/adapters/middlewares/code.ts | 11 +++++++++++ .../shared/src/adapters/middlewares/index.ts | 1 + .../src/__tests__/adapters/html.unit.spec.ts | 1 + .../src/__tests__/adapters/markdown.unit.spec.ts | 4 ++++ .../__tests__/adapters/notion-html.unit.spec.ts | 1 + blocksuite/blocks/src/index.ts | 1 + .../presets/_common/components/text-renderer.ts | 14 ++++++++------ .../presets/_common/utils/markdown-utils.ts | 6 +----- .../blocksuite/presets/ai/utils/editor-actions.ts | 4 +++- 12 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 blocksuite/affine/shared/src/adapters/middlewares/code.ts diff --git a/blocksuite/affine/block-code/src/adapters/html.ts b/blocksuite/affine/block-code/src/adapters/html.ts index 579e67a425..9f908fe5d5 100644 --- a/blocksuite/affine/block-code/src/adapters/html.ts +++ b/blocksuite/affine/block-code/src/adapters/html.ts @@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model'; import { BlockHtmlAdapterExtension, type BlockHtmlAdapterMatcher, + CODE_BLOCK_WRAP_KEY, HastUtils, } from '@blocksuite/affine-shared/adapters'; import type { DeltaInsert } from '@blocksuite/inline'; @@ -37,7 +38,8 @@ export const codeBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = { ? codeLang.replace('code-', '') : undefined; - const { walkerContext, deltaConverter } = context; + const { walkerContext, deltaConverter, configs } = context; + const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true'; walkerContext .openNode( { @@ -46,6 +48,7 @@ export const codeBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = { flavour: 'affine:code', props: { language: codeLang ?? 'Plain Text', + wrap, text: { '$blocksuite:internal:text$': true, delta: deltaConverter.astToDelta(codeText, { diff --git a/blocksuite/affine/block-code/src/adapters/markdown.ts b/blocksuite/affine/block-code/src/adapters/markdown.ts index 34b978b1c4..a54ad1ee80 100644 --- a/blocksuite/affine/block-code/src/adapters/markdown.ts +++ b/blocksuite/affine/block-code/src/adapters/markdown.ts @@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model'; import { BlockMarkdownAdapterExtension, type BlockMarkdownAdapterMatcher, + CODE_BLOCK_WRAP_KEY, type MarkdownAST, } from '@blocksuite/affine-shared/adapters'; import type { DeltaInsert } from '@blocksuite/inline'; @@ -19,7 +20,8 @@ export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = { if (!isCodeNode(o.node)) { return; } - const { walkerContext } = context; + const { walkerContext, configs } = context; + const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true'; walkerContext .openNode( { @@ -28,6 +30,7 @@ export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = { flavour: 'affine:code', props: { language: o.node.lang ?? 'Plain Text', + wrap, text: { '$blocksuite:internal:text$': true, delta: [ diff --git a/blocksuite/affine/block-code/src/adapters/notion-html.ts b/blocksuite/affine/block-code/src/adapters/notion-html.ts index 4fa971baf5..c528e05cfa 100644 --- a/blocksuite/affine/block-code/src/adapters/notion-html.ts +++ b/blocksuite/affine/block-code/src/adapters/notion-html.ts @@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model'; import { BlockNotionHtmlAdapterExtension, type BlockNotionHtmlAdapterMatcher, + CODE_BLOCK_WRAP_KEY, HastUtils, } from '@blocksuite/affine-shared/adapters'; import { nanoid } from '@blocksuite/store'; @@ -20,7 +21,8 @@ export const codeBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatcher = if (!code) { return; } - const { walkerContext, deltaConverter } = context; + const { walkerContext, deltaConverter, configs } = context; + const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true'; const codeText = code.children.length === 1 && code.children[0].type === 'text' ? code.children[0] @@ -33,6 +35,7 @@ export const codeBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatcher = flavour: CodeBlockSchema.model.flavour, props: { language: 'Plain Text', + wrap, text: { '$blocksuite:internal:text$': true, delta: deltaConverter.astToDelta(codeText, { diff --git a/blocksuite/affine/shared/src/adapters/middlewares/code.ts b/blocksuite/affine/shared/src/adapters/middlewares/code.ts new file mode 100644 index 0000000000..f118a209c3 --- /dev/null +++ b/blocksuite/affine/shared/src/adapters/middlewares/code.ts @@ -0,0 +1,11 @@ +import type { TransformerMiddleware } from '@blocksuite/store'; + +export const CODE_BLOCK_WRAP_KEY = 'codeBlockWrap'; + +export const codeBlockWrapMiddleware = ( + wrap: boolean +): TransformerMiddleware => { + return ({ adapterConfigs }) => { + adapterConfigs.set(CODE_BLOCK_WRAP_KEY, String(wrap)); + }; +}; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/index.ts b/blocksuite/affine/shared/src/adapters/middlewares/index.ts index 786b913103..44e3cd8fbf 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/index.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/index.ts @@ -1,2 +1,3 @@ +export * from './code'; export * from './copy'; export * from './paste'; diff --git a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts index 93fe637de3..14e38ddd38 100644 --- a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts @@ -1980,6 +1980,7 @@ describe('html to snapshot', () => { flavour: 'affine:code', props: { language: 'python', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ diff --git a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts index ea71a2570b..975db9528a 100644 --- a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts @@ -2481,6 +2481,7 @@ describe('markdown to snapshot', () => { flavour: 'affine:code', props: { language: 'python', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ @@ -2526,6 +2527,7 @@ describe('markdown to snapshot', () => { flavour: 'affine:code', props: { language: 'python', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ @@ -2577,6 +2579,7 @@ describe('markdown to snapshot', () => { flavour: 'affine:code', props: { language: 'python', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ @@ -2628,6 +2631,7 @@ describe('markdown to snapshot', () => { flavour: 'affine:code', props: { language: 'python', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ diff --git a/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts index 8d30f55eb5..eb97c4c55b 100644 --- a/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts @@ -51,6 +51,7 @@ describe('notion html to snapshot', () => { flavour: 'affine:code', props: { language: 'Plain Text', + wrap: false, text: { '$blocksuite:internal:text$': true, delta: [ diff --git a/blocksuite/blocks/src/index.ts b/blocksuite/blocks/src/index.ts index 8b92b20256..608c00d99f 100644 --- a/blocksuite/blocks/src/index.ts +++ b/blocksuite/blocks/src/index.ts @@ -102,6 +102,7 @@ export { AttachmentAdapter, AttachmentAdapterFactoryExtension, AttachmentAdapterFactoryIdentifier, + codeBlockWrapMiddleware, FetchUtils, HtmlAdapter, HtmlAdapterFactoryExtension, diff --git a/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts b/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts index 79854a10df..f0d565dac5 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts @@ -9,7 +9,9 @@ import type { } from '@blocksuite/affine/blocks'; import { CodeBlockComponent, + codeBlockWrapMiddleware, defaultBlockMarkdownAdapterMatchers, + defaultImageProxyMiddleware, DividerBlockComponent, InlineDeltaToMarkdownAdapterExtensions, ListBlockComponent, @@ -213,12 +215,12 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) { provider = container.provider(); } if (latestAnswer && schema) { - markDownToDoc( - provider, - schema, - latestAnswer, - this.options.additionalMiddlewares - ) + const middlewares = [ + defaultImageProxyMiddleware, + codeBlockWrapMiddleware(true), + ...(this.options.additionalMiddlewares ?? []), + ]; + markDownToDoc(provider, schema, latestAnswer, middlewares) .then(doc => { this.disposeDoc(); this._doc = doc.doc.getStore({ 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 728e39041b..85c9d8d7fc 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 @@ -206,17 +206,13 @@ export async function markDownToDoc( provider: ServiceProvider, schema: Schema, answer: string, - additionalMiddlewares?: TransformerMiddleware[] + middlewares?: TransformerMiddleware[] ) { // Should not create a new doc in the original collection const collection = new WorkspaceImpl({ schema, }); collection.meta.initialize(); - const middlewares = [defaultImageProxyMiddleware]; - if (additionalMiddlewares) { - middlewares.push(...additionalMiddlewares); - } const transformer = new Transformer({ schema: collection.schema, blobCRUD: collection.blobSync, diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts index 13de9406f3..e68ff7905d 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts @@ -7,6 +7,7 @@ import { } from '@blocksuite/affine/block-std'; import type { AffineAIPanelWidget } from '@blocksuite/affine/blocks'; import { + defaultImageProxyMiddleware, deleteTextCommand, isInsideEdgelessEditor, } from '@blocksuite/affine/blocks'; @@ -151,7 +152,8 @@ export const copyText = async (host: EditorHost, text: string) => { const previewDoc = await markDownToDoc( host.std.provider, host.std.store.schema, - text + text, + [defaultImageProxyMiddleware] ); const models = previewDoc .getBlocksByFlavour('affine:note')