mirror of
https://github.com/Microsoft/vscode
synced 2024-10-14 15:29:54 +00:00
editors - shorten diff labels (#110694)
This commit is contained in:
parent
54cdd9c58b
commit
adee8fa29a
|
@ -48,13 +48,6 @@ export class GitFileSystemProvider implements FileSystemProvider {
|
|||
model.onDidChangeRepository(this.onDidChangeRepository, this),
|
||||
model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this),
|
||||
workspace.registerFileSystemProvider('git', this, { isReadonly: true, isCaseSensitive: true }),
|
||||
workspace.registerResourceLabelFormatter({
|
||||
scheme: 'git',
|
||||
formatting: {
|
||||
label: '${path} (git)',
|
||||
separator: '/'
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
setInterval(() => this.cleanup(), FIVE_MINUTES);
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
opacity: 0.75;
|
||||
font-size: 90%;
|
||||
font-weight: 600;
|
||||
margin: 0 16px 0 5px;
|
||||
margin: auto 16px 0 5px; /* https://github.com/microsoft/vscode/issues/113223 */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
|
|||
|
||||
return isDirty ? localize('entryAriaLabelDirty', "{0}, dirty", nameAndDescription) : nameAndDescription;
|
||||
})(),
|
||||
description: editor.getDescription(),
|
||||
description,
|
||||
iconClasses: getIconClasses(this.modelService, this.modeService, resource).concat(editor.getLabelExtraClasses()),
|
||||
italic: !this.editorGroupService.getGroup(groupId)?.isPinned(editor),
|
||||
buttons: (() => {
|
||||
|
|
|
@ -78,13 +78,13 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
this._register(addDisposableListener(titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleTap(e)));
|
||||
|
||||
// Context Menu
|
||||
[EventType.CONTEXT_MENU, TouchEventType.Contextmenu].forEach(event => {
|
||||
for (const event of [EventType.CONTEXT_MENU, TouchEventType.Contextmenu]) {
|
||||
this._register(addDisposableListener(titleContainer, event, e => {
|
||||
if (this.group.activeEditor) {
|
||||
this.onContextMenu(this.group.activeEditor, e, titleContainer);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private onTitleLabelClick(e: MouseEvent): void {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import 'vs/css!./media/tabstitlecontrol';
|
||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { shorten } from 'vs/base/common/labels';
|
||||
import { EditorResourceAccessor, GroupIdentifier, Verbosity, IEditorPartOptions, SideBySideEditor, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
|
||||
import { EditorResourceAccessor, GroupIdentifier, Verbosity, IEditorPartOptions, SideBySideEditor, DEFAULT_EDITOR_ASSOCIATION, EditorInputCapabilities } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { computeEditorAriaLabel } from 'vs/workbench/browser/editor';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
@ -40,7 +40,7 @@ import { CloseOneEditorAction, UnpinEditorAction } from 'vs/workbench/browser/pa
|
|||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/common/types';
|
||||
import { assertAllDefined, assertIsDefined } from 'vs/base/common/types';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
@ -56,11 +56,12 @@ import { UNLOCK_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/edito
|
|||
interface IEditorInputLabel {
|
||||
name?: string;
|
||||
description?: string;
|
||||
forceDescription?: boolean;
|
||||
title?: string;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
type AugmentedLabel = IEditorInputLabel & { editor: EditorInput };
|
||||
type IEditorInputLabelAndEditor = IEditorInputLabel & { editor: EditorInput };
|
||||
|
||||
export class TabsTitleControl extends TitleControl {
|
||||
|
||||
|
@ -218,7 +219,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
}));
|
||||
|
||||
// New file when double clicking on tabs container (but not tabs)
|
||||
[TouchEventType.Tap, EventType.DBLCLICK].forEach(eventType => {
|
||||
for (const eventType of [TouchEventType.Tap, EventType.DBLCLICK]) {
|
||||
this._register(addDisposableListener(tabsContainer, eventType, (e: MouseEvent | GestureEvent) => {
|
||||
if (eventType === EventType.DBLCLICK) {
|
||||
if (e.target !== tabsContainer) {
|
||||
|
@ -245,7 +246,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
}
|
||||
}, this.group.id);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Prevent auto-scrolling (https://github.com/microsoft/vscode/issues/16690)
|
||||
this._register(addDisposableListener(tabsContainer, EventType.MOUSE_DOWN, e => {
|
||||
|
@ -784,7 +785,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
}));
|
||||
|
||||
// Double click: either pin or toggle maximized
|
||||
[TouchEventType.Tap, EventType.DBLCLICK].forEach(eventType => {
|
||||
for (const eventType of [TouchEventType.Tap, EventType.DBLCLICK]) {
|
||||
disposables.add(addDisposableListener(tab, eventType, (e: MouseEvent | GestureEvent) => {
|
||||
if (eventType === EventType.DBLCLICK) {
|
||||
EventHelper.stop(e);
|
||||
|
@ -799,7 +800,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
this.group.pinEditor(editor);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Context menu
|
||||
disposables.add(addDisposableListener(tab, EventType.CONTEXT_MENU, e => {
|
||||
|
@ -953,11 +954,12 @@ export class TabsTitleControl extends TitleControl {
|
|||
const { verbosity, shortenDuplicates } = this.getLabelConfigFlags(labelFormat);
|
||||
|
||||
// Build labels and descriptions for each editor
|
||||
const labels = this.group.editors.map((editor, index) => ({
|
||||
const labels: IEditorInputLabelAndEditor[] = this.group.editors.map((editor, index) => ({
|
||||
editor,
|
||||
name: editor.getName(),
|
||||
description: editor.getDescription(verbosity),
|
||||
title: withNullAsUndefined(editor.getTitle(Verbosity.LONG)),
|
||||
forceDescription: editor.hasCapability(EditorInputCapabilities.ForceDescription),
|
||||
title: editor.getTitle(Verbosity.LONG),
|
||||
ariaLabel: computeEditorAriaLabel(editor, index, this.group, this.editorGroupService.count)
|
||||
}));
|
||||
|
||||
|
@ -969,63 +971,68 @@ export class TabsTitleControl extends TitleControl {
|
|||
this.tabLabels = labels;
|
||||
}
|
||||
|
||||
private shortenTabLabels(labels: AugmentedLabel[]): void {
|
||||
private shortenTabLabels(labels: IEditorInputLabelAndEditor[]): void {
|
||||
|
||||
// Gather duplicate titles, while filtering out invalid descriptions
|
||||
const mapTitleToDuplicates = new Map<string, AugmentedLabel[]>();
|
||||
const mapNameToDuplicates = new Map<string, IEditorInputLabelAndEditor[]>();
|
||||
for (const label of labels) {
|
||||
if (typeof label.description === 'string') {
|
||||
getOrSet(mapTitleToDuplicates, label.name, []).push(label);
|
||||
getOrSet(mapNameToDuplicates, label.name, []).push(label);
|
||||
} else {
|
||||
label.description = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Identify duplicate titles and shorten descriptions
|
||||
mapTitleToDuplicates.forEach(duplicateTitles => {
|
||||
// Identify duplicate names and shorten descriptions
|
||||
for (const [, duplicateLabels] of mapNameToDuplicates) {
|
||||
|
||||
// Remove description if the title isn't duplicated
|
||||
if (duplicateTitles.length === 1) {
|
||||
duplicateTitles[0].description = '';
|
||||
// and we have no indication to enforce description
|
||||
if (duplicateLabels.length === 1 && !duplicateLabels[0].forceDescription) {
|
||||
duplicateLabels[0].description = '';
|
||||
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Identify duplicate descriptions
|
||||
const mapDescriptionToDuplicates = new Map<string, AugmentedLabel[]>();
|
||||
for (const label of duplicateTitles) {
|
||||
getOrSet(mapDescriptionToDuplicates, label.description, []).push(label);
|
||||
const mapDescriptionToDuplicates = new Map<string, IEditorInputLabelAndEditor[]>();
|
||||
for (const duplicateLabel of duplicateLabels) {
|
||||
getOrSet(mapDescriptionToDuplicates, duplicateLabel.description, []).push(duplicateLabel);
|
||||
}
|
||||
|
||||
// For editors with duplicate descriptions, check whether any long descriptions differ
|
||||
let useLongDescriptions = false;
|
||||
mapDescriptionToDuplicates.forEach((duplicateDescriptions, name) => {
|
||||
if (!useLongDescriptions && duplicateDescriptions.length > 1) {
|
||||
const [first, ...rest] = duplicateDescriptions.map(({ editor }) => editor.getDescription(Verbosity.LONG));
|
||||
for (const [, duplicateLabels] of mapDescriptionToDuplicates) {
|
||||
if (!useLongDescriptions && duplicateLabels.length > 1) {
|
||||
const [first, ...rest] = duplicateLabels.map(({ editor }) => editor.getDescription(Verbosity.LONG));
|
||||
useLongDescriptions = rest.some(description => description !== first);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If so, replace all descriptions with long descriptions
|
||||
if (useLongDescriptions) {
|
||||
mapDescriptionToDuplicates.clear();
|
||||
duplicateTitles.forEach(label => {
|
||||
label.description = label.editor.getDescription(Verbosity.LONG);
|
||||
getOrSet(mapDescriptionToDuplicates, label.description, []).push(label);
|
||||
});
|
||||
for (const duplicateLabel of duplicateLabels) {
|
||||
duplicateLabel.description = duplicateLabel.editor.getDescription(Verbosity.LONG);
|
||||
getOrSet(mapDescriptionToDuplicates, duplicateLabel.description, []).push(duplicateLabel);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain final set of descriptions
|
||||
const descriptions: string[] = [];
|
||||
mapDescriptionToDuplicates.forEach((_, description) => descriptions.push(description));
|
||||
for (const [description] of mapDescriptionToDuplicates) {
|
||||
descriptions.push(description);
|
||||
}
|
||||
|
||||
// Remove description if all descriptions are identical
|
||||
// Remove description if all descriptions are identical unless forced
|
||||
if (descriptions.length === 1) {
|
||||
for (const label of mapDescriptionToDuplicates.get(descriptions[0]) || []) {
|
||||
label.description = '';
|
||||
if (!label.forceDescription) {
|
||||
label.description = '';
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Shorten descriptions
|
||||
|
@ -1035,7 +1042,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
label.description = shortenedDescriptions[index];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getLabelConfigFlags(value: string | undefined) {
|
||||
|
@ -1096,21 +1103,21 @@ export class TabsTitleControl extends TitleControl {
|
|||
|
||||
// Settings
|
||||
const tabActionsVisibility = isTabSticky && options.pinnedTabSizing === 'compact' ? 'off' /* treat sticky compact tabs as tabCloseButton: 'off' */ : options.tabCloseButton;
|
||||
['off', 'left', 'right'].forEach(option => {
|
||||
for (const option of ['off', 'left', 'right']) {
|
||||
tabContainer.classList.toggle(`tab-actions-${option}`, tabActionsVisibility === option);
|
||||
});
|
||||
}
|
||||
|
||||
const tabSizing = isTabSticky && options.pinnedTabSizing === 'shrink' ? 'shrink' /* treat sticky shrink tabs as tabSizing: 'shrink' */ : options.tabSizing;
|
||||
['fit', 'shrink'].forEach(option => {
|
||||
for (const option of ['fit', 'shrink']) {
|
||||
tabContainer.classList.toggle(`sizing-${option}`, tabSizing === option);
|
||||
});
|
||||
}
|
||||
|
||||
tabContainer.classList.toggle('has-icon', options.showIcons && options.hasIcons);
|
||||
|
||||
tabContainer.classList.toggle('sticky', isTabSticky);
|
||||
['normal', 'compact', 'shrink'].forEach(option => {
|
||||
for (const option of ['normal', 'compact', 'shrink']) {
|
||||
tabContainer.classList.toggle(`sticky-${option}`, isTabSticky && options.pinnedTabSizing === option);
|
||||
});
|
||||
}
|
||||
|
||||
// Sticky compact/shrink tabs need a position to remain at their location
|
||||
// when scrolling to stay in view (requirement for position: sticky)
|
||||
|
|
|
@ -522,7 +522,15 @@ export const enum EditorInputCapabilities {
|
|||
* Signals that the editor can split into 2 in the same
|
||||
* editor group.
|
||||
*/
|
||||
CanSplitInGroup = 1 << 5
|
||||
CanSplitInGroup = 1 << 5,
|
||||
|
||||
/**
|
||||
* Signals that the editor wants it's description to be
|
||||
* visible when presented to the user. By default, a UI
|
||||
* component may decide to hide the description portion
|
||||
* for brevity.
|
||||
*/
|
||||
ForceDescription = 1 << 6
|
||||
}
|
||||
|
||||
export type IUntypedEditorInput = IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput | IResourceSideBySideEditorInput;
|
||||
|
|
|
@ -3,22 +3,32 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { AbstractSideBySideEditorInputSerializer, SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
||||
import { TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID, Verbosity, IEditorDescriptor, IEditorPane, GroupIdentifier, IResourceDiffEditorInput, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, isResourceDiffEditorInput, IDiffEditorInput, IResourceSideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID, Verbosity, IEditorDescriptor, IEditorPane, GroupIdentifier, IResourceDiffEditorInput, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, isResourceDiffEditorInput, IDiffEditorInput, IResourceSideBySideEditorInput, EditorInputCapabilities } from 'vs/workbench/common/editor';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel';
|
||||
import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput';
|
||||
import { dirname } from 'vs/base/common/resources';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { shorten } from 'vs/base/common/labels';
|
||||
|
||||
interface IDiffEditorInputLabels {
|
||||
name: string;
|
||||
|
||||
shortDescription: string | undefined;
|
||||
mediumDescription: string | undefined;
|
||||
longDescription: string | undefined;
|
||||
|
||||
forceDescription: boolean;
|
||||
|
||||
shortTitle: string;
|
||||
mediumTitle: string;
|
||||
longTitle: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base editor input for the diff editor. It is made up of two editor inputs, the original version
|
||||
|
@ -36,66 +46,119 @@ export class DiffEditorInput extends SideBySideEditorInput implements IDiffEdito
|
|||
return DEFAULT_EDITOR_ASSOCIATION.id;
|
||||
}
|
||||
|
||||
override get capabilities(): EditorInputCapabilities {
|
||||
let capabilities = super.capabilities;
|
||||
|
||||
// Force description capability depends on labels
|
||||
if (this.labels.forceDescription) {
|
||||
capabilities |= EditorInputCapabilities.ForceDescription;
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
private cachedModel: DiffEditorModel | undefined = undefined;
|
||||
|
||||
private readonly labels = this.computeLabels();
|
||||
|
||||
constructor(
|
||||
name: string | undefined,
|
||||
description: string | undefined,
|
||||
preferredName: string | undefined,
|
||||
preferredDescription: string | undefined,
|
||||
readonly original: EditorInput,
|
||||
readonly modified: EditorInput,
|
||||
private readonly forceOpenAsBinary: boolean | undefined,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IEditorService editorService: IEditorService
|
||||
) {
|
||||
super(name, description, original, modified, editorService);
|
||||
super(preferredName, preferredDescription, original, modified, editorService);
|
||||
}
|
||||
|
||||
private computeLabels(): IDiffEditorInputLabels {
|
||||
|
||||
// Name
|
||||
let name: string;
|
||||
let forceDescription = false;
|
||||
if (this.preferredName) {
|
||||
name = this.preferredName;
|
||||
} else {
|
||||
const originalName = this.original.getName();
|
||||
const modifiedName = this.modified.getName();
|
||||
|
||||
name = localize('sideBySideLabels', "{0} ↔ {1}", originalName, modifiedName);
|
||||
|
||||
// Enforce description when the names are identical
|
||||
forceDescription = originalName === modifiedName;
|
||||
}
|
||||
|
||||
// Description
|
||||
let shortDescription: string | undefined;
|
||||
let mediumDescription: string | undefined;
|
||||
let longDescription: string | undefined;
|
||||
if (this.preferredDescription) {
|
||||
shortDescription = this.preferredDescription;
|
||||
mediumDescription = this.preferredDescription;
|
||||
longDescription = this.preferredDescription;
|
||||
} else {
|
||||
shortDescription = this.computeLabel(this.original.getDescription(Verbosity.SHORT), this.modified.getDescription(Verbosity.SHORT));
|
||||
longDescription = this.computeLabel(this.original.getDescription(Verbosity.LONG), this.modified.getDescription(Verbosity.LONG));
|
||||
|
||||
// Medium Description: try to be verbose by computing
|
||||
// a label that resembles the difference between the two
|
||||
const originalMediumDescription = this.original.getDescription(Verbosity.MEDIUM);
|
||||
const modifiedMediumDescription = this.modified.getDescription(Verbosity.MEDIUM);
|
||||
if (originalMediumDescription && modifiedMediumDescription) {
|
||||
const [shortenedOriginalMediumDescription, shortenedModifiedMediumDescription] = shorten([originalMediumDescription, modifiedMediumDescription]);
|
||||
mediumDescription = this.computeLabel(shortenedOriginalMediumDescription, shortenedModifiedMediumDescription);
|
||||
}
|
||||
}
|
||||
|
||||
// Title
|
||||
const shortTitle = this.computeLabel(this.original.getTitle(Verbosity.SHORT) ?? this.original.getName(), this.modified.getTitle(Verbosity.SHORT) ?? this.modified.getName(), ' ↔ ');
|
||||
const mediumTitle = this.computeLabel(this.original.getTitle(Verbosity.MEDIUM) ?? this.original.getName(), this.modified.getTitle(Verbosity.MEDIUM) ?? this.modified.getName(), ' ↔ ');
|
||||
const longTitle = this.computeLabel(this.original.getTitle(Verbosity.LONG) ?? this.original.getName(), this.modified.getTitle(Verbosity.LONG) ?? this.modified.getName(), ' ↔ ');
|
||||
|
||||
return { name, shortDescription, mediumDescription, longDescription, forceDescription, shortTitle, mediumTitle, longTitle };
|
||||
}
|
||||
|
||||
private computeLabel(originalLabel: string, modifiedLabel: string, separator?: string): string;
|
||||
private computeLabel(originalLabel: string | undefined, modifiedLabel: string | undefined, separator?: string): string | undefined;
|
||||
private computeLabel(originalLabel: string | undefined, modifiedLabel: string | undefined, separator = ' - '): string | undefined {
|
||||
if (!originalLabel || !modifiedLabel) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (originalLabel === modifiedLabel) {
|
||||
return modifiedLabel;
|
||||
}
|
||||
|
||||
return `${originalLabel}${separator}${modifiedLabel}`;
|
||||
}
|
||||
|
||||
override getName(): string {
|
||||
if (!this.name) {
|
||||
|
||||
// Craft a name from original and modified input that includes the
|
||||
// relative path in case both sides have different parents and we
|
||||
// compare file resources.
|
||||
const fileResources = this.asFileResources();
|
||||
if (fileResources && dirname(fileResources.original).path !== dirname(fileResources.modified).path) {
|
||||
return `${this.labelService.getUriLabel(fileResources.original, { relative: true })} ↔ ${this.labelService.getUriLabel(fileResources.modified, { relative: true })}`;
|
||||
}
|
||||
|
||||
return localize('sideBySideLabels', "{0} ↔ {1}", this.original.getName(), this.modified.getName());
|
||||
}
|
||||
|
||||
return this.name;
|
||||
return this.labels.name;
|
||||
}
|
||||
|
||||
override getDescription(verbosity = Verbosity.MEDIUM): string | undefined {
|
||||
if (typeof this.description !== 'string') {
|
||||
|
||||
// Pass the description of the modified side in case both original
|
||||
// and modified input have the same parent and we compare file resources.
|
||||
const fileResources = this.asFileResources();
|
||||
if (fileResources && dirname(fileResources.original).path === dirname(fileResources.modified).path) {
|
||||
return this.modified.getDescription(verbosity);
|
||||
}
|
||||
switch (verbosity) {
|
||||
case Verbosity.SHORT:
|
||||
return this.labels.shortDescription;
|
||||
case Verbosity.LONG:
|
||||
return this.labels.longDescription;
|
||||
case Verbosity.MEDIUM:
|
||||
default:
|
||||
return this.labels.mediumDescription;
|
||||
}
|
||||
|
||||
return this.description;
|
||||
}
|
||||
|
||||
private asFileResources(): { original: URI, modified: URI } | undefined {
|
||||
if (
|
||||
this.original instanceof AbstractTextResourceEditorInput &&
|
||||
this.modified instanceof AbstractTextResourceEditorInput &&
|
||||
this.fileService.canHandleResource(this.original.preferredResource) &&
|
||||
this.fileService.canHandleResource(this.modified.preferredResource)
|
||||
) {
|
||||
return {
|
||||
original: this.original.preferredResource,
|
||||
modified: this.modified.preferredResource
|
||||
};
|
||||
override getTitle(verbosity?: Verbosity): string {
|
||||
switch (verbosity) {
|
||||
case Verbosity.SHORT:
|
||||
return this.labels.shortTitle;
|
||||
case Verbosity.LONG:
|
||||
return this.labels.longTitle;
|
||||
default:
|
||||
case Verbosity.MEDIUM:
|
||||
return this.labels.mediumTitle;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
override async resolve(): Promise<EditorModel> {
|
||||
|
@ -184,7 +247,7 @@ export class DiffEditorInput extends SideBySideEditorInput implements IDiffEdito
|
|||
|
||||
export class DiffEditorInputSerializer extends AbstractSideBySideEditorInputSerializer {
|
||||
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string | undefined, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return instantiationService.createInstance(DiffEditorInput, name, description, secondaryInput, primaryInput, undefined);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,13 +99,6 @@ export abstract class EditorInput extends AbstractEditorInput {
|
|||
return `Editor ${this.typeId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra classes to apply to the label of this input.
|
||||
*/
|
||||
getLabelExtraClasses(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display description of this input.
|
||||
*/
|
||||
|
@ -120,6 +113,13 @@ export abstract class EditorInput extends AbstractEditorInput {
|
|||
return this.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra classes to apply to the label of this input.
|
||||
*/
|
||||
getLabelExtraClasses(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aria label to be read out by a screen reader.
|
||||
*/
|
||||
|
|
|
@ -60,8 +60,8 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
private hasIdenticalSides = this.primary.matches(this.secondary);
|
||||
|
||||
constructor(
|
||||
protected readonly name: string | undefined,
|
||||
protected readonly description: string | undefined,
|
||||
protected readonly preferredName: string | undefined,
|
||||
protected readonly preferredDescription: string | undefined,
|
||||
readonly secondary: EditorInput,
|
||||
readonly primary: EditorInput,
|
||||
@IEditorService private readonly editorService: IEditorService
|
||||
|
@ -91,31 +91,37 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
}
|
||||
|
||||
override getName(): string {
|
||||
if (!this.name) {
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getName(); // keep name concise when same editor is opened side by side
|
||||
}
|
||||
|
||||
return localize('sideBySideLabels', "{0} - {1}", this.secondary.getName(), this.primary.getName());
|
||||
const preferredName = this.getPreferredName();
|
||||
if (preferredName) {
|
||||
return preferredName;
|
||||
}
|
||||
|
||||
return this.name;
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getName(); // keep name concise when same editor is opened side by side
|
||||
}
|
||||
|
||||
return localize('sideBySideLabels', "{0} - {1}", this.secondary.getName(), this.primary.getName());
|
||||
}
|
||||
|
||||
override getLabelExtraClasses(): string[] {
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getLabelExtraClasses();
|
||||
}
|
||||
|
||||
return super.getLabelExtraClasses();
|
||||
getPreferredName(): string | undefined {
|
||||
return this.preferredName;
|
||||
}
|
||||
|
||||
override getDescription(verbosity?: Verbosity): string | undefined {
|
||||
const preferredDescription = this.getPreferredDescription();
|
||||
if (preferredDescription) {
|
||||
return preferredDescription;
|
||||
}
|
||||
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getDescription(verbosity);
|
||||
}
|
||||
|
||||
return this.description;
|
||||
return super.getDescription(verbosity);
|
||||
}
|
||||
|
||||
getPreferredDescription(): string | undefined {
|
||||
return this.preferredDescription;
|
||||
}
|
||||
|
||||
override getTitle(verbosity?: Verbosity): string {
|
||||
|
@ -126,6 +132,14 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
return super.getTitle(verbosity);
|
||||
}
|
||||
|
||||
override getLabelExtraClasses(): string[] {
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getLabelExtraClasses();
|
||||
}
|
||||
|
||||
return super.getLabelExtraClasses();
|
||||
}
|
||||
|
||||
override getAriaLabel(): string {
|
||||
if (this.hasIdenticalSides) {
|
||||
return this.primary.getAriaLabel();
|
||||
|
@ -154,7 +168,7 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
return editor;
|
||||
}
|
||||
|
||||
return new SideBySideEditorInput(this.name, this.description, editor, editor, this.editorService);
|
||||
return new SideBySideEditorInput(this.preferredName, this.preferredDescription, editor, editor, this.editorService);
|
||||
}
|
||||
|
||||
override async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<EditorInput | undefined> {
|
||||
|
@ -163,7 +177,7 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
return editor;
|
||||
}
|
||||
|
||||
return new SideBySideEditorInput(this.name, this.description, editor, editor, this.editorService);
|
||||
return new SideBySideEditorInput(this.preferredName, this.preferredDescription, editor, editor, this.editorService);
|
||||
}
|
||||
|
||||
override revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> {
|
||||
|
@ -185,7 +199,7 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
|
||||
if (isEditorInput(renameResult.editor)) {
|
||||
return {
|
||||
editor: new SideBySideEditorInput(this.name, this.description, renameResult.editor, renameResult.editor, this.editorService),
|
||||
editor: new SideBySideEditorInput(this.preferredName, this.preferredDescription, renameResult.editor, renameResult.editor, this.editorService),
|
||||
options: {
|
||||
...renameResult.options,
|
||||
viewState: findViewStateForEditor(this, group, this.editorService)
|
||||
|
@ -196,8 +210,8 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
if (isResourceEditorInput(renameResult.editor)) {
|
||||
return {
|
||||
editor: {
|
||||
label: this.name,
|
||||
description: this.description,
|
||||
label: this.preferredName,
|
||||
description: this.preferredDescription,
|
||||
primary: renameResult.editor,
|
||||
secondary: renameResult.editor,
|
||||
options: {
|
||||
|
@ -222,8 +236,8 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
!isResourceSideBySideEditorInput(primaryResourceEditorInput) && !isResourceSideBySideEditorInput(secondaryResourceEditorInput)
|
||||
) {
|
||||
const untypedInput: IResourceSideBySideEditorInput = {
|
||||
label: this.name,
|
||||
description: this.description,
|
||||
label: this.preferredName,
|
||||
description: this.preferredDescription,
|
||||
primary: primaryResourceEditorInput,
|
||||
secondary: secondaryResourceEditorInput
|
||||
};
|
||||
|
@ -263,7 +277,7 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi
|
|||
|
||||
// Register SideBySide/DiffEditor Input Serializer
|
||||
interface ISerializedSideBySideEditorInput {
|
||||
name: string;
|
||||
name: string | undefined;
|
||||
description: string | undefined;
|
||||
|
||||
primarySerialized: string;
|
||||
|
@ -298,8 +312,8 @@ export abstract class AbstractSideBySideEditorInputSerializer implements IEditor
|
|||
|
||||
if (primarySerialized && secondarySerialized) {
|
||||
const serializedEditorInput: ISerializedSideBySideEditorInput = {
|
||||
name: input.getName(),
|
||||
description: input.getDescription(),
|
||||
name: input.getPreferredName(),
|
||||
description: input.getPreferredDescription(),
|
||||
primarySerialized: primarySerialized,
|
||||
secondarySerialized: secondarySerialized,
|
||||
primaryTypeId: input.primary.typeId,
|
||||
|
@ -336,12 +350,12 @@ export abstract class AbstractSideBySideEditorInputSerializer implements IEditor
|
|||
return [registry.getEditorSerializer(secondaryEditorInputTypeId), registry.getEditorSerializer(primaryEditorInputTypeId)];
|
||||
}
|
||||
|
||||
protected abstract createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
|
||||
protected abstract createEditorInput(instantiationService: IInstantiationService, name: string | undefined, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
|
||||
}
|
||||
|
||||
export class SideBySideEditorInputSerializer extends AbstractSideBySideEditorInputSerializer {
|
||||
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
protected createEditorInput(instantiationService: IInstantiationService, name: string | undefined, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return instantiationService.createInstance(SideBySideEditorInput, name, description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,8 @@ import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotebookDiffEditorModel, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
class NotebookDiffEditorModel extends EditorModel implements INotebookDiffEditorModel {
|
||||
|
@ -52,8 +50,6 @@ export class NotebookDiffEditorInput extends DiffEditorInput {
|
|||
override readonly original: NotebookEditorInput,
|
||||
override readonly modified: NotebookEditorInput,
|
||||
public readonly viewType: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IEditorService editorService: IEditorService
|
||||
) {
|
||||
super(
|
||||
|
@ -62,8 +58,6 @@ export class NotebookDiffEditorInput extends DiffEditorInput {
|
|||
original,
|
||||
modified,
|
||||
undefined,
|
||||
labelService,
|
||||
fileService,
|
||||
editorService
|
||||
);
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
|
|||
private registerListeners(): void {
|
||||
|
||||
// Creates
|
||||
this._register(this.files.onDidCreate(model => {
|
||||
this._register(this.files.onDidResolve(({ model }) => {
|
||||
if (model.isReadonly() || model.hasState(TextFileEditorModelState.ORPHAN)) {
|
||||
this._onDidChange.fire([model.resource]);
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ export class FileWorkingCopyManager<S extends IStoredFileWorkingCopyModel, U ext
|
|||
private registerListeners(): void {
|
||||
|
||||
// Creates
|
||||
this._register(this.stored.onDidCreate(workingCopy => {
|
||||
this._register(this.stored.onDidResolve(workingCopy => {
|
||||
if (workingCopy.isReadonly() || workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN)) {
|
||||
this._onDidChange.fire([workingCopy.resource]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue