Skip to content

Commit

Permalink
[prompt snippets]: revert changes for the ImplicitContext
Browse files Browse the repository at this point in the history
  • Loading branch information
legomushroom committed Dec 11, 2024
1 parent bff4eae commit 40790c7
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 182 deletions.
6 changes: 5 additions & 1 deletion src/vs/base/common/codecs/baseDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { Emitter } from '../event.js';
import { ReadableStream } from '../stream.js';
import { AsyncDecoder } from './asyncDecoder.js';
import { Disposable, IDisposable } from '../lifecycle.js';
import { TStreamListenerNames } from './types/TStreamListenerEventNames.js';

/**
* Event names of {@link ReadableStream} stream.
*/
export type TStreamListenerNames = 'data' | 'error' | 'end';

/**
* Base decoder class that can be used to convert stream messages data type
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js';
import { Button } from '../../../../../base/browser/ui/button/button.js';
import { getDefaultHoverDelegate } from '../../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { IMarkdownString, MarkdownString } from '../../../../../base/common/htmlContent.js';
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
import { basename, dirname } from '../../../../../base/common/resources.js';
import { URI } from '../../../../../base/common/uri.js';
Expand All @@ -24,15 +23,15 @@ import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
import { ILabelService } from '../../../../../platform/label/common/label.js';
import { ResourceLabels } from '../../../../browser/labels.js';
import { ResourceContextKey } from '../../../../common/contextkeys.js';
import { ChatImplicitContext } from '../contrib/chatImplicitContext.js';
import { IChatRequestImplicitVariableEntry } from '../../common/chatModel.js';

export class ImplicitContextAttachmentWidget extends Disposable {
public readonly domNode: HTMLElement;

private readonly renderDisposables = this._register(new DisposableStore());

constructor(
private readonly attachment: ChatImplicitContext,
private readonly attachment: IChatRequestImplicitVariableEntry,
private readonly resourceLabels: ResourceLabels,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
Expand Down Expand Up @@ -63,26 +62,20 @@ export class ImplicitContextAttachmentWidget extends Disposable {
const friendlyName = `${fileBasename} ${fileDirname}`;
const ariaLabel = range ? localize('chat.fileAttachmentWithRange', "Attached file, {0}, line {1} to line {2}", friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.fileAttachment', "Attached file, {0}", friendlyName);

const uriLabel = this.labelService.getUriLabel(file, { relative: true });
const currentFile = localize('openEditor', "Current file context");
const inactive = localize('enableHint', "disabled");
const currentFileHint = new MarkdownString(currentFile + (this.attachment.enabled ? '' : ` (${inactive})`));

const title = [currentFileHint, ...this.getUriLabel(file)]
.map((markdown) => {
return markdown.value;
})
.join('\n');

const currentFileHint = currentFile + (this.attachment.enabled ? '' : ` (${inactive})`);
const title = `${currentFileHint}\n${uriLabel}`;
label.setFile(file, {
fileKind: FileKind.FILE,
hidePath: true,
range,
title,
title
});
this.domNode.ariaLabel = ariaLabel;
this.domNode.tabIndex = 0;

const hintElement = dom.append(this.domNode, dom.$('span.chat-implicit-hint', undefined, localize('current file', 'Current file')));
const hintElement = dom.append(this.domNode, dom.$('span.chat-implicit-hint', undefined, 'Current file'));
this._register(this.hoverService.setupManagedHover(getDefaultHoverDelegate('element'), hintElement, title));

const buttonMsg = this.attachment.enabled ? localize('disable', "Disable current file context") : localize('enable', "Enable current file context");
Expand Down Expand Up @@ -113,24 +106,4 @@ export class ImplicitContextAttachmentWidget extends Disposable {
});
}));
}

/**
* Get file URIs label, including its possible nested file references.
*/
private getUriLabel(
file: URI,
): IMarkdownString[] {
const result = [new MarkdownString(
`- ${this.labelService.getUriLabel(file, { relative: true })}`,
)];

// if file is a prompt that references other files, add them to the label
for (const child of this.attachment.validFileReferenceUris) {
result.push(new MarkdownString(
` - ${this.labelService.getUriLabel(child, { relative: true })}`,
));
}

return result;
}
}
130 changes: 86 additions & 44 deletions src/vs/workbench/contrib/chat/browser/chatInputPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Button } from '../../../../base/browser/ui/button/button.js';
import { IManagedHoverTooltipMarkdownString } from '../../../../base/browser/ui/hover/hover.js';
import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js';
import { getBaseLayerHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate2.js';
import { createInstantHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { createInstantHoverDelegate, getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';
import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js';
import { ProgressBar } from '../../../../base/browser/ui/progressbar/progressbar.js';
Expand All @@ -24,7 +24,7 @@ import { Codicon } from '../../../../base/common/codicons.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { HistoryNavigator2 } from '../../../../base/common/history.js';
import { KeyCode } from '../../../../base/common/keyCodes.js';
import { Disposable, DisposableStore, IDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { ResourceSet } from '../../../../base/common/map.js';
import { basename, dirname } from '../../../../base/common/path.js';
import { isMacintosh } from '../../../../base/common/platform.js';
Expand All @@ -37,10 +37,13 @@ import { IDimension } from '../../../../editor/common/core/dimension.js';
import { IPosition } from '../../../../editor/common/core/position.js';
import { IRange, Range } from '../../../../editor/common/core/range.js';
import { isLocation } from '../../../../editor/common/languages.js';
import { ILanguageService } from '../../../../editor/common/languages/language.js';
import { ITextModel } from '../../../../editor/common/model.js';
import { getIconClasses } from '../../../../editor/common/services/getIconClasses.js';
import { IModelService } from '../../../../editor/common/services/model.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { CopyPasteController } from '../../../../editor/contrib/dropOrPasteInto/browser/copyPasteController.js';
import { DropIntoEditorController } from '../../../../editor/contrib/dropOrPasteInto/browser/dropIntoEditorController.js';
import { ContentHoverController } from '../../../../editor/contrib/hover/browser/contentHoverController.js';
import { GlyphHoverController } from '../../../../editor/contrib/hover/browser/glyphHoverController.js';
import { SuggestController } from '../../../../editor/contrib/suggest/browser/suggestController.js';
Expand All @@ -62,6 +65,7 @@ import { IHoverService } from '../../../../platform/hover/browser/hover.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
import { ILabelService } from '../../../../platform/label/common/label.js';
import { WorkbenchList } from '../../../../platform/list/browser/listService.js';
import { ILogService } from '../../../../platform/log/common/log.js';
import { INotificationService } from '../../../../platform/notification/common/notification.js';
Expand All @@ -76,8 +80,8 @@ import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions, setupSimpleEd
import { revealInSideBarCommand } from '../../files/browser/fileActions.contribution.js';
import { ChatAgentLocation, IChatAgentService } from '../common/chatAgents.js';
import { ChatContextKeys } from '../common/chatContextKeys.js';
import { ChatEditingSessionState, IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../common/chatEditingService.js';
import { IBaseChatRequestVariableEntry, IChatRequestVariableEntry } from '../common/chatModel.js';
import { ChatEditingSessionState, IChatEditingService, IChatEditingSession, WorkingSetEntryRemovalReason, WorkingSetEntryState } from '../common/chatEditingService.js';
import { IChatRequestVariableEntry, isPasteVariableEntry } from '../common/chatModel.js';
import { ChatRequestDynamicVariablePart } from '../common/chatParserTypes.js';
import { IChatFollowup } from '../common/chatService.js';
import { IChatResponseViewModel } from '../common/chatViewModel.js';
Expand Down Expand Up @@ -146,29 +150,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
return this._attachmentModel;
}

public getAttachedAndImplicitContext(
chatWidget: IChatWidget,
): IChatRequestVariableEntry[] {
public getAttachedAndImplicitContext(chatWidget: IChatWidget): IChatRequestVariableEntry[] {
const contextArr = [...this.attachmentModel.attachments];

if (this._implicitContext?.enabled && this._implicitContext.value) {
const mainEntry = this._implicitContext.toBaseEntry();

contextArr.push(mainEntry);

// if the implicit context is a file, it can have nested
// file references that should be included in the context
if (this._implicitContext.validFileReferenceUris) {
const childReferences = this._implicitContext.validFileReferenceUris
.map((uri): IBaseChatRequestVariableEntry => {
return {
...mainEntry,
name: `file:${basename(uri.path)}`,
value: uri,
};
});
contextArr.push(...childReferences);
}
if (this.implicitContext?.enabled && this.implicitContext.value) {
contextArr.push(this.implicitContext.toBaseEntry());
}

// factor in nested references of dynamic variables into the implicit attached context
Expand Down Expand Up @@ -308,6 +293,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
getContribsInputState: () => any,
@IChatWidgetHistoryService private readonly historyService: IChatWidgetHistoryService,
@IModelService private readonly modelService: IModelService,
@ILanguageService private readonly languageService: ILanguageService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
Expand All @@ -324,6 +310,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
@IThemeService private readonly themeService: IThemeService,
@ITextModelService private readonly textModelResolverService: ITextModelService,
@IStorageService private readonly storageService: IStorageService,
@ILabelService private readonly labelService: ILabelService,
) {
super();

Expand Down Expand Up @@ -621,9 +608,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
const toolbarsContainer = elements.inputToolbars;
this.chatEditingSessionWidgetContainer = elements.chatEditingSessionWidgetContainer;
this.renderAttachedContext();

if (this.options.enableImplicitContext && !this._implicitContext) {
this._implicitContext = this._register(this.instantiationService.createInstance(ChatImplicitContext));
if (this.options.enableImplicitContext) {
this._implicitContext = this._register(new ChatImplicitContext());
this._register(this._implicitContext.onDidChangeValue(() => this._handleAttachedContextChange()));
}

Expand Down Expand Up @@ -696,6 +682,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge

this._onDidBlur.fire();
}));
this._register(this._inputEditor.onDidBlurEditorWidget(() => {
CopyPasteController.get(this._inputEditor)?.clearWidgets();
DropIntoEditorController.get(this._inputEditor)?.clearWidgets();
}));

const hoverDelegate = this._register(createInstantHoverDelegate());

Expand Down Expand Up @@ -907,24 +897,25 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
} else if (isPasteVariableEntry(attachment)) {
ariaLabel = localize('chat.attachment', "Attached context, {0}", attachment.name);

const hoverContent: IManagedHoverTooltipMarkdownString = {
markdown: {
value: `\`\`\`${attachment.language}\n${attachment.code}\n\`\`\``,
},
markdownNotSupportedFallback: attachment.code,
};

const classNames = ['file-icon', `${attachment.language}-lang-file-icon`];
if (attachment.copiedFrom) {
resource = attachment.copiedFrom.uri;
range = attachment.copiedFrom.range;
label.setFile(attachment.copiedFrom.uri, { extraClasses: classNames });
const filename = basename(resource.path);
label.setLabel(filename, undefined, { extraClasses: classNames });
} else {
label.setLabel(attachment.fileName, undefined, { extraClasses: classNames });
}
widget.appendChild(dom.$('span.attachment-additional-info', {}, `Pasted ${attachment.pastedLines}`));

widget.style.position = 'relative';

const hoverContent: IManagedHoverTooltipMarkdownString = {
markdown: {
value: `${attachment.copiedFrom ? this.labelService.getUriLabel(attachment.copiedFrom.uri, { relative: true }) : attachment.fileName}\n\n---\n\n\`\`\`${attachment.language}\n\n${attachment.code}\n\`\`\``,
},
markdownNotSupportedFallback: attachment.code,
};
store.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverContent, { trapFocus: true }));
this.attachButtonAndDisposables(widget, index, attachment, hoverDelegate);

Expand All @@ -945,7 +936,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge

if (attachment.kind === 'symbol') {
const scopedContextKeyService = store.add(this.contextKeyService.createScoped(widget));
store.add(this.instantiationService.invokeFunction(accessor => hookUpSymbolAttachmentDragAndContextMenu(accessor, widget, scopedContextKeyService, attachment, MenuId.ChatInputSymbolAttachmentContext)));
store.add(this.instantiationService.invokeFunction(accessor => hookUpSymbolAttachmentDragAndContextMenu(accessor, widget, scopedContextKeyService, { ...attachment, kind: attachment.symbolKind }, MenuId.ChatInputSymbolAttachmentContext)));
}

await Promise.all(attachmentInitPromises);
Expand Down Expand Up @@ -1102,12 +1093,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
seenEntries.add(attachment.value);
}
}
for (const [file, state] of chatEditingSession.workingSet.entries()) {
if (!seenEntries.has(file)) {
for (const [file, metadata] of chatEditingSession.workingSet.entries()) {
if (!seenEntries.has(file) && metadata.state !== WorkingSetEntryState.Suggested) {
entries.unshift({
reference: file,
state: state.state,
description: state.description,
state: metadata.state,
description: metadata.description,
kind: 'reference',
});
seenEntries.add(file);
Expand Down Expand Up @@ -1265,7 +1256,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
if (e.element?.kind === 'reference' && URI.isUri(e.element.reference)) {
const modifiedFileUri = e.element.reference;

const entry = chatEditingSession.entries.get().find(entry => entry.modifiedURI.toString() === modifiedFileUri.toString());
const entry = chatEditingSession.getEntry(modifiedFileUri);
const diffInfo = entry?.diffInfo.get();
const range = diffInfo?.changes.at(0)?.modified.toExclusiveRange();

Expand Down Expand Up @@ -1299,9 +1290,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge

const addFilesElement = innerContainer.querySelector('.chat-editing-session-toolbar-actions') as HTMLElement ?? dom.append(innerContainer, $('.chat-editing-session-toolbar-actions'));

const hoverDelegate = getDefaultHoverDelegate('element');

const button = this._chatEditsActionsDisposables.add(new Button(addFilesElement, {
supportIcons: true,
secondary: true
secondary: true,
hoverDelegate
}));
// Disable the button if the entries that are not suggested exceed the budget
button.enabled = remainingFileEntriesBudget > 0;
Expand All @@ -1311,6 +1305,54 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
this.commandService.executeCommand('workbench.action.chat.editing.attachFiles', { widget: chatWidget });
}));
dom.append(addFilesElement, button.element);

// REALTED files (after Add Files...)
for (const [uri, metadata] of chatEditingSession.workingSet) {
if (metadata.state !== WorkingSetEntryState.Suggested) {
continue;
}
const addBtn = this._chatEditsActionsDisposables.add(new Button(addFilesElement, {
supportIcons: true,
secondary: true,
hoverDelegate
}));
addBtn.enabled = remainingFileEntriesBudget > 0;
addBtn.label = this.labelService.getUriBasenameLabel(uri);
addBtn.element.classList.add('monaco-icon-label', ...getIconClasses(this.modelService, this.languageService, uri, FileKind.FILE));
addBtn.setTitle(localize('suggeste.title', "{0} - {1}", this.labelService.getUriLabel(uri, { relative: true }), metadata.description ?? ''));

this._chatEditsActionsDisposables.add(addBtn.onDidClick(() => {
group.remove(); // REMOVE asap
chatEditingSession.addFileToWorkingSet(uri);
}));

const rmBtn = this._chatEditsActionsDisposables.add(new Button(addFilesElement, {
supportIcons: false,
secondary: true,
hoverDelegate
}));
rmBtn.icon = Codicon.close;
rmBtn.setTitle(localize('chatEditingSession.removeSuggested', 'Remove suggestion'));
this._chatEditsActionsDisposables.add(rmBtn.onDidClick(() => {
group.remove(); // REMOVE asap
chatEditingSession.remove(WorkingSetEntryRemovalReason.User, uri);
}));

const sep = document.createElement('div');
sep.classList.add('separator');

const group = document.createElement('span');
group.classList.add('monaco-button-dropdown', 'sidebyside-button');
group.appendChild(addBtn.element);
group.appendChild(sep);
group.appendChild(rmBtn.element);
dom.append(addFilesElement, group);

this._chatEditsActionsDisposables.add(toDisposable(() => {
group.remove();
}));
}

}

async renderFollowups(items: IChatFollowup[] | undefined, response: IChatResponseViewModel | undefined): Promise<void> {
Expand Down
Loading

0 comments on commit 40790c7

Please sign in to comment.