Skip to content

Commit a6139a4

Browse files
authored
Fix hovers in chat attachments 2 (microsoft#229831)
fix attachment in other attachments render location...
1 parent a3c6381 commit a6139a4

File tree

1 file changed

+37
-43
lines changed

1 file changed

+37
-43
lines changed

src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ import { basename, dirname } from '../../../../../base/common/path.js';
1616
import { localize } from '../../../../../nls.js';
1717
import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../common/chatService.js';
1818
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
19-
import { StandardKeyboardEvent } from '../../../../../base/browser/keyboardEvent.js';
20-
import { KeyCode } from '../../../../../base/common/keyCodes.js';
2119
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
2220
import { createInstantHoverDelegate } from '../../../../../base/browser/ui/hover/hoverDelegateFactory.js';
21+
import { IManagedHoverContentOrFactory } from '../../../../../base/browser/ui/hover/hover.js';
2322

2423
export class ChatAttachmentsContentPart extends Disposable {
2524
private readonly attachedContextDisposables = this._register(new DisposableStore());
@@ -49,19 +48,22 @@ export class ChatAttachmentsContentPart extends Disposable {
4948

5049
this.variables.forEach(async (attachment) => {
5150
const widget = dom.append(container, dom.$('.chat-attached-context-attachment.show-file-icons'));
52-
const label = this._contextResourceLabels.create(widget, { supportIcons: true });
51+
const label = this._contextResourceLabels.create(widget, { supportIcons: true, hoverDelegate });
5352
const file = 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;
5453
const range = attachment.value && typeof attachment.value === 'object' && 'range' in attachment.value && Range.isIRange(attachment.value.range) ? attachment.value.range : undefined;
5554

5655
const correspondingContentReference = this.contentReferences.find((ref) => typeof ref.reference === 'object' && 'variableName' in ref.reference && ref.reference.variableName === attachment.name);
5756
const isAttachmentOmitted = correspondingContentReference?.options?.status?.kind === ChatResponseReferencePartStatusKind.Omitted;
5857
const isAttachmentPartialOrOmitted = isAttachmentOmitted || correspondingContentReference?.options?.status?.kind === ChatResponseReferencePartStatusKind.Partial;
5958

59+
let hoverElement: IManagedHoverContentOrFactory;
60+
let ariaLabel: string | undefined;
61+
6062
if (file && attachment.isFile) {
6163
const fileBasename = basename(file.path);
6264
const fileDirname = dirname(file.path);
6365
const friendlyName = `${fileBasename} ${fileDirname}`;
64-
let ariaLabel;
66+
6567
if (isAttachmentOmitted) {
6668
ariaLabel = range ? localize('chat.omittedFileAttachmentWithRange', "Omitted: {0}, line {1} to line {2}.", friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.omittedFileAttachment', "Omitted: {0}.", friendlyName);
6769
} else if (isAttachmentPartialOrOmitted) {
@@ -70,42 +72,27 @@ export class ChatAttachmentsContentPart extends Disposable {
7072
ariaLabel = range ? localize('chat.fileAttachmentWithRange3', "Attached: {0}, line {1} to line {2}.", friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.fileAttachment3', "Attached: {0}.", friendlyName);
7173
}
7274

75+
hoverElement = file.fsPath;
76+
7377
label.setFile(file, {
7478
fileKind: FileKind.FILE,
7579
hidePath: true,
7680
range,
7781
title: correspondingContentReference?.options?.status?.description
7882
});
79-
widget.ariaLabel = ariaLabel;
80-
widget.tabIndex = 0;
81-
widget.style.cursor = 'pointer';
82-
83-
this.attachedContextDisposables.add(dom.addDisposableListener(widget, dom.EventType.CLICK, async (e: MouseEvent) => {
84-
dom.EventHelper.stop(e, true);
85-
if (file) {
86-
this.openerService.open(
87-
file,
88-
{
89-
fromUserGesture: true,
90-
editorOptions: {
91-
selection: range
92-
} as any
93-
});
94-
}
95-
}));
9683
} else if (attachment.isImage) {
97-
let buffer: Uint8Array;
98-
const ariaLabel = localize('chat.imageAttachment', "Attached image, {0}", attachment.name);
99-
const pillIcon = dom.$('div.chat-attached-context-pill', {}, dom.$('span.codicon.codicon-file-media'));
84+
ariaLabel = localize('chat.imageAttachment', "Attached image, {0}", attachment.name);
10085

101-
const hoverElement = dom.$('div.chat-attached-context-hover');
86+
hoverElement = dom.$('div.chat-attached-context-hover');
10287
hoverElement.setAttribute('aria-label', ariaLabel);
10388

10489
// Custom label
90+
const pillIcon = dom.$('div.chat-attached-context-pill', {}, dom.$('span.codicon.codicon-file-media'));
10591
const textLabel = dom.$('span.chat-attached-context-custom-text', {}, attachment.name);
10692
widget.appendChild(pillIcon);
10793
widget.appendChild(textLabel);
10894

95+
let buffer: Uint8Array;
10996
try {
11097
if (attachment.value instanceof URI) {
11198
const readFile = await this.fileService.readFile(attachment.value);
@@ -120,43 +107,50 @@ export class ChatAttachmentsContentPart extends Disposable {
120107
}
121108

122109
widget.style.position = 'relative';
123-
widget.ariaLabel = ariaLabel;
124-
widget.tabIndex = 0;
125-
126-
if (!this.attachedContextDisposables.isDisposed) {
127-
this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement));
128-
129-
// No delay for keyboard
130-
this.attachedContextDisposables.add(dom.addDisposableListener(widget, 'keydown', (event) => {
131-
const keyboardEvent = new StandardKeyboardEvent(event);
132-
if (keyboardEvent.keyCode === KeyCode.Enter || keyboardEvent.keyCode === KeyCode.Space) {
133-
this.hoverService.showManagedHover(widget);
134-
}
135-
}));
136-
}
137-
138110
} else {
139111
const attachmentLabel = attachment.fullName ?? attachment.name;
140112
const withIcon = attachment.icon?.id ? `$(${attachment.icon.id}) ${attachmentLabel}` : attachmentLabel;
141113
label.setLabel(withIcon, correspondingContentReference?.options?.status?.description);
142114

143-
widget.ariaLabel = localize('chat.attachment3', "Attached context: {0}.", attachment.name);
144-
widget.tabIndex = 0;
115+
hoverElement = attachmentLabel;
116+
ariaLabel = localize('chat.attachment3', "Attached context: {0}.", attachment.name);
145117
}
146118

147119
if (isAttachmentPartialOrOmitted) {
148120
widget.classList.add('warning');
149121
}
150122
const description = correspondingContentReference?.options?.status?.description;
151123
if (isAttachmentPartialOrOmitted) {
152-
widget.ariaLabel = `${widget.ariaLabel}${description ? ` ${description}` : ''}`;
124+
ariaLabel = `${ariaLabel}${description ? ` ${description}` : ''}`;
125+
hoverElement = description;
153126
for (const selector of ['.monaco-icon-suffix-container', '.monaco-icon-name-container']) {
154127
const element = label.element.querySelector(selector);
155128
if (element) {
156129
element.classList.add('warning');
157130
}
158131
}
159132
}
133+
134+
if (file) {
135+
widget.style.cursor = 'pointer';
136+
this.attachedContextDisposables.add(dom.addDisposableListener(widget, dom.EventType.CLICK, async (e: MouseEvent) => {
137+
dom.EventHelper.stop(e, true);
138+
this.openerService.open(
139+
file,
140+
{
141+
fromUserGesture: true,
142+
editorOptions: {
143+
selection: range
144+
} as any
145+
});
146+
}));
147+
}
148+
149+
widget.ariaLabel = ariaLabel;
150+
widget.tabIndex = 0;
151+
if (!this.attachedContextDisposables.isDisposed) {
152+
this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement));
153+
}
160154
});
161155
}
162156

0 commit comments

Comments
 (0)