Skip to content

Commit

Permalink
Joh/homely-damselfly (microsoft#213376)
Browse files Browse the repository at this point in the history
* chore - `ReplyResponse` cleanup

* associate hunk data with response id

* Associate hunk data with response state so that accepting hunks updates the text edit group

* first cut of moving N-edits conversion from inline chat to panel
  • Loading branch information
jrieken authored and andremmsilva committed May 26, 2024
1 parent 3d8c6fd commit 5535c05
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ export function registerChatCodeCompareBlockActions() {
const instaService = accessor.get(IInstantiationService);

const editor = instaService.createInstance(DefaultChatTextEditor);
await editor.apply(context.element, context.edit);
await editor.apply(context.element, context.edit, context.diffEditor);

await editorService.openEditor({
resource: context.edit.uri,
Expand Down
31 changes: 27 additions & 4 deletions src/vs/workbench/contrib/chat/browser/chatListRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import { IMarkdownVulnerability, annotateSpecialMarkdownContent } from '../commo
import { CodeBlockModelCollection } from '../common/codeBlockModelCollection';
import { IChatListItemRendererOptions } from './chat';
import { ChatMarkdownRenderer } from 'vs/workbench/contrib/chat/browser/chatMarkdownRenderer';
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';

const $ = dom.$;

Expand Down Expand Up @@ -1072,12 +1073,34 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
false
);
store.add(modified);
if (!chatTextEdit.state?.applied) {
for (const group of chatTextEdit.edits) {
const edits = group.map(TextEdit.asEditOperation);
modified.pushEditOperations(null, edits, () => null);

const editGroups: ISingleEditOperation[][] = [];
if (isResponseVM(element)) {
const chatModel = this.chatService.getSession(element.sessionId)!;

for (const request of chatModel.getRequests()) {
if (!request.response) {
continue;
}
for (const item of request.response.response.value) {
if (item.kind !== 'textEditGroup' || item.state?.applied) {
continue;
}
for (const group of item.edits) {
const edits = group.map(TextEdit.asEditOperation);
editGroups.push(edits);
}
}
if (request.response === element.model) {
break;
}
}
}

for (const edits of editGroups) {
modified.pushEditOperations(null, edits, () => null);
}

return {
modified,
original,
Expand Down
21 changes: 11 additions & 10 deletions src/vs/workbench/contrib/chat/browser/codeBlockPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ export class DefaultChatTextEditor {
@IDialogService private readonly dialogService: IDialogService,
) { }

async apply(response: IChatResponseModel | IChatResponseViewModel, item: IChatTextEditGroup): Promise<void> {
async apply(response: IChatResponseModel | IChatResponseViewModel, item: IChatTextEditGroup, diffEditor: IDiffEditor | undefined): Promise<void> {

if (!response.response.value.includes(item)) {
// bogous item
Expand All @@ -787,15 +787,16 @@ export class DefaultChatTextEditor {
return;
}

let diffEditor: IDiffEditor | undefined;
for (const candidate of this.editorService.listDiffEditors()) {
if (!candidate.getContainerDomNode().isConnected) {
continue;
}
const model = candidate.getModel();
if (!model || !isEqual(model.original.uri, item.uri) || model.modified.uri.scheme !== Schemas.vscodeChatCodeCompareBlock) {
diffEditor = candidate;
break;
if (!diffEditor) {
for (const candidate of this.editorService.listDiffEditors()) {
if (!candidate.getContainerDomNode().isConnected) {
continue;
}
const model = candidate.getModel();
if (!model || !isEqual(model.original.uri, item.uri) || model.modified.uri.scheme !== Schemas.vscodeChatCodeCompareBlock) {
diffEditor = candidate;
break;
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/vs/workbench/contrib/chat/common/chatModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ export interface IChatRequestModel {
readonly response?: IChatResponseModel;
}

export interface IChatTextEditGroupState {
sha1: string;
applied: number;
}

export interface IChatTextEditGroup {
uri: URI;
edits: TextEdit[][];
state?: {
sha1: string;
applied: number;
};
state?: IChatTextEditGroupState;
kind: 'textEditGroup';
}

Expand Down
64 changes: 46 additions & 18 deletions src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ import { StashedSession } from './inlineChatSession';
import { IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model';
import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatContentWidget';
import { MessageController } from 'vs/editor/contrib/message/browser/messageController';
import { ChatModel, IChatRequestModel, IResponse } from 'vs/workbench/contrib/chat/common/chatModel';
import { ChatModel, IChatRequestModel, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from 'vs/workbench/contrib/chat/common/chatModel';
import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
import { isEqual } from 'vs/base/common/resources';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
import { DefaultModelSHA1Computer } from 'vs/editor/common/services/modelService';
import { generateUuid } from 'vs/base/common/uuid';
import { isEqual } from 'vs/base/common/resources';

export const enum State {
CREATE_SESSION = 'CREATE_SESSION',
Expand Down Expand Up @@ -653,6 +655,13 @@ export class InlineChatController implements IEditorContribution {
let lastLength = 0;
let isFirstChange = true;

const sha1 = new DefaultModelSHA1Computer();
const textModel0Sha1 = sha1.canComputeSHA1(this._session.textModel0)
? sha1.computeSHA1(this._session.textModel0)
: generateUuid();
const editState: IChatTextEditGroupState = { sha1: textModel0Sha1, applied: 0 };
let localEditGroup: IChatTextEditGroup | undefined;

// apply edits
store.add(response.onDidChange(() => {

Expand All @@ -667,17 +676,18 @@ export class InlineChatController implements IEditorContribution {
return;
}

const edits = response.response.value.map(part => {
if (part.kind === 'textEditGroup' && isEqual(part.uri, this._session?.textModelN.uri)) {
return part.edits;
} else {
return [];
}
}).flat();
if (!localEditGroup) {
localEditGroup = <IChatTextEditGroup>response.response.value.find(part => part.kind === 'textEditGroup' && isEqual(part.uri, this._session?.textModelN.uri));
}

// const edits = response.edits.get(this._session!.textModelN.uri) ?? [];
if (!localEditGroup) {
return;
}

localEditGroup.state ??= editState;

const edits = localEditGroup.edits;
const newEdits = edits.slice(lastLength);
// console.log('NEW edits', newEdits, edits);
if (newEdits.length === 0) {
return; // NO change
}
Expand Down Expand Up @@ -720,7 +730,7 @@ export class InlineChatController implements IEditorContribution {
const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { computeMoves: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, ignoreTrimWhitespace: false }, 'advanced');
this._session.wholeRange.fixup(diff?.changes ?? []);

await this._session.hunkData.recompute();
await this._session.hunkData.recompute(editState);

this._zone.value.widget.updateToolbar(true);
this._zone.value.widget.updateProgress(false);
Expand Down Expand Up @@ -1007,15 +1017,33 @@ export class InlineChatController implements IEditorContribution {
return;
}

// TODO@jrieken REMOVE this as soon as we can mark responses as accepted
// and as soon as hunks support request-linking
const textEditsResponseCount = this._session.chatModel.getRequests().filter(request => request.response?.response.value.some(part => part.kind === 'textEditGroup')).length;
if (textEditsResponseCount > 1) {
return;
let someApplied = false;
let lastEdit: IChatTextEditGroup | undefined;

const uri = this._editor.getModel()?.uri;
const requests = this._session.chatModel.getRequests();
for (const request of requests) {
if (!request.response) {
continue;
}
for (const part of request.response.response.value) {
if (part.kind === 'textEditGroup' && isEqual(part.uri, uri)) {
// fully or partially applied edits
someApplied = someApplied || Boolean(part.state?.applied);
lastEdit = part;
}
}
}

const doEdits = this._strategy.cancel();

if (someApplied) {
assertType(lastEdit);
lastEdit.edits = [doEdits];
}

this._strategy.cancel();
await this._instaService.invokeFunction(moveToPanelChat, this._session?.chatModel);

this.cancelSession();
}

Expand Down
Loading

0 comments on commit 5535c05

Please sign in to comment.