Skip to content

Commit

Permalink
fix: inline chat code blocks controller (#3809)
Browse files Browse the repository at this point in the history
* chore: improve inline chat codeblocks render

* chore: improve inline chat codeblocks render

* chore: improve code
  • Loading branch information
Ricbet committed Jun 27, 2024
1 parent 5a66542 commit 07a6f8a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
AbortError,
ChatResponse,
Deferred,
Emitter,
ErrorResponse,
Expand All @@ -20,10 +19,6 @@ export interface InlineChatControllerOptions {
*/
enableCodeblockRender: boolean;
}

const rgCodeBlockBefore = /```([a-zA-Z]+)?\n([\s\S]*)/;
const rgCodeBlockAfter = /([\s\S]+)?\n?```/;

export class InlineChatController {
static is(controller: any): boolean {
return controller instanceof InlineChatController && typeof controller.mountReadable === 'function';
Expand All @@ -41,59 +36,57 @@ export class InlineChatController {
private readonly _onError = new Emitter<ErrorResponse>();
public readonly onError: Event<ErrorResponse> = this._onError.event;

private isInCodeBlock = false;

constructor(readonly options?: InlineChatControllerOptions) {}

public deffered: Deferred<void> = new Deferred();

private fencedCodeBlocks(content: string): string {
let _content = content;

private calculateCodeBlocks(content: string): string {
if (!this.options?.enableCodeblockRender) {
return _content;
return content;
}

if (_content.includes(BACK_QUOTE_3_SYMBOL)) {
if (!this.isInCodeBlock) {
// 第一次进入代码块时,去除反引号符号
const match = _content.match(rgCodeBlockBefore);
if (match && match.length >= 3) {
_content = match[2];
}
} else {
const match = _content.match(rgCodeBlockAfter);
if (match && match.length >= 2) {
_content = match[1];
}
}
const lines = content.split('\n');

this.isInCodeBlock = !this.isInCodeBlock;
return _content || '';
}
let newContents: string[] = [];
let inBlock = false;
let startLine = 0;

if (this.isInCodeBlock) {
return _content;
}
lines.forEach((line, i) => {
if (!inBlock && line.startsWith(BACK_QUOTE_3_SYMBOL)) {
inBlock = true;
startLine = i + 1;
} else if (inBlock && line.startsWith(BACK_QUOTE_3_SYMBOL)) {
inBlock = false;
const endLine = i;
newContents = lines.slice(startLine, endLine);
}

return '';
if (inBlock && startLine !== i + 1) {
newContents.push(line);
}
});

return newContents.join('\n');
}

public async mountReadable(stream: SumiReadableStream<IChatProgress>): Promise<void> {
await this.deffered.promise;
const reply = new ReplyResponse('');
let wholeContent = '';

listenReadable<IChatProgress>(stream, {
onData: (data) => {
reply.updateMessage(this.fencedCodeBlocks((data as IChatContent).content));
const chatContent = (data as IChatContent).content;
wholeContent += chatContent;

const content = this.calculateCodeBlocks(wholeContent);
reply.updateMessage(content);
this._onData.fireAndAwait(reply);
},
onEnd: () => {
this.isInCodeBlock = false;
this._onEnd.fire();
},
onError: (error) => {
this.isInCodeBlock = false;
if (AbortError.is(error)) {
this._onAbort.fire();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di';
import { Disposable, ErrorResponse, ReplyResponse } from '@opensumi/ide-core-common';
import { ICodeEditor, IPosition, ITextModel, Position, Range, Selection } from '@opensumi/ide-monaco';
import { EOL, ICodeEditor, IPosition, ITextModel, Position, Selection } from '@opensumi/ide-monaco';
import { DefaultEndOfLine } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model';
import { createTextBuffer } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
import { ModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/modelService';

import { EResultKind } from '../inline-chat/inline-chat.service';
import { EComputerMode, InlineStreamDiffHandler } from '../inline-stream-diff/inline-stream-diff.handler';
Expand Down Expand Up @@ -117,18 +120,14 @@ export class SideBySideInlineDiffWidget extends BaseInlineDiffPreviewer<InlineDi
}
onData(data: ReplyResponse): void {
const { message } = data;
const modifiedModel = this.node.getModifiedModel();

const lastLine = modifiedModel!.getLineCount();
const lastColumn = modifiedModel!.getLineMaxColumn(lastLine);
const modifiedModel = this.node.getModifiedModel()!;

const range = new Range(lastLine, lastColumn, lastLine, lastColumn);
const defaultEOL = modifiedModel.getEOL() === EOL.CRLF ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF;
const { textBuffer, disposable } = createTextBuffer(message, defaultEOL);
const singleEditOperation = ModelService._computeEdits(modifiedModel, textBuffer);
modifiedModel.pushEditOperations([], singleEditOperation, () => []);

const edit = {
range,
text: message || '',
};
modifiedModel!.pushEditOperations(null, [edit], () => null);
disposable.dispose();
this.node.layout();
}
onError(error: ErrorResponse): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export enum EComputerMode {

@Injectable({ multiple: true })
export class InlineStreamDiffHandler extends Disposable {
private modifiedModel: ITextModel;
private virtualModel: ITextModel;
private rawOriginalTextLines: string[];
private livePreviewDiffDecorationModel: LivePreviewDiffDecorationModel;

Expand All @@ -52,7 +52,7 @@ export class InlineStreamDiffHandler extends Disposable {
this.livePreviewDiffDecorationModel = new LivePreviewDiffDecorationModel(this.monacoEditor, this.selection);

const modelService = StandaloneServices.get(IModelService);
this.modifiedModel = modelService.createModel('', null);
this.virtualModel = modelService.createModel('', null);

this.rawOriginalTextLines = this.getNewOriginalTextLines();
this.livePreviewDiffDecorationModel.calcTextLinesTokens(this.rawOriginalTextLines);
Expand Down Expand Up @@ -277,22 +277,12 @@ export class InlineStreamDiffHandler extends Disposable {
}

public addLinesToDiff(newText: string, computerMode: EComputerMode = EComputerMode.default): void {
const lastLine = this.modifiedModel.getLineCount();
const lastColumn = this.modifiedModel.getLineMaxColumn(lastLine);

const range = new Range(lastLine, lastColumn, lastLine, lastColumn);

const edit = {
range,
text: newText,
};
this.modifiedModel.pushEditOperations(null, [edit], () => null);

this.virtualModel.setValue(newText);
this.recompute(computerMode);
}

public recompute(computerMode: EComputerMode): void {
const newTextLines = this.modifiedModel.getLinesContent();
const newTextLines = this.virtualModel.getLinesContent();
const diffModel = this.computeDiff(this.rawOriginalTextLines, newTextLines, computerMode);
this.currentDiffModel = diffModel;

Expand Down

0 comments on commit 07a6f8a

Please sign in to comment.