Cannot distinguish different files with the same path.filename(x) (fixes #8499)

This commit is contained in:
Benjamin Pasero 2016-08-12 11:48:14 +02:00
parent 6df36e50f2
commit be4b9711f6
6 changed files with 77 additions and 101 deletions

View file

@ -9,7 +9,6 @@ import platform = require('vs/base/common/platform');
import types = require('vs/base/common/types');
import strings = require('vs/base/common/strings');
import paths = require('vs/base/common/paths');
import {LinkedMap} from 'vs/base/common/map';
export interface ILabelProvider {
@ -71,34 +70,4 @@ function getPath(arg1: URI | string | IWorkspaceProvider): string {
}
return (<URI>arg1).fsPath;
}
export interface IPathLabel {
resource: URI;
label: string;
meta?: string;
}
export function getPathLabels(resources: URI[], provider?: IWorkspaceProvider): LinkedMap<URI, IPathLabel> {
const labels = new LinkedMap<URI, IPathLabel>();
const mapLabelToDuplicates = new LinkedMap<string, IPathLabel[]>();
resources.forEach(resource => {
const item = { resource, label: paths.basename(resource.fsPath) };
labels.set(resource, item);
const duplicates = mapLabelToDuplicates.getOrSet(item.label, []);
duplicates.push(item);
});
const duplicates = mapLabelToDuplicates.values();
duplicates.forEach(duplicates => {
if (duplicates.length > 1) {
duplicates.forEach(duplicate => {
duplicate.meta = getPathLabel(paths.dirname(duplicate.resource.fsPath), provider);
});
}
});
return labels;
}

View file

@ -1,46 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import {getPathLabels} from 'vs/base/common/labels';
import uri from 'vs/base/common/uri';
suite('Labels', () => {
test('getPathLabels - no collisions', () => {
const uris = [
uri.file('/parentA/childA.txt'),
uri.file('/parentA/childB.txt'),
uri.file('/parentA/other/childC.txt')
];
const res = getPathLabels(uris).values();
assert.equal(res.length, 3);
assert.equal(res[0].label, 'childA.txt');
assert.ok(!res[0].meta);
assert.equal(res[1].label, 'childB.txt');
assert.ok(!res[1].meta);
assert.equal(res[2].label, 'childC.txt');
assert.ok(!res[2].meta);
});
test('getPathLabels - collisions', () => {
const uris = [
uri.file('/parentA/childA.txt'),
uri.file('/parentB/childA.txt'),
uri.file('/parentC/other/childA.txt')
];
const res = getPathLabels(uris).values();
assert.equal(res.length, 3);
assert.equal(res[0].label, 'childA.txt');
assert.equal(res[0].meta, '/parentA');
assert.equal(res[1].label, 'childA.txt');
assert.equal(res[1].meta, '/parentB');
assert.equal(res[2].label, 'childA.txt');
assert.equal(res[2].meta, '/parentC/other');
});
});

View file

@ -35,22 +35,6 @@
padding-left: 2px;
}
/* Title Description */
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
margin-left: 0.5em;
font-size: 0.9em;
cursor: default;
}
.vs .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
color: rgba(108, 108, 108, 0.7);
}
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
color: rgba(204, 204, 204, 0.7);
}
/* Title Actions */
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-actions {
display: flex;

View file

@ -24,7 +24,8 @@
cursor: pointer;
}
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span,
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab .tab-label span {
cursor: pointer;
}
@ -48,6 +49,24 @@
color: white;
}
/* Title Description */
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab .tab-label span,
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
margin-left: 0.5em;
font-size: 0.9em;
}
.vs .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab .tab-label span,
.vs .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
color: rgba(108, 108, 108, 0.7);
}
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab .tab-label span,
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label span {
color: rgba(204, 204, 204, 0.7);
}
/* Title Actions */
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-actions .action-label,

View file

