From d705f554bbafea8d9c3f4bded4d2acfc7faf8d46 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 21 Sep 2016 13:00:31 +0200 Subject: [PATCH] icons: in editor picker --- .../parts/quickopen/browser/quickOpenModel.ts | 39 ++++----- .../quickopen/browser/quickOpenWidget.ts | 6 +- src/vs/workbench/browser/labels.ts | 80 +++++++++---------- .../browser/parts/editor/editorPicker.ts | 19 +++-- .../parts/quickopen/quickOpenController.ts | 4 +- 5 files changed, 77 insertions(+), 71 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 9eb84ef4847..2c9f66c54cf 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -13,6 +13,7 @@ import {ITree, IElementCallback} from 'vs/base/parts/tree/browser/tree'; import filters = require('vs/base/common/filters'); import strings = require('vs/base/common/strings'); import paths = require('vs/base/common/paths'); +import {IconLabel, IIconLabelOptions} from 'vs/base/browser/ui/iconLabel/iconLabel'; import {IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode} from 'vs/base/parts/quickopen/common/quickOpen'; import {IActionProvider} from 'vs/base/parts/tree/browser/actionsRenderer'; import {Action, IAction, IActionRunner} from 'vs/base/common/actions'; @@ -73,6 +74,13 @@ export class QuickOpenEntry { return null; } + /** + * The options for the label to use for this entry + */ + public getLabelOptions(): IIconLabelOptions { + return null; + } + /** * The label of the entry to use when a screen reader wants to read about the entry */ @@ -109,13 +117,6 @@ export class QuickOpenEntry { return null; } - /** - * Extra CSS class name to add to the quick open entry to do custom styling of entries. - */ - public getExtraClass(): string { - return null; - } - /** * Allows to reuse the same model while filtering. Hidden entries will not show up in the viewer. */ @@ -331,6 +332,10 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry ? this.entry.getLabel() : super.getLabel(); } + public getLabelOptions(): IIconLabelOptions { + return this.entry ? this.entry.getLabelOptions() : super.getLabelOptions(); + } + public getAriaLabel(): string { return this.entry ? this.entry.getAriaLabel() : super.getAriaLabel(); } @@ -359,10 +364,6 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry ? this.entry.getHighlights() : super.getHighlights(); } - public getExtraClass(): string { - return this.entry ? this.entry.getExtraClass() : super.getExtraClass(); - } - public isHidden(): boolean { return this.entry ? this.entry.isHidden() : super.isHidden(); } @@ -426,7 +427,7 @@ export interface IQuickOpenEntryTemplateData { container: HTMLElement; entry: HTMLElement; icon: HTMLSpanElement; - label: HighlightedLabel; + label: IconLabel; detail: HighlightedLabel; description: HighlightedLabel; actionBar: ActionBar; @@ -510,7 +511,7 @@ class Renderer implements IRenderer { entry.appendChild(icon); // Label - const label = new HighlightedLabel(entry); + const label = new IconLabel(entry, { supportHighlights: true }); // Description const descriptionContainer = document.createElement('span'); @@ -585,20 +586,14 @@ class Renderer implements IRenderer { if (entry instanceof QuickOpenEntry) { const [labelHighlights, descriptionHighlights, detailHighlights] = entry.getHighlights(); - // Extra Class - const extraClass = entry.getExtraClass(); - if (extraClass) { - DOM.addClass(data.entry, extraClass); - } else { - data.entry.className = 'quick-open-entry'; - } - // Icon const iconClass = entry.getIcon() ? ('quick-open-entry-icon ' + entry.getIcon()) : ''; data.icon.className = iconClass; // Label - data.label.set(entry.getLabel(), labelHighlights || []); + const options:IIconLabelOptions = entry.getLabelOptions() || Object.create(null); + options.matches = labelHighlights || []; + data.label.setValue(entry.getLabel(), null, options); // Meta data.detail.set(entry.getDetail(), detailHighlights); diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index e2c7814a47d..793a0930625 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -108,7 +108,7 @@ export class QuickOpenWidget implements IModelProvider { this.model = null; } - getModel(): IModel { + public getModel(): IModel { return this.model; } @@ -116,7 +116,7 @@ export class QuickOpenWidget implements IModelProvider { this.callbacks = callbacks; } - public create(): void { + public create(): HTMLElement { this.builder = $().div((div: Builder) => { // Eventing @@ -300,6 +300,8 @@ export class QuickOpenWidget implements IModelProvider { if (this.layoutDimensions) { this.layout(this.layoutDimensions); } + + return this.builder.getHTMLElement(); } private onType(): void { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index c7d5ba6e481..47c37f77fd6 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -80,7 +80,7 @@ export class ResourceLabel extends IconLabel { title = resource.fsPath; } - const extraClasses = this.getIconClasses(resource); + const extraClasses = getIconClasses(this.modeService, resource, this.options && this.options.isFolder); if (this.options && this.options.extraClasses) { extraClasses.push(...this.options.extraClasses); } @@ -91,45 +91,6 @@ export class ResourceLabel extends IconLabel { this.setValue(this.label.name, this.label.description, { title, extraClasses, italic, matches }); } - protected getIconClasses(arg1?: uri | string): string[] { - let path: string; - if (typeof arg1 === 'string') { - path = arg1; - } else if (arg1) { - path = arg1.fsPath; - } - - const classes = (this.options && this.options.isFolder) ? ['folder-icon'] : ['file-icon']; - - if (path) { - const basename = paths.basename(path); - const dotSegments = basename.split('.'); - - const name = dotSegments[0]; // file.txt => "file", .dockerfile => "", file.some.txt => "file" - if (name) { - classes.push(`${this.cssEscape(name.toLowerCase())}-name-file-icon`); - } - - const extensions = dotSegments.splice(1); - if (extensions.length > 0) { - for (let i = 0; i < extensions.length; i++) { - classes.push(`${this.cssEscape(extensions.slice(i).join('.').toLowerCase())}-ext-file-icon`); // add each combination of all found extensions if more than one - } - } - - const langId = this.modeService.getModeIdByFilenameOrFirstLine(path); - if (langId) { - classes.push(`${this.cssEscape(langId)}-lang-file-icon`); - } - } - - return classes; - } - - private cssEscape(val: string): string { - return val.replace(/\s/g, '\\$&'); // make sure to not introduce CSS classes from files that contain whitespace - } - public dispose(): void { super.dispose(); @@ -164,4 +125,43 @@ export class FileLabel extends ResourceLabel { description: !options.hidePath ? getPathLabel(paths.dirname(resource.fsPath), this.contextService) : void 0 }, options); } +} + +export function getIconClasses(modeService: IModeService, arg1?: uri | string, isFolder?: boolean): string[] { + let path: string; + if (typeof arg1 === 'string') { + path = arg1; + } else if (arg1) { + path = arg1.fsPath; + } + + const classes = isFolder ? ['folder-icon'] : ['file-icon']; + + if (path) { + const basename = paths.basename(path); + const dotSegments = basename.split('.'); + + const name = dotSegments[0]; // file.txt => "file", .dockerfile => "", file.some.txt => "file" + if (name) { + classes.push(`${cssEscape(name.toLowerCase())}-name-file-icon`); + } + + const extensions = dotSegments.splice(1); + if (extensions.length > 0) { + for (let i = 0; i < extensions.length; i++) { + classes.push(`${cssEscape(extensions.slice(i).join('.').toLowerCase())}-ext-file-icon`); // add each combination of all found extensions if more than one + } + } + + const langId = modeService.getModeIdByFilenameOrFirstLine(path); + if (langId) { + classes.push(`${cssEscape(langId)}-lang-file-icon`); + } + } + + return classes; +} + +function cssEscape(val: string): string { + return val.replace(/\s/g, '\\$&'); // make sure to not introduce CSS classes from files that contain whitespace } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 84e912c101b..96b94b38ce3 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -11,9 +11,12 @@ import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); import strings = require('vs/base/common/strings'); +import {IIconLabelOptions} from 'vs/base/browser/ui/iconLabel/iconLabel'; import {IAutoFocus, Mode, IEntryRunContext, IQuickNavigateConfiguration} from 'vs/base/parts/quickopen/common/quickOpen'; import {QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup} from 'vs/base/parts/quickopen/browser/quickOpenModel'; import scorer = require('vs/base/common/scorer'); +import {IModeService} from 'vs/editor/common/services/modeService'; +import {getIconClasses} from 'vs/workbench/browser/labels'; import {QuickOpenHandler} from 'vs/workbench/browser/quickopen'; import {Position} from 'vs/platform/editor/common/editor'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; @@ -29,6 +32,7 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { private editor: EditorInput, private _group: IEditorGroup, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IModeService private modeService: IModeService, @IEditorGroupService private editorGroupService: IEditorGroupService ) { super(); @@ -36,14 +40,21 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { this.stacks = editorGroupService.getStacksModel(); } - public getIcon(): string { - return this.editor.isDirty() ? 'dirty' : ''; + public getLabelOptions(): IIconLabelOptions { + return { + extraClasses: getIconClasses(this.modeService, this.getResource()), + italic: this._group.isPreview(this.editor) + }; } public getLabel(): string { return this.editor.getName(); } + public getIcon(): string { + return this.editor.isDirty() ? 'dirty' : ''; + } + public get group(): IEditorGroup { return this._group; } @@ -62,10 +73,6 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { return this.editor.getDescription(); } - public getExtraClass(): string { - return this._group.isPreview(this.editor) ? 'editor-preview' : ''; - } - public run(mode: Mode, context: IEntryRunContext): boolean { if (mode === Mode.OPEN) { return this.runOpen(context); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index b8530af4f15..16f44c9e600 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -12,6 +12,7 @@ import nls = require('vs/nls'); import {Dimension, withElementById} from 'vs/base/browser/builder'; import strings = require('vs/base/common/strings'); import filters = require('vs/base/common/filters'); +import DOM = require('vs/base/browser/dom'); import URI from 'vs/base/common/uri'; import uuid = require('vs/base/common/uuid'); import types = require('vs/base/common/types'); @@ -514,7 +515,8 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe this.telemetryService ); - this.quickOpenWidget.create(); + const quickOpenContainer = this.quickOpenWidget.create(); + DOM.addClass(quickOpenContainer, 'show-file-icons'); } // Layout