Skip to content

Commit ed787a5

Browse files
authored
revert implicit context to old implicit context flow (microsoft#251637)
1 parent 36d6045 commit ed787a5

File tree

5 files changed

+73
-56
lines changed

5 files changed

+73
-56
lines changed

src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as dom from '../../../../../base/browser/dom.js';
7-
import { StandardKeyboardEvent } from '../../../../../base/browser/keyboardEvent.js';
87
import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js';
9-
import { KeyCode } from '../../../../../base/common/keyCodes.js';
8+
import { Button } from '../../../../../base/browser/ui/button/button.js';
9+
import { getDefaultHoverDelegate } from '../../../../../base/browser/ui/hover/hoverDelegateFactory.js';
10+
import { Codicon } from '../../../../../base/common/codicons.js';
1011
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
1112
import { Schemas } from '../../../../../base/common/network.js';
1213
import { basename, dirname } from '../../../../../base/common/resources.js';
@@ -19,12 +20,11 @@ import { IMenuService, MenuId } from '../../../../../platform/actions/common/act
1920
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
2021
import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js';
2122
import { FileKind, IFileService } from '../../../../../platform/files/common/files.js';
23+
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
2224
import { ILabelService } from '../../../../../platform/label/common/label.js';
2325
import { ResourceLabels } from '../../../../browser/labels.js';
2426
import { ResourceContextKey } from '../../../../common/contextkeys.js';
2527
import { IChatRequestImplicitVariableEntry } from '../../common/chatVariableEntries.js';
26-
import { IChatWidgetService } from '../chat.js';
27-
import { ChatAttachmentModel } from '../chatAttachmentModel.js';
2828

2929
export class ImplicitContextAttachmentWidget extends Disposable {
3030
public readonly domNode: HTMLElement;
@@ -34,15 +34,14 @@ export class ImplicitContextAttachmentWidget extends Disposable {
3434
constructor(
3535
private readonly attachment: IChatRequestImplicitVariableEntry,
3636
private readonly resourceLabels: ResourceLabels,
37-
private readonly attachmentModel: ChatAttachmentModel,
3837
@IContextKeyService private readonly contextKeyService: IContextKeyService,
3938
@IContextMenuService private readonly contextMenuService: IContextMenuService,
4039
@ILabelService private readonly labelService: ILabelService,
4140
@IMenuService private readonly menuService: IMenuService,
4241
@IFileService private readonly fileService: IFileService,
4342
@ILanguageService private readonly languageService: ILanguageService,
4443
@IModelService private readonly modelService: IModelService,
45-
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
44+
@IHoverService private readonly hoverService: IHoverService,
4645
) {
4746
super();
4847

@@ -54,17 +53,17 @@ export class ImplicitContextAttachmentWidget extends Disposable {
5453
dom.clearNode(this.domNode);
5554
this.renderDisposables.clear();
5655

57-
this.domNode.classList.add('disabled');
56+
this.domNode.classList.toggle('disabled', !this.attachment.enabled);
5857
const label = this.resourceLabels.create(this.domNode, { supportIcons: true });
5958
const file = URI.isUri(this.attachment.value) ? this.attachment.value : this.attachment.value!.uri;
60-
const range = undefined;
59+
const range = URI.isUri(this.attachment.value) || !this.attachment.isSelection ? undefined : this.attachment.value!.range;
6160

6261
const attachmentTypeName = file.scheme === Schemas.vscodeNotebookCell ? localize('cell.lowercase', "cell") : localize('file.lowercase', "file");
6362

6463
const fileBasename = basename(file);
6564
const fileDirname = dirname(file);
6665
const friendlyName = `${fileBasename} ${fileDirname}`;
67-
const ariaLabel = localize('chat.fileAttachment', "Attached {0}, {1}", attachmentTypeName, friendlyName);
66+
const ariaLabel = range ? localize('chat.fileAttachmentWithRange', "Attached {0}, {1}, line {2} to line {3}", attachmentTypeName, friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.fileAttachment', "Attached {0}, {1}", attachmentTypeName, friendlyName);
6867

6968
const uriLabel = this.labelService.getUriLabel(file, { relative: true });
7069
const currentFile = localize('openEditor', "Suggested context (current file)");
@@ -79,17 +78,16 @@ export class ImplicitContextAttachmentWidget extends Disposable {
7978
this.domNode.ariaLabel = ariaLabel;
8079
this.domNode.tabIndex = 0;
8180

82-
this.renderDisposables.add(dom.addDisposableListener(this.domNode, dom.EventType.CLICK, e => {
83-
this.convertToRegularAttachment();
84-
}));
81+
const hintLabel = localize('hint.label.current', "Current {0}", attachmentTypeName);
82+
const hintElement = dom.append(this.domNode, dom.$('span.chat-implicit-hint', undefined, hintLabel));
83+
this._register(this.hoverService.setupManagedHover(getDefaultHoverDelegate('element'), hintElement, title));
8584

86-
this.renderDisposables.add(dom.addDisposableListener(this.domNode, dom.EventType.KEY_DOWN, e => {
87-
const event = new StandardKeyboardEvent(e);
88-
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
89-
e.preventDefault();
90-
e.stopPropagation();
91-
this.convertToRegularAttachment();
92-
}
85+
const buttonMsg = this.attachment.enabled ? localize('disable', "Disable current {0} context", attachmentTypeName) : localize('enable', "Enable current {0} context", attachmentTypeName);
86+
const toggleButton = this.renderDisposables.add(new Button(this.domNode, { supportIcons: true, title: buttonMsg }));
87+
toggleButton.icon = this.attachment.enabled ? Codicon.eye : Codicon.eyeClosed;
88+
this.renderDisposables.add(toggleButton.onDidClick((e) => {
89+
e.stopPropagation(); // prevent it from triggering the click handler on the parent immediately after rerendering
90+
this.attachment.enabled = !this.attachment.enabled;
9391
}));
9492

9593
// Context menu
@@ -112,14 +110,4 @@ export class ImplicitContextAttachmentWidget extends Disposable {
112110
});
113111
}));
114112
}
115-
116-
private convertToRegularAttachment(): void {
117-
if (!this.attachment.value) {
118-
return;
119-
}
120-
121-
const file = URI.isUri(this.attachment.value) ? this.attachment.value : this.attachment.value.uri;
122-
this.attachmentModel.addFile(file);
123-
this.chatWidgetService.lastFocusedWidget?.focusInput();
124-
}
125113
}

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

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { ResourceSet } from '../../../../base/common/map.js';
2525
import { observableFromEvent } from '../../../../base/common/observable.js';
2626
import { isMacintosh } from '../../../../base/common/platform.js';
2727
import { ScrollbarVisibility } from '../../../../base/common/scrollable.js';
28-
import { isEqual } from '../../../../base/common/resources.js';
2928
import { assertType } from '../../../../base/common/types.js';
3029
import { URI } from '../../../../base/common/uri.js';
3130
import { Schemas } from '../../../../base/common/network.js';
@@ -1250,6 +1249,11 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12501249
this._indexOfLastOpenedContext = -1;
12511250
}
12521251

1252+
if (this.implicitContext?.value) {
1253+
const implicitPart = store.add(this.instantiationService.createInstance(ImplicitContextAttachmentWidget, this.implicitContext, this._contextResourceLabels));
1254+
container.appendChild(implicitPart.domNode);
1255+
}
1256+
12531257
this.promptFileAttached.set(this.hasPromptFileAttachments);
12541258

12551259
for (const [index, attachment] of attachments) {
@@ -1297,18 +1301,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
12971301
}));
12981302
}
12991303

