diff --git a/src/vs/editor/contrib/colorPicker/colorPickerModel.ts b/src/vs/editor/contrib/colorPicker/colorPickerModel.ts index 9b9748767321e999a7b9820314a871d94b3f1833..772f252613fd2bdb88c412c6935dc61a59e51625 100644 --- a/src/vs/editor/contrib/colorPicker/colorPickerModel.ts +++ b/src/vs/editor/contrib/colorPicker/colorPickerModel.ts @@ -64,7 +64,7 @@ export class ColorPickerModel { guessColorPresentation(color: Color, originalText: string): void { for (let i = 0; i < this.colorPresentations.length; i++) { - if (originalText === this.colorPresentations[i].label) { + if (originalText.toLowerCase() === this.colorPresentations[i].label) { this.presentationIndex = i; this._onDidChangePresentation.fire(this.presentation); break; diff --git a/src/vs/workbench/api/browser/mainThreadTheming.ts b/src/vs/workbench/api/browser/mainThreadTheming.ts index 4f0fa4172408b5eb9bf25a0c7ca6b0b088333372..d810863f852a95c7517293066f767c72ac7a7ed5 100644 --- a/src/vs/workbench/api/browser/mainThreadTheming.ts +++ b/src/vs/workbench/api/browser/mainThreadTheming.ts @@ -25,6 +25,7 @@ export class MainThreadTheming implements MainThreadThemingShape { this._themeChangeListener = this._themeService.onDidColorThemeChange(e => { this._proxy.$onColorThemeChange(this._themeService.getColorTheme().type); }); + this._proxy.$onColorThemeChange(this._themeService.getColorTheme().type); } dispose(): void { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 3da11230ff91303951927b11fb50cba139672873..827a98b8a9ece6a406c5691384dac9425599c7c2 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editorgroupview'; - import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, EditorStickyContext, EditorPinnedContext } from 'vs/workbench/common/editor'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom'; @@ -220,8 +219,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private handleGroupContextKeys(contextKeyService: IContextKeyService): void { const groupActiveEditorDirtyContextKey = EditorGroupActiveEditorDirtyContext.bindTo(contextKeyService); const groupEditorsCountContext = EditorGroupEditorsCountContext.bindTo(contextKeyService); + const groupActiveEditorPinnedContext = EditorPinnedContext.bindTo(contextKeyService); + const groupActiveEditorStickyContext = EditorStickyContext.bindTo(contextKeyService); - let activeEditorListener = new MutableDisposable(); + const activeEditorListener = new MutableDisposable(); const observeActiveEditor = () => { activeEditorListener.clear(); @@ -237,11 +238,22 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Update group contexts based on group changes this._register(this.onDidGroupChange(e => { - - // Track the active editor and update context key that reflects - // the dirty state of this editor - if (e.kind === GroupChangeKind.EDITOR_ACTIVE) { - observeActiveEditor(); + switch (e.kind) { + case GroupChangeKind.EDITOR_ACTIVE: + // Track the active editor and update context key that reflects + // the dirty state of this editor + observeActiveEditor(); + break; + case GroupChangeKind.EDITOR_PIN: + if (e.editor && e.editor === this._group.activeEditor) { + groupActiveEditorPinnedContext.set(this._group.isPinned(this._group.activeEditor)); + } + break; + case GroupChangeKind.EDITOR_STICKY: + if (e.editor && e.editor === this._group.activeEditor) { + groupActiveEditorStickyContext.set(this._group.isSticky(this._group.activeEditor)); + } + break; } // Group editors count context @@ -464,6 +476,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Model Events this._register(this._group.onDidChangeEditorPinned(editor => this.onDidChangeEditorPinned(editor))); + this._register(this._group.onDidChangeEditorSticky(editor => this.onDidChangeEditorSticky(editor))); this._register(this._group.onDidOpenEditor(editor => this.onDidOpenEditor(editor))); this._register(this._group.onDidCloseEditor(editor => this.handleOnDidCloseEditor(editor))); this._register(this._group.onDidDisposeEditor(editor => this.onDidDisposeEditor(editor))); @@ -478,11 +491,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } private onDidChangeEditorPinned(editor: EditorInput): void { - - // Event this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_PIN, editor }); } + private onDidChangeEditorSticky(editor: EditorInput): void { + this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_STICKY, editor }); + } + private onDidOpenEditor(editor: EditorInput): void { /* __GDPR__ diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index 537d857d717a1ef4aee5d19529815baf59c48fa4..178aa1d792f5433a04e67929cc840e18765123cd 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -83,6 +83,9 @@ export class EditorGroup extends Disposable { private readonly _onDidChangeEditorPinned = this._register(new Emitter()); readonly onDidChangeEditorPinned = this._onDidChangeEditorPinned.event; + private readonly _onDidChangeEditorSticky = this._register(new Emitter()); + readonly onDidChangeEditorSticky = this._onDidChangeEditorSticky.event; + //#endregion private _id: GroupIdentifier; @@ -560,6 +563,9 @@ export class EditorGroup extends Disposable { // Adjust sticky index this.sticky++; + + // Event + this._onDidChangeEditorSticky.fire(editor); } unstick(candidate: EditorInput): EditorInput | undefined { @@ -585,6 +591,9 @@ export class EditorGroup extends Disposable { // Adjust sticky index this.sticky--; + + // Event + this._onDidChangeEditorSticky.fire(editor); } isSticky(candidateOrIndex: EditorInput | number): boolean { diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 325f1e7f4f748e3138f284a2f4dacb56c20c7fa8..9e944c02c83008a056c0f87ff0893eb5343c620a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -366,7 +366,7 @@ export class DebugSession implements IDebugSession { } } - async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }> { + async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean } | undefined> { if (!this.raw) { throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'data breakpoints info')); } @@ -592,7 +592,7 @@ export class DebugSession implements IDebugSession { } const response = await this.raw.loadedSources({}); - if (response.body && response.body.sources) { + if (response && response.body && response.body.sources) { return response.body.sources.map(src => this.getSource(src)); } else { return []; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 16bdbd92f9cbb1f42904bc6e243c73091ebc7ae0..c677a1fdd2a9328acb249e0a7331319276d582fd 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -87,7 +87,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { private replInputContainer!: HTMLElement; private dimension!: dom.Dimension; private replInputLineCount = 1; - private model!: ITextModel; + private model: ITextModel | undefined; private historyNavigationEnablement!: IContextKey; private scopedInstantiationService!: IInstantiationService; private replElementsChangeListener: IDisposable | undefined; @@ -271,7 +271,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { if (isCodeEditor(activeEditorControl)) { this.modelChangeListener.dispose(); this.modelChangeListener = activeEditorControl.onDidChangeModelLanguage(() => this.setMode()); - if (activeEditorControl.hasModel()) { + if (this.model && activeEditorControl.hasModel()) { this.model.setMode(activeEditorControl.getModel().getLanguageIdentifier()); } } @@ -397,16 +397,18 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { getVisibleContent(): string { let text = ''; - const lineDelimiter = this.textResourcePropertiesService.getEOL(this.model.uri); - const traverseAndAppend = (node: ITreeNode) => { - node.children.forEach(child => { - text += child.element.toString().trimRight() + lineDelimiter; - if (!child.collapsed && child.children.length) { - traverseAndAppend(child); - } - }); - }; - traverseAndAppend(this.tree.getNode()); + if (this.model) { + const lineDelimiter = this.textResourcePropertiesService.getEOL(this.model.uri); + const traverseAndAppend = (node: ITreeNode) => { + node.children.forEach(child => { + text += child.element.toString().trimRight() + lineDelimiter; + if (!child.collapsed && child.children.length) { + traverseAndAppend(child); + } + }); + }; + traverseAndAppend(this.tree.getNode()); + } return removeAnsiEscapeCodes(text); } diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index cbcd596bd394bd9fe37fdd508a4cd5222defbe72..d9c75bd8be4dee850b45880a4e9c61d67fbf982f 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -194,8 +194,8 @@ export class VariablesView extends ViewPane { } if (session && session.capabilities.supportsDataBreakpoints) { const response = await session.dataBreakpointInfo(variable.name, variable.parent.reference); - const dataid = response.dataId; - if (dataid) { + const dataid = response?.dataId; + if (response && dataid) { actions.push(new Separator()); actions.push(new Action('debug.breakWhenValueChanges', nls.localize('breakWhenValueChanges', "Break When Value Changes"), undefined, true, () => { return this.debugService.addDataBreakpoint(response.description, dataid, !!response.canPersist, response.accessTypes); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 51113e0b13583f550e4c074dc45e3a35613447e4..d270afdffbcaf32dcc274c176784f1951c1d23a1 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -214,7 +214,7 @@ export interface IDebugSession extends ITreeElement { sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise; sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise; - dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean, accessTypes?: DebugProtocol.DataBreakpointAccessType[] }>; + dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean, accessTypes?: DebugProtocol.DataBreakpointAccessType[] } | undefined>; sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise; sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise; breakpointsLocations(uri: uri, lineNumber: number): Promise; diff --git a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index 5ce7663389af50d492e05d32745cc5b8aba2b4a7..7d95a04c6d22963b9aaa2c2e866b693eda8e6243 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -144,7 +144,7 @@ export class MockSession implements IDebugSession { throw new Error('Method not implemented.'); } - dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> { + dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; } | undefined> { throw new Error('Method not implemented.'); } diff --git a/src/vs/workbench/services/credentials/node/credentialsService.ts b/src/vs/workbench/services/credentials/node/credentialsService.ts deleted file mode 100644 index 6ff56147902fe32f00bc73ed07e2a276ed26702a..0000000000000000000000000000000000000000 --- a/src/vs/workbench/services/credentials/node/credentialsService.ts +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import { IdleValue } from 'vs/base/common/async'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -type KeytarModule = typeof import('keytar'); -export class KeytarCredentialsService implements ICredentialsService { - - _serviceBrand: undefined; - - private readonly _keytar = new IdleValue>(() => import('keytar')); - - async getPassword(service: string, account: string): Promise { - const keytar = await this._keytar.value; - return keytar.getPassword(service, account); - } - - async setPassword(service: string, account: string, password: string): Promise { - const keytar = await this._keytar.value; - return keytar.setPassword(service, account, password); - } - - async deletePassword(service: string, account: string): Promise { - const keytar = await this._keytar.value; - return keytar.deletePassword(service, account); - } - - async findPassword(service: string): Promise { - const keytar = await this._keytar.value; - return keytar.findPassword(service); - } - - async findCredentials(service: string): Promise> { - const keytar = await this._keytar.value; - return keytar.findCredentials(service); - } -} - -registerSingleton(ICredentialsService, KeytarCredentialsService, true); diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index ea3c10d78a181f5b8ba83f9f9a6a21f5b389cf97..25d1d959bb5eb22fcd9d0eb1f41d0f47c3d5ebaf 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -359,6 +359,7 @@ export const enum GroupChangeKind { EDITOR_ACTIVE, EDITOR_LABEL, EDITOR_PIN, + EDITOR_STICKY, EDITOR_DIRTY } diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index d929a5c5338d6f940bb1216eaa877f1c0bd543a7..42bc6704225dfb59e1b0f40dac555d8623f16469 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -369,8 +369,9 @@ suite('EditorGroupsService', () => { let activeEditorChangeCounter = 0; let editorDidOpenCounter = 0; - let editorCloseCounter1 = 0; + let editorCloseCounter = 0; let editorPinCounter = 0; + let editorStickyCounter = 0; const editorGroupChangeListener = group.onDidGroupChange(e => { if (e.kind === GroupChangeKind.EDITOR_OPEN) { assert.ok(e.editor); @@ -380,16 +381,19 @@ suite('EditorGroupsService', () => { activeEditorChangeCounter++; } else if (e.kind === GroupChangeKind.EDITOR_CLOSE) { assert.ok(e.editor); - editorCloseCounter1++; + editorCloseCounter++; } else if (e.kind === GroupChangeKind.EDITOR_PIN) { assert.ok(e.editor); editorPinCounter++; + } else if (e.kind === GroupChangeKind.EDITOR_STICKY) { + assert.ok(e.editor); + editorStickyCounter++; } }); - let editorCloseCounter2 = 0; + let editorCloseCounter1 = 0; const editorCloseListener = group.onDidCloseEditor(() => { - editorCloseCounter2++; + editorCloseCounter1++; }); let editorWillCloseCounter = 0; @@ -440,12 +444,18 @@ suite('EditorGroupsService', () => { await group.closeEditor(inputInactive); assert.equal(activeEditorChangeCounter, 3); + assert.equal(editorCloseCounter, 1); assert.equal(editorCloseCounter1, 1); - assert.equal(editorCloseCounter2, 1); assert.equal(editorWillCloseCounter, 1); assert.equal(group.activeEditor, input); + assert.equal(editorStickyCounter, 0); + group.stickEditor(input); + assert.equal(editorStickyCounter, 1); + group.unstickEditor(input); + assert.equal(editorStickyCounter, 2); + editorCloseListener.dispose(); editorWillCloseListener.dispose(); editorWillOpenListener.dispose(); diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 9d76cd2dbaa1e4336de073be2489cf296c40e45d..58a5127018527018270325cbc8623bccc9e636f4 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -5,7 +5,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; -import { ITextEditorOptions, IResourceEditorInput, TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; +import { ITextEditorOptions, IResourceEditorInput, TextEditorSelectionRevealType, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IEditorInput, IEditorPane, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, IEditorIdentifier, GroupIdentifier, EditorsOrder } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; @@ -638,10 +638,22 @@ export class HistoryService extends Disposable implements IHistoryService { if (lastClosedFile) { (async () => { - const editor = await this.editorService.openEditor({ - resource: lastClosedFile.resource, - options: { pinned: true, sticky: lastClosedFile.sticky, index: lastClosedFile.index } - }); + let options: IEditorOptions; + if (lastClosedFile.sticky) { + // Sticky: in case the target index is outside of the range of + // sticky editors, we make sure to not provide the index as + // option. Otherwise the index will cause the sticky flag to + // be ignored. + if (!this.editorGroupService.activeGroup.isSticky(lastClosedFile.index)) { + options = { pinned: true, sticky: true }; + } else { + options = { pinned: true, sticky: true, index: lastClosedFile.index }; + } + } else { + options = { pinned: true, index: lastClosedFile.index }; + } + + const editor = await this.editorService.openEditor({ resource: lastClosedFile.resource, options }); // Fix for https://github.com/Microsoft/vscode/issues/67882 // If opening of the editor fails, make sure to try the next one diff --git a/src/vs/workbench/services/views/browser/viewDescriptorService.ts b/src/vs/workbench/services/views/browser/viewDescriptorService.ts index 6875ce28b082ad5f1a691abb649904d123d05a90..a0dc70de8fb1bd5a65581e238557982a3c88075a 100644 --- a/src/vs/workbench/services/views/browser/viewDescriptorService.ts +++ b/src/vs/workbench/services/views/browser/viewDescriptorService.ts @@ -98,6 +98,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor super(); storageKeysSyncRegistryService.registerStorageKey({ key: ViewDescriptorService.CACHED_VIEW_POSITIONS, version: 1 }); + storageKeysSyncRegistryService.registerStorageKey({ key: ViewDescriptorService.CACHED_VIEW_CONTAINER_LOCATIONS, version: 1 }); this.viewContainerModels = new Map(); this.activeViewContextKeys = new Map>(); this.movableViewContextKeys = new Map>(); diff --git a/src/vs/workbench/test/browser/parts/editor/editorGroups.test.ts b/src/vs/workbench/test/browser/parts/editor/editorGroups.test.ts index 2f18fe411d60e6d636cb5a62ae53c2c6229253bf..8ba94daf85efb8ae3c469418ac0716d0a93901e8 100644 --- a/src/vs/workbench/test/browser/parts/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/editorGroups.test.ts @@ -79,6 +79,8 @@ interface GroupEvents { closed: EditorCloseEvent[]; pinned: EditorInput[]; unpinned: EditorInput[]; + sticky: EditorInput[]; + unsticky: EditorInput[]; moved: EditorInput[]; disposed: EditorInput[]; } @@ -90,6 +92,8 @@ function groupListener(group: EditorGroup): GroupEvents { activated: [], pinned: [], unpinned: [], + sticky: [], + unsticky: [], moved: [], disposed: [] }; @@ -98,6 +102,7 @@ function groupListener(group: EditorGroup): GroupEvents { group.onDidCloseEditor(e => groupEvents.closed.push(e)); group.onDidActivateEditor(e => groupEvents.activated.push(e)); group.onDidChangeEditorPinned(e => group.isPinned(e) ? groupEvents.pinned.push(e) : groupEvents.unpinned.push(e)); + group.onDidChangeEditorSticky(e => group.isSticky(e) ? groupEvents.sticky.push(e) : groupEvents.unsticky.push(e)); group.onDidMoveEditor(e => groupEvents.moved.push(e)); group.onDidDisposeEditor(e => groupEvents.disposed.push(e)); @@ -609,6 +614,12 @@ suite('Workbench editor groups', () => { group.pin(sameInput1); assert.equal(events.pinned[0], input1); + group.stick(sameInput1); + assert.equal(events.sticky[0], input1); + + group.unstick(sameInput1); + assert.equal(events.unsticky[0], input1); + group.moveEditor(sameInput1, 1); assert.equal(events.moved[0], input1);