Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/core/src/core/diff-viewer/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IPartialEditEvent } from '@opensumi/ide-ai-native/lib/browser/widget/in
import { Event, URI } from '@opensumi/ide-core-common';
import { IResourceOpenOptions } from '@opensumi/ide-editor';
import { ITheme } from '@opensumi/ide-theme';
import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
import { IAppInstance } from '../../editor';
import { LandingProps } from '../types';

Expand Down Expand Up @@ -45,6 +46,12 @@ export interface IDiffViewerHandle {
newContent: string,
options?: IResourceOpenDiffOptions,
) => Promise<void>;
openDiffInTabByStream: (
filePath: string,
oldContent: string,
stream: SumiReadableStream<string>,
options?: IResourceOpenOptions,
) => Promise<void>;
/**
* 打开标签页
*/
Expand Down
61 changes: 61 additions & 0 deletions packages/core/src/core/diff-viewer/internal/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Domain,
Emitter,
Event,
IChatProgress,
ILogger,
Sequencer,
URI,
Expand All @@ -16,11 +17,13 @@ import { IResourceOpenOptions, WorkbenchEditorService } from '@opensumi/ide-edit
import { Selection, SelectionDirection } from '@opensumi/ide-monaco';

import { Autowired } from '@opensumi/di';
import { InlineChatController } from '@opensumi/ide-ai-native/lib/browser/widget/inline-chat/inline-chat-controller';
import { LiveInlineDiffPreviewer } from '@opensumi/ide-ai-native/lib/browser/widget/inline-diff/inline-diff-previewer';
import { InlineDiffHandler } from '@opensumi/ide-ai-native/lib/browser/widget/inline-diff/inline-diff.handler';
import { EResultKind } from '@opensumi/ide-ai-native/lib/common';
import { IMenuRegistry, MenuContribution } from '@opensumi/ide-core-browser/lib/menu/next';
import { IEditor, IEditorDocumentModelService } from '@opensumi/ide-editor/lib/browser';
import { listenReadable, SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
import path from 'path';
import { IDiffViewerProps, IDiffViewerTab, IExtendPartialEditEvent, ITabChangedEvent } from '../common';
import { removeStart } from '../utils';
Expand Down Expand Up @@ -135,6 +138,63 @@ export class DiffViewerContribution implements CommandContribution, ClientAppCon
previewer.revealFirstDiff();
};

const openDiffInTabByStream = async (
filePath: string,
oldContent: string,
stream: SumiReadableStream<string>,
options?: IResourceOpenOptions,
) => {
const { uri, result: openResourceResult } = await openFileInTab(filePath, oldContent, {
...options,
preview: false,
});

if (!openResourceResult) {
throw new Error('Failed to open file in tab: ' + filePath);
}

const editor = openResourceResult.group.codeEditor;

const model = this.editorDocumentModelService.getModelReference(uri);
if (!model || !model.instance) {
throw new Error('Failed to get model reference: ' + filePath);
}

const monacoModel = model.instance.getMonacoModel();

monacoModel.setValue(oldContent);
const fullRange = monacoModel.getFullModelRange();

const controller = new InlineChatController();
const newStream = new SumiReadableStream<IChatProgress>();
controller.mountReadable(newStream);
listenReadable<string>(stream, {
onData(data) {
newStream.emitData({
kind: 'content',
content: data,
});
},
onEnd() {
newStream.end();
},
onError(error) {
newStream.emitError(error);
},
});

this.inlineDiffHandler.showPreviewerByStream(
editor.monacoEditor,
{
crossSelection: Selection.fromRange(fullRange, SelectionDirection.LTR),
chatResponse: controller,
previewerOptions: {
disposeWhenEditorClosed: false,
},
},
) as LiveInlineDiffPreviewer;
};