1300-
const implicitUri = this.implicitContext?.value;
1301-
1302-
if (URI.isUri(implicitUri)) {
1303-
const currentlyAttached = attachments.some(
1304-
([, attachment]) => URI.isUri(attachment.value) && isEqual(attachment.value, implicitUri)
1305-
);
1306-
1307-
if (implicitUri && !currentlyAttached) {
1308-
const implicitPart = store.add(this.instantiationService.createInstance(ImplicitContextAttachmentWidget, this.implicitContext, this._contextResourceLabels, this._attachmentModel));
1309-
container.appendChild(implicitPart.domNode);
1310-
}
1311-
}
13121304

13131305
if (oldHeight !== this.attachmentsContainer.offsetHeight) {
13141306
this._onDidChangeHeight.fire();

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

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Emitter, Event } from '../../../../../base/common/event.js';
88
import { Disposable, DisposableStore, MutableDisposable } from '../../../../../base/common/lifecycle.js';
99
import { Schemas } from '../../../../../base/common/network.js';
1010
import { autorun } from '../../../../../base/common/observable.js';
11-
import { basename } from '../../../../../base/common/resources.js';
11+
import { basename, isEqual } from '../../../../../base/common/resources.js';
1212
import { URI } from '../../../../../base/common/uri.js';
1313
import { getCodeEditor, ICodeEditor } from '../../../../../editor/browser/editorBrowser.js';
1414
import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js';
@@ -57,7 +57,9 @@ export class ChatImplicitContextContribution extends Disposable implements IWork
5757
activeEditorDisposables.add(Event.debounce(
5858
Event.any(
5959
codeEditor.onDidChangeModel,
60-
codeEditor.onDidChangeModelLanguage),
60+
codeEditor.onDidChangeModelLanguage,
61+
codeEditor.onDidChangeCursorSelection,
62+
codeEditor.onDidScrollChange),
6163
() => undefined,
6264
500)(() => this.updateImplicitContext()));
6365
}
@@ -71,7 +73,9 @@ export class ChatImplicitContextContribution extends Disposable implements IWork
7173
if (codeEditor && codeEditor.getModel()?.uri.scheme === Schemas.vscodeNotebookCell) {
7274
activeCellDisposables.add(Event.debounce(
7375
Event.any(
74-
codeEditor.onDidChangeModel),
76+
codeEditor.onDidChangeModel,
77+
codeEditor.onDidChangeCursorSelection,
78+
codeEditor.onDidScrollChange),
7579
() => undefined,
7680
500)(() => this.updateImplicitContext()));
7781
}
@@ -146,18 +150,57 @@ export class ChatImplicitContextContribution extends Disposable implements IWork
146150
const cancelTokenSource = this._currentCancelTokenSource.value = new CancellationTokenSource();
147151
const codeEditor = this.findActiveCodeEditor();
148152
const model = codeEditor?.getModel();
153+
const selection = codeEditor?.getSelection();
149154
let newValue: Location | URI | undefined;
150-
const isSelection = false;
155+
let isSelection = false;
151156

