Skip to content

Commit c70211f

Browse files
authored
better keyboard handling for enter/delete/click (#250010)
* keep focus in input * better keyboard attachments * lots of better handling * better handling of keyboard attachments pt. 2 * cleanup
1 parent fb3c407 commit c70211f

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ abstract class AbstractChatAttachmentWidget extends Disposable {
6464
return this._onDidDelete.event;
6565
}
6666

67+
private readonly _onDidOpen: event.Emitter<void> = this._register(new event.Emitter<void>());
68+
get onDidOpen(): event.Event<void> {
69+
return this._onDidOpen.event;
70+
}
71+
6772
constructor(
6873
private readonly attachment: IChatRequestVariableEntry,
6974
private readonly options: { shouldFocusClearButton: boolean; supportsDeletion: boolean },
@@ -151,6 +156,7 @@ abstract class AbstractChatAttachmentWidget extends Disposable {
151156
editorOptions: { ...openTextEditorOptions, preserveFocus: true },
152157
};
153158
await this.openerService.open(resource, options);
159+
this._onDidOpen.fire();
154160
this.element.focus();
155161
}
156162
}

src/vs/workbench/contrib/chat/browser/chatInputPart.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
222222
}
223223

224224
private _indexOfLastAttachedContextDeletedWithKeyboard: number;
225+
private _indexOfLastOpenedContext: number;
225226

226227
private _implicitContext: ChatImplicitContext | undefined;
227228
public get implicitContext(): ChatImplicitContext | undefined {
@@ -409,6 +410,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
409410
this._onDidAcceptFollowup = this._register(new Emitter<{ followup: IChatFollowup; response: IChatResponseViewModel | undefined }>());
410411
this.onDidAcceptFollowup = this._onDidAcceptFollowup.event;
411412
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
413+
this._indexOfLastOpenedContext = -1;
412414
this._onDidChangeVisibility = this._register(new Emitter<boolean>());
413415
this._contextResourceLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility.event });
414416
this.inputEditorHeight = 0;
@@ -977,12 +979,18 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
977979
);
978980

979981
this._register(this._implicitContext.onDidChangeValue(() => {
982+
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
980983
this._handleAttachedContextChange();
981984
}));
982985
}
983986

984987
this.renderAttachedContext();
985-
this._register(this._attachmentModel.onDidChange(() => this._handleAttachedContextChange()));
988+
this._register(this._attachmentModel.onDidChange((e) => {
989+
if (e.added.length > 0) {
990+
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
991+
}
992+
this._handleAttachedContextChange();
993+
}));
986994
this.renderChatEditingSessionState(null);
987995

988996
if (this.options.renderWorkingSet) {
@@ -1239,6 +1247,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12391247
dom.setVisibility(hasAttachments, this.attachedContextContainer);
12401248
if (!attachments.length) {
12411249
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
1250+
this._indexOfLastOpenedContext = -1;
12421251
}
12431252

12441253
this.promptFileAttached.set(this.hasPromptFileAttachments);
@@ -1247,7 +1256,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12471256
for (const [index, attachment] of attachments) {
12481257
const resource = URI.isUri(attachment.value) ? attachment.value : attachment.value && typeof attachment.value === 'object' && 'uri' in attachment.value && URI.isUri(attachment.value.uri) ? attachment.value.uri : undefined;
12491258
const range = attachment.value && typeof attachment.value === 'object' && 'range' in attachment.value && Range.isIRange(attachment.value.range) ? attachment.value.range : undefined;
1250-
const shouldFocusClearButton = index === Math.min(this._indexOfLastAttachedContextDeletedWithKeyboard, this.attachmentModel.size - 1);
1259+
const shouldFocusClearButton = index === Math.min(this._indexOfLastAttachedContextDeletedWithKeyboard, this.attachmentModel.size - 1) && this._indexOfLastAttachedContextDeletedWithKeyboard > -1;
12511260

12521261
let attachmentWidget;
12531262
const options = { shouldFocusClearButton, supportsDeletion: true };
@@ -1268,10 +1277,23 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12681277
} else {
12691278
attachmentWidget = this.instantiationService.createInstance(DefaultChatAttachmentWidget, resource, range, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate);
12701279
}
1280+
1281+
if (shouldFocusClearButton) {
1282+
attachmentWidget.element.focus();
1283+
}
1284+
1285+
if (index === Math.min(this._indexOfLastOpenedContext, this.attachmentModel.size - 1)) {
1286+
attachmentWidget.element.focus();
1287+
}
1288+
12711289
store.add(attachmentWidget);
12721290
store.add(attachmentWidget.onDidDelete(e => {
12731291
this.handleAttachmentDeletion(e, index, attachment);
12741292
}));
1293+
1294+
store.add(attachmentWidget.onDidOpen(e => {
1295+
this.handleAttachmentOpen(index, attachment);
1296+
}));
12751297
}
12761298

12771299
const implicitUri = this.implicitContext?.value;
@@ -1290,6 +1312,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12901312
if (oldHeight !== this.attachmentsContainer.offsetHeight) {
12911313
this._onDidChangeHeight.fire();
12921314
}
1315+
1316+
this._indexOfLastOpenedContext = -1;
12931317
}
12941318

12951319
private handleAttachmentDeletion(e: KeyboardEvent | unknown, index: number, attachment: IChatRequestVariableEntry) {
@@ -1309,6 +1333,15 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
13091333
this.renderAttachedContext();
13101334
}
13111335

1336+
private handleAttachmentOpen(index: number, attachment: IChatRequestVariableEntry): void {
1337+
this._indexOfLastOpenedContext = index;
1338+
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
1339+
1340+
if (this._attachmentModel.size === 0) {
1341+
this.focus();
1342+
}
1343+
}
1344+
13121345
private handleAttachmentNavigation(e: StandardKeyboardEvent): void {
13131346
if (!e.equals(KeyCode.LeftArrow) && !e.equals(KeyCode.RightArrow)) {
13141347
return;

0 commit comments

Comments
 (0)