@ -12,7 +12,7 @@ import DOM = require('vs/base/browser/dom');
import {isMacintosh} from 'vs/base/common/platform';
import {MIME_BINARY} from 'vs/base/common/mime';
import {Position} from 'vs/platform/editor/common/editor';
import {IEditorGroup, IEditorIdentifier, asFileEditorInput} from 'vs/workbench/common/editor';
import {IEditorGroup, IEditorIdentifier, asFileEditorInput, getUniqueLabels} from 'vs/workbench/common/editor';
import {StandardKeyboardEvent} from 'vs/base/browser/keyboardEvent';
import {CommonKeybindings as Kb, KeyCode} from 'vs/base/common/keyCodes';
import {ActionBar} from 'vs/base/browser/ui/actionbar/actionbar';
@ -178,23 +178,37 @@ export class TabsTitleControl extends TitleControl {
DOM.removeClass(this.titleContainer, 'active');
}
// Compute labels and protect against duplicates
const editorsOfGroup = this.context.getEditors();
const labels = getUniqueLabels(editorsOfGroup);
// Tab label and styles
this.context.getEditors().forEach((editor, index) => {
editorsOfGroup.forEach((editor, index) => {
const tabContainer = this.tabsContainer.children[index];
if (tabContainer instanceof HTMLElement) {
const tabLabel = <HTMLAnchorElement>(<HTMLElement>tabContainer.children[0]).children[0];
const tabLabelsContainer = <HTMLElement>tabContainer.children[0];
const tabLabel = <HTMLAnchorElement>tabLabelsContainer.children[0];
const tabDescription = <HTMLSpanElement>tabLabelsContainer.children[1];
const isPinned = group.isPinned(editor);
const isActive = group.isActive(editor);
const isDirty = editor.isDirty();
const description = editor.getDescription(true) || '';
const name = editor.getName();
const label = labels[index];
const name = label.name;
const description = label.hasAmbiguosName && label.description ? label.description : '';
const verboseDescription = label.verboseDescription || '';
// Label & Description
tabContainer.setAttribute('aria-label', `tab, ${name}`);
tabContainer.title = description;
tabContainer.title = verboseDescription;
tabLabel.innerText = name;
tabDescription.innerText = description;
if (description) {
DOM.show(tabDescription);
} else {
DOM.hide(tabDescription);
}
// Pinned state
if (isPinned) {
@ -280,6 +294,10 @@ export class TabsTitleControl extends TitleControl {
const tabLabel = document.createElement('a');
tabLabelContainer.appendChild(tabLabel);
// Tab Description
const tabDescription = document.createElement('span');
tabLabelContainer.appendChild(tabDescription);
// Tab Close
const tabCloseContainer = document.createElement('div');
DOM.addClass(tabCloseContainer, 'tab-close');

View file

@ -16,6 +16,7 @@ import {Event as BaseEvent} from 'vs/base/common/events';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {SyncDescriptor, AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
import {IInstantiationService, IConstructorSignature0} from 'vs/platform/instantiation/common/instantiation';
import {LinkedMap} from 'vs/base/common/map';
export enum ConfirmResult {
SAVE,
@ -844,4 +845,35 @@ export interface ActiveEditorMoveArguments {
export var EditorCommands = {
MoveActiveEditor: 'moveActiveEditor'
};
};
export interface IEditorInputLabel {
name: string;
hasAmbiguosName?: boolean;
description?: string;
verboseDescription?: string;
}
export function getUniqueLabels(editors: IEditorInput[]): IEditorInputLabel[] {
const labels: IEditorInputLabel[] = [];
const mapLabelToDuplicates = new LinkedMap<string, IEditorInputLabel[]>();
editors.forEach(editor => {
const item:IEditorInputLabel = { name: editor.getName(), description: editor.getDescription(), verboseDescription: editor.getDescription(true) };
labels.push(item);
const duplicates = mapLabelToDuplicates.getOrSet(item.name, []);
duplicates.push(item);
});
const duplicates = mapLabelToDuplicates.values();
duplicates.forEach(duplicates => {
if (duplicates.length > 1) {
duplicates.forEach(duplicate => {
duplicate.hasAmbiguosName = true;
});
}
});
return labels;
}