152157
let languageId: string | undefined;
153158
if (model) {
154-
newValue = model.uri;
155159
languageId = model.getLanguageId();
160+
if (selection && !selection.isEmpty()) {
161+
newValue = { uri: model.uri, range: selection } satisfies Location;
162+
isSelection = true;
163+
} else {
164+
const visibleRanges = codeEditor?.getVisibleRanges();
165+
if (visibleRanges && visibleRanges.length > 0) {
166+
// Merge visible ranges. Maybe the reference value could actually be an array of Locations?
167+
// Something like a Location with an array of Ranges?
168+
let range = visibleRanges[0];
169+
visibleRanges.slice(1).forEach(r => {
170+
range = range.plusRange(r);
171+
});
172+
newValue = { uri: model.uri, range } satisfies Location;
173+
} else {
174+
newValue = model.uri;
175+
}
176+
}
156177
}
157178

158179
const notebookEditor = this.findActiveNotebookEditor();
159180
if (notebookEditor) {
160-
newValue = notebookEditor.textModel?.uri;
181+
const activeCell = notebookEditor.getActiveCell();
182+
if (activeCell) {
183+
const codeEditor = this.codeEditorService.getActiveCodeEditor();
184+
const selection = codeEditor?.getSelection();
185+
const visibleRanges = codeEditor?.getVisibleRanges() || [];
186+
newValue = activeCell.uri;
187+
if (isEqual(codeEditor?.getModel()?.uri, activeCell.uri)) {
188+
if (selection && !selection.isEmpty()) {
189+
newValue = { uri: activeCell.uri, range: selection } satisfies Location;
190+
isSelection = true;
191+
} else if (visibleRanges.length > 0) {
192+
// Merge visible ranges. Maybe the reference value could actually be an array of Locations?
193+
// Something like a Location with an array of Ranges?
194+
let range = visibleRanges[0];
195+
visibleRanges.slice(1).forEach(r => {
196+
range = range.plusRange(r);
197+
});
198+
newValue = { uri: activeCell.uri, range } satisfies Location;
199+
}
200+
}
201+
} else {
202+
newValue = notebookEditor.textModel?.uri;
203+
}
161204
}
162205

163206
const uri = newValue instanceof URI ? newValue : newValue?.uri;
@@ -243,7 +286,7 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli
243286
return this._value;
244287
}
245288

246-
private _enabled = false;
289+
private _enabled = true;
247290
get enabled() {
248291
return this._enabled;
249292
}

src/vs/workbench/contrib/chat/browser/media/chat.css

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,12 +1319,6 @@ have to be updated for changes to the rules above, or to support more deeply nes
13191319
border-style: dashed;
13201320
}
13211321

1322-
.interactive-session .chat-attached-context .chat-attached-context-attachment.implicit.disabled:hover {
1323-
cursor: pointer;
1324-
border-style: solid;
1325-
background-color: var(--vscode-toolbar-hoverBackground);
1326-
}
1327-
13281322
.interactive-session .chat-attached-context .chat-attached-context-attachment.implicit.disabled:focus {
13291323
outline: none;
13301324
border-color: var(--vscode-focusBorder);

src/vs/workbench/contrib/chat/common/chatVariableEntries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVaria
6767
readonly isFile: true;
6868
readonly value: URI | Location | undefined;
6969
readonly isSelection: boolean;
70-
readonly enabled: boolean;
70+
enabled: boolean;
7171
}
7272

7373
export interface IChatRequestPasteVariableEntry extends IBaseChatRequestVariableEntry {

0 commit comments

Comments
 (0)