mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Joh/homely-damselfly (#213376)
* 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
This commit is contained in:
parent
6bd20f68f8
commit
2e98100d22
|
@ -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,
|
||||
|
|
|
@ -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.$;
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
@ -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(() => {
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,16 +6,15 @@
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ResourceEdit, ResourceFileEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IWorkspaceTextEdit, TextEdit, WorkspaceEdit } from 'vs/editor/common/languages';
|
||||
import { TextEdit } from 'vs/editor/common/languages';
|
||||
import { IIdentifiedSingleEditOperation, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { EditMode, IInlineChatSession, IInlineChatBulkEditResponse, IInlineChatEditResponse, InlineChatResponseType, CTX_INLINE_CHAT_HAS_STASHED_SESSION } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import { EditMode, IInlineChatSession, CTX_INLINE_CHAT_HAS_STASHED_SESSION, IInlineChatResponse } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { isCancellationError } from 'vs/base/common/errors';
|
||||
import { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { DetailedLineRangeMapping, LineRangeMapping, RangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
|
@ -32,7 +31,7 @@ import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
|||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ChatModel, IChatRequestModel, IChatResponseModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { ChatModel, IChatRequestModel, IChatResponseModel, IChatTextEditGroupState } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IChatAgent } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
|
||||
|
@ -316,56 +315,40 @@ export class ErrorResponse {
|
|||
|
||||
export class ReplyResponse {
|
||||
|
||||
readonly allLocalEdits: TextEdit[][] = [];
|
||||
readonly untitledTextModel: IUntitledTextEditorModel | undefined;
|
||||
readonly workspaceEdit: WorkspaceEdit | undefined;
|
||||
|
||||
|
||||
constructor(
|
||||
readonly raw: IInlineChatBulkEditResponse | IInlineChatEditResponse,
|
||||
readonly mdContent: IMarkdownString,
|
||||
readonly raw: IInlineChatResponse,
|
||||
localUri: URI,
|
||||
readonly modelAltVersionId: number,
|
||||
progressEdits: TextEdit[][],
|
||||
readonly requestId: string,
|
||||
readonly chatResponse: IChatResponseModel | undefined,
|
||||
readonly chatRequest: IChatRequestModel,
|
||||
readonly chatResponse: IChatResponseModel,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@ILanguageService private readonly _languageService: ILanguageService,
|
||||
) {
|
||||
|
||||
const editsMap = new ResourceMap<TextEdit[][]>();
|
||||
const edits = ResourceEdit.convert(raw.edits);
|
||||
|
||||
editsMap.set(localUri, [...progressEdits]);
|
||||
|
||||
if (raw.type === InlineChatResponseType.EditorEdit) {
|
||||
//
|
||||
editsMap.get(localUri)!.push(raw.edits);
|
||||
|
||||
} else if (raw.type === InlineChatResponseType.BulkEdit) {
|
||||
//
|
||||
const edits = ResourceEdit.convert(raw.edits);
|
||||
|
||||
for (const edit of edits) {
|
||||
if (edit instanceof ResourceFileEdit) {
|
||||
if (edit.newResource && !edit.oldResource) {
|
||||
editsMap.set(edit.newResource, []);
|
||||
if (edit.options.contents) {
|
||||
console.warn('CONTENT not supported');
|
||||
}
|
||||
}
|
||||
} else if (edit instanceof ResourceTextEdit) {
|
||||
//
|
||||
const array = editsMap.get(edit.resource);
|
||||
if (array) {
|
||||
array.push([edit.textEdit]);
|
||||
} else {
|
||||
editsMap.set(edit.resource, [[edit.textEdit]]);
|
||||
for (const edit of edits) {
|
||||
if (edit instanceof ResourceFileEdit) {
|
||||
if (edit.newResource && !edit.oldResource) {
|
||||
editsMap.set(edit.newResource, []);
|
||||
if (edit.options.contents) {
|
||||
console.warn('CONTENT not supported');
|
||||
}
|
||||
}
|
||||
} else if (edit instanceof ResourceTextEdit) {
|
||||
//
|
||||
const array = editsMap.get(edit.resource);
|
||||
if (array) {
|
||||
array.push([edit.textEdit]);
|
||||
} else {
|
||||
editsMap.set(edit.resource, [[edit.textEdit]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let needsWorkspaceEdit = false;
|
||||
|
||||
for (const [uri, edits] of editsMap) {
|
||||
|
||||
|
@ -376,8 +359,6 @@ export class ReplyResponse {
|
|||
}
|
||||
|
||||
const isLocalUri = isEqual(uri, localUri);
|
||||
needsWorkspaceEdit = needsWorkspaceEdit || (uri.scheme !== Schemas.untitled && !isLocalUri);
|
||||
|
||||
if (uri.scheme === Schemas.untitled && !isLocalUri && !this.untitledTextModel) { //TODO@jrieken the first untitled model WINS
|
||||
const langSelection = this._languageService.createByFilepathOrFirstLine(uri, undefined);
|
||||
const untitledTextModel = this._textFileService.untitled.create({
|
||||
|
@ -388,18 +369,6 @@ export class ReplyResponse {
|
|||
untitledTextModel.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
this.allLocalEdits = editsMap.get(localUri) ?? [];
|
||||
|
||||
if (needsWorkspaceEdit) {
|
||||
const workspaceEdits: IWorkspaceTextEdit[] = [];
|
||||
for (const [uri, edits] of editsMap) {
|
||||
for (const edit of edits.flat()) {
|
||||
workspaceEdits.push({ resource: uri, textEdit: edit, versionId: undefined });
|
||||
}
|
||||
}
|
||||
this.workspaceEdit = { edits: workspaceEdits };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,7 +440,7 @@ export class HunkData {
|
|||
private static readonly _HUNK_THRESHOLD = 8;
|
||||
|
||||
private readonly _store = new DisposableStore();
|
||||
private readonly _data = new Map<RawHunk, { textModelNDecorations: string[]; textModel0Decorations: string[]; state: HunkState }>();
|
||||
private readonly _data = new Map<RawHunk, RawHunkData>();
|
||||
private _ignoreChanges: boolean = false;
|
||||
|
||||
constructor(
|
||||
|
@ -602,7 +571,7 @@ export class HunkData {
|
|||
this._textModel0.pushEditOperations(null, edits, () => null);
|
||||
}
|
||||
|
||||
async recompute() {
|
||||
async recompute(editState: IChatTextEditGroupState) {
|
||||
|
||||
const diff = await this._editorWorkerService.computeDiff(this._textModel0.uri, this._textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, computeMoves: false }, 'advanced');
|
||||
|
||||
|
@ -656,6 +625,7 @@ export class HunkData {
|
|||
}
|
||||
|
||||
this._data.set(hunk, {
|
||||
editState,
|
||||
textModelNDecorations,
|
||||
textModel0Decorations,
|
||||
state: HunkState.Pending
|
||||
|
@ -689,7 +659,7 @@ export class HunkData {
|
|||
discardAll() {
|
||||
const edits: ISingleEditOperation[][] = [];
|
||||
for (const item of this.getInfo()) {
|
||||
if (item.getState() !== HunkState.Rejected) {
|
||||
if (item.getState() === HunkState.Pending) {
|
||||
edits.push(this._discardEdits(item));
|
||||
}
|
||||
}
|
||||
|
@ -746,6 +716,7 @@ export class HunkData {
|
|||
}
|
||||
this._textModel0.pushEditOperations(null, edits, () => null);
|
||||
data.state = HunkState.Accepted;
|
||||
data.editState.applied += 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -764,6 +735,13 @@ class RawHunk {
|
|||
) { }
|
||||
}
|
||||
|
||||
type RawHunkData = {
|
||||
textModelNDecorations: string[];
|
||||
textModel0Decorations: string[];
|
||||
state: HunkState;
|
||||
editState: IChatTextEditGroupState;
|
||||
};
|
||||
|
||||
export const enum HunkState {
|
||||
Pending = 0,
|
||||
Accepted = 1,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
@ -23,7 +22,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
|
||||
import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { CTX_INLINE_CHAT_HAS_PROVIDER, EditMode, IInlineChatBulkEditResponse, IInlineChatSession, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import { CTX_INLINE_CHAT_HAS_PROVIDER, EditMode, IInlineChatResponse, IInlineChatSession } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { EmptyResponse, ErrorResponse, HunkData, ReplyResponse, Session, SessionExchange, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession';
|
||||
|
@ -199,17 +198,11 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
|
|||
inlineResponse = new EmptyResponse();
|
||||
} else {
|
||||
// replay response
|
||||
const markdownContent = new MarkdownString();
|
||||
const raw: IInlineChatBulkEditResponse = {
|
||||
id: Math.random(),
|
||||
type: InlineChatResponseType.BulkEdit,
|
||||
message: markdownContent,
|
||||
const raw: IInlineChatResponse = {
|
||||
edits: { edits: [] },
|
||||
};
|
||||
for (const item of response.response.value) {
|
||||
if (item.kind === 'markdownContent') {
|
||||
markdownContent.value += item.content.value;
|
||||
} else if (item.kind === 'textEditGroup') {
|
||||
if (item.kind === 'textEditGroup') {
|
||||
for (const group of item.edits) {
|
||||
for (const edit of group) {
|
||||
raw.edits.edits.push({
|
||||
|
@ -225,12 +218,10 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
|
|||
inlineResponse = this._instaService.createInstance(
|
||||
ReplyResponse,
|
||||
raw,
|
||||
markdownContent,
|
||||
session.textModelN.uri,
|
||||
modelAltVersionIdNow,
|
||||
[],
|
||||
e.request.id,
|
||||
e.request.response
|
||||
e.request,
|
||||
response
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ export abstract class EditModeStrategy {
|
|||
continue;
|
||||
}
|
||||
|
||||
await editor.apply(request.response, item);
|
||||
await editor.apply(request.response, item, undefined);
|
||||
|
||||
if (item.uri.scheme === Schemas.untitled) {
|
||||
const untitled = this._textFileService.untitled.get(item.uri);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { TextEdit, WorkspaceEdit } from 'vs/editor/common/languages';
|
||||
import { WorkspaceEdit } from 'vs/editor/common/languages';
|
||||
import { localize } from 'vs/nls';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
@ -24,13 +24,6 @@ export interface IInlineChatSession {
|
|||
wholeRange?: IRange;
|
||||
}
|
||||
|
||||
export type IInlineChatResponse = IInlineChatEditResponse | IInlineChatBulkEditResponse;
|
||||
|
||||
export const enum InlineChatResponseType {
|
||||
EditorEdit = 'editorEdit',
|
||||
BulkEdit = 'bulkEdit'
|
||||
}
|
||||
|
||||
export const enum InlineChatResponseTypes {
|
||||
Empty = 'empty',
|
||||
OnlyEdits = 'onlyEdits',
|
||||
|
@ -38,18 +31,7 @@ export const enum InlineChatResponseTypes {
|
|||
Mixed = 'mixed'
|
||||
}
|
||||
|
||||
export interface IInlineChatEditResponse {
|
||||
id: number;
|
||||
type: InlineChatResponseType.EditorEdit;
|
||||
edits: TextEdit[];
|
||||
message?: IMarkdownString;
|
||||
placeholder?: string;
|
||||
wholeRange?: IRange;
|
||||
}
|
||||
|
||||
export interface IInlineChatBulkEditResponse {
|
||||
id: number;
|
||||
type: InlineChatResponseType.BulkEdit;
|
||||
export interface IInlineChatResponse {
|
||||
edits: WorkspaceEdit;
|
||||
message?: IMarkdownString;
|
||||
placeholder?: string;
|
||||
|
@ -77,7 +59,6 @@ export const CTX_INLINE_CHAT_INNER_CURSOR_END = new RawContextKey<boolean>('inli
|
|||
export const CTX_INLINE_CHAT_OUTER_CURSOR_POSITION = new RawContextKey<'above' | 'below' | ''>('inlineChatOuterCursorPosition', '', localize('inlineChatOuterCursorPosition', "Whether the cursor of the outer editor is above or below the interactive editor input"));
|
||||
export const CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST = new RawContextKey<boolean>('inlineChatHasActiveRequest', false, localize('inlineChatHasActiveRequest', "Whether interactive editor has an active request"));
|
||||
export const CTX_INLINE_CHAT_HAS_STASHED_SESSION = new RawContextKey<boolean>('inlineChatHasStashedSession', false, localize('inlineChatHasStashedSession', "Whether interactive editor has kept a session for quick restore"));
|
||||
export const CTX_INLINE_CHAT_LAST_RESPONSE_TYPE = new RawContextKey<InlineChatResponseType | undefined>('inlineChatLastResponseType', undefined, localize('inlineChatResponseType', "What type was the last response of the current interactive editor session"));
|
||||
export const CTX_INLINE_CHAT_RESPONSE_TYPES = new RawContextKey<InlineChatResponseTypes | undefined>('inlineChatResponseTypes', InlineChatResponseTypes.Empty, localize('inlineChatResponseTypes', "What type was the responses have been receieved"));
|
||||
export const CTX_INLINE_CHAT_DID_EDIT = new RawContextKey<boolean>('inlineChatDidEdit', undefined, localize('inlineChatDidEdit', "Whether interactive editor did change any code"));
|
||||
export const CTX_INLINE_CHAT_USER_DID_EDIT = new RawContextKey<boolean>('inlineChatUserDidEdit', undefined, localize('inlineChatUserDidEdit', "Whether the user did changes ontop of the inline chat"));
|
||||
|
|
|
@ -160,7 +160,7 @@ suite('InlineChatSession', function () {
|
|||
} finally {
|
||||
session.hunkData.ignoreTextModelNChanges = false;
|
||||
}
|
||||
await session.hunkData.recompute();
|
||||
await session.hunkData.recompute({ applied: 0, sha1: 'fakeSha1' });
|
||||
}
|
||||
|
||||
function makeEdit(edit: EditOperation | EditOperation[]) {
|
||||
|
@ -433,4 +433,51 @@ suite('InlineChatSession', function () {
|
|||
assert.strictEqual(session.textModelN.getValue(), session.textModel0.getValue());
|
||||
});
|
||||
|
||||
test('HunkData, accept, discardAll', async function () {
|
||||
|
||||
const session = await inlineChatSessionService.createSession(editor, { editMode: EditMode.Live }, CancellationToken.None);
|
||||
assertType(session);
|
||||
|
||||
await makeEditAsAi([EditOperation.insert(new Position(1, 1), 'AI_EDIT\n'), EditOperation.insert(new Position(10, 1), 'AI_EDIT\n')]);
|
||||
|
||||
assert.strictEqual(session.hunkData.size, 2);
|
||||
assert.ok(!session.textModel0.equalsTextBuffer(session.textModelN.getTextBuffer()));
|
||||
|
||||
const textModeNNow = session.textModelN.getValue();
|
||||
|
||||
session.hunkData.getInfo()[0].acceptChanges();
|
||||
assert.strictEqual(textModeNNow, session.textModelN.getValue());
|
||||
|
||||
session.hunkData.discardAll(); // all remaining
|
||||
assert.strictEqual(session.textModelN.getValue(), 'AI_EDIT\none\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven');
|
||||
assert.strictEqual(session.textModelN.getValue(), session.textModel0.getValue());
|
||||
|
||||
inlineChatSessionService.releaseSession(session);
|
||||
});
|
||||
|
||||
test('HunkData, discardAll return undo edits', async function () {
|
||||
|
||||
const session = await inlineChatSessionService.createSession(editor, { editMode: EditMode.Live }, CancellationToken.None);
|
||||
assertType(session);
|
||||
|
||||
await makeEditAsAi([EditOperation.insert(new Position(1, 1), 'AI_EDIT\n'), EditOperation.insert(new Position(10, 1), 'AI_EDIT\n')]);
|
||||
|
||||
assert.strictEqual(session.hunkData.size, 2);
|
||||
assert.ok(!session.textModel0.equalsTextBuffer(session.textModelN.getTextBuffer()));
|
||||
|
||||
const textModeNNow = session.textModelN.getValue();
|
||||
|
||||
session.hunkData.getInfo()[0].acceptChanges();
|
||||
assert.strictEqual(textModeNNow, session.textModelN.getValue());
|
||||
|
||||
const undoEdits = session.hunkData.discardAll(); // all remaining
|
||||
assert.strictEqual(session.textModelN.getValue(), 'AI_EDIT\none\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven');
|
||||
assert.strictEqual(session.textModelN.getValue(), session.textModel0.getValue());
|
||||
|
||||
// undo the discards
|
||||
session.textModelN.pushEditOperations(null, undoEdits, () => null);
|
||||
assert.strictEqual(textModeNNow, session.textModelN.getValue());
|
||||
|
||||
inlineChatSessionService.releaseSession(session);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue