提交 3ae6814c 编写于 作者: M Martin Aeschlimann

[fileicons] single setting, laguageId/fileName/ext and theme overrides

上级 8a7a4edc
{
"definitions": {
"folder": {
"iconPath": "./images/Folder_16x_inverse.svg"
},
"folder_open": {
"iconPath": "./images/FolderOpen_16x_inverse.svg"
},
"file": {
"iconPath": "./images/Document_16x_inverse.svg"
}
},
"defaults": {
"folder-expanded": "folder_open",
"folder": "folder",
"file": "file"
},
"languageAssociations": {
"text": "file"
}
}
\ No newline at end of file
{
"definitions": {
"folder": {
"iconPath": "./images/Folder_16x.svg"
},
"folder_open": {
"iconPath": "./images/FolderOpen_16x.svg"
},
"file": {
"iconPath": "./images/Document_16x.svg"
}
},
"defaults": {
"folder-expanded": "folder_open",
"folder": "folder",
"file": "file"
},
"languageAssociations": {
"text": "file"
}
}
\ No newline at end of file
{
"iconDefinitions": {
"_folder_dark": {
"iconPath": "./images/Folder_16x_inverse.svg"
},
"_folder_open_dark": {
"iconPath": "./images/FolderOpen_16x_inverse.svg"
},
"_file_dark": {
"iconPath": "./images/Document_16x_inverse.svg"
},
"_folder_light": {
"iconPath": "./images/Folder_16x.svg"
},
"_folder_open_light": {
"iconPath": "./images/FolderOpen_16x.svg"
},
"_file_light": {
"iconPath": "./images/Document_16x.svg"
}
},
"folderExpanded": "_folder_open_dark",
"folder": "_folder_dark",
"file": "_file_dark",
"fileExtensions": {
// icons by file extension
},
"fileNames": {
// icons by file name
},
"languageIds": {
// icons by language id
},
"light": {
"folderExpanded": "_folder_open_light",
"folder": "_folder_light",
"file": "_file_light",
"fileExtensions": {
// icons by file extension
},
"fileNames": {
// icons by file name
},
"languageIds": {
// icons by language id
}
},
"highContrast": {
// overrides for high contrast
}
}
\ No newline at end of file
...@@ -36,22 +36,9 @@ ...@@ -36,22 +36,9 @@
], ],
"fileIcons": [ "fileIcons": [
{ {
"id": "vs-dark-standard", "id": "vs-standard",
"label": "Dark Theme File Icons (Default)", "label": "Visual Studio File Icons",
"uiTheme": "vs-dark", "path": "./fileicons/vs_standard.json"
"path": "./fileicons/dark_standard.json"
},
{
"id": "vs-light-standard",
"label": "Light Theme File Icons (Default)",
"uiTheme": "vs",
"path": "./fileicons/light_standard.json"
},
{
"id": "vs-highcontrast-standard",
"label": "High Contrast Theme File Icons (Default)",
"uiTheme": "hc-black",
"path": "./fileicons/light_standard.json"
} }
] ]
} }
......
...@@ -29,6 +29,7 @@ import pfs = require('vs/base/node/pfs'); ...@@ -29,6 +29,7 @@ import pfs = require('vs/base/node/pfs');
// implementation // implementation
const DEFAULT_THEME_ID = 'vs-dark vscode-theme-defaults-themes-dark_plus-json'; const DEFAULT_THEME_ID = 'vs-dark vscode-theme-defaults-themes-dark_plus-json';
const DEFAULT_FILE_ICONS = 'vs-standard';
const THEME_CHANNEL = 'vscode:changeTheme'; const THEME_CHANNEL = 'vscode:changeTheme';
const THEME_PREF = 'workbench.theme'; const THEME_PREF = 'workbench.theme';
...@@ -89,16 +90,12 @@ let fileIconsExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensio ...@@ -89,16 +90,12 @@ let fileIconsExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensio
description: nls.localize('vscode.extension.contributes.fileIcons.label', 'Label of the file icon set as shown in the UI.'), description: nls.localize('vscode.extension.contributes.fileIcons.label', 'Label of the file icon set as shown in the UI.'),
type: 'string' type: 'string'
}, },
uiTheme: {
description: nls.localize('vscode.extension.contributes.fileIcons.uiTheme', 'Base theme for which the file icon set is designed for: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme, \'hc-black\' is the dark high contrast theme.'),
enum: ['vs', 'vs-dark', 'hc-black']
},
path: { path: {
description: nls.localize('vscode.extension.contributes.fileIcons.path', 'Path of the file icons definition file. The path is relative to the extension folder and is typically \'./fileicons/fileIconsFile.json\'.'), description: nls.localize('vscode.extension.contributes.fileIcons.path', 'Path of the file icons definition file. The path is relative to the extension folder and is typically \'./fileicons/fileIconsFile.json\'.'),
type: 'string' type: 'string'
} }
}, },
required: ['path', 'id', 'uiTheme'] required: ['path', 'id']
} }
}); });
...@@ -129,33 +126,24 @@ interface IInternalThemeData extends IThemeData { ...@@ -129,33 +126,24 @@ interface IInternalThemeData extends IThemeData {
extensionId: string; extensionId: string;
} }
interface ThemedFileIconSets {
dark?: string;
light?: string;
highContrast?: string;
}
interface FileIconDefinition { interface FileIconDefinition {
iconPath: string; iconPath: string;
} }
interface FileIconsDocument { interface FileIconsAssociation {
definitions: { [key:string]: FileIconDefinition }; folder?: string;
defaults: {[defType:string]: string; }; file?: string;
languageAssociations: {[languageId:string]: string; }; folderExpanded?: string;
fileExtensions?: {[extension:string]: string; };
fileNames?: {[fileName:string]: string; };
languageIds?: {[languageId:string]: string; };
} }
const defaultFileIconSets : ThemedFileIconSets = { interface FileIconsDocument extends FileIconsAssociation {
dark: 'vs-dark-standard', iconDefinitions: { [key:string]: FileIconDefinition };
light: 'vs-light-standard', light?: FileIconsAssociation;
highContrast: 'vs-highcontrast-standard' highContrast?: FileIconsAssociation;
}; }
const baseThemeToPropertyKey = {
'vs': 'light',
'vs-dark': 'dark',
'hc_black': 'highContrast'
};
export class ThemeService implements IThemeService { export class ThemeService implements IThemeService {
_serviceBrand: any; _serviceBrand: any;
...@@ -166,7 +154,7 @@ export class ThemeService implements IThemeService { ...@@ -166,7 +154,7 @@ export class ThemeService implements IThemeService {
private onColorThemeChange: Emitter<string>; private onColorThemeChange: Emitter<string>;
private knownFileIconContributions: IInternalThemeData[]; private knownFileIconContributions: IInternalThemeData[];
private currentFileIconsId: ThemedFileIconSets; private currentFileIcons: string;
constructor( constructor(
@IExtensionService private extensionService: IExtensionService, @IExtensionService private extensionService: IExtensionService,
...@@ -178,7 +166,7 @@ export class ThemeService implements IThemeService { ...@@ -178,7 +166,7 @@ export class ThemeService implements IThemeService {
this.knownThemes = []; this.knownThemes = [];
this.onColorThemeChange = new Emitter<string>(); this.onColorThemeChange = new Emitter<string>();
this.knownFileIconContributions = []; this.knownFileIconContributions = [];
this.currentFileIconsId = {}; this.currentFileIcons = null;
themesExtPoint.setHandler((extensions) => { themesExtPoint.setHandler((extensions) => {
for (let ext of extensions) { for (let ext of extensions) {
...@@ -257,7 +245,6 @@ export class ThemeService implements IThemeService { ...@@ -257,7 +245,6 @@ export class ThemeService implements IThemeService {
this.sendTelemetry(newTheme); this.sendTelemetry(newTheme);
} }
this.onColorThemeChange.fire(newThemeId); this.onColorThemeChange.fire(newThemeId);
this.updateFileIcons();
}; };
return this.applyThemeCSS(themeId, DEFAULT_THEME_ID, onApply); return this.applyThemeCSS(themeId, DEFAULT_THEME_ID, onApply);
...@@ -401,40 +388,35 @@ export class ThemeService implements IThemeService { ...@@ -401,40 +388,35 @@ export class ThemeService implements IThemeService {
}); });
} }
private setFileIcons(iconSets: ThemedFileIconSets) : TPromise<boolean> { private setFileIcons(fileIcons: string) : TPromise<boolean> {
['dark', 'light', 'highContrast'].forEach(p => { if (fileIcons !== this.currentFileIcons) {
this.currentFileIconsId[p] = iconSets[p]; this.currentFileIcons = fileIcons;
}); return this._updateFileIcons();
return this.updateFileIcons();
} }
return TPromise.as(true);
private updateFileIcons() : TPromise<boolean> {
let baseId = getBaseThemeId(this.getColorTheme());
let propertyKey = baseThemeToPropertyKey[baseId];
return this.getFileIcons().then(allIconSets => {
let iconSetData = this.findFileIconSet(allIconSets, this.currentFileIconsId[propertyKey], defaultFileIconSets[propertyKey]);
if (iconSetData) {
return applyFileIcons(iconSetData);
}
return false;
});
} }
private findFileIconSet(allIconSets: IThemeData[], fileSetId: string, defaultIds: string): IInternalThemeData { private _updateFileIcons() : TPromise<boolean> {
let defaultData = void 0; return this.getFileIcons().then(allIconSets => {
let iconSetData;
for (let iconSet of allIconSets) { for (let iconSet of allIconSets) {
if (iconSet.id === fileSetId) { if (iconSet.id === this.currentFileIcons) {
return <IInternalThemeData> iconSet; iconSetData = <IInternalThemeData> iconSet;
break;
} }
if (iconSet.id === defaultIds) { if (iconSet.id === DEFAULT_FILE_ICONS) {
defaultData = <IInternalThemeData> iconSet; iconSetData = <IInternalThemeData> iconSet;
} }
} }
return defaultData; if (iconSetData) {
return _applyFileIcons(iconSetData);
}
return false;
});
} }
} }
function applyFileIcons(data: IInternalThemeData): TPromise<boolean> { function _applyFileIcons(data: IInternalThemeData): TPromise<boolean> {
if (data.styleSheetContent) { if (data.styleSheetContent) {
_applyRules(data.styleSheetContent, fileIconRulesClassName); _applyRules(data.styleSheetContent, fileIconRulesClassName);
return TPromise.as(true); return TPromise.as(true);
...@@ -461,10 +443,12 @@ function _loadFileIconsDocument(fileSetPath: string) : TPromise<FileIconsDocumen ...@@ -461,10 +443,12 @@ function _loadFileIconsDocument(fileSetPath: string) : TPromise<FileIconsDocumen
} }
function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDocument: FileIconsDocument) : string { function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDocument: FileIconsDocument) : string {
if (!fileIconsDocument.definitions) { if (!fileIconsDocument.iconDefinitions) {
return ''; return '';
} }
let selectorByDefinitionId : {[def:string]:string[]} = {}; let selectorByDefinitionId : {[def:string]:string[]} = {};
function collectSelectors(associations: FileIconsAssociation, baseThemeClassName?: string) {
function addSelector(selector: string, defId: string) { function addSelector(selector: string, defId: string) {
if (defId) { if (defId) {
let list = selectorByDefinitionId[defId]; let list = selectorByDefinitionId[defId];
...@@ -474,22 +458,46 @@ function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDoc ...@@ -474,22 +458,46 @@ function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDoc
list.push(selector); list.push(selector);
} }
} }
let defaults = fileIconsDocument.defaults; if (associations) {
if (defaults) { let qualifier = '.show-file-icons';
addSelector('.show-file-icons .folder-icon', defaults['folder']); if (baseThemeClassName) {
addSelector('.show-file-icons .expanded .folder-icon', defaults['folder-expanded']); qualifier = baseThemeClassName + ' ' + qualifier;
addSelector('.show-file-icons .file-icon', defaults['file']); }
addSelector(`${qualifier} .folder-icon`, associations.folder);
addSelector(`${qualifier} .expanded .folder-icon`, associations.folderExpanded);
addSelector(`${qualifier} .file-icon`, associations.file);
let fileExtensions = associations.fileExtensions;
if (fileExtensions) {
for (let fileExtension in fileExtensions) {
addSelector(`${qualifier} .${escapeCSS(fileExtension.toLowerCase())}-ext-file-icon.file-icon`, fileExtensions[fileExtension]);
}
}
let fileNames = associations.fileNames;
if (fileNames) {
for (let fileName in fileNames) {
let ext = Paths.extname(fileName).toLowerCase();
let name = fileName.substring(0, fileName.length - ext.length).toLowerCase();
addSelector(`${qualifier} .${escapeCSS(name)}-name-file-icon.${escapeCSS(ext)}-ext-file-icon.file-icon`, fileNames[fileName]);
}
} }
let languageAssociations = fileIconsDocument.languageAssociations; let languageIds = associations.languageIds;
if (languageAssociations) { if (languageIds) {
for (let languageId in languageAssociations) { for (let languageId in languageIds) {
addSelector(`.show-file-icons .${toCSSSelector(languageId)}-file-icon.file-icon`, languageAssociations[languageId]); addSelector(`${qualifier} .${escapeCSS(languageId)}-lang-file-icon.file-icon`, languageIds[languageId]);
} }
} }
}
}
collectSelectors(fileIconsDocument);
collectSelectors(fileIconsDocument.light, '.vs');
collectSelectors(fileIconsDocument.highContrast, '.hc_black');
let cssRules: string[] = []; let cssRules: string[] = [];
for (let defId in selectorByDefinitionId) { for (let defId in selectorByDefinitionId) {
let selectors = selectorByDefinitionId[defId]; let selectors = selectorByDefinitionId[defId];
let definition = fileIconsDocument.definitions[defId]; let definition = fileIconsDocument.iconDefinitions[defId];
if (definition) { if (definition) {
if (definition.iconPath) { if (definition.iconPath) {
let path = Paths.join(Paths.dirname(fileIconsPath), definition.iconPath); let path = Paths.join(Paths.dirname(fileIconsPath), definition.iconPath);
...@@ -500,6 +508,10 @@ function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDoc ...@@ -500,6 +508,10 @@ function _processFileIconsObject(id: string, fileIconsPath: string, fileIconsDoc
return cssRules.join('\n'); return cssRules.join('\n');
} }
function escapeCSS(str: string) {
return window['CSS'].escape(str);
}
function toCSSSelector(str: string) { function toCSSSelector(str: string) {
str = str.replace(/[^_\-a-zA-Z0-9]/g, '-'); str = str.replace(/[^_\-a-zA-Z0-9]/g, '-');
...@@ -730,20 +742,10 @@ configurationRegistry.registerConfiguration({ ...@@ -730,20 +742,10 @@ configurationRegistry.registerConfiguration({
'order': 9.01, 'order': 9.01,
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'files.icons.dark': { 'files.iconTheme': {
'type': 'string',
'default': defaultFileIconSets.dark,
'description': nls.localize('settings.icons.dark', 'The file icons to be used in dark themes.'),
},
'files.icons.light': {
'type': 'string',
'default': defaultFileIconSets.light,
'description': nls.localize('settings.icons.light', 'The file icons to be used in light themes.')
},
'files.icons.highContrast': {
'type': 'string', 'type': 'string',
'default': defaultFileIconSets.highContrast, 'default': DEFAULT_FILE_ICONS,
'description': nls.localize('settings.icons.highcontrast', 'The file icons to be used in high contrast themes.') 'description': nls.localize('settings.icons.dark', 'The active file icons. Use \'explorer.showFileIcons\' to enable file icons in the explorer'),
} }
} }
}); });
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册