提交 84afb9f0 编写于 作者: B Benjamin Pasero

debt - adopt some preferred URIs across the code

上级 c3af1349
......@@ -38,7 +38,7 @@ import { ResourceLabel } from 'vs/workbench/browser/labels';
import { BreadcrumbsConfig, IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrumbs';
import { BreadcrumbElement, EditorBreadcrumbsModel, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel';
import { BreadcrumbsPicker, createBreadcrumbsPicker } from 'vs/workbench/browser/parts/editor/breadcrumbsPicker';
import { IEditorPartOptions, toResource, SideBySideEditor, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions } from 'vs/workbench/common/editor';
import { IEditorPartOptions, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
import { ACTIVE_GROUP, ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -49,7 +49,6 @@ import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { ILabelService } from 'vs/platform/label/common/label';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
import { Registry } from 'vs/platform/registry/common/platform';
import { CATEGORIES } from 'vs/workbench/common/actions';
class Item extends BreadcrumbsItem {
......@@ -250,15 +249,8 @@ export class BreadcrumbsControl {
}
}
// display uri which can be derived from file input
let fileInfoUri = uri;
let input = this._editorGroup.activeEditor;
if (input instanceof SideBySideEditorInput) {
input = input.primary;
}
if (Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories).getFileEditorInputFactory().isFileEditorInput(input)) {
fileInfoUri = input.preferredResource;
}
// display uri which can be derived from certain inputs
const fileInfoUri = toResource(this._editorGroup.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
this.domNode.classList.toggle('hidden', false);
this._ckBreadcrumbsVisible.set(true);
......@@ -266,7 +258,7 @@ export class BreadcrumbsControl {
const editor = this._getActiveCodeEditor();
const model = new EditorBreadcrumbsModel(
fileInfoUri,
fileInfoUri ?? uri,
uri, editor,
this._configurationService,
this._textResourceConfigurationService,
......
......@@ -5,7 +5,7 @@
import 'vs/css!./media/editorgroupview';
import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, Deprecated_EditorPinnedContext, Deprecated_EditorDirtyContext } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, Deprecated_EditorPinnedContext, Deprecated_EditorDirtyContext, toResource } from 'vs/workbench/common/editor';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom';
......@@ -575,7 +575,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
private toEditorTelemetryDescriptor(editor: EditorInput): object {
const descriptor = editor.getTelemetryDescriptor();
const resource = editor.resource;
const resource = toResource(editor, { usePreferredResource: true });
const path = resource ? resource.scheme === Schemas.file ? resource.fsPath : resource.path : undefined;
if (resource && path) {
descriptor['resource'] = { mimeType: guessMimeTypes(resource).join(', '), scheme: resource.scheme, ext: extname(resource), path: hash(path) };
......
......@@ -137,7 +137,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
}
return this.doGetEditors().map(({ editor, groupId }): IEditorQuickPickItem => {
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
const isDirty = editor.isDirty() && !editor.isSaving();
const description = editor.getDescription();
const nameAndDescription = description ? `${editor.getName()} ${description}` : editor.getName();
......
......@@ -1059,7 +1059,7 @@ export class ChangeModeAction extends Action {
}
const textModel = activeTextEditorControl.getModel();
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }) : null;
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true }) : null;
let hasLanguageSupport = !!resource;
if (resource?.scheme === Schemas.untitled && !this.textFileService.untitled.get(resource)?.hasAssociatedFilePath) {
......@@ -1157,7 +1157,7 @@ export class ChangeModeAction extends Action {
let languageSelection: ILanguageSelection | undefined;
if (pick === autoDetectMode) {
if (textModel) {
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (resource) {
languageSelection = this.modeService.createByFilepathOrFirstLine(resource, textModel.getLineContent(1));
}
......@@ -1336,7 +1336,7 @@ export class ChangeEncodingAction extends Action {
await timeout(50); // quick input is sensitive to being opened so soon after another
const resource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (!resource || (!this.fileService.canHandleResource(resource) && resource.scheme !== Schemas.untitled)) {
return; // encoding detection only possible for resources the file service can handle or that are untitled
}
......
......@@ -274,7 +274,7 @@ export class NoTabsTitleControl extends TitleControl {
editorLabel.setResource(
{
resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH }),
resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH, usePreferredResource: true }),
name: editor.getName(),
description
},
......
......@@ -1114,12 +1114,12 @@ export class TabsTitleControl extends TitleControl {
// Label
tabLabelWidget.setResource(
{ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH }) },
{ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH, usePreferredResource: true }) },
{ title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor), forceLabel }
);
// Tests helper
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (resource) {
tabContainer.setAttribute('data-resource-name', basenameOrAuthority(resource));
} else {
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/titlebarpart';
import * as resources from 'vs/base/common/resources';
import { dirname, basename } from 'vs/base/common/resources';
import { Part } from 'vs/workbench/browser/part';
import { ITitleService, ITitleProperties } from 'vs/workbench/services/title/common/titleService';
import { getZoomFactor } from 'vs/base/browser/browser';
......@@ -40,6 +40,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IProductService } from 'vs/platform/product/common/productService';
import { Schemas } from 'vs/base/common/network';
import { withNullAsUndefined } from 'vs/base/common/types';
export class TitlebarPart extends Part implements ITitleService {
......@@ -258,8 +259,8 @@ export class TitlebarPart extends Part implements ITitleService {
}
// Compute active editor folder
const editorResource = editor ? toResource(editor) : undefined;
let editorFolderResource = editorResource ? resources.dirname(editorResource) : undefined;
const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
let editorFolderResource = editorResource ? dirname(editorResource) : undefined;
if (editorFolderResource?.path === '.') {
editorFolderResource = undefined;
}
......@@ -267,21 +268,18 @@ export class TitlebarPart extends Part implements ITitleService {
// Compute folder resource
// Single Root Workspace: always the root single workspace in this case
// Otherwise: root folder of the currently active file if any
let folder: IWorkspaceFolder | null = null;
let folder: IWorkspaceFolder | undefined = undefined;
if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) {
folder = workspace.folders[0];
} else {
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
if (resource) {
folder = this.contextService.getWorkspaceFolder(resource);
}
} else if (editorResource) {
folder = withNullAsUndefined(this.contextService.getWorkspaceFolder(editorResource));
}
// Variables
const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : '';
const activeEditorMedium = editor ? editor.getTitle(Verbosity.MEDIUM) : activeEditorShort;
const activeEditorLong = editor ? editor.getTitle(Verbosity.LONG) : activeEditorMedium;
const activeFolderShort = editorFolderResource ? resources.basename(editorFolderResource) : '';
const activeFolderShort = editorFolderResource ? basename(editorFolderResource) : '';
const activeFolderMedium = editorFolderResource ? this.labelService.getUriLabel(editorFolderResource, { relative: true }) : '';
const activeFolderLong = editorFolderResource ? this.labelService.getUriLabel(editorFolderResource) : '';
const rootName = this.labelService.getWorkspaceLabel(workspace);
......
......@@ -659,11 +659,35 @@ export interface IModeSupport {
setMode(mode: string): void;
}
export interface IEditorInputWithPreferredResource {
/**
* An editor may provide an additional preferred resource alongside
* the `resource` property. While the `resource` property serves as
* unique identifier of the editor that should be used whenever we
* compare to other editors, the `preferredResource` should be used
* in places where e.g. the resource is shown to the user.
*
* For example: on Windows and macOS, the same URI with different
* casing may point to the same file. The editor may chose to
* "normalize" the URIs so that only one editor opens for different
* URIs. But when displaying the editor label to the user, the
* preferred URI should be used.
*/
readonly preferredResource: URI;
}
export function isEditorInputWithPreferredResource(obj: unknown): obj is IEditorInputWithPreferredResource {
const editorInputWithPreferredResource = obj as IEditorInputWithPreferredResource;
return editorInputWithPreferredResource && !!editorInputWithPreferredResource.preferredResource;
}
/**
* This is a tagging interface to declare an editor input being capable of dealing with files. It is only used in the editor registry
* to register this kind of input to the platform.
*/
export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeSupport {
export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeSupport, IEditorInputWithPreferredResource {
/**
* Gets the resource this file input is about. This will always be the
......@@ -673,14 +697,6 @@ export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeS
*/
readonly resource: URI;
/**
* Gets the preferred resource of the editor. In most cases this will
* be identical to the resource. But in some cases the preferredResource
* may differ in path casing to the actual resource because we keep
* canonical forms of resources in-memory.
*/
readonly preferredResource: URI;
/**
* Sets the preferred resource to use for this file input.
*/
......@@ -1267,8 +1283,33 @@ export enum SideBySideEditor {
}
export interface IResourceOptions {
/**
* Allows to access the `resource` of side by side editors.
*/
supportSideBySide?: SideBySideEditor;
/**
* Allows to filter the scheme to consider.
*/
filterByScheme?: string | string[];
/**
* Will return the `preferredResource` of an editor if any.
*
* An editor may provide an additional preferred resource alongside
* the `resource` property. While the `resource` property serves as
* unique identifier of the editor that should be used whenever we
* compare to other editors, the `preferredResource` should be used
* in places where e.g. the resource is shown to the user.
*
* For example: on Windows and macOS, the same URI with different
* casing may point to the same file. The editor may chose to
* "normalize" the URIs so that only one editor opens for different
* URIs. But when displaying the editor label to the user, the
* preferred URI should be used.
*/
usePreferredResource?: boolean;
}
export function toResource(editor: IEditorInput | undefined | null): URI | undefined;
......@@ -1282,15 +1323,15 @@ export function toResource(editor: IEditorInput | undefined | null, options?: IR
if (options?.supportSideBySide && editor instanceof SideBySideEditorInput) {
if (options?.supportSideBySide === SideBySideEditor.BOTH) {
return {
primary: toResource(editor.primary, { filterByScheme: options.filterByScheme }),
secondary: toResource(editor.secondary, { filterByScheme: options.filterByScheme })
primary: toResource(editor.primary, { filterByScheme: options.filterByScheme, usePreferredResource: options.usePreferredResource }),
secondary: toResource(editor.secondary, { filterByScheme: options.filterByScheme, usePreferredResource: options.usePreferredResource })
};
}
editor = options.supportSideBySide === SideBySideEditor.PRIMARY ? editor.primary : editor.secondary;
}
const resource = editor.resource;
const resource = (options?.usePreferredResource && isEditorInputWithPreferredResource(editor)) ? editor.preferredResource : editor.resource;
if (!resource || !options || !options.filterByScheme) {
return resource;
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EditorInput, Verbosity, GroupIdentifier, IEditorInput, ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
import { EditorInput, Verbosity, GroupIdentifier, IEditorInput, ISaveOptions, IRevertOptions, IEditorInputWithPreferredResource } from 'vs/workbench/common/editor';
import { URI } from 'vs/base/common/uri';
import { ITextFileService, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -18,7 +18,7 @@ import { dirname, extUri } from 'vs/base/common/resources';
/**
* The base class for all editor inputs that open in text editors.
*/
export abstract class AbstractTextResourceEditorInput extends EditorInput {
export abstract class AbstractTextResourceEditorInput extends EditorInput implements IEditorInputWithPreferredResource {
private static readonly MEMOIZER = createMemoizer();
......
......@@ -160,14 +160,14 @@ export class TextFileEditor extends BaseTextEditor {
}
// Offer to create a file from the error if we have a file not found and the name is valid
if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND && isValidBasename(basename(input.resource))) {
if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND && isValidBasename(basename(input.preferredResource))) {
throw createErrorWithActions(toErrorMessage(error), {
actions: [
new Action('workbench.files.action.createMissingFile', nls.localize('createFile', "Create File"), undefined, true, async () => {
await this.textFileService.create(input.resource);
await this.textFileService.create(input.preferredResource);
return this.editorService.openEditor({
resource: input.resource,
resource: input.preferredResource,
options: {
pinned: true // new file gets pinned by default
}
......@@ -207,10 +207,10 @@ export class TextFileEditor extends BaseTextEditor {
await this.group.closeEditor(this.input);
// Best we can do is to reveal the folder in the explorer
if (this.contextService.isInsideWorkspace(input.resource)) {
if (this.contextService.isInsideWorkspace(input.preferredResource)) {
await this.viewletService.openViewlet(VIEWLET_ID);
this.explorerService.select(input.resource, true);
this.explorerService.select(input.preferredResource, true);
}
}
......
......@@ -451,7 +451,7 @@ export class GlobalCompareResourcesAction extends Action {
async run(): Promise<void> {
const activeInput = this.editorService.activeEditor;
const activeResource = activeInput ? activeInput.resource : undefined;
const activeResource = toResource(activeInput, { usePreferredResource: true });
if (activeResource && this.textModelService.canHandleResource(activeResource)) {
// Compare with next editor that opens
......@@ -462,7 +462,7 @@ export class GlobalCompareResourcesAction extends Action {
toDispose.dispose();
// Open editor as diff
const resource = editor.resource;
const resource = toResource(editor, { usePreferredResource: true });
if (resource && this.textModelService.canHandleResource(resource)) {
return {
override: this.editorService.openEditor({
......@@ -633,7 +633,7 @@ export class ShowActiveFileInExplorer extends Action {
}
async run(): Promise<void> {
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (resource) {
this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource);
} else {
......@@ -701,7 +701,7 @@ export class ShowOpenedFileInNewWindow extends Action {
}
async run(): Promise<void> {
const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (fileResource) {
if (this.fileService.canHandleResource(fileResource)) {
this.hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true });
......@@ -813,7 +813,7 @@ export class CompareWithClipboardAction extends Action {
}
async run(): Promise<void> {
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
const scheme = `clipboardCompare${CompareWithClipboardAction.SCHEME_COUNTER++}`;
if (resource && (this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
if (!this.registrationDisposal) {
......
......@@ -305,7 +305,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
handler: async (accessor) => {
const editorService = accessor.get(IEditorService);
const activeInput = editorService.activeEditor;
const resource = activeInput ? activeInput.resource : null;
const resource = toResource(activeInput, { usePreferredResource: true, supportSideBySide: SideBySideEditor.PRIMARY });
const resources = resource ? [resource] : [];
await resourcesToClipboard(resources, false, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService));
}
......
......@@ -50,7 +50,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe
return focus.getResource();
}
return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }) : undefined;
return toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
}
export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService, explorerService: IExplorerService): Array<URI> {
......
......@@ -680,7 +680,7 @@ export class ExplorerView extends ViewPane {
}
// check for files
return withNullAsUndefined(toResource(input, { supportSideBySide: SideBySideEditor.PRIMARY }));
return withNullAsUndefined(toResource(input, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true }));
}
public async selectResource(resource: URI | undefined, reveal = this.autoReveal, retry = 0): Promise<void> {
......
......@@ -57,6 +57,7 @@ import { domEvent } from 'vs/base/browser/event';
import { IEditableData } from 'vs/workbench/common/views';
import { IEditorInput } from 'vs/workbench/common/editor';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
......@@ -541,6 +542,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IExplorerService private readonly explorerService: IExplorerService,
@IEditorService private readonly editorService: IEditorService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService
) {
this.hiddenExpressionPerRoot = new Map<string, CachedParsedExpression>();
this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateConfiguration()));
......@@ -554,7 +556,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
let shouldFire = false;
this.hiddenUris.forEach(u => {
editors.forEach(e => {
if (e.resource && isEqualOrParent(e.resource, u)) {
if (e.resource && this.uriIdentityService.extUri.isEqualOrParent(e.resource, u)) {
// A filtered resource suddenly became visible since user opened an editor
shouldFire = true;
}
......@@ -629,7 +631,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
if ((cached && cached.parsed(path.relative(stat.root.resource.path, stat.resource.path), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) || stat.parent?.isExcluded) {
stat.isExcluded = true;
const editors = this.editorService.visibleEditors;
const editor = editors.find(e => e.resource && isEqualOrParent(e.resource, stat.resource));
const editor = editors.find(e => e.resource && this.uriIdentityService.extUri.isEqualOrParent(e.resource, stat.resource));
if (editor) {
this.editorsAffectingFilter.add(editor);
return true; // Show all opened files and their parents
......
......@@ -379,7 +379,7 @@ export class OpenEditorsView extends ViewPane {
const element = e.element;
const actions: IAction[] = [];
const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? element.editor.resource : {} }, actions, this.contextMenuService);
const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? toResource(element.editor, { usePreferredResource: true }) : {} }, actions, this.contextMenuService);
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
......@@ -597,7 +597,7 @@ class OpenEditorRenderer implements IListRenderer<OpenEditor, IOpenEditorTemplat
templateData.actionRunner.editor = openedEditor;
editor.isDirty() && !editor.isSaving() ? templateData.container.classList.add('dirty') : templateData.container.classList.remove('dirty');
templateData.root.setResource({
resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH }),
resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH, usePreferredResource: true }),
name: editor.getName(),
description: editor.getDescription(Verbosity.MEDIUM)
}, {
......
......@@ -282,7 +282,7 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements
}
private async doResolveAsBinary(): Promise<BinaryEditorModel> {
return this.instantiationService.createInstance(BinaryEditorModel, this.resource, this.getName()).load();
return this.instantiationService.createInstance(BinaryEditorModel, this.preferredResource, this.getName()).load();
}
isResolved(): boolean {
......
......@@ -19,6 +19,7 @@ import { IExpression } from 'vs/base/common/glob';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditableData } from 'vs/workbench/common/views';
import { toResource } from 'vs/workbench/common/editor';
function getFileEventsExcludes(configurationService: IConfigurationService, root?: URI): IExpression {
const scope = root ? { resource: root } : undefined;
......@@ -193,7 +194,7 @@ export class ExplorerService implements IExplorerService {
this.model.roots.forEach(r => r.forgetChildren());
if (this.view) {
await this.view.refresh(true);
const resource = this.editorService.activeEditor ? this.editorService.activeEditor.resource : undefined;
const resource = toResource(this.editorService.activeEditor, { usePreferredResource: true });
const autoReveal = this.configurationService.getValue<IFilesConfiguration>().explorer.autoReveal;
if (reveal && resource && autoReveal) {
......
......@@ -263,6 +263,6 @@ export class OpenEditor implements IEditorIdentifier {
}
getResource(): URI | undefined {
return toResource(this.editor, { supportSideBySide: SideBySideEditor.PRIMARY });
return toResource(this.editor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
}
}
......@@ -22,6 +22,7 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { ResourceContextKey } from 'vs/workbench/common/resources';
import { appendToCommandPalette, appendEditorTitleContextMenuItem } from 'vs/workbench/contrib/files/browser/fileActions.contribution';
import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
import { SideBySideEditor, toResource } from 'vs/workbench/common/editor';
const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS';
const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in File Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder");
......@@ -40,15 +41,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
const REVEAL_ACTIVE_FILE_IN_OS_COMMAND_ID = 'workbench.action.files.revealActiveFileInWindows';
KeybindingsRegistry.registerCommandAndKeybindingRule({
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R),
id: 'workbench.action.files.revealActiveFileInWindows',
id: REVEAL_ACTIVE_FILE_IN_OS_COMMAND_ID,
handler: (accessor: ServicesAccessor) => {
const editorService = accessor.get(IEditorService);
const activeInput = editorService.activeEditor;
const resource = activeInput ? activeInput.resource : null;
const resource = toResource(activeInput, { filterByScheme: Schemas.file, usePreferredResource: true, supportSideBySide: SideBySideEditor.PRIMARY });
const resources = resource ? [resource] : [];
revealResourcesInOS(resources, accessor.get(INativeHostService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService));
}
......
......@@ -14,6 +14,7 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { toResource } from 'vs/workbench/common/editor';
function getCount(repository: ISCMRepository): number {
if (typeof repository.provider.count === 'number') {
......@@ -56,11 +57,7 @@ export class SCMStatusController implements IWorkbenchContribution {
}
private tryFocusRepositoryBasedOnActiveEditor(): boolean {
if (!this.editorService.activeEditor) {
return false;
}
const resource = this.editorService.activeEditor.resource;
const resource = toResource(this.editorService.activeEditor, { usePreferredResource: true });
if (!resource) {
return false;
......
......@@ -959,13 +959,7 @@ class ViewModel {
return;
}
const editor = this.editorService.activeEditor;
if (!editor) {
return;
}
const uri = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
const uri = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (!uri) {
return;
......
......@@ -15,7 +15,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { untildify } from 'vs/base/common/labels';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { URI } from 'vs/base/common/uri';
import { toLocalResource, dirname, basenameOrAuthority, isEqual } from 'vs/base/common/resources';
import { toLocalResource, dirname, basenameOrAuthority } from 'vs/base/common/resources';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IFileService } from 'vs/platform/files/common/files';
import { CancellationToken } from 'vs/base/common/cancellation';
......@@ -27,7 +27,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { localize } from 'vs/nls';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchEditorConfiguration, IEditorInput, EditorInput } from 'vs/workbench/common/editor';
import { IWorkbenchEditorConfiguration, IEditorInput, EditorInput, toResource } from 'vs/workbench/common/editor';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { Range, IRange } from 'vs/editor/common/core/range';
import { ThrottledDelayer } from 'vs/base/common/async';
......@@ -49,6 +49,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe
import { getIEditor } from 'vs/editor/browser/editorBrowser';
import { withNullAsUndefined } from 'vs/base/common/types';
import { Codicon, stripCodicons } from 'vs/base/common/codicons';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
interface IAnythingQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource { }
......@@ -173,7 +174,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
@IEditorService private readonly editorService: IEditorService,
@IHistoryService private readonly historyService: IHistoryService,
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService,
@ITextModelService private readonly textModelService: ITextModelService
@ITextModelService private readonly textModelService: ITextModelService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService
) {
super(AnythingQuickAccessProvider.PREFIX, {
canAcceptInBackground: true,
......@@ -228,7 +230,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
private decorateAndRevealSymbolRange(pick: IEditorSymbolAnythingQuickPickItem): IDisposable {
const activeEditor = this.editorService.activeEditor;
if (!isEqual(pick.resource, activeEditor?.resource)) {
if (!this.uriIdentityService.extUri.isEqual(pick.resource, activeEditor?.resource)) {
return Disposable.None; // active editor needs to be for resource
}
......@@ -862,7 +864,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
let isDirty: boolean | undefined = undefined;
if (resourceOrEditor instanceof EditorInput) {
resource = resourceOrEditor.resource;
resource = toResource(resourceOrEditor, { usePreferredResource: true });
label = resourceOrEditor.getName();
description = resourceOrEditor.getDescription();
isDirty = resourceOrEditor.isDirty() && !resourceOrEditor.isSaving();
......
......@@ -29,6 +29,7 @@ import { IViewsService } from 'vs/workbench/common/views';
import { SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { searchRefreshIcon, searchCollapseAllIcon, searchExpandAllIcon, searchClearIcon, searchReplaceAllIcon, searchReplaceIcon, searchRemoveIcon, searchStopIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
export function isSearchViewFocused(viewsService: IViewsService): boolean {
const searchView = getSearchView(viewsService);
......@@ -689,7 +690,9 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction {
@IReplaceService private readonly replaceService: IReplaceService,
@IKeybindingService keyBindingService: IKeybindingService,
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService) {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService
) {
super(Constants.ReplaceActionId, appendKeyBindingLabel(ReplaceAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceActionId), keyBindingService), searchReplaceIcon.classNames);
}
......@@ -752,14 +755,14 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction {
}
private hasSameParent(element: RenderableMatch): boolean {
return element && element instanceof Match && element.parent().resource === this.element.parent().resource;
return element && element instanceof Match && this.uriIdentityService.extUri.isEqual(element.parent().resource, this.element.parent().resource);
}
private hasToOpenFile(): boolean {
const activeEditor = this.editorService.activeEditor;
const file = activeEditor ? activeEditor.resource : undefined;
const file = activeEditor?.resource;
if (file) {
return file.toString() === this.element.parent().resource.toString();
return this.uriIdentityService.extUri.isEqual(file, this.element.parent().resource);
}
return false;
}
......
......@@ -343,12 +343,7 @@ export class TimelinePane extends ViewPane {
return;
}
let uri;
const editor = this.editorService.activeEditor;
if (editor) {
uri = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
}
const uri = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if ((uri?.toString(true) === this.uri?.toString(true) && uri !== undefined) ||
// Fallback to match on fsPath if we are dealing with files or git schemes
......
......@@ -136,7 +136,7 @@ export class NativeWindow extends Disposable {
if (request.from === 'touchbar') {
const activeEditor = this.editorService.activeEditor;
if (activeEditor) {
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, usePreferredResource: true });
if (resource) {
args.push(resource);
}
......@@ -226,7 +226,7 @@ export class NativeWindow extends Disposable {
// macOS OS integration
if (isMacintosh) {
this._register(this.editorService.onDidActiveEditorChange(() => {
const file = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, filterByScheme: Schemas.file });
const file = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY, filterByScheme: Schemas.file, usePreferredResource: true });
// Represented Filename
this.updateRepresentedFilename(file?.fsPath);
......
......@@ -7,7 +7,7 @@ import { URI as uri } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import * as Types from 'vs/base/common/types';
import { Schemas } from 'vs/base/common/network';
import { toResource } from 'vs/workbench/common/editor';
import { SideBySideEditor, toResource } from 'vs/workbench/common/editor';
import { IStringDictionary, forEach, fromMap } from 'vs/base/common/collections';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
......@@ -16,7 +16,6 @@ import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/p
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { ConfiguredInput, IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IProcessEnvironment } from 'vs/base/common/platform';
......@@ -52,11 +51,11 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR
return context.getExecPath();
},
getFilePath: (): string | undefined => {
let activeEditor = editorService.activeEditor;
if (activeEditor instanceof DiffEditorInput) {
activeEditor = activeEditor.modifiedInput;
}
const fileResource = toResource(activeEditor, { filterByScheme: [Schemas.file, Schemas.userData, Schemas.vscodeRemote] });
const fileResource = toResource(editorService.activeEditor, {
supportSideBySide: SideBySideEditor.PRIMARY,
filterByScheme: [Schemas.file, Schemas.userData, Schemas.vscodeRemote],
usePreferredResource: true
});
if (!fileResource) {
return undefined;
}
......
......@@ -877,7 +877,6 @@ export class EditorService extends Disposable implements EditorServiceImpl {
// with different resource forms (e.g. path casing on Windows)
const canonicalResource = this.asCanonicalEditorResource(preferredResource);
return this.createOrGetCached(canonicalResource, () => {
// File
......@@ -970,11 +969,9 @@ export class EditorService extends Disposable implements EditorServiceImpl {
}
private toSideBySideLabel(leftInput: EditorInput, rightInput: EditorInput, divider: string): string | undefined {
const leftResource = leftInput.resource;
const rightResource = rightInput.resource;
// Without any resource, do not try to compute a label
if (!leftResource || !rightResource) {
if (!leftInput.resource || !rightInput.resource) {
return undefined;
}
......@@ -982,7 +979,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
// by adding the relative path of both inputs to the label. This
// makes it easier to understand a file-based comparison.
if (this.fileEditorInputFactory.isFileEditorInput(leftInput) && this.fileEditorInputFactory.isFileEditorInput(rightInput)) {
return `${this.labelService.getUriLabel(leftResource, { relative: true })} ${divider} ${this.labelService.getUriLabel(rightResource, { relative: true })}`;
return `${this.labelService.getUriLabel(leftInput.preferredResource, { relative: true })} ${divider} ${this.labelService.getUriLabel(rightInput.preferredResource, { relative: true })}`;
}
// Signal back that the label should be computed from within the editor
......
......@@ -9,7 +9,7 @@ import { IConfigurationNode, IConfigurationRegistry, Extensions } from 'vs/platf
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { ICustomEditorInfo, IEditorService, IOpenEditorOverrideHandler, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService';
import { IEditorInput, IEditorPane, IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { IEditorInput, IEditorPane, IEditorInputFactoryRegistry, Extensions as EditorExtensions, toResource } from 'vs/workbench/common/editor';
import { ITextEditorOptions, IEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorGroup, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -37,7 +37,7 @@ export async function openEditorWith(
configurationService: IConfigurationService,
quickInputService: IQuickInputService,
): Promise<IEditorPane | undefined> {
const resource = input.resource;
const resource = toResource(input, { usePreferredResource: true });
if (!resource) {
return;
}
......@@ -146,11 +146,12 @@ export function getAllAvailableEditors(
overrides.unshift([
{
open: (input: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) => {
if (!input.resource) {
const resource = toResource(input, { usePreferredResource: true });
if (!resource) {
return;
}
const fileEditorInput = editorService.createEditorInput({ resource: input.resource, forceFile: true });
const fileEditorInput = editorService.createEditorInput({ resource, forceFile: true });
const textOptions: IEditorOptions | ITextEditorOptions = options ? { ...options, override: false } : { override: false };
return { override: editorService.openEditor(fileEditorInput, textOptions, group) };
}
......
......@@ -32,10 +32,10 @@ import { addDisposableListener, EventType, EventHelper } from 'vs/base/browser/d
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { Schemas } from 'vs/base/common/network';
import { onUnexpectedError } from 'vs/base/common/errors';
import { extUri } from 'vs/base/common/resources';
import { IdleValue } from 'vs/base/common/async';
import { ResourceGlobMatcher } from 'vs/workbench/common/resources';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
/**
* Stores the selection & view state of an editor and allows to compare it to other selection states.
......@@ -119,7 +119,8 @@ export class HistoryService extends Disposable implements IHistoryService {
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IPathService private readonly pathService: IPathService
@IPathService private readonly pathService: IPathService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService
) {
super();
......@@ -581,7 +582,7 @@ export class HistoryService extends Disposable implements IHistoryService {
const resourceEditorInputA = arg1 as IResourceEditorInput;
const resourceEditorInputB = inputB as IResourceEditorInput;
return resourceEditorInputA && resourceEditorInputB && extUri.isEqual(resourceEditorInputA.resource, resourceEditorInputB.resource);
return resourceEditorInputA && resourceEditorInputB && this.uriIdentityService.extUri.isEqual(resourceEditorInputA.resource, resourceEditorInputB.resource);
}
private matchesFile(resource: URI, arg2: IEditorInput | IResourceEditorInput | FileChangesEvent): boolean {
......@@ -599,12 +600,12 @@ export class HistoryService extends Disposable implements IHistoryService {
return false; // make sure to only check this when workbench has restored (for https://github.com/microsoft/vscode/issues/48275)
}
return extUri.isEqual(inputResource, resource);
return this.uriIdentityService.extUri.isEqual(inputResource, resource);
}
const resourceEditorInput = arg2 as IResourceEditorInput;
return extUri.isEqual(resourceEditorInput?.resource, resource);
return this.uriIdentityService.extUri.isEqual(resourceEditorInput?.resource, resource);
}
//#endregion
......@@ -1001,7 +1002,7 @@ export class HistoryService extends Disposable implements IHistoryService {
for (const input of this.getHistory()) {
let resource: URI | undefined;
if (input instanceof EditorInput) {
resource = toResource(input, { filterByScheme });
resource = toResource(input, { filterByScheme, usePreferredResource: true });
} else {
resource = (input as IResourceEditorInput).resource;
}
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
import { toResource, SideBySideEditor, IEditorInputWithPreferredResource } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { URI } from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
......@@ -12,6 +12,13 @@ import { workbenchInstantiationService, TestServiceAccessor, TestEditorInput } f
import { Schemas } from 'vs/base/common/network';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
export class TestEditorInputWithPreferredResource extends TestEditorInput implements IEditorInputWithPreferredResource {
constructor(resource: URI, public preferredResource: URI, typeId: string) {
super(resource, typeId);
}
}
suite('Workbench editor', () => {
let instantiationService: IInstantiationService;
......@@ -71,5 +78,12 @@ suite('Workbench editor', () => {
assert.equal((toResource(diffEditorInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
assert.equal((toResource(diffEditorInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
assert.equal((toResource(diffEditorInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
const resource = URI.file('/some/path.txt');
const preferredResource = URI.file('/some/PATH.txt');
const fileWithPreferredResource = new TestEditorInputWithPreferredResource(URI.file('/some/path.txt'), URI.file('/some/PATH.txt'), 'editorResourceFileTest');
assert.equal(toResource(fileWithPreferredResource)?.toString(), resource.toString());
assert.equal(toResource(fileWithPreferredResource, { usePreferredResource: true })?.toString(), preferredResource.toString());
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册