diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 6de22b4778b2ef0b3bbe7ca2d8667c5ae1abe52d..acd7ae00bfce0b932b0b25f99d9653daa12b1954 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -45,7 +45,7 @@ export function getComparisonKey(resource: URI, caseInsensitivePath = hasToIgnor if (caseInsensitivePath) { path = path.toLowerCase(); } - return `${resource.scheme}://${resource.authority.toLowerCase()}/${path}?${resource.query}`; + return resource.with({ authority: resource.authority.toLowerCase(), path: path, fragment: null }).toString(); } export function hasToIgnoreCase(resource: URI | undefined): boolean { diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index f3a93bdf189bd4817ebb1bc823655685215b7583..109ceca360bb4b77892e380cce78d78bb3b1dbf1 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -205,7 +205,7 @@ export class URI implements UriComponents { // if (this.scheme !== 'file') { // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`); // } - return _makeFsPath(this); + return _makeFsPath(this, false); } // ---- modify to new ------------------------- @@ -347,9 +347,13 @@ export class URI implements UriComponents { if (!uri.path) { throw new Error(`[UriError]: cannot call joinPaths on URI without path`); } - return uri.with({ - path: paths.posix.join(uri.path, ...pathFragment) - }); + let newPath: string; + if (isWindows && uri.scheme === 'file') { + newPath = URI.file(paths.win32.join(_makeFsPath(uri, true), ...pathFragment)).path; + } else { + newPath = paths.posix.join(uri.path, ...pathFragment); + } + return uri.with({ path: newPath }); } // ---- printing/externalize --------------------------- @@ -416,7 +420,7 @@ class _URI extends URI { get fsPath(): string { if (!this._fsPath) { - this._fsPath = _makeFsPath(this); + this._fsPath = _makeFsPath(this, false); } return this._fsPath; } @@ -572,7 +576,7 @@ function encodeURIComponentMinimal(path: string): string { /** * Compute `fsPath` for the given uri */ -function _makeFsPath(uri: URI): string { +function _makeFsPath(uri: URI, keepDriveLetterCasing: boolean): string { let value: string; if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') { @@ -584,7 +588,11 @@ function _makeFsPath(uri: URI): string { && uri.path.charCodeAt(2) === CharCode.Colon ) { // windows drive letter: file:///c:/far/boo - value = uri.path[1].toLowerCase() + uri.path.substr(2); + if (!keepDriveLetterCasing) { + value = uri.path[1].toLowerCase() + uri.path.substr(2); + } else { + value = uri.path.substr(1, 2); + } } else { // other path value = uri.path; diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 519c50af7293fd32b25688e64d31604f388b3c9d..6777e5f53042186466e73f424c2a97b54fd415c6 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -503,29 +503,22 @@ suite('URI', () => { // } // console.profileEnd(); }); - - test('URI#joinPath', function () { - - function assertJoined(base: string, fragment: string, expected: string, checkWithUrl: boolean = true) { - const baseUri = URI.parse(base); - const newUri = URI.joinPath(baseUri, fragment); - const actual = newUri.toString(true); - assert.equal(actual, expected); - - if (checkWithUrl) { - const actualUrl = new URL(fragment, base).href; - assert.equal(actualUrl, expected); - } + function assertJoined(base: string, fragment: string, expected: string, checkWithUrl: boolean = true) { + const baseUri = URI.parse(base); + const newUri = URI.joinPath(baseUri, fragment); + const actual = newUri.toString(true); + assert.equal(actual, expected); + + if (checkWithUrl) { + const actualUrl = new URL(fragment, base).href; + assert.equal(actualUrl, expected, 'DIFFERENT from URL'); } + } + test('URI#joinPath', function () { - assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/bazz'); - assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/bazz'); assertJoined(('file:///foo/'), '../../bazz', 'file:///bazz'); assertJoined(('file:///foo'), '../../bazz', 'file:///bazz'); assertJoined(('file:///foo'), '../../bazz', 'file:///bazz'); - assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///bazz', false); - assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz'); - assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz'); assertJoined(('file:///foo/bar/'), './bazz', 'file:///foo/bar/bazz'); assertJoined(('file:///foo/bar'), './bazz', 'file:///foo/bar/bazz', false); assertJoined(('file:///foo/bar'), 'bazz', 'file:///foo/bar/bazz', false); @@ -547,4 +540,28 @@ suite('URI', () => { assert.throws(() => assertJoined(('foo://bar'), 'bazz', '')); assert.throws(() => new URL('bazz', 'foo://bar')); }); + + test('URI#joinPath (posix)', function () { + if (isWindows) { + this.skip(); + } + assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///bazz', false); + assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/bazz', false); + assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/bazz', false); + + assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz'); + assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz'); + }); + + test('URI#joinPath (windows)', function () { + if (!isWindows) { + this.skip(); + } + assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///c:/bazz', false); + assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/share/bazz', false); + assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/share/bazz', false); + + assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/foo/bazz', false); + assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/foo/bazz', false); + }); }); diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index bc2a5d3e8816fe234506d44265fc9ddb18436efd..b6bf77177b83990c1b6a4f80e3cc15a2e8ea691f 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -452,6 +452,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments id: COMMENTS_VIEW_ID, name: COMMENTS_VIEW_TITLE, ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [COMMENTS_VIEW_ID, COMMENTS_VIEW_TITLE, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), + hideIfEmpty: true, order: 10, }, ViewContainerLocation.Panel); @@ -460,6 +461,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments name: COMMENTS_VIEW_TITLE, canToggleVisibility: false, ctorDescriptor: new SyncDescriptor(CommentsPanel), + canMoveView: true, focusCommand: { id: 'workbench.action.focusCommentsPanel' } diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 8375e443d49afc63f183baa8250f929409a881d9..354fbf83287497e7744478fa0558a3adaba2d540 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -64,6 +64,11 @@ export const viewsContainersContribution: IJSONSchema = { description: localize('views.container.activitybar', "Contribute views containers to Activity Bar"), type: 'array', items: viewsContainerSchema + }, + 'panel': { + description: localize('views.container.panel', "Contribute views containers to Panel"), + type: 'array', + items: viewsContainerSchema } } }; @@ -214,7 +219,8 @@ class ViewsExtensionHandler implements IWorkbenchContribution { private addCustomViewContainers(extensionPoints: readonly IExtensionPointUser[], existingViewContainers: ViewContainer[]): void { const viewContainersRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); - let order = TEST_VIEW_CONTAINER_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId).length + 1; + let activityBarOrder = TEST_VIEW_CONTAINER_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Sidebar).length + 1; + let panelOrder = 5 + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Panel).length + 1; for (let { value, collector, description } of extensionPoints) { forEach(value, entry => { if (!this.isValidViewsContainer(entry.value, collector)) { @@ -222,7 +228,10 @@ class ViewsExtensionHandler implements IWorkbenchContribution { } switch (entry.key) { case 'activitybar': - order = this.registerCustomViewContainers(entry.value, description, order, existingViewContainers); + activityBarOrder = this.registerCustomViewContainers(entry.value, description, activityBarOrder, existingViewContainers, ViewContainerLocation.Sidebar); + break; + case 'panel': + panelOrder = this.registerCustomViewContainers(entry.value, description, panelOrder, existingViewContainers, ViewContainerLocation.Panel); break; } }); @@ -248,7 +257,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { const title = localize('test', "Test"); const icon = URI.parse(require.toUrl('./media/test.svg')); - this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, undefined); + this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, undefined, ViewContainerLocation.Sidebar); } private isValidViewsContainer(viewsContainersDescriptors: IUserFriendlyViewsContainerDescriptor[], collector: ExtensionMessageCollector): boolean { @@ -279,11 +288,11 @@ class ViewsExtensionHandler implements IWorkbenchContribution { return true; } - private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number, existingViewContainers: ViewContainer[]): number { + private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number, existingViewContainers: ViewContainer[], location: ViewContainerLocation): number { containers.forEach(descriptor => { const icon = resources.joinPath(extension.extensionLocation, descriptor.icon); const id = `workbench.view.extension.${descriptor.id}`; - const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, extension.identifier); + const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, extension.identifier, location); // Move those views that belongs to this container if (existingViewContainers.length) { @@ -301,7 +310,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { return order; } - private registerCustomViewContainer(id: string, title: string, icon: URI, order: number, extensionId: ExtensionIdentifier | undefined): ViewContainer { + private registerCustomViewContainer(id: string, title: string, icon: URI, order: number, extensionId: ExtensionIdentifier | undefined, location: ViewContainerLocation): ViewContainer { let viewContainer = this.viewContainersRegistry.get(id); if (!viewContainer) { @@ -316,7 +325,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { hideIfEmpty: true, order, icon, - }, ViewContainerLocation.Sidebar); + }, location); // Register Action to Open Viewlet class OpenCustomViewletAction extends ShowViewletAction { diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index f047707083bfea3a0002afaea543161051359330..1f751f9b21c9e1ef3d892b4d78944538bcbe196a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -20,7 +20,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; +import { IColorMapping } from 'vs/platform/theme/common/styler'; export const COMMENTS_VIEW_ID = 'workbench.panel.comments'; export const COMMENTS_VIEW_TITLE = 'Comments'; @@ -149,10 +149,15 @@ export class CommentNodeRenderer implements IListRenderer } } +export interface ICommentsListOptions { + overrideStyles?: IColorMapping; +} + export class CommentsList extends WorkbenchAsyncDataTree { constructor( labels: ResourceLabels, container: HTMLElement, + options: ICommentsListOptions, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @IThemeService themeService: IThemeService, @@ -202,9 +207,7 @@ export class CommentsList extends WorkbenchAsyncDataTree { collapseByDefault: () => { return false; }, - overrideStyles: { - listBackground: PANEL_BACKGROUND - } + overrideStyles: options.overrideStyles }, contextKeyService, listService, diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index 3a60d76d6378240e0a830642348f885b57b12afb..40d35505b7b7685752ea4d7fa88c4753235125ac 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -149,7 +149,7 @@ export class CommentsPanel extends ViewPane { private createTree(): void { this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); - this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer)); + this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer, { overrideStyles: { listBackground: this.getBackgroundColor() } })); const commentsNavigator = this._register(ResourceNavigator.createTreeResourceNavigator(this.tree, { openOnFocus: true })); this._register(commentsNavigator.onDidOpenResource(e => { diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 8cb2bb87d47b6cf7629462f80f9f9f8a56b56497..8c5573ed307200efff1baa7ffe865def72a70d98 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -76,7 +76,7 @@ const viewContainer = Registry.as(ViewExtensions.ViewCo name: nls.localize('run', "Run"), ctorDescriptor: new SyncDescriptor(DebugViewPaneContainer), icon: 'codicon-debug-alt-2', - order: 3 + order: 2 }, ViewContainerLocation.Sidebar); const openViewletKb: IKeybindings = { @@ -96,6 +96,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as(ViewE id: OpenDebugPanelAction.ID, keybindings: openPanelKb }, + order: 3, hideIfEmpty: true }, ViewContainerLocation.Panel); diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 42c5a0a8f7bd26eef09a9773b5b688016f8c4c37..c2f33188437aab84cdbcf214ae488cc22708ca14 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -208,9 +208,20 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { })); this._register(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('debug.console.lineHeight') || e.affectsConfiguration('debug.console.fontSize') || e.affectsConfiguration('debug.console.fontFamily')) { - this.onDidFontChange(); + this.onDidStyleChange(); } })); + + this._register(this.themeService.onDidColorThemeChange(e => { + this.onDidStyleChange(); + })); + + this._register(this.viewDescriptorService.onDidChangeLocation(e => { + if (e.views.some(v => v.id === this.id)) { + this.onDidStyleChange(); + } + })); + this._register(this.editorService.onDidActiveEditorChange(() => { this.setMode(); })); @@ -253,14 +264,15 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } } - private onDidFontChange(): void { + private onDidStyleChange(): void { if (this.styleElement) { const debugConsole = this.configurationService.getValue('debug').console; const fontSize = debugConsole.fontSize; const fontFamily = debugConsole.fontFamily === 'default' ? 'var(--monaco-monospace-font)' : debugConsole.fontFamily; const lineHeight = debugConsole.lineHeight ? `${debugConsole.lineHeight}px` : '1.4em'; + const backgroundColor = this.themeService.getColorTheme().getColor(this.getBackgroundColor()); - // Set the font size, font family, line height and align the twistie to be centered + // Set the font size, font family, line height and align the twistie to be centered, and input theme color this.styleElement.innerHTML = ` .repl .repl-tree .expression { font-size: ${fontSize}px; @@ -274,6 +286,10 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { .repl .repl-tree .monaco-tl-twistie { background-position-y: calc(100% - ${fontSize * 1.4 / 2 - 8}px); } + + .repl .repl-input-wrapper .monaco-editor .lines-content { + background-color: ${backgroundColor}; + } `; this.tree.rerender(); @@ -510,7 +526,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { // Make sure to select the session if debugging is already active this.selectSession(); this.styleElement = dom.createStyleSheet(this.container); - this.onDidFontChange(); + this.onDidStyleChange(); } private createReplInput(container: HTMLElement): void { diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 971d20f9ea0f2d2465ec1bb5d9ecc1583e170847..f16693fc666373866514aa3f251b6120322996f3 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -112,6 +112,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as(ViewC id: Constants.MARKERS_CONTAINER_ID, name: Messages.MARKERS_PANEL_TITLE_PROBLEMS, hideIfEmpty: true, + order: 0, ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [Constants.MARKERS_CONTAINER_ID, Constants.MARKERS_VIEW_STORAGE_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), focusCommand: { id: ToggleMarkersPanelAction.ID, keybindings: { @@ -122,6 +123,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as(ViewC Registry.as(ViewContainerExtensions.ViewsRegistry).registerViews([{ id: Constants.MARKERS_VIEW_ID, + containerIcon: 'codicon-warning', name: Messages.MARKERS_PANEL_TITLE_PROBLEMS, canToggleVisibility: false, canMoveView: true, diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 1bbf4ad8b0f07a42cbe115d11eab0fbb564b12df..cb20863d50d33aaba766b7e1573afcddb43972a3 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -61,6 +61,7 @@ const toggleOutputActionKeybindings = { const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ id: OUTPUT_VIEW_ID, name: nls.localize('output', "Output"), + order: 1, ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [OUTPUT_VIEW_ID, OUTPUT_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), focusCommand: { id: toggleOutputAcitonId, keybindings: toggleOutputActionKeybindings } }, ViewContainerLocation.Panel); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 739884ee6cb1226b31cb5399c8750fff238264ba..918af1f977b7b3d24494a32cbe9a26eff382751f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -382,7 +382,8 @@ const VIEW_CONTAINER = Registry.as(ViewContainerExtensi name: nls.localize('terminal', "Terminal"), ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [TERMINAL_VIEW_ID, TERMINAL_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), focusCommand: { id: TERMINAL_COMMAND_ID.FOCUS }, - hideIfEmpty: true + hideIfEmpty: true, + order: 3 }, ViewContainerLocation.Panel); Registry.as(panel.Extensions.Panels).setDefaultPanelId(TERMINAL_VIEW_ID); diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index bc1cc7403825b57061bc7604881e559e7fa0b272..43b5c26163086bc5fbe73d4aebfd26883cdf046e 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -148,31 +148,19 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { // update settings schema setting for theme specific settings this.colorThemeRegistry.onDidChange(async event => { updateColorThemeConfigurationSchemas(event.themes); - - const colorThemeSetting = this.settings.colorTheme; - if (colorThemeSetting !== this.currentColorTheme.settingsId) { - const theme = await this.colorThemeRegistry.findThemeBySettingsId(colorThemeSetting, undefined); - if (theme) { - this.setColorTheme(theme.id, undefined); - return; - } - } - - if (this.currentColorTheme.isLoaded) { - const themeData = await this.colorThemeRegistry.findThemeById(this.currentColorTheme.id); - if (!themeData) { - // current theme is no longer available - prevColorId = this.currentColorTheme.id; - this.setColorTheme(DEFAULT_COLOR_THEME_ID, 'auto'); - } else { - if (this.currentColorTheme.id === DEFAULT_COLOR_THEME_ID && !types.isUndefined(prevColorId) && await this.colorThemeRegistry.findThemeById(prevColorId)) { - // restore theme - this.setColorTheme(prevColorId, 'auto'); - prevColorId = undefined; - } else if (event.added.some(t => t.settingsId === this.currentColorTheme.settingsId)) { - this.reloadCurrentColorTheme(); - } + if (await this.restoreColorTheme()) { // checks if theme from settings exists and is set + // restore theme + if (this.currentColorTheme.id === DEFAULT_COLOR_THEME_ID && !types.isUndefined(prevColorId) && await this.colorThemeRegistry.findThemeById(prevColorId)) { + // restore theme + this.setColorTheme(prevColorId, 'auto'); + prevColorId = undefined; + } else if (event.added.some(t => t.settingsId === this.currentColorTheme.settingsId)) { + this.reloadCurrentColorTheme(); } + } else if (event.removed.some(t => t.settingsId === this.currentColorTheme.settingsId)) { + // current theme is no longer available + prevColorId = this.currentColorTheme.id; + this.setColorTheme(DEFAULT_COLOR_THEME_ID, 'auto'); } }); @@ -187,7 +175,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } else if (event.added.some(t => t.settingsId === this.currentFileIconTheme.settingsId)) { this.reloadCurrentFileIconTheme(); } - } else { + } else if (event.removed.some(t => t.settingsId === this.currentFileIconTheme.settingsId)) { // current theme is no longer available prevFileIconId = this.currentFileIconTheme.id; this.setFileIconTheme(DEFAULT_FILE_ICON_THEME_ID, 'auto'); @@ -206,7 +194,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } else if (event.added.some(t => t.settingsId === this.currentProductIconTheme.settingsId)) { this.reloadCurrentProductIconTheme(); } - } else { + } else if (event.removed.some(t => t.settingsId === this.currentProductIconTheme.settingsId)) { // current theme is no longer available prevProductIconId = this.currentProductIconTheme.id; this.setProductIconTheme(DEFAULT_PRODUCT_ICON_THEME_ID, 'auto'); @@ -389,17 +377,19 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.applyTheme(this.currentColorTheme, undefined, false); } - public restoreColorTheme() { - const colorThemeSetting = this.settings.colorTheme; - if (colorThemeSetting !== this.currentColorTheme.settingsId) { - this.colorThemeRegistry.findThemeBySettingsId(colorThemeSetting, undefined).then(theme => { - if (theme) { - this.setColorTheme(theme.id, undefined); - } - }); + public async restoreColorTheme(): Promise { + const settingId = this.settings.colorTheme; + const theme = await this.colorThemeRegistry.findThemeBySettingsId(settingId); + if (theme) { + if (settingId !== this.currentColorTheme.settingsId) { + await this.setColorTheme(theme.id, undefined); + } + return true; } + return false; } + private updateDynamicCSSRules(themeData: IColorTheme) { const cssRules = new Set(); const ruleCollector = { diff --git a/src/vs/workbench/services/themes/common/themeExtensionPoints.ts b/src/vs/workbench/services/themes/common/themeExtensionPoints.ts index 2d01c6b95eabd3702e7e21f18ecc42d98f56ee48..53ff6442917a9406fe16d1bdc28f10405c257fca 100644 --- a/src/vs/workbench/services/themes/common/themeExtensionPoints.ts +++ b/src/vs/workbench/services/themes/common/themeExtensionPoints.ts @@ -107,6 +107,7 @@ export function registerProductIconThemeExtensionPoint() { export interface ThemeChangeEvent { themes: T[]; added: T[]; + removed: T[]; } export interface IThemeData { @@ -135,10 +136,11 @@ export class ThemeRegistry { private initialize() { this.themesExtPoint.setHandler((extensions, delta) => { - const previousIds: { [key: string]: boolean } = {}; + const previousIds: { [key: string]: T } = {}; + const added: T[] = []; for (const theme of this.extensionThemes) { - previousIds[theme.id] = true; + previousIds[theme.id] = theme; } this.extensionThemes.length = 0; for (let ext of extensions) { @@ -154,9 +156,12 @@ export class ThemeRegistry { for (const theme of this.extensionThemes) { if (!previousIds[theme.id]) { added.push(theme); + } else { + delete previousIds[theme.id]; } } - this.onDidChangeEmitter.fire({ themes: this.extensionThemes, added }); + const removed = Object.values(previousIds); + this.onDidChangeEmitter.fire({ themes: this.extensionThemes, added, removed }); }); } diff --git a/test/unit/README.md b/test/unit/README.md index f471ebb7d8e6d8550a425614c02e773b42831f40..cf338465a74888065a2e2d34c1c64ea2d7e55b6a 100644 --- a/test/unit/README.md +++ b/test/unit/README.md @@ -4,7 +4,7 @@ ./scripts/test.[sh|bat] -All unit tests are run inside a electron-browser environment which access to DOM and Nodejs api. This is the closest to the enviroment in which VS Code itself ships. Notes: +All unit tests are run inside a electron-browser environment which access to DOM and Nodejs api. This is the closest to the environment in which VS Code itself ships. Notes: - use the `--debug` to see an electron window with dev tools which allows for debugging - to run only a subset of tests use the `--run` or `--glob` options