mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
fix(core): wrap code in ai chat (#10108)
[BS-2540](https://linear.app/affine-design/issue/BS-2540/ai-chat-中-code-block-需要默认换行)
This commit is contained in:
@@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model';
|
|||||||
import {
|
import {
|
||||||
BlockHtmlAdapterExtension,
|
BlockHtmlAdapterExtension,
|
||||||
type BlockHtmlAdapterMatcher,
|
type BlockHtmlAdapterMatcher,
|
||||||
|
CODE_BLOCK_WRAP_KEY,
|
||||||
HastUtils,
|
HastUtils,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import type { DeltaInsert } from '@blocksuite/inline';
|
import type { DeltaInsert } from '@blocksuite/inline';
|
||||||
@@ -37,7 +38,8 @@ export const codeBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
|||||||
? codeLang.replace('code-', '')
|
? codeLang.replace('code-', '')
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { walkerContext, deltaConverter } = context;
|
const { walkerContext, deltaConverter, configs } = context;
|
||||||
|
const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true';
|
||||||
walkerContext
|
walkerContext
|
||||||
.openNode(
|
.openNode(
|
||||||
{
|
{
|
||||||
@@ -46,6 +48,7 @@ export const codeBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: codeLang ?? 'Plain Text',
|
language: codeLang ?? 'Plain Text',
|
||||||
|
wrap,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: deltaConverter.astToDelta(codeText, {
|
delta: deltaConverter.astToDelta(codeText, {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model';
|
|||||||
import {
|
import {
|
||||||
BlockMarkdownAdapterExtension,
|
BlockMarkdownAdapterExtension,
|
||||||
type BlockMarkdownAdapterMatcher,
|
type BlockMarkdownAdapterMatcher,
|
||||||
|
CODE_BLOCK_WRAP_KEY,
|
||||||
type MarkdownAST,
|
type MarkdownAST,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import type { DeltaInsert } from '@blocksuite/inline';
|
import type { DeltaInsert } from '@blocksuite/inline';
|
||||||
@@ -19,7 +20,8 @@ export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
|||||||
if (!isCodeNode(o.node)) {
|
if (!isCodeNode(o.node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { walkerContext } = context;
|
const { walkerContext, configs } = context;
|
||||||
|
const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true';
|
||||||
walkerContext
|
walkerContext
|
||||||
.openNode(
|
.openNode(
|
||||||
{
|
{
|
||||||
@@ -28,6 +30,7 @@ export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: o.node.lang ?? 'Plain Text',
|
language: o.node.lang ?? 'Plain Text',
|
||||||
|
wrap,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { CodeBlockSchema } from '@blocksuite/affine-model';
|
|||||||
import {
|
import {
|
||||||
BlockNotionHtmlAdapterExtension,
|
BlockNotionHtmlAdapterExtension,
|
||||||
type BlockNotionHtmlAdapterMatcher,
|
type BlockNotionHtmlAdapterMatcher,
|
||||||
|
CODE_BLOCK_WRAP_KEY,
|
||||||
HastUtils,
|
HastUtils,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
@@ -20,7 +21,8 @@ export const codeBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatcher =
|
|||||||
if (!code) {
|
if (!code) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { walkerContext, deltaConverter } = context;
|
const { walkerContext, deltaConverter, configs } = context;
|
||||||
|
const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true';
|
||||||
const codeText =
|
const codeText =
|
||||||
code.children.length === 1 && code.children[0].type === 'text'
|
code.children.length === 1 && code.children[0].type === 'text'
|
||||||
? code.children[0]
|
? code.children[0]
|
||||||
@@ -33,6 +35,7 @@ export const codeBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatcher =
|
|||||||
flavour: CodeBlockSchema.model.flavour,
|
flavour: CodeBlockSchema.model.flavour,
|
||||||
props: {
|
props: {
|
||||||
language: 'Plain Text',
|
language: 'Plain Text',
|
||||||
|
wrap,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: deltaConverter.astToDelta(codeText, {
|
delta: deltaConverter.astToDelta(codeText, {
|
||||||
|
|||||||
@@ -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));
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
|
export * from './code';
|
||||||
export * from './copy';
|
export * from './copy';
|
||||||
export * from './paste';
|
export * from './paste';
|
||||||
|
|||||||
@@ -1980,6 +1980,7 @@ describe('html to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
|
|||||||
@@ -2481,6 +2481,7 @@ describe('markdown to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
@@ -2526,6 +2527,7 @@ describe('markdown to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
@@ -2577,6 +2579,7 @@ describe('markdown to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
@@ -2628,6 +2631,7 @@ describe('markdown to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ describe('notion html to snapshot', () => {
|
|||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'Plain Text',
|
language: 'Plain Text',
|
||||||
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ export {
|
|||||||
AttachmentAdapter,
|
AttachmentAdapter,
|
||||||
AttachmentAdapterFactoryExtension,
|
AttachmentAdapterFactoryExtension,
|
||||||
AttachmentAdapterFactoryIdentifier,
|
AttachmentAdapterFactoryIdentifier,
|
||||||
|
codeBlockWrapMiddleware,
|
||||||
FetchUtils,
|
FetchUtils,
|
||||||
HtmlAdapter,
|
HtmlAdapter,
|
||||||
HtmlAdapterFactoryExtension,
|
HtmlAdapterFactoryExtension,
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import type {
|
|||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import {
|
import {
|
||||||
CodeBlockComponent,
|
CodeBlockComponent,
|
||||||
|
codeBlockWrapMiddleware,
|
||||||
defaultBlockMarkdownAdapterMatchers,
|
defaultBlockMarkdownAdapterMatchers,
|
||||||
|
defaultImageProxyMiddleware,
|
||||||
DividerBlockComponent,
|
DividerBlockComponent,
|
||||||
InlineDeltaToMarkdownAdapterExtensions,
|
InlineDeltaToMarkdownAdapterExtensions,
|
||||||
ListBlockComponent,
|
ListBlockComponent,
|
||||||
@@ -213,12 +215,12 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
|||||||
provider = container.provider();
|
provider = container.provider();
|
||||||
}
|
}
|
||||||
if (latestAnswer && schema) {
|
if (latestAnswer && schema) {
|
||||||
markDownToDoc(
|
const middlewares = [
|
||||||
provider,
|
defaultImageProxyMiddleware,
|
||||||
schema,
|
codeBlockWrapMiddleware(true),
|
||||||
latestAnswer,
|
...(this.options.additionalMiddlewares ?? []),
|
||||||
this.options.additionalMiddlewares
|
];
|
||||||
)
|
markDownToDoc(provider, schema, latestAnswer, middlewares)
|
||||||
.then(doc => {
|
.then(doc => {
|
||||||
this.disposeDoc();
|
this.disposeDoc();
|
||||||
this._doc = doc.doc.getStore({
|
this._doc = doc.doc.getStore({
|
||||||
|
|||||||
@@ -206,17 +206,13 @@ export async function markDownToDoc(
|
|||||||
provider: ServiceProvider,
|
provider: ServiceProvider,
|
||||||
schema: Schema,
|
schema: Schema,
|
||||||
answer: string,
|
answer: string,
|
||||||
additionalMiddlewares?: TransformerMiddleware[]
|
middlewares?: TransformerMiddleware[]
|
||||||
) {
|
) {
|
||||||
// Should not create a new doc in the original collection
|
// Should not create a new doc in the original collection
|
||||||
const collection = new WorkspaceImpl({
|
const collection = new WorkspaceImpl({
|
||||||
schema,
|
schema,
|
||||||
});
|
});
|
||||||
collection.meta.initialize();
|
collection.meta.initialize();
|
||||||
const middlewares = [defaultImageProxyMiddleware];
|
|
||||||
if (additionalMiddlewares) {
|
|
||||||
middlewares.push(...additionalMiddlewares);
|
|
||||||
}
|
|
||||||
const transformer = new Transformer({
|
const transformer = new Transformer({
|
||||||
schema: collection.schema,
|
schema: collection.schema,
|
||||||
blobCRUD: collection.blobSync,
|
blobCRUD: collection.blobSync,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from '@blocksuite/affine/block-std';
|
} from '@blocksuite/affine/block-std';
|
||||||
import type { AffineAIPanelWidget } from '@blocksuite/affine/blocks';
|
import type { AffineAIPanelWidget } from '@blocksuite/affine/blocks';
|
||||||
import {
|
import {
|
||||||
|
defaultImageProxyMiddleware,
|
||||||
deleteTextCommand,
|
deleteTextCommand,
|
||||||
isInsideEdgelessEditor,
|
isInsideEdgelessEditor,
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
@@ -151,7 +152,8 @@ export const copyText = async (host: EditorHost, text: string) => {
|
|||||||
const previewDoc = await markDownToDoc(
|
const previewDoc = await markDownToDoc(
|
||||||
host.std.provider,
|
host.std.provider,
|
||||||
host.std.store.schema,
|
host.std.store.schema,
|
||||||
text
|
text,
|
||||||
|
[defaultImageProxyMiddleware]
|
||||||
);
|
);
|
||||||
const models = previewDoc
|
const models = previewDoc
|
||||||
.getBlocksByFlavour('affine:note')
|
.getBlocksByFlavour('affine:note')
|
||||||
|
|||||||
Reference in New Issue
Block a user