mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Optimize inline anchor widget
This commit is contained in:
@@ -614,8 +614,7 @@ export class DefaultChatAttachmentWidget extends AbstractChatAttachmentWidget {
|
||||
}
|
||||
|
||||
if (attachment.kind === 'symbol') {
|
||||
const scopedContextKeyService = this._register(this.contextKeyService.createScoped(this.element));
|
||||
this._register(this.instantiationService.invokeFunction(hookUpSymbolAttachmentDragAndContextMenu, this.element, scopedContextKeyService, { ...attachment, kind: attachment.symbolKind }, MenuId.ChatInputSymbolAttachmentContext));
|
||||
this._register(this.instantiationService.invokeFunction(hookUpSymbolAttachmentDragAndContextMenu, this.element, this.contextKeyService, { ...attachment, kind: attachment.symbolKind }, MenuId.ChatInputSymbolAttachmentContext));
|
||||
}
|
||||
|
||||
// Handle click for string context attachments with context commands
|
||||
@@ -1115,19 +1114,15 @@ export function hookUpResourceAttachmentDragAndContextMenu(accessor: ServicesAcc
|
||||
return store;
|
||||
}
|
||||
|
||||
export function hookUpSymbolAttachmentDragAndContextMenu(accessor: ServicesAccessor, widget: HTMLElement, scopedContextKeyService: IScopedContextKeyService, attachment: { name: string; value: Location; kind: SymbolKind }, contextMenuId: MenuId): IDisposable {
|
||||
export function hookUpSymbolAttachmentDragAndContextMenu(accessor: ServicesAccessor, widget: HTMLElement, parentContextKeyService: IContextKeyService, attachment: { name: string; value: Location; kind: SymbolKind }, contextMenuId: MenuId): IDisposable {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
|
||||
const textModelService = accessor.get(ITextModelService);
|
||||
const contextMenuService = accessor.get(IContextMenuService);
|
||||
const menuService = accessor.get(IMenuService);
|
||||
|
||||
const store = new DisposableStore();
|
||||
|
||||
// Context
|
||||
store.add(setResourceContext(accessor, scopedContextKeyService, attachment.value.uri));
|
||||
|
||||
const chatResourceContext = chatAttachmentResourceContextKey.bindTo(scopedContextKeyService);
|
||||
chatResourceContext.set(attachment.value.uri.toString());
|
||||
|
||||
// Drag and drop
|
||||
widget.draggable = true;
|
||||
store.add(dom.addDisposableListener(widget, 'dragstart', e => {
|
||||
@@ -1143,26 +1138,57 @@ export function hookUpSymbolAttachmentDragAndContextMenu(accessor: ServicesAcces
|
||||
e.dataTransfer?.setDragImage(widget, 0, 0);
|
||||
}));
|
||||
|
||||
// Context menu
|
||||
const providerContexts: ReadonlyArray<[IContextKey<boolean>, LanguageFeatureRegistry<unknown>]> = [
|
||||
[EditorContextKeys.hasDefinitionProvider.bindTo(scopedContextKeyService), languageFeaturesService.definitionProvider],
|
||||
[EditorContextKeys.hasReferenceProvider.bindTo(scopedContextKeyService), languageFeaturesService.referenceProvider],
|
||||
[EditorContextKeys.hasImplementationProvider.bindTo(scopedContextKeyService), languageFeaturesService.implementationProvider],
|
||||
[EditorContextKeys.hasTypeDefinitionProvider.bindTo(scopedContextKeyService), languageFeaturesService.typeDefinitionProvider],
|
||||
];
|
||||
// Context menu (context key service created eagerly for keybinding preconditions,
|
||||
// but resource context and provider contexts are initialized lazily on first use)
|
||||
const scopedContextKeyService = store.add(parentContextKeyService.createScoped(widget));
|
||||
chatAttachmentResourceContextKey.bindTo(scopedContextKeyService).set(attachment.value.uri.toString());
|
||||
store.add(setResourceContext(accessor, scopedContextKeyService, attachment.value.uri));
|
||||
|
||||
let providerContexts: ReadonlyArray<[IContextKey<boolean>, LanguageFeatureRegistry<unknown>]> | undefined;
|
||||
|
||||
const ensureProviderContexts = () => {
|
||||
if (!providerContexts) {
|
||||
providerContexts = [
|
||||
[EditorContextKeys.hasDefinitionProvider.bindTo(scopedContextKeyService), languageFeaturesService.definitionProvider],
|
||||
[EditorContextKeys.hasReferenceProvider.bindTo(scopedContextKeyService), languageFeaturesService.referenceProvider],
|
||||
[EditorContextKeys.hasImplementationProvider.bindTo(scopedContextKeyService), languageFeaturesService.implementationProvider],
|
||||
[EditorContextKeys.hasTypeDefinitionProvider.bindTo(scopedContextKeyService), languageFeaturesService.typeDefinitionProvider],
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const updateContextKeys = async () => {
|
||||
ensureProviderContexts();
|
||||
const modelRef = await textModelService.createModelReference(attachment.value.uri);
|
||||
try {
|
||||
const model = modelRef.object.textEditorModel;
|
||||
for (const [contextKey, registry] of providerContexts) {
|
||||
for (const [contextKey, registry] of providerContexts!) {
|
||||
contextKey.set(registry.has(model));
|
||||
}
|
||||
} finally {
|
||||
modelRef.dispose();
|
||||
}
|
||||
};
|
||||
store.add(addBasicContextMenu(accessor, widget, scopedContextKeyService, contextMenuId, attachment.value, updateContextKeys));
|
||||
|
||||
store.add(dom.addDisposableListener(widget, dom.EventType.CONTEXT_MENU, async domEvent => {
|
||||
const event = new StandardMouseEvent(dom.getWindow(domEvent), domEvent);
|
||||
dom.EventHelper.stop(domEvent, true);
|
||||
|
||||
try {
|
||||
await updateContextKeys();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
contextMenuService.showContextMenu({
|
||||
contextKeyService: scopedContextKeyService,
|
||||
getAnchor: () => event,
|
||||
getActions: () => {
|
||||
const menu = menuService.getMenuActions(contextMenuId, scopedContextKeyService, { arg: attachment.value });
|
||||
return getFlatContextMenuActions(menu);
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import { getFlatContextMenuActions } from '../../../../../../platform/actions/br
|
||||
import { Action2, IMenuService, MenuId, registerAction2 } from '../../../../../../platform/actions/common/actions.js';
|
||||
import { IClipboardService } from '../../../../../../platform/clipboard/common/clipboardService.js';
|
||||
import { ICommandService } from '../../../../../../platform/commands/common/commands.js';
|
||||
import { IContextKey, IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js';
|
||||
import { IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js';
|
||||
import { IContextMenuService } from '../../../../../../platform/contextview/browser/contextView.js';
|
||||
import { IResourceStat } from '../../../../../../platform/dnd/browser/dnd.js';
|
||||
import { ITextResourceEditorInput } from '../../../../../../platform/editor/common/editor.js';
|
||||
@@ -125,8 +125,6 @@ export class InlineAnchorWidget extends Disposable {
|
||||
|
||||
public static readonly className = 'chat-inline-anchor-widget';
|
||||
|
||||
private readonly _chatResourceContext: IContextKey<string>;
|
||||
|
||||
readonly data: ContentRefData;
|
||||
|
||||
constructor(
|
||||
@@ -158,9 +156,6 @@ export class InlineAnchorWidget extends Disposable {
|
||||
? { kind: 'symbol', symbol: inlineReference.inlineReference }
|
||||
: { uri: inlineReference.inlineReference };
|
||||
|
||||
const contextKeyService = this._register(originalContextKeyService.createScoped(element));
|
||||
this._chatResourceContext = chatAttachmentResourceContextKey.bindTo(contextKeyService);
|
||||
|
||||
element.classList.add(InlineAnchorWidget.className, 'show-file-icons');
|
||||
|
||||
let iconText: Array<string | HTMLElement>;
|
||||
@@ -168,7 +163,6 @@ export class InlineAnchorWidget extends Disposable {
|
||||
|
||||
let location: { readonly uri: URI; readonly range?: IRange };
|
||||
|
||||
let updateContextKeys: (() => Promise<void>) | undefined;
|
||||
if (this.data.kind === 'symbol') {
|
||||
const symbol = this.data.symbol;
|
||||
|
||||
@@ -176,7 +170,7 @@ export class InlineAnchorWidget extends Disposable {
|
||||
iconText = [this.data.symbol.name];
|
||||
iconClasses = ['codicon', ...getIconClasses(modelService, languageService, undefined, undefined, SymbolKinds.toIcon(symbol.kind))];
|
||||
|
||||
this._store.add(instantiationService.invokeFunction(accessor => hookUpSymbolAttachmentDragAndContextMenu(accessor, element, contextKeyService, { value: symbol.location, name: symbol.name, kind: symbol.kind }, MenuId.ChatInlineSymbolAnchorContext)));
|
||||
this._store.add(instantiationService.invokeFunction(accessor => hookUpSymbolAttachmentDragAndContextMenu(accessor, element, originalContextKeyService, { value: symbol.location, name: symbol.name, kind: symbol.kind }, MenuId.ChatInlineSymbolAnchorContext)));
|
||||
} else {
|
||||
location = this.data;
|
||||
|
||||
@@ -209,10 +203,10 @@ export class InlineAnchorWidget extends Disposable {
|
||||
refreshIconClasses();
|
||||
}));
|
||||
|
||||
const isFolderContext = ExplorerFolderContext.bindTo(contextKeyService);
|
||||
let isDirectory = false;
|
||||
fileService.stat(location.uri)
|
||||
.then(stat => {
|
||||
isFolderContext.set(stat.isDirectory);
|
||||
isDirectory = stat.isDirectory;
|
||||
if (stat.isDirectory) {
|
||||
fileKind = FileKind.FOLDER;
|
||||
refreshIconClasses();
|
||||
@@ -221,15 +215,20 @@ export class InlineAnchorWidget extends Disposable {
|
||||
.catch(() => { });
|
||||
|
||||
// Context menu
|
||||
const contextKeyService = this._register(originalContextKeyService.createScoped(element));
|
||||
chatAttachmentResourceContextKey.bindTo(contextKeyService).set(location.uri.toString());
|
||||
const isFolderContext = ExplorerFolderContext.bindTo(contextKeyService);
|
||||
let contextMenuInitialized = false;
|
||||
this._register(dom.addDisposableListener(element, dom.EventType.CONTEXT_MENU, async domEvent => {
|
||||
const event = new StandardMouseEvent(dom.getWindow(domEvent), domEvent);
|
||||
dom.EventHelper.stop(domEvent, true);
|
||||
|
||||
try {
|
||||
await updateContextKeys?.();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (!contextMenuInitialized) {
|
||||
contextMenuInitialized = true;
|
||||
const resourceContextKey = new StaticResourceContextKey(contextKeyService, fileService, languageService, modelService);
|
||||
resourceContextKey.set(location.uri);
|
||||
}
|
||||
isFolderContext.set(isDirectory);
|
||||
|
||||
if (this._store.isDisposed) {
|
||||
return;
|
||||
@@ -255,10 +254,6 @@ export class InlineAnchorWidget extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
const resourceContextKey = new StaticResourceContextKey(contextKeyService, fileService, languageService, modelService);
|
||||
resourceContextKey.set(location.uri);
|
||||
this._chatResourceContext.set(location.uri.toString());
|
||||
|
||||
const iconEl = dom.$('span.icon');
|
||||
iconEl.classList.add(...iconClasses);
|
||||
element.replaceChildren(iconEl, dom.$('span.icon-label', {}, ...iconText));
|
||||
|
||||
Reference in New Issue
Block a user