const getFilePathForEditor = (editor: IEditor) => {
return this.stripDirectory(editor.currentUri!.codeUri.fsPath);
};
Expand Down Expand Up @@ -184,6 +244,7 @@ export class DiffViewerContribution implements CommandContribution, ClientAppCon
openDiffInTab: async (filePath, oldContent, newContent, options?: IResourceOpenOptions) => {
await sequencer.queue(() => openDiffInTab(filePath, oldContent, newContent, options));
},
openDiffInTabByStream,
openFileInTab: async (filePath: string, content: string, options?: IResourceOpenOptions) => {
const { uri } = await openFileInTab(filePath, content, options);
return uri;
Expand Down
3 changes: 2 additions & 1 deletion packages/startup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
"@types/react-dom": "^18.2.0",
"split-retain": "^1.0.1"
},
"peerDependencies": {
"react": "^18.2.0",
Expand Down
37 changes: 32 additions & 5 deletions packages/startup/src/diff-viewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { createRoot } from 'react-dom/client';
import '../index.css';
import { DiffViewerRenderer } from '@codeblitzjs/ide-core/lib/api/renderDiffViewer';
import { IDiffViewerHandle } from '@codeblitzjs/ide-core/lib/core/diff-viewer';
import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
import splitRetain from 'split-retain';
import jsonData from './data.json';

const data = [
Expand All @@ -30,26 +32,42 @@ const data = [

data.push(...jsonData);

function createMockStream(data: string) {
const streamData = splitRetain(data, '\n');
const length = streamData.length;
const chatReadableStream = new SumiReadableStream<string>();

streamData.forEach((chunk, index) => {
setTimeout(() => {
chatReadableStream.emitData(chunk.toString());

if (length - 1 === index) {
chatReadableStream.end();
}
}, index * 100);
});

return chatReadableStream;
}

const App = () => {
const handleRef = useRef<IDiffViewerHandle | null>(null);
const [eventInfo, setEventInfo] = React.useState<any | null>(null);

const memo = useMemo(() => (
<DiffViewerRenderer
tabBarRightExtraContent={{
component: () => <div>hello</div>,
// component: () => <div>代码生成中</div>,
}}
appConfig={{
layoutViewSize: {
editorTabsHeight: 50
}
layoutViewSize: {},
}}
onWillApplyTheme={() => {
return {
'editorGroupHeader.tabsBackground': '#ECF1FE',
'editor.background': '#fff',
'aiNative.inlineDiffAddedRange': '#26bf6d1f',
'aiNative.inlineDiffRemovedRange': "#ff4d4f1e",
'aiNative.inlineDiffRemovedRange': '#ff4d4f1e',
'aiNative.inlineDiffAcceptPartialEdit': '#26bf6d80',
'aiNative.inlineDiffDiscardPartialEdit': '#ff4d4f80',
'aiNative.inlineDiffAcceptPartialEdit.foreground': '#000',
Expand Down Expand Up @@ -155,6 +173,15 @@ const App = () => {
>
reset
</button>
<button
onClick={() => {
if (!handleRef.current) return;
const item = data[data.length - 1];
handleRef.current.openDiffInTabByStream(item.path, item.oldCode, createMockStream(item.newCode));
}}
>
流式
</button>

{data.map((item, index) => {
return (
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ __metadata:
"@types/react-dom": "npm:^18.2.0"
antd: "npm:^4.0.0"
lodash: "npm:^4.17.21"
split-retain: "npm:^1.0.1"
tslib: "npm:^2.2.0"
peerDependencies:
react: ^18.2.0
Expand Down Expand Up @@ -14765,6 +14766,13 @@ __metadata:
languageName: node
linkType: hard

"split-retain@npm:^1.0.1":
version: 1.0.1
resolution: "split-retain@npm:1.0.1"
checksum: 10/8fe5217e0e2953141ddbce755cc68a5bb2db4f071e2a56991c57b9aabb999ea2d74868e166e288e9247d1920b611d4477bb81fab666157db433066de0d787631
languageName: node
linkType: hard

"split-string@npm:^3.0.1, split-string@npm:^3.0.2":
version: 3.1.0
resolution: "split-string@npm:3.1.0"
Expand Down