Skip to content

Commit

Permalink
feat: support rate edit controller (#3896)
Browse files Browse the repository at this point in the history
* feat: support rate edit controller

* fix: setValue

* chore: improve code

* fix: stream end

* chore: rebase

* chore: add pushRateFinallyDiffStack

* fix: typo

* fix: discard

* fix: side by side
  • Loading branch information
Ricbet authored Jul 31, 2024
1 parent 371f2cb commit 50af6c9
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export abstract class BaseInlineDiffPreviewer<N extends IDisposable> extends Dis

public mount(contentWidget: AIInlineContentWidget): void {
this.inlineContentWidget = contentWidget;

this.inlineContentWidget.addDispose(this);
}

public layout(): void {
Expand Down Expand Up @@ -189,10 +191,12 @@ export class SideBySideInlineDiffWidget extends BaseInlineDiffPreviewer<InlineDi
}
onData(data: ReplyResponse): void {
const { message } = data;

const indentMessage = this.formatIndentation(message);
const modifiedModel = this.node.getModifiedModel()!;

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

Expand Down Expand Up @@ -262,11 +266,11 @@ export class LiveInlineDiffPreviewer extends BaseInlineDiffPreviewer<InlineStrea
}
onEnd(): void {
const diffModel = this.node.recompute(EComputerMode.legacy);
this.node.readyRender(diffModel);
this.node.pushRateFinallyDiffStack(diffModel);
}
setValue(content: string): void {
this.node.addLinesToDiff(this.formatIndentation(content));
this.onEnd();
const diffModel = this.node.recompute(EComputerMode.legacy, this.formatIndentation(content));
this.node.finallyRender(diffModel);
}
serializeState(): IExtendedSerializedState {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CancellationTokenSource,
Disposable,
Event,
FRAME_THREE,
IDisposable,
InlineChatFeatureRegistryToken,
ReplyResponse,
Expand Down Expand Up @@ -221,7 +222,7 @@ export class InlineInputHandler extends Disposable {
Event.debounce(
collection.onDidChange.bind(collection),
() => {},
16 * 3,
FRAME_THREE,
)(() => {
if (!collection.getRange(0)) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di';
import { Disposable, Emitter, Event, RunOnceScheduler, sleep } from '@opensumi/ide-core-browser';
import { Disposable, Emitter, Event, FRAME_THREE, sleep } from '@opensumi/ide-core-browser';
import { ISingleEditOperation } from '@opensumi/ide-editor';
import { ICodeEditor, ITextModel, Range, Selection } from '@opensumi/ide-monaco';
import { StandaloneServices } from '@opensumi/ide-monaco/lib/browser/monaco-api/services';
Expand Down Expand Up @@ -54,9 +54,6 @@ export class InlineStreamDiffHandler extends Disposable {

private livePreviewDiffDecorationModel: LivePreviewDiffDecorationModel;

private schedulerHandleEdits: RunOnceScheduler;
private currentDiffModel: IComputeDiffData;

private undoRedoGroup: UndoRedoGroup;
private originalModel: ITextModel;
private inlineStreamDiffComputer: InlineStreamDiffComputer = new InlineStreamDiffComputer();
Expand Down Expand Up @@ -87,14 +84,6 @@ export class InlineStreamDiffHandler extends Disposable {
return lineTokens;
});

this.schedulerHandleEdits = this.registerDispose(
new RunOnceScheduler(() => {
if (this.currentDiffModel) {
this.handleEdits(this.currentDiffModel);
}
}, 16 * 3),
);

this.initializeDecorationModel();
}

Expand Down Expand Up @@ -386,32 +375,59 @@ export class InlineStreamDiffHandler extends Disposable {
this._onDidEditChange.fire();
}

private doSchedulerEdits(): void {
if (!this.schedulerHandleEdits.isScheduled()) {
this.schedulerHandleEdits.schedule();
}
}

public recompute(computerMode: EComputerMode, newContent?: string): IComputeDiffData {
if (newContent) {
this.virtualModel.setValue(newContent);
}

const newTextLines = this.virtualModel.getLinesContent();
this.currentDiffModel = this.computeDiff(this.rawOriginalTextLines, newTextLines, computerMode);
return this.currentDiffModel;
return this.computeDiff(this.rawOriginalTextLines, newTextLines, computerMode);
}

private currentEditLine = 0;
private finallyDiffModel: IComputeDiffData | null = null;
private isEditing = false;
private async rateEditController(): Promise<void> {
if (this.isEditing === false) {
this.isEditing = true;

while (this.currentEditLine <= this.virtualModel.getLinesContent().length) {
const virtualTextLines = this.virtualModel.getLinesContent();
const currentText = virtualTextLines.slice(0, this.currentEditLine);
const currentDiffModel = this.computeDiff(this.rawOriginalTextLines, currentText);
this.handleEdits(currentDiffModel);

this.currentEditLine += 1;

await sleep(FRAME_THREE);
}

if (this.finallyDiffModel) {
this.finallyRender(this.finallyDiffModel);
}

this.isEditing = false;
}
}

public addLinesToDiff(newText: string, computerMode: EComputerMode = EComputerMode.default): void {
this.recompute(computerMode, newText);
this.doSchedulerEdits();
this.rateEditController();
}

public readyRender(diffModel: IComputeDiffData): void {
public pushRateFinallyDiffStack(diffModel: IComputeDiffData): void {
this.finallyDiffModel = diffModel;

// 可能存在 rate editr controller 处理完之后接口层流式才结束
if (this.isEditing === false) {
this.finallyRender(this.finallyDiffModel);
}
}

public finallyRender(diffModel: IComputeDiffData): void {
// 流式结束后才会确定所有的 added range,再渲染 partial edit widgets
this.renderPartialEditWidgets(diffModel);
this.schedulerHandleEdits.trigger();

this.handleEdits(diffModel);
this.pushStackElement();
this.monacoEditor.focus();
}
Expand All @@ -434,7 +450,6 @@ export class InlineStreamDiffHandler extends Disposable {
this.livePreviewDiffDecorationModel.discardUnProcessed();
this.dispose();
}

revealFirstDiff() {
this.livePreviewDiffDecorationModel.revealFirstDiff();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ReactDOMClient from 'react-dom/client';

import { Autowired, Injectable } from '@opensumi/di';
import { AppConfig, ConfigProvider, StackingLevelStr } from '@opensumi/ide-core-browser';
import { Disposable, runWhenIdle } from '@opensumi/ide-core-common';
import { Disposable, FRAME_THREE, runWhenIdle } from '@opensumi/ide-core-common';

import * as monaco from '../../common';
import { ContentWidgetPositionPreference } from '../monaco-exports/editor';
Expand Down Expand Up @@ -124,7 +124,7 @@ export abstract class ReactInlineContentWidget extends Disposable implements IIn

const throttled = throttle(() => {
requestAnimationFrame(() => this.layoutContentWidget());
}, 16 * 3);
}, FRAME_THREE);

const id = monaco.createLayoutEventType(this.id());

Expand Down
18 changes: 11 additions & 7 deletions packages/monaco/src/browser/contrib/merge-editor/view/grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
IOpenMergeEditorArgs,
MergeEditorInputData,
} from '@opensumi/ide-core-browser/lib/monaco/merge-editor-widget';
import { CommandRegistry } from '@opensumi/ide-core-common';
import { CommandRegistry, FRAME_THREE } from '@opensumi/ide-core-common';
import { IWorkspaceService } from '@opensumi/ide-workspace';

import { MergeActions } from '../components/merge-actions';
Expand Down Expand Up @@ -53,12 +53,16 @@ const TitleHead: React.FC<ITitleHeadProps> = ({ contrastType }) => {
const [encoding, setEncoding] = useState<string>('');
const [currentURI, setCurrentURI] = useState<URI>();

useDisposable(() => commandRegistry.afterExecuteCommand(EDITOR_COMMANDS.CHANGE_ENCODING.id, () => {
update();
setTimeout(() => {
mergeEditorService.compare();
}, 16 * 3);
}), [commandRegistry, mergeEditorService]);
useDisposable(
() =>
commandRegistry.afterExecuteCommand(EDITOR_COMMANDS.CHANGE_ENCODING.id, () => {
update();
setTimeout(() => {
mergeEditorService.compare();
}, FRAME_THREE);
}),
[commandRegistry, mergeEditorService],
);

const toRelativePath = useCallback((uri: URI) => {
// 获取相对路径
Expand Down
3 changes: 2 additions & 1 deletion packages/preferences/src/browser/preferences.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { VirtualList } from '@opensumi/ide-components/lib/virtual-list';
import { IVirtualListRange } from '@opensumi/ide-components/lib/virtual-list/types';
import {
Disposable,
FRAME_THREE,
IPreferenceSettingsService,
IResolvedSettingSection,
ISettingGroup,
Expand Down Expand Up @@ -402,7 +403,7 @@ const PreferenceBody = (props: PreferenceBodyProps) => {
setFocusItem(item._path);
}
},
16 * 3,
FRAME_THREE,
{
leading: true,
trailing: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class AINativeContribution implements AINativeCoreContribution {
{
providerDiffPreviewStrategy: async (editor: ICodeEditor, token) => {
const crossCode = this.getCrossCode(editor);
const prompt = `Comment the code: \`\`\`\n ${crossCode}\`\`\`. It is required to return only the code results without explanation.`;
const prompt = `Add Chinese comments to the code: \`\`\`\n ${crossCode}\`\`\`.`;

const controller = new InlineChatController({ enableCodeblockRender: true });
const stream = await this.aiBackService.requestStream(prompt, {}, token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import debounce from 'lodash/debounce';
import { observer } from 'mobx-react-lite';
import React from 'react';

import { getIcon, localize, useEventEffect, useInjectable } from '@opensumi/ide-core-browser';
import { FRAME_THREE, getIcon, localize, useEventEffect, useInjectable } from '@opensumi/ide-core-browser';

import {
ITerminalController,
Expand Down Expand Up @@ -53,7 +53,7 @@ export default observer(() => {
const [errors, setErrors] = React.useState(errorService.errors);
const func = debounce(() => {
setErrors(errorService.errors);
}, 16 * 3);
}, FRAME_THREE);
useEventEffect(errorService.onErrorsChange, func);

const renderWidget = React.useCallback(
Expand Down
5 changes: 5 additions & 0 deletions packages/utils/src/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { canceled } from './errors';

export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;

// 浏览器渲染帧
export const FRAME_ONE = 16;
export const FRAME_TWO = FRAME_ONE * 2;
export const FRAME_THREE = FRAME_ONE * 3;

export interface CancelablePromise<T> extends Promise<T> {
cancel(): void;
}
Expand Down

0 comments on commit 50af6c9

Please sign in to comment.