From a578ed163dc3c9231aeae0251f22b0d575567015 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 15:07:18 +0200 Subject: [PATCH 001/303] fix missing dirty diff decorations --- .../electron-browser/dirtydiffDecorator.ts | 65 ++++++++++++------- src/vs/workbench/services/scm/common/scm.ts | 1 - .../services/scm/common/scmService.ts | 3 - 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e512ed141a0..e29d4a29225 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -9,11 +9,12 @@ import nls = require('vs/nls'); import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; +import { any as anyEvent, filterEvent } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; import * as common from 'vs/editor/common/editorCommon'; -import * as widget from 'vs/editor/browser/codeEditor'; +import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -23,7 +24,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import URI from 'vs/base/common/uri'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ISCMService } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; @@ -87,15 +88,17 @@ class DirtyDiffModelDecorator { } }); - private decorations: string[]; + private decorations: string[] = []; private baselineModel: common.IModel; private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; - private toDispose: IDisposable[]; + + private repositoryDisposables = new Set(); + private toDispose: IDisposable[] = []; constructor( private model: common.IModel, - private uri: URI, + // private editor: CodeEditor, @ISCMService private scmService: ISCMService, @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, @@ -103,12 +106,28 @@ class DirtyDiffModelDecorator { @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextModelService private textModelResolverService: ITextModelService ) { - this.decorations = []; this.diffDelayer = new ThrottledDelayer(200); - this.toDispose = []; - this.triggerDiff(); + this.toDispose.push(model.onDidChangeContent(() => this.triggerDiff())); - this.toDispose.push(scmService.onDidChangeRepository(() => this.triggerDiff())); + scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); + scmService.repositories.forEach(r => this.onDidAddRepository(r)); + + this.triggerDiff(); + } + + private onDidAddRepository(repository: ISCMRepository): void { + const disposables: IDisposable[] = []; + + this.repositoryDisposables.add(disposables); + disposables.push(toDisposable(() => this.repositoryDisposables.delete(disposables))); + + const onDidChange = anyEvent(repository.provider.onDidChange, repository.provider.onDidChangeResources); + onDidChange(this.triggerDiff, this, disposables); + + const onDidRemoveThis = filterEvent(this.scmService.onDidRemoveRepository, r => r === repository); + onDidRemoveThis(() => dispose(disposables)); + + this.triggerDiff(); } private triggerDiff(): TPromise { @@ -174,7 +193,7 @@ class DirtyDiffModelDecorator { private async getOriginalResource(): TPromise { for (const repository of this.scmService.repositories) { - const result = repository.provider.getOriginalResource(this.uri); + const result = repository.provider.getOriginalResource(this.model.uri); if (result) { return result; @@ -237,6 +256,9 @@ class DirtyDiffModelDecorator { this.diffDelayer.cancel(); this.diffDelayer = null; } + + this.repositoryDisposables.forEach(d => dispose(d)); + this.repositoryDisposables.clear(); } } @@ -271,28 +293,25 @@ export class DirtyDiffDecorator implements ext.IWorkbenchContribution { .map(e => e.getControl()) // only interested in code editor widgets - .filter(c => c instanceof widget.CodeEditor) + .filter(c => c instanceof CodeEditor) // map to models - .map(e => (e).getModel()) + .map(editor => (editor as CodeEditor).getModel()) // remove nulls and duplicates - .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1) + .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1); - // get the associated resource - .map(m => ({ model: m, uri: m.uri })); + const newModels = models.filter(p => this.models.every(m => p !== m)); + const oldModels = this.models.filter(m => models.every(p => p !== m)); - const newModels = models.filter(p => this.models.every(m => p.model !== m)); - const oldModels = this.models.filter(m => models.every(p => p.model !== m)); - - newModels.forEach(({ model, uri }) => this.onModelVisible(model, uri)); + newModels.forEach(m => this.onModelVisible(m)); oldModels.forEach(m => this.onModelInvisible(m)); - this.models = models.map(p => p.model); + this.models = models; } - private onModelVisible(model: common.IModel, uri: URI): void { - this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model, uri); + private onModelVisible(model: common.IModel): void { + this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model); } private onModelInvisible(model: common.IModel): void { diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 7147cff15d6..a9337cf69b8 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -88,7 +88,6 @@ export interface ISCMService { readonly _serviceBrand: any; readonly onDidAddRepository: Event; readonly onDidRemoveRepository: Event; - readonly onDidChangeRepository: Event; readonly repositories: ISCMRepository[]; diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index 6e429c117b1..1a582fa342a 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -62,9 +62,6 @@ export class SCMService implements ISCMService { private _onDidRemoveProvider = new Emitter(); get onDidRemoveRepository(): Event { return this._onDidRemoveProvider.event; } - private _onDidChangeProvider = new Emitter(); - get onDidChangeRepository(): Event { return this._onDidChangeProvider.event; } - constructor() { } registerSCMProvider(provider: ISCMProvider): ISCMRepository { From a28ff684b91232ec88e055e758e9c47ea96ecc33 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 17:44:06 +0200 Subject: [PATCH 002/303] wip: dirtydiff widget --- .../electron-browser/dirtydiffDecorator.ts | 313 ++++++++++++++---- .../scm/electron-browser/scm.contribution.ts | 4 +- 2 files changed, 250 insertions(+), 67 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e29d4a29225..0c3ae214a96 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -9,9 +9,9 @@ import nls = require('vs/nls'); import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import { any as anyEvent, filterEvent } from 'vs/base/common/event'; +import Event, { Emitter, any as anyEvent, filterEvent, once } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; import * as common from 'vs/editor/common/editorCommon'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; @@ -30,6 +30,142 @@ import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromI import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; +import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { PeekViewWidget, PeekContext } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { IRange } from 'vs/editor/common/core/range'; + +export interface IModelRegistry { + getModel(editorModel: common.IEditorModel): DirtyDiffModel; +} + +class DirtyDiffWidget extends PeekViewWidget { + + constructor(editor: ICodeEditor, model: DirtyDiffModel) { + super(editor, {}); + + model.onDidChange(this.onDidModelChange, this, this._disposables); + this.create(); + } + + private onDidModelChange(): void { + console.log('MODEL CHANGED'); + } +} + +@editorAction +export class ReferenceAction extends EditorAction { + + constructor() { + super({ + id: 'editor.action.dirtydiff.trigger', + // TODO@joao come up with better name + label: nls.localize('dirtydiff.action.label', "Trigger Dirty Diff"), + alias: 'Trigger Dirty Diff', + precondition: ContextKeyExpr.and( + // EditorContextKeys.hasReferenceProvider, + PeekContext.notInPeekEditor, + EditorContextKeys.isInEmbeddedEditor.toNegated()), + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_D + } + }); + } + + public run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { + const controller = DirtyDiffController.get(editor); + + if (!controller) { + return; + } + + const range = editor.getSelection(); + controller.showWidget(range); + } +} + +@editorContribution +export class DirtyDiffController implements common.IEditorContribution { + + private static ID = 'editor.contrib.dirtydiff'; + + static get(editor: common.ICommonCodeEditor): DirtyDiffController { + return editor.getContribution(DirtyDiffController.ID); + } + + _modelRegistry: IModelRegistry | null = null; + + private widget: DirtyDiffWidget | null = null; + private widgetDisposable: IDisposable = EmptyDisposable; + + constructor(private editor: ICodeEditor) { + // this.disposables.push(editor.onMouseMove(e => this.onMouseMove(e))); + // this.disposables.push(editor.onMouseLeave(e => this.onMouseLeave(e))); + + // const widget = new DirtyDiffWidget(editor); + // widget. + + // editor. + } + + showWidget(range: IRange): void { + if (this.widget) { + return; + } + + if (!this._modelRegistry) { + return; + } + + const editorModel = this.editor.getModel(); + + if (!editorModel) { + return; + } + + const model = this._modelRegistry.getModel(editorModel); + + if (!model) { + return; + } + + this.widget = new DirtyDiffWidget(this.editor, model); + this.widget.setTitle('HELLO'); + this.widget.show(range, 18); + + const disposables: IDisposable[] = [ + this.widget, + toDisposable(() => this.widget = null) + ]; + + once(this.widget.onDidClose)(this.onDidCloseWidget, this, disposables); + this.widgetDisposable = combinedDisposable(disposables); + } + + private onDidCloseWidget(): void { + this.widgetDisposable.dispose(); + this.widgetDisposable = EmptyDisposable; + } + + // private onMouseMove(e: IEditorMouseEvent): void { + // if (e.target.type === MouseTargetType.GUTTER_LINE_DECORATIONS) { + // console.log(e.target.element); + // } + // } + + getId(): string { + return DirtyDiffController.ID; + } + + dispose(): void { + return; + } +} export const editorGutterModifiedBackground = registerColor('editorGutter.modifiedBackground', { dark: Color.fromHex('#00bcf2').transparent(0.6), @@ -55,8 +191,7 @@ export const overviewRulerModifiedForeground = registerColor('editorOverviewRule export const overviewRulerAddedForeground = registerColor('editorOverviewRuler.addedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerAddedForeground', 'Overview ruler marker color for added content.')); export const overviewRulerDeletedForeground = registerColor('editorOverviewRuler.deletedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerDeletedForeground', 'Overview ruler marker color for deleted content.')); - -class DirtyDiffModelDecorator { +class DirtyDiffDecorator { static MODIFIED_DECORATION_OPTIONS = ModelDecorationOptions.register({ linesDecorationsClassName: 'dirty-diff-modified-glyph', @@ -89,16 +224,80 @@ class DirtyDiffModelDecorator { }); private decorations: string[] = []; + private disposables: IDisposable[] = []; + + constructor( + private editorModel: common.IModel, + private model: DirtyDiffModel + ) { + model.onDidChange(this.onDidChange, this, this.disposables); + } + + private onDidChange(diff: common.IChange[]): void { + const decorations = diff.map((change) => { + const startLineNumber = change.modifiedStartLineNumber; + const endLineNumber = change.modifiedEndLineNumber || startLineNumber; + + // Added + if (change.originalEndLineNumber === 0) { + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.ADDED_DECORATION_OPTIONS + }; + } + + // Removed + if (change.modifiedEndLineNumber === 0) { + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: startLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.DELETED_DECORATION_OPTIONS + }; + } + + // Modified + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.MODIFIED_DECORATION_OPTIONS + }; + }); + + this.decorations = this.editorModel.deltaDecorations(this.decorations, decorations); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + + if (this.editorModel && !this.editorModel.isDisposed()) { + this.editorModel.deltaDecorations(this.decorations, []); + } + + this.editorModel = null; + this.decorations = []; + } +} + +export class DirtyDiffModel { + private baselineModel: common.IModel; private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; - private repositoryDisposables = new Set(); private toDispose: IDisposable[] = []; + private _onDidChange = new Emitter(); + readonly onDidChange: Event = this._onDidChange.event; + constructor( private model: common.IModel, - // private editor: CodeEditor, @ISCMService private scmService: ISCMService, @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, @@ -146,7 +345,7 @@ class DirtyDiffModelDecorator { diff = []; } - return this.decorations = this.model.deltaDecorations(this.decorations, DirtyDiffModelDecorator.changesToDecorations(diff || [])); + this._onDidChange.fire(diff); }); } @@ -203,54 +402,11 @@ class DirtyDiffModelDecorator { return null; } - private static changesToDecorations(diff: common.IChange[]): common.IModelDeltaDecoration[] { - return diff.map((change) => { - const startLineNumber = change.modifiedStartLineNumber; - const endLineNumber = change.modifiedEndLineNumber || startLineNumber; - - // Added - if (change.originalEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.ADDED_DECORATION_OPTIONS - }; - } - - // Removed - if (change.modifiedEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: startLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.DELETED_DECORATION_OPTIONS - }; - } - - // Modified - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.MODIFIED_DECORATION_OPTIONS - }; - }); - } - dispose(): void { this.toDispose = dispose(this.toDispose); - if (this.model && !this.model.isDisposed()) { - this.model.deltaDecorations(this.decorations, []); - } - this.model = null; this.baselineModel = null; - this.decorations = null; if (this.diffDelayer) { this.diffDelayer.cancel(); @@ -262,10 +418,20 @@ class DirtyDiffModelDecorator { } } -export class DirtyDiffDecorator implements ext.IWorkbenchContribution { +class DirtyDiffItem { + + constructor(readonly model: DirtyDiffModel, readonly decorator: DirtyDiffDecorator) { } + + dispose(): void { + this.decorator.dispose(); + this.model.dispose(); + } +} + +export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, IModelRegistry { private models: common.IModel[] = []; - private decorators: { [modelId: string]: DirtyDiffModelDecorator } = Object.create(null); + private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); private toDispose: IDisposable[] = []; constructor( @@ -296,34 +462,51 @@ export class DirtyDiffDecorator implements ext.IWorkbenchContribution { .filter(c => c instanceof CodeEditor) // map to models - .map(editor => (editor as CodeEditor).getModel()) + .map(editor => ({ model: (editor as CodeEditor).getModel(), controller: DirtyDiffController.get(editor as CodeEditor) })) // remove nulls and duplicates - .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1); + .filter((o, i, a) => !!o.model && !!o.model.uri && a.indexOf(o, i + 1) === -1); - const newModels = models.filter(p => this.models.every(m => p !== m)); - const oldModels = this.models.filter(m => models.every(p => p !== m)); + const newModels = models.filter(o => this.models.every(m => o.model !== m)); + const oldModels = this.models.filter(m => models.every(o => o.model !== m)); - newModels.forEach(m => this.onModelVisible(m)); oldModels.forEach(m => this.onModelInvisible(m)); + newModels.forEach(({ model, controller }) => { + controller._modelRegistry = this; + this.onModelVisible(model); + }); - this.models = models; + this.models = models.map(({ model }) => model); } - private onModelVisible(model: common.IModel): void { - this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model); + private onModelVisible(editorModel: common.IModel): void { + const model = this.instantiationService.createInstance(DirtyDiffModel, editorModel); + const decorator = new DirtyDiffDecorator(editorModel, model); + + this.items[editorModel.id] = new DirtyDiffItem(model, decorator); } - private onModelInvisible(model: common.IModel): void { - this.decorators[model.id].dispose(); - delete this.decorators[model.id]; + private onModelInvisible(editorModel: common.IModel): void { + this.items[editorModel.id].dispose(); + delete this.items[editorModel.id]; + } + + getModel(editorModel: common.IModel): DirtyDiffModel | null { + const item = this.items[editorModel.id]; + + if (!item) { + return null; + } + + return item.model; } dispose(): void { this.toDispose = dispose(this.toDispose); - this.models.forEach(m => this.decorators[m.id].dispose()); + this.models.forEach(m => this.items[m.id].dispose()); + this.models = null; - this.decorators = null; + this.items = null; } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index ad709f8092c..929fabf9f20 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { DirtyDiffDecorator } from './dirtydiffDecorator'; +import { DirtyDiffWorkbenchController } from './dirtydiffDecorator'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; @@ -29,7 +29,7 @@ class OpenSCMViewletAction extends ToggleViewletAction { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(DirtyDiffDecorator); + .registerWorkbenchContribution(DirtyDiffWorkbenchController); const viewletDescriptor = new ViewletDescriptor( 'vs/workbench/parts/scm/electron-browser/scmViewlet', From 2a7c70937ad15c1fc9cb8be3bd19c5b182126744 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 18:47:01 +0200 Subject: [PATCH 003/303] wip: wire up dirty diff machine --- src/vs/base/common/numbers.ts | 4 + .../electron-browser/dirtydiffDecorator.ts | 256 +++++++++++++----- 2 files changed, 192 insertions(+), 68 deletions(-) diff --git a/src/vs/base/common/numbers.ts b/src/vs/base/common/numbers.ts index 9f804fe6dd9..f23b941b7fe 100644 --- a/src/vs/base/common/numbers.ts +++ b/src/vs/base/common/numbers.ts @@ -50,4 +50,8 @@ export function countToArray(fromOrTo: number, to?: number): number[] { export function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max); +} + +export function rot(index: number, modulo: number): number { + return (modulo + (index % modulo)) % modulo; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 0c3ae214a96..bfcee8772ba 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -32,63 +32,108 @@ import { localize } from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { PeekViewWidget, PeekContext } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { PeekViewWidget, getOuterEditor } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; +import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IRange } from 'vs/editor/common/core/range'; +import { Position } from 'vs/editor/common/core/position'; +import { rot } from 'vs/base/common/numbers'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; } +export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', false); + class DirtyDiffWidget extends PeekViewWidget { - constructor(editor: ICodeEditor, model: DirtyDiffModel) { + constructor(editor: ICodeEditor) { super(editor, {}); - model.onDidChange(this.onDidModelChange, this, this._disposables); this.create(); + this.setTitle('HELLO'); } - private onDidModelChange(): void { - console.log('MODEL CHANGED'); + showChange(change: common.IChange): void { + const position = new Position(change.modifiedEndLineNumber, 1); + this.show(position, 10); } } @editorAction -export class ReferenceAction extends EditorAction { +export class ReferenceAction2 extends EditorAction { constructor() { super({ - id: 'editor.action.dirtydiff.trigger', + id: 'editor.action.dirtydiff.trigger2', // TODO@joao come up with better name label: nls.localize('dirtydiff.action.label', "Trigger Dirty Diff"), alias: 'Trigger Dirty Diff', - precondition: ContextKeyExpr.and( - // EditorContextKeys.hasReferenceProvider, - PeekContext.notInPeekEditor, - EditorContextKeys.isInEmbeddedEditor.toNegated()), - kbOpts: { - kbExpr: EditorContextKeys.textFocus, - primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_D - } + precondition: ContextKeyExpr.and(EditorContextKeys.isInEmbeddedEditor.toNegated()), + kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_S } }); } - public run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { + run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { const controller = DirtyDiffController.get(editor); if (!controller) { return; } - const range = editor.getSelection(); - controller.showWidget(range); + controller.previous(); } } +@editorAction +export class ReferenceAction3 extends EditorAction { + + constructor() { + super({ + id: 'editor.action.dirtydiff.trigger3', + // TODO@joao come up with better name + label: nls.localize('dirtydiff.action.label', "Trigger Dirty Diff"), + alias: 'Trigger Dirty Diff', + precondition: ContextKeyExpr.and(EditorContextKeys.isInEmbeddedEditor.toNegated()), + kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F } + }); + } + + run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { + const controller = DirtyDiffController.get(editor); + + if (!controller) { + return; + } + + controller.next(); + } +} + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'closeDirtyDiff', + weight: CommonEditorRegistry.commandWeight(50), + primary: KeyCode.Escape, + secondary: [KeyMod.Shift | KeyCode.Escape], + when: ContextKeyExpr.and(isDirtyDiffVisible, ContextKeyExpr.not('config.editor.stablePeek')), + handler: (accessor: ServicesAccessor) => { + const editor = getOuterEditor(accessor); + if (!editor) { + return; + } + + const controller = DirtyDiffController.get(editor); + + if (!controller) { + return; + } + + controller.close(); + } +}); + @editorContribution export class DirtyDiffController implements common.IEditorContribution { @@ -98,68 +143,135 @@ export class DirtyDiffController implements common.IEditorContribution { return editor.getContribution(DirtyDiffController.ID); } - _modelRegistry: IModelRegistry | null = null; + modelRegistry: IModelRegistry | null = null; + private model: DirtyDiffModel | null = null; private widget: DirtyDiffWidget | null = null; - private widgetDisposable: IDisposable = EmptyDisposable; + private changeIndex: number = -1; + private readonly isDirtyDiffVisible: IContextKey; + private session: IDisposable = EmptyDisposable; - constructor(private editor: ICodeEditor) { - // this.disposables.push(editor.onMouseMove(e => this.onMouseMove(e))); - // this.disposables.push(editor.onMouseLeave(e => this.onMouseLeave(e))); - - // const widget = new DirtyDiffWidget(editor); - // widget. - - // editor. + constructor( + private editor: ICodeEditor, + @IContextKeyService contextKeyService: IContextKeyService + ) { + this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); } - showWidget(range: IRange): void { - if (this.widget) { + getId(): string { + return DirtyDiffController.ID; + } + + next(): void { + if (!this.assertWidget()) { return; } - if (!this._modelRegistry) { + if (this.changeIndex === -1) { + this.changeIndex = this.findNextClosestChange(this.editor.getPosition().lineNumber); + } else { + this.changeIndex = rot(this.changeIndex + 1, this.model.changes.length); + } + + this.widget.showChange(this.model.changes[this.changeIndex]); + } + + previous(): void { + if (!this.assertWidget()) { return; } + if (this.changeIndex === -1) { + this.changeIndex = this.findPreviousClosestChange(this.editor.getPosition().lineNumber); + } else { + this.changeIndex = rot(this.changeIndex - 1, this.model.changes.length); + } + + this.widget.showChange(this.model.changes[this.changeIndex]); + } + + close(): void { + this.session.dispose(); + this.session = EmptyDisposable; + } + + private assertWidget(): boolean { + if (this.widget) { + if (this.model.changes.length === 0) { + this.close(); + return false; + } + + return true; + // this.widget.dispose(); + // this.widget = null; + } + + if (!this.modelRegistry) { + return false; + } + const editorModel = this.editor.getModel(); if (!editorModel) { - return; + return false; } - const model = this._modelRegistry.getModel(editorModel); + const model = this.modelRegistry.getModel(editorModel); if (!model) { - return; + return false; } - this.widget = new DirtyDiffWidget(this.editor, model); - this.widget.setTitle('HELLO'); - this.widget.show(range, 18); + if (model.changes.length === 0) { + return false; + } - const disposables: IDisposable[] = [ + this.changeIndex = -1; + this.model = model; + this.widget = new DirtyDiffWidget(this.editor); + this.isDirtyDiffVisible.set(true); + + // TODO react on model changes + + // const range = editor.getSelection(); + // this.widget.show(range, 18); + + const disposables: IDisposable[] = []; + once(this.widget.onDidClose)(this.close, this, disposables); + + disposables.push( this.widget, - toDisposable(() => this.widget = null) - ]; + toDisposable(() => this.model = this.widget = null), + toDisposable(() => this.isDirtyDiffVisible.set(false)) + ); - once(this.widget.onDidClose)(this.onDidCloseWidget, this, disposables); - this.widgetDisposable = combinedDisposable(disposables); + this.session = combinedDisposable(disposables); + return true; } - private onDidCloseWidget(): void { - this.widgetDisposable.dispose(); - this.widgetDisposable = EmptyDisposable; + private findNextClosestChange(lineNumber: number): number { + for (let i = 0; i < this.model.changes.length; i++) { + const change = this.model.changes[i]; + + if (change.modifiedEndLineNumber >= lineNumber) { + return i; + } + } + + return 0; } - // private onMouseMove(e: IEditorMouseEvent): void { - // if (e.target.type === MouseTargetType.GUTTER_LINE_DECORATIONS) { - // console.log(e.target.element); - // } - // } + private findPreviousClosestChange(lineNumber: number): number { + for (let i = this.model.changes.length - 1; i >= 0; i--) { + const change = this.model.changes[i]; - getId(): string { - return DirtyDiffController.ID; + if (change.modifiedStartLineNumber <= lineNumber) { + return i; + } + } + + return 0; } dispose(): void { @@ -296,6 +408,11 @@ export class DirtyDiffModel { private _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; + private _changes: common.IChange[] = []; + get changes(): common.IChange[] { + return this._changes; + } + constructor( private model: common.IModel, @ISCMService private scmService: ISCMService, @@ -336,16 +453,17 @@ export class DirtyDiffModel { return this.diffDelayer .trigger(() => this.diff()) - .then((diff: common.IChange[]) => { + .then((changes: common.IChange[]) => { if (!this.model || this.model.isDisposed() || !this.baselineModel || this.baselineModel.isDisposed()) { return undefined; // disposed } if (this.baselineModel.getValueLength() === 0) { - diff = []; + changes = []; } - this._onDidChange.fire(diff); + this._changes = changes; + this._onDidChange.fire(changes); }); } @@ -461,22 +579,24 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, // only interested in code editor widgets .filter(c => c instanceof CodeEditor) - // map to models - .map(editor => ({ model: (editor as CodeEditor).getModel(), controller: DirtyDiffController.get(editor as CodeEditor) })) + // set model registry and map to models + .map(editor => { + const codeEditor = editor as CodeEditor; + const controller = DirtyDiffController.get(codeEditor); + controller.modelRegistry = this; + return codeEditor.getModel(); + }) // remove nulls and duplicates - .filter((o, i, a) => !!o.model && !!o.model.uri && a.indexOf(o, i + 1) === -1); + .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1); - const newModels = models.filter(o => this.models.every(m => o.model !== m)); - const oldModels = this.models.filter(m => models.every(o => o.model !== m)); + const newModels = models.filter(o => this.models.every(m => o !== m)); + const oldModels = this.models.filter(m => models.every(o => o !== m)); oldModels.forEach(m => this.onModelInvisible(m)); - newModels.forEach(({ model, controller }) => { - controller._modelRegistry = this; - this.onModelVisible(model); - }); + newModels.forEach(m => this.onModelVisible(m)); - this.models = models.map(({ model }) => model); + this.models = models; } private onModelVisible(editorModel: common.IModel): void { From 80b7a2e208d289af268a5ed2a163a933992a2f16 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 18:52:29 +0200 Subject: [PATCH 004/303] dirtydiff widget: styles --- .../electron-browser/dirtydiffDecorator.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index bfcee8772ba..4de65409dd8 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -26,7 +26,7 @@ import URI from 'vs/base/common/uri'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; -import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId, IThemeService } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; @@ -40,6 +40,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Position } from 'vs/editor/common/core/position'; import { rot } from 'vs/base/common/numbers'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -49,9 +50,12 @@ export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', class DirtyDiffWidget extends PeekViewWidget { - constructor(editor: ICodeEditor) { + constructor(editor: ICodeEditor, themeService: IThemeService) { super(editor, {}); + themeService.onThemeChange(this._applyTheme, this, this._disposables); + this._applyTheme(themeService.getTheme()); + this.create(); this.setTitle('HELLO'); } @@ -60,6 +64,17 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(change.modifiedEndLineNumber, 1); this.show(position, 10); } + + private _applyTheme(theme: ITheme) { + let borderColor = theme.getColor(peekViewBorder) || Color.transparent; + this.style({ + arrowColor: borderColor, + frameColor: borderColor, + headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent, + primaryHeadingColor: theme.getColor(peekViewTitleForeground), + secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) + }); + } } @editorAction @@ -153,7 +168,8 @@ export class DirtyDiffController implements common.IEditorContribution { constructor( private editor: ICodeEditor, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, + @IThemeService private themeService: IThemeService ) { this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); } @@ -229,7 +245,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = -1; this.model = model; - this.widget = new DirtyDiffWidget(this.editor); + this.widget = new DirtyDiffWidget(this.editor, this.themeService); this.isDirtyDiffVisible.set(true); // TODO react on model changes From 4c1cad1fd18133b4533768947d8e83443d73a827 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 23:13:21 +0200 Subject: [PATCH 005/303] wip: dirtydiff show original contents --- .../electron-browser/dirtydiffDecorator.ts | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 4de65409dd8..5d0c993c63e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -38,9 +38,11 @@ import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from ' import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; import { rot } from 'vs/base/common/numbers'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; +import { append, $ } from 'vs/base/browser/dom'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -50,7 +52,9 @@ export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', class DirtyDiffWidget extends PeekViewWidget { - constructor(editor: ICodeEditor, themeService: IThemeService) { + private contents: HTMLElement; + + constructor(editor: ICodeEditor, private model: DirtyDiffModel, themeService: IThemeService) { super(editor, {}); themeService.onThemeChange(this._applyTheme, this, this._disposables); @@ -61,8 +65,24 @@ class DirtyDiffWidget extends PeekViewWidget { } showChange(change: common.IChange): void { + const originalModel = this.model.originalModel; + + if (!originalModel) { + return; + } + + const range = new Range(change.originalStartLineNumber, 0, change.originalEndLineNumber, Number.MAX_VALUE); + const text = originalModel.getValueInRange(range); + this.contents.textContent = text; + const position = new Position(change.modifiedEndLineNumber, 1); this.show(position, 10); + + } + + + protected _fillBody(container: HTMLElement): void { + this.contents = append(container, $('.text')); } private _applyTheme(theme: ITheme) { @@ -245,7 +265,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = -1; this.model = model; - this.widget = new DirtyDiffWidget(this.editor, this.themeService); + this.widget = new DirtyDiffWidget(this.editor, model, this.themeService); this.isDirtyDiffVisible.set(true); // TODO react on model changes @@ -415,7 +435,12 @@ class DirtyDiffDecorator { export class DirtyDiffModel { - private baselineModel: common.IModel; + private _originalModel: common.IModel; + + get originalModel(): common.IModel { + return this._originalModel; + } + private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; private repositoryDisposables = new Set(); @@ -470,11 +495,11 @@ export class DirtyDiffModel { return this.diffDelayer .trigger(() => this.diff()) .then((changes: common.IChange[]) => { - if (!this.model || this.model.isDisposed() || !this.baselineModel || this.baselineModel.isDisposed()) { + if (!this.model || this.model.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) { return undefined; // disposed } - if (this.baselineModel.getValueLength() === 0) { + if (this._originalModel.getValueLength() === 0) { changes = []; } @@ -505,12 +530,13 @@ export class DirtyDiffModel { this._originalURIPromise = this.getOriginalResource() .then(originalUri => { if (!originalUri) { + this._originalModel = null; return null; } return this.textModelResolverService.createModelReference(originalUri) .then(ref => { - this.baselineModel = ref.object.textEditorModel; + this._originalModel = ref.object.textEditorModel; this.toDispose.push(ref); this.toDispose.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); @@ -540,7 +566,7 @@ export class DirtyDiffModel { this.toDispose = dispose(this.toDispose); this.model = null; - this.baselineModel = null; + this._originalModel = null; if (this.diffDelayer) { this.diffDelayer.cancel(); From bcf9df598af438912fbc7c08652426fbce17535e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?= Date: Sat, 23 Sep 2017 22:47:42 +0200 Subject: [PATCH 006/303] Add editorFileExtension when clause context --- src/vs/editor/common/editorContextKeys.ts | 1 + src/vs/editor/common/modes/editorModeContext.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts index 8843cf821d4..0aa240df5e4 100644 --- a/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -28,6 +28,7 @@ export namespace EditorContextKeys { // -- mode context keys export const languageId = new RawContextKey('editorLangId', undefined); + export const fileExtension = new RawContextKey('editorFileExtension', undefined); export const hasCompletionItemProvider = new RawContextKey('editorHasCompletionItemProvider', undefined); export const hasCodeActionsProvider = new RawContextKey('editorHasCodeActionsProvider', undefined); export const hasCodeLensProvider = new RawContextKey('editorHasCodeLensProvider', undefined); diff --git a/src/vs/editor/common/modes/editorModeContext.ts b/src/vs/editor/common/modes/editorModeContext.ts index a22237cf04e..a52892edccf 100644 --- a/src/vs/editor/common/modes/editorModeContext.ts +++ b/src/vs/editor/common/modes/editorModeContext.ts @@ -16,6 +16,7 @@ export class EditorModeContext extends Disposable { private _editor: ICommonCodeEditor; private _langId: IContextKey; + private _fileExtension: IContextKey; private _hasCompletionItemProvider: IContextKey; private _hasCodeActionsProvider: IContextKey; private _hasCodeLensProvider: IContextKey; @@ -40,6 +41,7 @@ export class EditorModeContext extends Disposable { this._editor = editor; this._langId = EditorContextKeys.languageId.bindTo(contextKeyService); + this._fileExtension = EditorContextKeys.fileExtension.bindTo(contextKeyService); this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService); this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService); @@ -87,6 +89,7 @@ export class EditorModeContext extends Disposable { reset() { this._langId.reset(); + this._fileExtension.reset(); this._hasCompletionItemProvider.reset(); this._hasCodeActionsProvider.reset(); this._hasCodeLensProvider.reset(); @@ -111,6 +114,7 @@ export class EditorModeContext extends Disposable { return; } this._langId.set(model.getLanguageIdentifier().language); + this._fileExtension.set(model.uri.path.split('.').pop()); this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model)); this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); From c5d19f539c838240e1becaacc1fcb2f9471113b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?= Date: Wed, 27 Sep 2017 17:23:11 +0200 Subject: [PATCH 007/303] Add extension context to ResourceContextKey --- src/vs/workbench/common/resources.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 34b7d02d846..67857f78e7c 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -23,11 +23,13 @@ export class ResourceContextKey implements IContextKey { static Filename = new RawContextKey('resourceFilename', undefined); static LangId = new RawContextKey('resourceLangId', undefined); static Resource = new RawContextKey('resource', undefined); + static Extension = new RawContextKey('resourceExtension', undefined); private _resourceKey: IContextKey; private _schemeKey: IContextKey; private _filenameKey: IContextKey; private _langIdKey: IContextKey; + private _extensionKey: IContextKey; constructor( @IContextKeyService contextKeyService: IContextKeyService, @@ -37,6 +39,7 @@ export class ResourceContextKey implements IContextKey { this._filenameKey = ResourceContextKey.Filename.bindTo(contextKeyService); this._langIdKey = ResourceContextKey.LangId.bindTo(contextKeyService); this._resourceKey = ResourceContextKey.Resource.bindTo(contextKeyService); + this._extensionKey = ResourceContextKey.Extension.bindTo(contextKeyService); } set(value: URI) { @@ -44,12 +47,14 @@ export class ResourceContextKey implements IContextKey { this._schemeKey.set(value && value.scheme); this._filenameKey.set(value && basename(value.fsPath)); this._langIdKey.set(value && this._modeService.getModeIdByFilenameOrFirstLine(value.fsPath)); + this._extensionKey.set(value && paths.extname(value.fsPath)); } reset(): void { this._schemeKey.reset(); this._langIdKey.reset(); this._resourceKey.reset(); + this._extensionKey.reset(); } public get(): URI { From e2f198edf12111251ffe94f9ad5490bda2e9928c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?= Date: Wed, 27 Sep 2017 17:28:30 +0200 Subject: [PATCH 008/303] Rename context and small fixes --- src/vs/editor/common/editorContextKeys.ts | 2 +- src/vs/editor/common/modes/editorModeContext.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts index 0aa240df5e4..4283b4e989a 100644 --- a/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -28,7 +28,7 @@ export namespace EditorContextKeys { // -- mode context keys export const languageId = new RawContextKey('editorLangId', undefined); - export const fileExtension = new RawContextKey('editorFileExtension', undefined); + export const editorExtension = new RawContextKey('editorExtension', undefined); export const hasCompletionItemProvider = new RawContextKey('editorHasCompletionItemProvider', undefined); export const hasCodeActionsProvider = new RawContextKey('editorHasCodeActionsProvider', undefined); export const hasCodeLensProvider = new RawContextKey('editorHasCodeLensProvider', undefined); diff --git a/src/vs/editor/common/modes/editorModeContext.ts b/src/vs/editor/common/modes/editorModeContext.ts index a52892edccf..b503700f9d7 100644 --- a/src/vs/editor/common/modes/editorModeContext.ts +++ b/src/vs/editor/common/modes/editorModeContext.ts @@ -10,13 +10,14 @@ import * as modes from 'vs/editor/common/modes'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { Schemas } from 'vs/base/common/network'; +import * as paths from 'vs/base/common/paths'; export class EditorModeContext extends Disposable { private _editor: ICommonCodeEditor; private _langId: IContextKey; - private _fileExtension: IContextKey; + private _editorExtension: IContextKey; private _hasCompletionItemProvider: IContextKey; private _hasCodeActionsProvider: IContextKey; private _hasCodeLensProvider: IContextKey; @@ -41,7 +42,7 @@ export class EditorModeContext extends Disposable { this._editor = editor; this._langId = EditorContextKeys.languageId.bindTo(contextKeyService); - this._fileExtension = EditorContextKeys.fileExtension.bindTo(contextKeyService); + this._editorExtension = EditorContextKeys.editorExtension.bindTo(contextKeyService); this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService); this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService); @@ -89,7 +90,7 @@ export class EditorModeContext extends Disposable { reset() { this._langId.reset(); - this._fileExtension.reset(); + this._editorExtension.reset(); this._hasCompletionItemProvider.reset(); this._hasCodeActionsProvider.reset(); this._hasCodeLensProvider.reset(); @@ -114,7 +115,7 @@ export class EditorModeContext extends Disposable { return; } this._langId.set(model.getLanguageIdentifier().language); - this._fileExtension.set(model.uri.path.split('.').pop()); + this._editorExtension.set(paths.extname(model.uri.fsPath)); this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model)); this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); From 8dbc74e36fbc7429ae7b6603e1fb62ca34e33e66 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 4 Oct 2017 09:59:58 +0200 Subject: [PATCH 009/303] Configuration API blueprint --- .../configuration/common/configuration2.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/vs/platform/configuration/common/configuration2.ts diff --git a/src/vs/platform/configuration/common/configuration2.ts b/src/vs/platform/configuration/common/configuration2.ts new file mode 100644 index 00000000000..a3edb5c0048 --- /dev/null +++ b/src/vs/platform/configuration/common/configuration2.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import Event from 'vs/base/common/event'; + +export const IConfigurationService = createDecorator('configurationService'); + +export interface IConfigurationOverrides { + overrideIdentifier?: string; + resource?: URI; +} + +export enum ConfigurationTarget { + USER, + WORKSPACE, + WORKSPACE_FOLDER, + MEMORY +} + +export interface IConfigurationServiceEvent { + sections: string[]; + keys: string[]; +} + +export interface IConfiguration { + readonly [key: string]: any; +} + +export interface IConfigurationService { + _serviceBrand: any; + + onDidUpdateConfiguration: Event; + + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; + + updateConfiguration(key: string, value: any): TPromise; + updateConfiguration(key: string, value: any, overrides: IConfigurationOverrides): TPromise; + updateConfiguration(key: string, value: any, target: ConfigurationTarget): TPromise; + updateConfiguration(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; + + inspect(key: string): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T, + }; + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + }; +} \ No newline at end of file From 7ec6ecda504c22197b1fec07dc85839f55e4a1c5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 4 Oct 2017 10:09:58 +0200 Subject: [PATCH 010/303] Adopt to new configuration API --- .../configuration/common/configuration.ts | 55 +++++--------- .../common/configurationRegistry.ts | 14 ++-- .../node/configurationService.ts | 73 ++++++++++--------- .../configuration/common/configuration.ts | 2 +- 4 files changed, 61 insertions(+), 83 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index d541ed739df..16dc333a62f 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -240,7 +240,13 @@ export class Configuration { return section ? configModel.getContentsFor(section) : configModel.contents; } - lookup(key: string, overrides: IConfigurationOverrides = {}): IConfigurationValue { + lookup(key: string, overrides: IConfigurationOverrides = {}): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + value: C, + } { // make sure to clone the configuration so that the receiver does not tamper with the values const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); @@ -248,53 +254,26 @@ export class Configuration { default: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)), user: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)), workspace: objects.clone(this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0), //Check on workspace exists or not because _workspaceConfiguration is never null - folder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), + workspaceFolder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) }; } - keys(overrides: IConfigurationOverrides = {}): IConfigurationKeys { - const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + const folderConfigurationModel = this.getFolderConfigurationModelForResource(); return { default: this._defaults.keys, user: this._user.keys, workspace: this._workspaceConfiguration.keys, - folder: folderConfigurationModel ? folderConfigurationModel.keys : [] + workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : [] }; } - values(): IConfigurationValues { - const result = Object.create(null); - const keyset = this.keys(); - const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); - - let lastKey: string; - for (const key of keys) { - if (key !== lastKey) { - lastKey = key; - result[key] = this.lookup(key); - } - } - - return result; - } - - values2(): Map> { - const result: Map> = new Map>(); - const keyset = this.keys(); - const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); - - let lastKey: string; - for (const key of keys) { - if (key !== lastKey) { - lastKey = key; - result.set(key, this.lookup(key)); - } - } - - return result; - } - private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; @@ -317,7 +296,7 @@ export class Configuration { return this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration; } - private getFolderConfigurationModelForResource(resource: URI): ConfigurationModel { + private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { if (!this._workspace || !resource) { return null; } diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 0d3276bf69d..f93837028b1 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -35,7 +35,7 @@ export interface IConfigurationRegistry { * Event that fires whenver a configuratio has been * registered. */ - onDidRegisterConfiguration: Event; + onDidRegisterConfiguration: Event; /** * Returns all configuration nodes contributed to this registry. @@ -90,27 +90,25 @@ export const editorConfigurationSchemaId = 'vscode://schemas/settings/editor'; const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); class ConfigurationRegistry implements IConfigurationRegistry { + private configurationContributors: IConfigurationNode[]; private configurationProperties: { [qualifiedKey: string]: IJSONSchema }; private editorConfigurationSchema: IJSONSchema; - private _onDidRegisterConfiguration: Emitter; private overrideIdentifiers: string[] = []; private overridePropertyPattern: string; + private _onDidRegisterConfiguration: Emitter = new Emitter(); + readonly onDidRegisterConfiguration: Event = this._onDidRegisterConfiguration.event; + constructor() { this.configurationContributors = []; this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting' }; - this._onDidRegisterConfiguration = new Emitter(); this.configurationProperties = {}; this.computeOverridePropertyPattern(); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); } - public get onDidRegisterConfiguration() { - return this._onDidRegisterConfiguration.event; - } - public registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void { this.registerConfigurations([configuration], validate); } @@ -123,7 +121,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { this.updateSchemaForOverrideSettingsConfiguration(configuration); }); - this._onDidRegisterConfiguration.fire(this); + this._onDidRegisterConfiguration.fire(configurations); } public registerOverrideIdentifiers(overrideIdentifiers: string[]): void { diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 8f6005c6430..843cd285b4d 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TPromise } from 'vs/base/common/winjs.base'; import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationRegistry, Extensions, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ConfigurationSource, IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, IConfigurationKeys, ConfigurationModel, IConfigurationOverrides, Configuration, IConfigurationValues, IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationServiceEvent, IConfigurationOverrides, IConfiguration } from 'vs/platform/configuration/common/configuration2'; +import { ConfigurationModel, Configuration } from 'vs/platform/configuration/common/configuration'; import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -40,52 +40,53 @@ export class ConfigurationService extends Disposable implements IConfiguratio this._register(this.userConfigModelWatcher); // Listeners - this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onConfigurationChange(ConfigurationSource.User))); - this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(() => this.onConfigurationChange(ConfigurationSource.Default))); + this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onDidUpdateConfigModel())); + this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(configurationNodes => this.onDidRegisterConfiguration(configurationNodes))); } - public configuration(): Configuration { + public get configuration(): Configuration { return this._configuration || (this._configuration = this.consolidateConfigurations()); } - private onConfigurationChange(source: ConfigurationSource): void { + private onDidUpdateConfigModel(): void { + // get the diff + // reset and trigger + this.onConfigurationChange([], []); + } + + private onDidRegisterConfiguration(configurations: IConfigurationNode[]): void { + // get the diff + // reset and trigger + this.onConfigurationChange([], []); + } + + private onConfigurationChange(sections: string[], keys: string[]): void { this.reset(); // reset our caches - const cache = this.configuration(); - - this._onDidUpdateConfiguration.fire({ - source, - sourceConfig: source === ConfigurationSource.Default ? cache.defaults.contents : cache.user.contents - }); + this._onDidUpdateConfiguration.fire({ sections, keys }); } - public reloadConfiguration(section?: string): TPromise { - return new TPromise(c => { - this.userConfigModelWatcher.reload(() => { - this.reset(); // reset our caches - c(this.getConfiguration(section)); - }); - }); + public getConfiguration(section?: string, options?: IConfigurationOverrides): IConfiguration { + return this.configuration.getValue(section, options); } - public getConfiguration(section?: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue(section, options); + public inspect(key: string): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T + } { + return this.configuration.lookup(key); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { - return this.configuration().lookup(key, overrides); - } - - public keys(overrides?: IConfigurationOverrides): IConfigurationKeys { - return this.configuration().keys(overrides); - } - - public values(): IConfigurationValues { - return this._configuration.values(); - } - - public getConfigurationData(): IConfigurationData { - return this.configuration().toData(); + public keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return this.configuration.keys(); } private reset(): void { diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 28c1b711fed..9dffb9cba33 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration2'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const CONFIG_DEFAULT_NAME = 'settings'; From 5aab156e5953d5e2fb3e83a9cd06a09860cca97f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 4 Oct 2017 10:20:44 +0200 Subject: [PATCH 011/303] :lipstick: --- .../electron-browser/dirtydiffDecorator.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 5d0c993c63e..4cfc994ad10 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -77,10 +77,8 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(change.modifiedEndLineNumber, 1); this.show(position, 10); - } - protected _fillBody(container: HTMLElement): void { this.contents = append(container, $('.text')); } @@ -444,7 +442,7 @@ export class DirtyDiffModel { private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; private repositoryDisposables = new Set(); - private toDispose: IDisposable[] = []; + private disposables: IDisposable[] = []; private _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; @@ -465,8 +463,8 @@ export class DirtyDiffModel { ) { this.diffDelayer = new ThrottledDelayer(200); - this.toDispose.push(model.onDidChangeContent(() => this.triggerDiff())); - scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); + this.disposables.push(model.onDidChangeContent(() => this.triggerDiff())); + scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); scmService.repositories.forEach(r => this.onDidAddRepository(r)); this.triggerDiff(); @@ -538,8 +536,8 @@ export class DirtyDiffModel { .then(ref => { this._originalModel = ref.object.textEditorModel; - this.toDispose.push(ref); - this.toDispose.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); + this.disposables.push(ref); + this.disposables.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); return originalUri; }); @@ -563,7 +561,7 @@ export class DirtyDiffModel { } dispose(): void { - this.toDispose = dispose(this.toDispose); + this.disposables = dispose(this.disposables); this.model = null; this._originalModel = null; @@ -592,7 +590,7 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, private models: common.IModel[] = []; private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); - private toDispose: IDisposable[] = []; + private disposables: IDisposable[] = []; constructor( @IMessageService private messageService: IMessageService, @@ -601,7 +599,7 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService ) { - this.toDispose.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + this.disposables.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); } getId(): string { @@ -664,7 +662,7 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, } dispose(): void { - this.toDispose = dispose(this.toDispose); + this.disposables = dispose(this.disposables); this.models.forEach(m => this.items[m.id].dispose()); this.models = null; From dbf4cea57513f15584173ecfc312e522f3073bc6 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 4 Oct 2017 11:53:32 +0200 Subject: [PATCH 012/303] dirtydiff: show diff editor --- .../widget/embeddedCodeEditorWidget.ts | 51 +++++++- .../referenceSearch/browser/peekViewWidget.ts | 4 +- .../electron-browser/dirtydiffDecorator.ts | 115 ++++++++++++++---- 3 files changed, 138 insertions(+), 32 deletions(-) diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index 185f3537c51..050937ddb51 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -11,8 +11,11 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; -import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationChangedEvent, IEditorOptions, IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { IMessageService } from 'vs/platform/message/common/message'; export class EmbeddedCodeEditorWidget extends CodeEditor { @@ -40,7 +43,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditor { this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); } - public getParentEditor(): ICodeEditor { + getParentEditor(): ICodeEditor { return this._parentEditor; } @@ -49,7 +52,49 @@ export class EmbeddedCodeEditorWidget extends CodeEditor { super.updateOptions(this._overwriteOptions); } - public updateOptions(newOptions: IEditorOptions): void { + updateOptions(newOptions: IEditorOptions): void { + objects.mixin(this._overwriteOptions, newOptions, true); + super.updateOptions(this._overwriteOptions); + } +} + +export class EmbeddedDiffEditorWidget extends DiffEditorWidget { + + private _parentEditor: ICodeEditor; + private _overwriteOptions: IDiffEditorOptions; + + constructor( + domElement: HTMLElement, + options: IDiffEditorOptions, + parentEditor: ICodeEditor, + @IEditorWorkerService editorWorkerService: IEditorWorkerService, + @IContextKeyService contextKeyService: IContextKeyService, + @IInstantiationService instantiationService: IInstantiationService, + @ICodeEditorService codeEditorService: ICodeEditorService, + @IThemeService themeService: IThemeService, + @IMessageService messageService: IMessageService + ) { + super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, messageService); + + this._parentEditor = parentEditor; + this._overwriteOptions = options; + + // Overwrite parent's options + super.updateOptions(this._overwriteOptions); + + this._register(parentEditor.onDidChangeConfiguration(e => this._onParentConfigurationChanged(e))); + } + + getParentEditor(): ICodeEditor { + return this._parentEditor; + } + + private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawConfiguration()); + super.updateOptions(this._overwriteOptions); + } + + updateOptions(newOptions: IEditorOptions): void { objects.mixin(this._overwriteOptions, newOptions, true); super.updateOptions(this._overwriteOptions); } diff --git a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts index a0a78bac128..5332768c677 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts @@ -165,9 +165,7 @@ export abstract class PeekViewWidget extends ZoneWidget { } } - protected _fillBody(container: HTMLElement): void { - // implement me - } + protected abstract _fillBody(container: HTMLElement): void; public _doLayout(heightInPixel: number, widthInPixel: number): void { diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 4cfc994ad10..505b89237c5 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -38,11 +38,11 @@ import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from ' import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Position } from 'vs/editor/common/core/position'; -import { Range } from 'vs/editor/common/core/range'; import { rot } from 'vs/base/common/numbers'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; -import { append, $ } from 'vs/base/browser/dom'; +import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; +import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -50,37 +50,101 @@ export interface IModelRegistry { export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', false); +function getChangeHeight(change: common.IChange): number { + const modified = change.modifiedEndLineNumber - change.modifiedStartLineNumber + 1; + const original = change.originalEndLineNumber - change.originalStartLineNumber + 1; + + if (change.originalEndLineNumber === 0) { + return modified; + } else if (change.modifiedEndLineNumber === 0) { + return original; + } else { + return modified + original; + } +} + +function getModifiedMiddleLineNumber(change: common.IChange): number { + if (change.modifiedEndLineNumber === 0) { + return change.modifiedStartLineNumber; + } else { + return Math.round((change.modifiedEndLineNumber + change.modifiedStartLineNumber) / 2); + } +} + class DirtyDiffWidget extends PeekViewWidget { - private contents: HTMLElement; + private diffEditor: EmbeddedDiffEditorWidget; + private change: common.IChange; + private didLayout = false; - constructor(editor: ICodeEditor, private model: DirtyDiffModel, themeService: IThemeService) { - super(editor, {}); + constructor( + editor: ICodeEditor, + private model: DirtyDiffModel, + themeService: IThemeService, + private instantiationService: IInstantiationService + ) { + super(editor, { isResizeable: true }); themeService.onThemeChange(this._applyTheme, this, this._disposables); this._applyTheme(themeService.getTheme()); this.create(); - this.setTitle('HELLO'); + this.setTitle('Diff'); } showChange(change: common.IChange): void { - const originalModel = this.model.originalModel; + this.change = change; + + const originalModel = this.model.original; if (!originalModel) { return; } - const range = new Range(change.originalStartLineNumber, 0, change.originalEndLineNumber, Number.MAX_VALUE); - const text = originalModel.getValueInRange(range); - this.contents.textContent = text; + this.diffEditor.setModel(this.model); const position = new Position(change.modifiedEndLineNumber, 1); - this.show(position, 10); + const height = getChangeHeight(change) + /* padding */ 8; + + this.show(position, height); + + // TODO@joao TODO@alex for some reason this doesn't work for some changes + // unless we delay it + setTimeout(() => this.revealChange(change), 100); } protected _fillBody(container: HTMLElement): void { - this.contents = append(container, $('.text')); + const options: IDiffEditorOptions = { + scrollBeyondLastLine: false, + scrollbar: { + verticalScrollbarSize: 14, + horizontal: 'auto', + useShadows: true, + verticalHasArrows: false, + horizontalHasArrows: false + }, + overviewRulerLanes: 2, + fixedOverflowWidgets: true, + minimap: { enabled: false }, + renderSideBySide: false + }; + + this.diffEditor = this.instantiationService.createInstance(EmbeddedDiffEditorWidget, container, options, this.editor); + } + + protected _doLayoutBody(heightInPixel: number, widthInPixel: number): void { + super._doLayoutBody(heightInPixel, widthInPixel); + this.diffEditor.layout({ height: heightInPixel, width: widthInPixel }); + + if (!this.didLayout) { + this.revealChange(this.change); + this.didLayout = true; + } + } + + private revealChange(change: common.IChange): void { + const position = new Position(getModifiedMiddleLineNumber(this.change), 1); + this.diffEditor.revealPositionInCenter(position, common.ScrollType.Immediate); } private _applyTheme(theme: ITheme) { @@ -187,7 +251,8 @@ export class DirtyDiffController implements common.IEditorContribution { constructor( private editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @IInstantiationService private instantiationService: IInstantiationService ) { this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); } @@ -263,7 +328,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = -1; this.model = model; - this.widget = new DirtyDiffWidget(this.editor, model, this.themeService); + this.widget = new DirtyDiffWidget(this.editor, model, this.themeService, this.instantiationService); this.isDirtyDiffVisible.set(true); // TODO react on model changes @@ -434,10 +499,8 @@ class DirtyDiffDecorator { export class DirtyDiffModel { private _originalModel: common.IModel; - - get originalModel(): common.IModel { - return this._originalModel; - } + get original(): common.IModel { return this._originalModel; } + get modified(): common.IModel { return this._editorModel; } private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; @@ -453,7 +516,7 @@ export class DirtyDiffModel { } constructor( - private model: common.IModel, + private _editorModel: common.IModel, @ISCMService private scmService: ISCMService, @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, @@ -463,7 +526,7 @@ export class DirtyDiffModel { ) { this.diffDelayer = new ThrottledDelayer(200); - this.disposables.push(model.onDidChangeContent(() => this.triggerDiff())); + this.disposables.push(_editorModel.onDidChangeContent(() => this.triggerDiff())); scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); scmService.repositories.forEach(r => this.onDidAddRepository(r)); @@ -493,7 +556,7 @@ export class DirtyDiffModel { return this.diffDelayer .trigger(() => this.diff()) .then((changes: common.IChange[]) => { - if (!this.model || this.model.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) { + if (!this._editorModel || this._editorModel.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) { return undefined; // disposed } @@ -508,15 +571,15 @@ export class DirtyDiffModel { private diff(): TPromise { return this.getOriginalURIPromise().then(originalURI => { - if (!this.model || this.model.isDisposed() || !originalURI) { + if (!this._editorModel || this._editorModel.isDisposed() || !originalURI) { return TPromise.as([]); // disposed } - if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this.model.uri)) { + if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this._editorModel.uri)) { return TPromise.as([]); // Files too large } - return this.editorWorkerService.computeDirtyDiff(originalURI, this.model.uri, true); + return this.editorWorkerService.computeDirtyDiff(originalURI, this._editorModel.uri, true); }); } @@ -550,7 +613,7 @@ export class DirtyDiffModel { private async getOriginalResource(): TPromise { for (const repository of this.scmService.repositories) { - const result = repository.provider.getOriginalResource(this.model.uri); + const result = repository.provider.getOriginalResource(this._editorModel.uri); if (result) { return result; @@ -563,7 +626,7 @@ export class DirtyDiffModel { dispose(): void { this.disposables = dispose(this.disposables); - this.model = null; + this._editorModel = null; this._originalModel = null; if (this.diffDelayer) { From 3def2847fa4558e6e95222c9bfc12dc8369643e0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 5 Oct 2017 10:25:27 +0200 Subject: [PATCH 013/303] update diff editor with correct event --- .../parts/scm/electron-browser/dirtydiffDecorator.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 505b89237c5..6d53ce9c9c1 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -101,16 +101,18 @@ class DirtyDiffWidget extends PeekViewWidget { return; } + const onFirstDiffUpdate = once(this.diffEditor.onDidUpdateDiff); + + // TODO@joao TODO@alex need this setTimeout probably because the + // non-side-by-side diff still hasn't created the view zones + onFirstDiffUpdate(() => setTimeout(() => this.revealChange(change), 0)); + this.diffEditor.setModel(this.model); const position = new Position(change.modifiedEndLineNumber, 1); const height = getChangeHeight(change) + /* padding */ 8; this.show(position, height); - - // TODO@joao TODO@alex for some reason this doesn't work for some changes - // unless we delay it - setTimeout(() => this.revealChange(change), 100); } protected _fillBody(container: HTMLElement): void { From 75cf7dabb50ace4604806404c7f134e546406828 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 5 Oct 2017 23:13:18 +0200 Subject: [PATCH 014/303] Refactor Configuration Service - API to get a value given a key - API to update value smartly - Fine grained configuration change event - Smart reload API - Remove unnecessary APIs --- .../browser/referencesController.ts | 2 +- .../standalone/browser/simpleServices.ts | 49 +- .../configuration/common/configuration.ts | 148 ++-- .../configuration/common/configuration2.ts | 63 -- .../common/configurationRegistry.ts | 22 +- .../node/configurationService.ts | 106 ++- .../test/common/testConfigurationService.ts | 38 +- .../test/node/configurationService.test.ts | 13 +- .../telemetry/common/telemetryUtils.ts | 8 +- .../electron-browser/telemetryService.test.ts | 18 +- .../mainThreadConfiguration.ts | 2 +- .../mainThreadSaveParticipant.ts | 8 +- .../api/node/extHostConfiguration.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 2 +- .../browser/parts/titlebar/titlebarPart.ts | 2 +- src/vs/workbench/electron-browser/actions.ts | 4 +- src/vs/workbench/electron-browser/main.ts | 2 +- src/vs/workbench/electron-browser/window.ts | 2 +- .../workbench/electron-browser/workbench.ts | 30 +- .../electron-browser/wordWrapMigration.ts | 2 +- .../parts/debug/browser/debugActionItems.ts | 2 +- .../debug/electron-browser/debugService.ts | 2 +- .../browser/preferencesRenderers.ts | 6 +- .../preferences/browser/preferencesService.ts | 2 + .../preferences/common/preferencesModels.ts | 4 +- .../electron-browser/terminalConfigHelper.ts | 4 +- .../terminalConfigHelper.test.ts | 11 +- .../electron-browser/themes.contribution.ts | 4 +- .../watermark/electron-browser/watermark.ts | 4 +- .../page/electron-browser/welcomePage.ts | 4 +- .../electron-browser/walkThroughPart.ts | 6 +- .../configuration/common/configuration.ts | 9 +- .../common/configurationExtensionPoint.ts | 212 ++++++ .../common/configurationModels.ts | 91 ++- .../node/configurationEditingService.ts | 6 +- ...nfiguration.ts => configurationService.ts} | 717 +++++++----------- .../node/configurationEditingService.test.ts | 14 +- ...n.test.ts => configurationService.test.ts} | 62 +- .../node/configurationResolverService.test.ts | 11 +- .../electron-browser/extensionHost.ts | 2 +- .../electron-browser/workbenchThemeService.ts | 16 +- .../workspace/node/workspaceEditingService.ts | 4 +- src/vs/workbench/workbench.main.ts | 3 + 43 files changed, 969 insertions(+), 750 deletions(-) delete mode 100644 src/vs/platform/configuration/common/configuration2.ts create mode 100644 src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts rename src/vs/workbench/services/configuration/node/{configuration.ts => configurationService.ts} (56%) rename src/vs/workbench/services/configuration/test/node/{configuration.test.ts => configurationService.test.ts} (90%) diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts index d268a392aff..7678766238c 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts @@ -123,7 +123,7 @@ export class ReferencesController implements editorCommon.IEditorContribution { switch (kind) { case 'open': if (event.source === 'editor' - && this._configurationService.lookup('editor.stablePeek').value) { + && this._configurationService.getValue('editor.stablePeek')) { // when stable peek is configured we don't close // the peek window on selecting the editor diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 41ddb0f59ee..75aaa4492f9 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -8,7 +8,7 @@ import { Schemas } from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, IConfigurationKeys, IConfigurationValues, Configuration, IConfigurationData, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, Configuration, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IEditor, IEditorInput, IEditorOptions, IEditorService, IResourceInput, Position } from 'vs/platform/editor/common/editor'; import { ICommandService, ICommand, ICommandEvent, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -428,12 +428,19 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { } } +function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { + return thing + && typeof thing === 'object' + && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') + && (!thing.resource || thing.resource instanceof URI); +} + export class SimpleConfigurationService implements IConfigurationService { _serviceBrand: any; - private _onDidUpdateConfiguration = new Emitter(); - public onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidUpdateConfiguration = new Emitter(); + public onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; private _configuration: Configuration; @@ -445,28 +452,40 @@ export class SimpleConfigurationService implements IConfigurationService { return this._configuration; } - public reloadConfiguration(section?: string): TPromise { - return TPromise.as(this.getConfiguration(section)); + getConfiguration(): T + getConfiguration(section: string): T + getConfiguration(overrides: IConfigurationOverrides): T + getConfiguration(section: string, overrides: IConfigurationOverrides): T + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; + return this.configuration().getValue(section, overrides); } - public getConfiguration(section?: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue(section, options); + public getValue(key: string, options?: IConfigurationOverrides): C { + return this.configuration().getValue2(key, options); } - public lookup(key: string, options?: IConfigurationOverrides): IConfigurationValue { + public updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + return TPromise.as(null); + } + + public inspect(key: string, options?: IConfigurationOverrides): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + value: C, + } { return this.configuration().lookup(key, options); } - public keys(): IConfigurationKeys { + public keys() { return this.configuration().keys(); } - public values(): IConfigurationValues { - return this._configuration.values(); - } - - public getConfigurationData(): IConfigurationData { - return this.configuration().toData(); + public reloadConfiguration(): TPromise { + return TPromise.as(null); } } diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 16dc333a62f..20f1b668201 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -9,9 +9,10 @@ import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { StrictResourceMap } from 'vs/base/common/map'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { Workspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; +import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; export const IConfigurationService = createDecorator('configurationService'); @@ -20,80 +21,79 @@ export interface IConfigurationOverrides { resource?: URI; } -export type IConfigurationValues = { [key: string]: IConfigurationValue }; +export enum ConfigurationTarget { + DEFAULT = 1, + USER, + WORKSPACE, + WORKSPACE_FOLDER, + MEMORY +} + +export interface IConfigurationChangeEvent { + keys: string[]; + sections: string[]; + overrideIdentifiers?: string[]; + + hasSectionChanged(section: string): boolean; + hasKeyChanged(key: string): boolean; + + // Following data is used for telemetry + source: ConfigurationTarget; + sourceConfig: any; +} export interface IConfigurationService { _serviceBrand: any; - getConfigurationData(): IConfigurationData; + onDidUpdateConfiguration: Event; - /** - * Fetches the appropriate section of the configuration JSON file. - * This will be an object keyed off the section name. - */ - getConfiguration(section?: string, overrides?: IConfigurationOverrides): T; + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; - /** - * Resolves a configuration key to its values in the different scopes - * the setting is defined. - */ - lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue; + getValue(key: string, overrides?: IConfigurationOverrides): T; - /** - * Returns the defined keys of configurations in the different scopes - * the key is defined. - */ - keys(overrides?: IConfigurationOverrides): IConfigurationKeys; + updateValue(key: string, value: any): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise; + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; - /** - * Similar to #getConfiguration() but ensures that the latest configuration - * from disk is fetched. - */ - reloadConfiguration(section?: string): TPromise; + reloadConfiguration(): TPromise; + reloadConfiguration(folder?: IWorkspaceFolder): TPromise; - /** - * Event that fires when the configuration changes. - */ - onDidUpdateConfiguration: Event; + inspect(key: string): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T, + }; - /** - * Returns the defined values of configurations in the different scopes. - */ - values(): IConfigurationValues; + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + }; } -export enum ConfigurationSource { - Default = 1, - User, - Workspace -} +export function toConfigurationUpdateEvent(udpated: string[], source: ConfigurationTarget, sourceConfig: any): IConfigurationChangeEvent { + const overrideIdentifiers = []; + const keys: string[] = []; + for (const key of udpated) { + if (OVERRIDE_PROPERTY_PATTERN.test(key)) { + overrideIdentifiers.push(key); + } else { + keys.push(key); + } + } + const sections = arrays.distinct(keys.map(key => key.split('.')[0])); + const hasSectionChanged = (section) => sections.indexOf(section) !== -1; + const hasKeyChanged = (key) => keys.indexOf(key) !== -1; -export interface IConfigurationServiceEvent { - /** - * The type of source that triggered this event. - */ - source: ConfigurationSource; - /** - * The part of the configuration contributed by the source of this event. - */ - sourceConfig: any; + return { keys, sections, overrideIdentifiers, source, sourceConfig, hasSectionChanged, hasKeyChanged }; } - -export interface IConfigurationValue { - value: T; - default: T; - user: T; - workspace: T; - folder: T; -} - -export interface IConfigurationKeys { - default: string[]; - user: string[]; - workspace: string[]; - folder: string[]; -} - /** * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting) */ @@ -197,6 +197,22 @@ export class ConfigurationModel implements IConfiguraionModel { } } +export function compare(from: ConfigurationModel, to: ConfigurationModel): { added: string[], removed: string[], updated: string[] } { + const added = to.keys.filter(key => from.keys.indexOf(key) === -1); + const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); + const updated = []; + + for (const key of from.keys) { + const value1 = getConfigurationValue(from.contents, key); + const value2 = getConfigurationValue(to.contents, key); + if (!objects.equals(value1, value2)) { + updated.push(key); + } + } + + return { added, removed, updated }; +} + export interface IConfigurationData { defaults: IConfiguraionModel; user: IConfiguraionModel; @@ -222,6 +238,10 @@ export class Configuration { return this._user; } + get workspace(): ConfigurationModel { + return this._workspaceConfiguration; + } + protected merge(): void { this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); @@ -240,6 +260,12 @@ export class Configuration { return section ? configModel.getContentsFor(section) : configModel.contents; } + getValue2(key: string, overrides: IConfigurationOverrides = {}): any { + // make sure to clone the configuration so that the receiver does not tamper with the values + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); + return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); + } + lookup(key: string, overrides: IConfigurationOverrides = {}): { default: C, user: C, diff --git a/src/vs/platform/configuration/common/configuration2.ts b/src/vs/platform/configuration/common/configuration2.ts deleted file mode 100644 index a3edb5c0048..00000000000 --- a/src/vs/platform/configuration/common/configuration2.ts +++ /dev/null @@ -1,63 +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 { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import Event from 'vs/base/common/event'; - -export const IConfigurationService = createDecorator('configurationService'); - -export interface IConfigurationOverrides { - overrideIdentifier?: string; - resource?: URI; -} - -export enum ConfigurationTarget { - USER, - WORKSPACE, - WORKSPACE_FOLDER, - MEMORY -} - -export interface IConfigurationServiceEvent { - sections: string[]; - keys: string[]; -} - -export interface IConfiguration { - readonly [key: string]: any; -} - -export interface IConfigurationService { - _serviceBrand: any; - - onDidUpdateConfiguration: Event; - - getConfiguration(): T; - getConfiguration(section: string): T; - getConfiguration(overrides: IConfigurationOverrides): T; - getConfiguration(section: string, overrides: IConfigurationOverrides): T; - - updateConfiguration(key: string, value: any): TPromise; - updateConfiguration(key: string, value: any, overrides: IConfigurationOverrides): TPromise; - updateConfiguration(key: string, value: any, target: ConfigurationTarget): TPromise; - updateConfiguration(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; - - inspect(key: string): { - default: T, - user: T, - workspace: T, - workspaceFolder: T - value: T, - }; - - keys(): { - default: string[]; - user: string[]; - workspace: string[]; - workspaceFolder: string[]; - }; -} \ No newline at end of file diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index f93837028b1..83d78eda6da 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -32,10 +32,10 @@ export interface IConfigurationRegistry { registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void; /** - * Event that fires whenver a configuratio has been + * Event that fires whenver a configuration has been * registered. */ - onDidRegisterConfiguration: Event; + onDidRegisterConfiguration: Event; /** * Returns all configuration nodes contributed to this registry. @@ -97,8 +97,8 @@ class ConfigurationRegistry implements IConfigurationRegistry { private overrideIdentifiers: string[] = []; private overridePropertyPattern: string; - private _onDidRegisterConfiguration: Emitter = new Emitter(); - readonly onDidRegisterConfiguration: Event = this._onDidRegisterConfiguration.event; + private _onDidRegisterConfiguration: Emitter = new Emitter(); + readonly onDidRegisterConfiguration: Event = this._onDidRegisterConfiguration.event; constructor() { this.configurationContributors = []; @@ -114,14 +114,15 @@ class ConfigurationRegistry implements IConfigurationRegistry { } public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void { + const properties = []; configurations.forEach(configuration => { - this.validateAndRegisterProperties(configuration, validate); // fills in defaults + properties.push(this.validateAndRegisterProperties(configuration, validate)); // fills in defaults this.configurationContributors.push(configuration); this.registerJSONConfiguration(configuration); this.updateSchemaForOverrideSettingsConfiguration(configuration); }); - this._onDidRegisterConfiguration.fire(configurations); + this._onDidRegisterConfiguration.fire(properties); } public registerOverrideIdentifiers(overrideIdentifiers: string[]): void { @@ -153,9 +154,10 @@ class ConfigurationRegistry implements IConfigurationRegistry { } } - private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, overridable: boolean = false) { + private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, overridable: boolean = false): string[] { scope = configuration.scope !== void 0 && configuration.scope !== null ? configuration.scope : scope; overridable = configuration.overridable || overridable; + let propertyKeys = []; let properties = configuration.properties; if (properties) { for (let key in properties) { @@ -180,14 +182,16 @@ class ConfigurationRegistry implements IConfigurationRegistry { } // add to properties map this.configurationProperties[key] = properties[key]; + propertyKeys.push(key); } } let subNodes = configuration.allOf; if (subNodes) { for (let node of subNodes) { - this.validateAndRegisterProperties(node, validate, scope, overridable); + propertyKeys.push(...this.validateAndRegisterProperties(node, validate, scope, overridable)); } } + return propertyKeys; } validateProperty(property: string): boolean { @@ -302,4 +306,4 @@ export function validateProperty(property: string): string { return nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", property); } return null; -} +} \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 843cd285b4d..0d97199766b 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -6,14 +6,24 @@ import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationServiceEvent, IConfigurationOverrides, IConfiguration } from 'vs/platform/configuration/common/configuration2'; -import { ConfigurationModel, Configuration } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, toConfigurationUpdateEvent, ConfigurationModel, Configuration, compare } from 'vs/platform/configuration/common/configuration'; import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { onUnexpectedError } from 'vs/base/common/errors'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { equals } from 'vs/base/common/objects'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; + +export function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { + return thing + && typeof thing === 'object' + && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') + && (!thing.resource || thing.resource instanceof URI); +} export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { @@ -22,8 +32,8 @@ export class ConfigurationService extends Disposable implements IConfiguratio private _configuration: Configuration; private userConfigModelWatcher: ConfigWatcher>; - private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); + readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; constructor( @IEnvironmentService environmentService: IEnvironmentService @@ -39,38 +49,40 @@ export class ConfigurationService extends Disposable implements IConfiguratio }); this._register(this.userConfigModelWatcher); + this.reset(); + // Listeners this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onDidUpdateConfigModel())); - this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(configurationNodes => this.onDidRegisterConfiguration(configurationNodes))); + this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(configurationProperties => this.onDidRegisterConfiguration(configurationProperties))); } - public get configuration(): Configuration { - return this._configuration || (this._configuration = this.consolidateConfigurations()); + get configuration(): Configuration { + return this._configuration; } - private onDidUpdateConfigModel(): void { - // get the diff - // reset and trigger - this.onConfigurationChange([], []); + getConfiguration(): T + getConfiguration(section: string): T + getConfiguration(overrides: IConfigurationOverrides): T + getConfiguration(section: string, overrides: IConfigurationOverrides): T + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; + return this.configuration.getValue(section, overrides); } - private onDidRegisterConfiguration(configurations: IConfigurationNode[]): void { - // get the diff - // reset and trigger - this.onConfigurationChange([], []); + getValue(key: string, overrides: IConfigurationOverrides): any { + return this.configuration.getValue2(key, overrides); } - private onConfigurationChange(sections: string[], keys: string[]): void { - this.reset(); // reset our caches - - this._onDidUpdateConfiguration.fire({ sections, keys }); + updateValue(key: string, value: any): TPromise + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise + updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + return TPromise.wrapError(new Error('not supported')); } - public getConfiguration(section?: string, options?: IConfigurationOverrides): IConfiguration { - return this.configuration.getValue(section, options); - } - - public inspect(key: string): { + inspect(key: string): { default: T, user: T, workspace: T, @@ -80,7 +92,7 @@ export class ConfigurationService extends Disposable implements IConfiguratio return this.configuration.lookup(key); } - public keys(): { + keys(): { default: string[]; user: string[]; workspace: string[]; @@ -89,13 +101,47 @@ export class ConfigurationService extends Disposable implements IConfiguratio return this.configuration.keys(); } - private reset(): void { - this._configuration = this.consolidateConfigurations(); + reloadConfiguration(folder?: IWorkspaceFolder): TPromise { + return folder ? TPromise.as(null) : + new TPromise((c, e) => this.userConfigModelWatcher.reload(() => c(this.onDidUpdateConfigModel()))); } - private consolidateConfigurations(): Configuration { + private onDidUpdateConfigModel(): void { + let changedKeys = []; + const { added, updated, removed } = compare(this._configuration.user, this.userConfigModelWatcher.getConfig()); + changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = this._configuration; + this.reset(); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this._configuration.getValue2(key))); + if (changedKeys.length) { + this.trigger(changedKeys, ConfigurationTarget.USER); + } + } + } + + private onDidRegisterConfiguration(keys: string[]): void { + this.reset(); // reset our caches + this.trigger(keys, ConfigurationTarget.DEFAULT); + } + + private reset(): void { const defaults = new DefaultConfigurationModel(); const user = this.userConfigModelWatcher.getConfig(); - return new Configuration(defaults, user); + this._configuration = new Configuration(defaults, user); + } + + private trigger(keys: string[], source: ConfigurationTarget): void { + this._onDidUpdateConfiguration.fire(toConfigurationUpdateEvent(keys, source, this.getTargetConfiguration(source))); + } + + private getTargetConfiguration(target: ConfigurationTarget): any { + switch (target) { + case ConfigurationTarget.DEFAULT: + return this._configuration.defaults.contents; + case ConfigurationTarget.USER: + return this._configuration.user.contents; + } + return {}; } } \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index aed4574d678..5653f211b14 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -10,7 +10,7 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; import { getConfigurationKeys } from 'vs/platform/configuration/common/model'; -import { IConfigurationOverrides, IConfigurationService, getConfigurationValue, IConfigurationValue, IConfigurationKeys, IConfigurationValues, IConfigurationData, Configuration, ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationOverrides, IConfigurationService, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService extends EventEmitter implements IConfigurationService { public _serviceBrand: any; @@ -19,11 +19,11 @@ export class TestConfigurationService extends EventEmitter implements IConfigura private configurationByRoot: TernarySearchTree = TernarySearchTree.forPaths(); - public reloadConfiguration(section?: string): TPromise { + public reloadConfiguration(): TPromise { return TPromise.as(this.getConfiguration()); } - public getConfiguration(section?: string, overrides?: IConfigurationOverrides): any { + public getConfiguration(section?: any, overrides?: any): C { if (overrides && overrides.resource) { const configForResource = this.configurationByRoot.findSubstr(overrides.resource.fsPath); return configForResource || this.configuration; @@ -32,8 +32,12 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return this.configuration; } - public getConfigurationData(): IConfigurationData { - return new Configuration(new ConfigurationModel(), new ConfigurationModel(this.configuration)).toData(); + public getValue(key: string, overrides?: IConfigurationOverrides): any { + return this.inspect(key).value; + } + + public updateValue(key: string, overrides?: IConfigurationOverrides): TPromise { + return TPromise.as(null); } public setUserConfiguration(key: any, value: any, root?: URI): Thenable { @@ -52,28 +56,30 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return { dispose() { } }; } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { + public inspect(key: string, overrides?: IConfigurationOverrides): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T, + } { const config = this.getConfiguration(undefined, overrides); return { - value: getConfigurationValue(config, key), - default: getConfigurationValue(config, key), - user: getConfigurationValue(config, key), + value: getConfigurationValue(config, key), + default: getConfigurationValue(config, key), + user: getConfigurationValue(config, key), workspace: null, - folder: null + workspaceFolder: null }; } - public keys(): IConfigurationKeys { + public keys() { return { default: getConfigurationKeys(), user: Object.keys(this.configuration), workspace: [], - folder: [] + workspaceFolder: [] }; } - - public values(): IConfigurationValues { - return {}; - } } diff --git a/src/vs/platform/configuration/test/node/configurationService.test.ts b/src/vs/platform/configuration/test/node/configurationService.test.ts index 594a6eb5287..60652d4b614 100644 --- a/src/vs/platform/configuration/test/node/configurationService.test.ts +++ b/src/vs/platform/configuration/test/node/configurationService.test.ts @@ -122,7 +122,8 @@ suite('ConfigurationService - Node', () => { assert.equal(config.foo, 'bar'); // force a reload to get latest - service.reloadConfiguration<{ foo: string }>().then(config => { + service.reloadConfiguration().then(() => { + config = service.getConfiguration<{ foo: string }>(); assert.ok(config); assert.equal(config.foo, 'changed'); @@ -202,12 +203,12 @@ suite('ConfigurationService - Node', () => { testFile((testFile, cleanUp) => { const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile)); - let res = service.lookup('something.missing'); + let res = service.inspect('something.missing'); assert.strictEqual(res.value, void 0); assert.strictEqual(res.default, void 0); assert.strictEqual(res.user, void 0); - res = service.lookup('lookup.service.testSetting'); + res = service.inspect('lookup.service.testSetting'); assert.strictEqual(res.default, 'isSet'); assert.strictEqual(res.value, 'isSet'); assert.strictEqual(res.user, void 0); @@ -215,7 +216,7 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(testFile, '{ "lookup.service.testSetting": "bar" }'); return service.reloadConfiguration().then(() => { - res = service.lookup('lookup.service.testSetting'); + res = service.inspect('lookup.service.testSetting'); assert.strictEqual(res.default, 'isSet'); assert.strictEqual(res.user, 'bar'); assert.strictEqual(res.value, 'bar'); @@ -242,7 +243,7 @@ suite('ConfigurationService - Node', () => { testFile((testFile, cleanUp) => { const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile)); - let res = service.lookup('lookup.service.testNullSetting'); + let res = service.inspect('lookup.service.testNullSetting'); assert.strictEqual(res.default, null); assert.strictEqual(res.value, null); assert.strictEqual(res.user, void 0); @@ -250,7 +251,7 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(testFile, '{ "lookup.service.testNullSetting": null }'); return service.reloadConfiguration().then(() => { - res = service.lookup('lookup.service.testNullSetting'); + res = service.inspect('lookup.service.testNullSetting'); assert.strictEqual(res.default, null); assert.strictEqual(res.value, null); assert.strictEqual(res.user, null); diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index a910df65983..9ef38db2fa9 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -9,7 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { guessMimeTypes } from 'vs/base/common/mime'; import paths = require('vs/base/common/paths'); import URI from 'vs/base/common/uri'; -import { ConfigurationSource, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; @@ -186,7 +186,7 @@ const configurationValueWhitelist = [ export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable { return configurationService.onDidUpdateConfiguration(event => { - if (event.source !== ConfigurationSource.Default) { + if (event.source !== ConfigurationTarget.DEFAULT) { /* __GDPR__ "updateConfiguration" : { "configurationSource" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -194,7 +194,7 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf } */ telemetryService.publicLog('updateConfiguration', { - configurationSource: ConfigurationSource[event.source], + configurationSource: ConfigurationTarget[event.source], configurationKeys: flattenKeys(event.sourceConfig) }); /* __GDPR__ @@ -204,7 +204,7 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf } */ telemetryService.publicLog('updateConfigurationValues', { - configurationSource: ConfigurationSource[event.source], + configurationSource: ConfigurationTarget[event.source], configurationValues: flattenValues(event.sourceConfig, configurationValueWhitelist) }); } diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index 494159a5f56..45173045d9a 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -681,24 +681,24 @@ suite('TelemetryService', () => { enableTelemetry: enableTelemetry } as any; }, - getConfigurationData(): any { + getValue(key) { + return getConfigurationValue(this.getConfiguration(), key); + }, + updateValue() { return null; }, - reloadConfiguration() { - return TPromise.as(this.getConfiguration()); - }, - lookup(key: string) { + inspect(key: string) { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: null, - folder: null + workspaceFolder: null }; }, - keys() { return { default: [], user: [], workspace: [], folder: [] }; }, - values() { return {}; }, - onDidUpdateConfiguration: emitter.event + keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, + onDidUpdateConfiguration: emitter.event, + reloadConfiguration() { return null; } }); assert.equal(service.isOptedIn, false); diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 71f54113cfd..46648b2b1ae 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -29,7 +29,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); this._configurationListener = configurationService.onDidUpdateConfiguration(() => { - proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); + proxy.$acceptConfigurationChanged(configurationService.getConfiguration()); }); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts index 777ec4918af..d46aff79813 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts @@ -41,7 +41,7 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant { } public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { - if (this.configurationService.lookup('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) { + if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -99,7 +99,7 @@ export class FinalNewLineParticipant implements INamedSaveParticpant { } public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { - if (this.configurationService.lookup('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) { + if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doInsertFinalNewLine(model.textEditorModel); } } @@ -139,7 +139,7 @@ export class TrimFinalNewLinesParticipant implements INamedSaveParticpant { } public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { - if (this.configurationService.lookup('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) { + if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doTrimFinalNewLines(model.textEditorModel); } } @@ -189,7 +189,7 @@ class FormatOnSaveParticipant implements INamedSaveParticpant { const model = editorModel.textEditorModel; if (env.reason === SaveReason.AUTO - || !this._configurationService.lookup('editor.formatOnSave', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }).value) { + || !this._configurationService.getValue('editor.formatOnSave', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() })) { return undefined; } diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 931b01fc875..9e5101340bf 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -104,7 +104,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { defaultValue: config.default, globalValue: config.user, workspaceValue: config.workspace, - workspaceFolderValue: config.folder + workspaceFolderValue: config.workspaceFolder }; } return undefined; diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 28a91b2db63..ab16b258da8 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -966,7 +966,7 @@ export class ChangeModeAction extends Action { TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).done(() => { this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).done(language => { if (language) { - const fileAssociationsConfig = this.configurationService.lookup(ChangeModeAction.FILE_ASSOCIATION_KEY); + const fileAssociationsConfig = this.configurationService.inspect(ChangeModeAction.FILE_ASSOCIATION_KEY); let associationKey: string; if (extension && basename[0] !== '.') { diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 806c5d7d2c8..bfba7464b3d 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -118,7 +118,7 @@ export class TitlebarPart extends Part implements ITitleService { private onConfigurationChanged(update?: boolean): void { const currentTitleTemplate = this.titleTemplate; - this.titleTemplate = this.configurationService.lookup('window.title').value; + this.titleTemplate = this.configurationService.getValue('window.title'); if (update && currentTitleTemplate !== this.titleTemplate) { this.setTitle(this.getWindowTitle()); diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 67796b9bc2f..70406345142 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -164,7 +164,7 @@ export class ToggleMenuBarAction extends Action { } public run(): TPromise { - let currentVisibilityValue = this.configurationService.lookup(ToggleMenuBarAction.menuBarVisibilityKey).value; + let currentVisibilityValue = this.configurationService.getValue(ToggleMenuBarAction.menuBarVisibilityKey); if (typeof currentVisibilityValue !== 'string') { currentVisibilityValue = 'default'; } @@ -210,7 +210,7 @@ export abstract class BaseZoomAction extends Action { protected setConfiguredZoomLevel(level: number): void { let target = ConfigurationTarget.USER; - if (typeof this.configurationService.lookup(BaseZoomAction.SETTING_KEY).workspace === 'number') { + if (typeof this.configurationService.inspect(BaseZoomAction.SETTING_KEY).workspace === 'number') { target = ConfigurationTarget.WORKSPACE; } diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index f461e27e464..7784777acea 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -17,7 +17,7 @@ import paths = require('vs/base/common/paths'); import uri from 'vs/base/common/uri'; import strings = require('vs/base/common/strings'); import { IWorkspaceContextService, Workspace, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { realpath } from 'vs/base/node/pfs'; diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index bdf4e7eeef2..d90e9c76efc 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -498,7 +498,7 @@ export class ElectronWindow extends Themable { } private toggleAutoSave(): void { - const setting = this.configurationService.lookup(ElectronWindow.AUTO_SAVE_SETTING); + const setting = this.configurationService.inspect(ElectronWindow.AUTO_SAVE_SETTING); let userAutoSaveConfig = setting.user; if (types.isUndefinedOrNull(userAutoSaveConfig)) { userAutoSaveConfig = setting.default; // use default if setting not defined diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index c565be4c877..59b300fc28b 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -46,7 +46,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; @@ -407,7 +407,7 @@ export class Workbench implements IPartService { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File")); // Actions for macOS native tabs management (only when enabled) - const windowConfig = this.configurationService.getConfiguration(); + const windowConfig = this.configurationService.getConfiguration(); if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab'); @@ -484,13 +484,13 @@ export class Workbench implements IPartService { } private openUntitledFile() { - const startupEditor = this.configurationService.lookup('workbench.startupEditor'); + const startupEditor = this.configurationService.inspect('workbench.startupEditor'); // Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined if (!startupEditor.user && !startupEditor.workspace) { - const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled'); - if (typeof welcomeEnabled.value === 'boolean') { - return !welcomeEnabled.value; + const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled'); + if (typeof welcomeEnabledValue === 'boolean') { + return !welcomeEnabledValue; } } @@ -639,19 +639,19 @@ export class Workbench implements IPartService { } // Sidebar position - const sideBarPosition = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + const sideBarPosition = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT; // Statusbar visibility - const statusBarVisible = this.configurationService.lookup(Workbench.statusbarVisibleConfigurationKey).value; + const statusBarVisible = this.configurationService.getValue(Workbench.statusbarVisibleConfigurationKey); this.statusBarHidden = !statusBarVisible; // Activity bar visibility - const activityBarVisible = this.configurationService.lookup(Workbench.activityBarVisibleConfigurationKey).value; + const activityBarVisible = this.configurationService.getValue(Workbench.activityBarVisibleConfigurationKey); this.activityBarHidden = !activityBarVisible; // Font aliasing - this.fontAliasing = this.configurationService.lookup(Workbench.fontAliasingConfigurationKey).value; + this.fontAliasing = this.configurationService.getValue(Workbench.fontAliasingConfigurationKey); // Zen mode this.zenMode = { @@ -1036,7 +1036,7 @@ export class Workbench implements IPartService { // Overruled by: window has a workspace opened or this window is for extension development // or setting is disabled. Also enabled when running with --wait from the command line. if (visibleEditors === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) { - const closeWhenEmpty = this.configurationService.lookup(Workbench.closeWhenEmptyConfigurationKey).value; + const closeWhenEmpty = this.configurationService.getValue(Workbench.closeWhenEmptyConfigurationKey); if (closeWhenEmpty || this.environmentService.args.wait) { this.closeEmptyWindowScheduler.schedule(); } @@ -1068,24 +1068,24 @@ export class Workbench implements IPartService { } private onDidUpdateConfiguration(skipLayout?: boolean): void { - const newSidebarPositionValue = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + const newSidebarPositionValue = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT; if (newSidebarPosition !== this.getSideBarPosition()) { this.setSideBarPosition(newSidebarPosition); } - const fontAliasing = this.configurationService.lookup(Workbench.fontAliasingConfigurationKey).value; + const fontAliasing = this.configurationService.getValue(Workbench.fontAliasingConfigurationKey); if (fontAliasing !== this.fontAliasing) { this.setFontAliasing(fontAliasing); } if (!this.zenMode.active) { - const newStatusbarHiddenValue = !this.configurationService.lookup(Workbench.statusbarVisibleConfigurationKey).value; + const newStatusbarHiddenValue = !this.configurationService.getValue(Workbench.statusbarVisibleConfigurationKey); if (newStatusbarHiddenValue !== this.statusBarHidden) { this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout); } - const newActivityBarHiddenValue = !this.configurationService.lookup(Workbench.activityBarVisibleConfigurationKey).value; + const newActivityBarHiddenValue = !this.configurationService.getValue(Workbench.activityBarVisibleConfigurationKey); if (newActivityBarHiddenValue !== this.activityBarHidden) { this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout); } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts b/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts index 83b7176dcbc..e2e99c99949 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts @@ -83,7 +83,7 @@ class WordWrapMigrationController extends Disposable implements IEditorContribut } WordWrapMigrationController._checked = true; - let result = this.configurationService.lookup('editor.wrappingColumn'); + let result = this.configurationService.inspect('editor.wrappingColumn'); if (typeof result.value === 'undefined') { // Setting is not used return; diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index 346461ba287..18b677b7f61 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -55,7 +55,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { private registerListeners(): void { this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.sourceConfig.launch) { + if (e.hasSectionChanged('launch')) { this.updateOptions(); } })); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 3ea09044e57..15d1484701b 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -648,7 +648,7 @@ export class DebugService implements debug.IDebugService { public startDebugging(root: IWorkspaceFolder, configOrName?: debug.IConfig | string, noDebug = false, topCompoundName?: string): TPromise { // make sure to save all files and that the configuration is up to date - return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration().then(() => + return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(root).then(() => this.extensionService.onReady().then(() => { if (this.model.getProcesses().length === 0) { this.removeReplExpressions(); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index d74dd56da46..e3491f2e20a 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -561,8 +561,10 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr range, options: { stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'findMatch' - } + className: 'findMatch', + + }, + }; } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 5e5597721c6..b8e39c05e11 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -129,6 +129,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic .then(preferencesEditorModel => preferencesEditorModel ? preferencesEditorModel.content : null); } + // vsode://DefaultSettings/1 createPreferencesEditorModel(uri: URI): TPromise> { let promise = this.defaultPreferencesEditorModels.get(uri); if (promise) { @@ -264,6 +265,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource) .then(editableSettingsEditorInput => { if (openDefaultSettings) { + // get a new URI for default settings here const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget)); const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, editableSettingsEditorInput); this.lastOpenedSettingsInput = preferencesEditorInput; diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index f17231a589b..26e4c93d348 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -244,7 +244,9 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti constructor(reference: IReference, private _configurationTarget: ConfigurationTarget, @ITextFileService protected textFileService: ITextFileService) { super(); this.settingsModel = reference.object.textEditorModel; - this._register(this.onDispose(() => reference.dispose())); + this._register(this.onDispose(() => { + reference.dispose(); + })); this._register(this.settingsModel.onDidChangeContent(() => { this._settingsGroups = null; })); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts index 6507587aa97..a5e20e79b5d 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts @@ -114,8 +114,8 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig): void { // Check whether there is a workspace setting const platformKey = platform.isWindows ? 'windows' : platform.isMacintosh ? 'osx' : 'linux'; - const shellConfigValue = this._workspaceConfigurationService.lookup(`terminal.integrated.shell.${platformKey}`); - const shellArgsConfigValue = this._workspaceConfigurationService.lookup(`terminal.integrated.shellArgs.${platformKey}`); + const shellConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shell.${platformKey}`); + const shellArgsConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shellArgs.${platformKey}`); // Check if workspace setting exists and whether it's whitelisted let isWorkspaceShellAllowed = false; diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts index e95533d078f..faa3f2ac009 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import { IConfigurationService, getConfigurationValue, IConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { Platform } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; @@ -17,13 +17,14 @@ class MockConfigurationService implements IConfigurationService { public _serviceBrand: any; public serviceId = IConfigurationService; public constructor(private configuration: any = {}) { } - public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; } - public keys() { return { default: [], user: [], workspace: [], folder: [] }; } - public values() { return {}; } + public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, workspaceFolder: void 0 }; } + public keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; } public getConfiguration(): any { return this.configuration; } + public getValue(key: string, overrides?: IConfigurationOverrides): T { return getConfigurationValue(this.getConfiguration(), key); } + public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } public onDidUpdateConfiguration() { return { dispose() { } }; } + public reloadConfiguration() { return null; } } suite('Workbench - TerminalConfigHelper', () => { diff --git a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts index 2c44384ef13..10069d1f991 100644 --- a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts +++ b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts @@ -60,7 +60,7 @@ export class SelectColorThemeAction extends Action { } let target = null; if (applyTheme) { - let confValue = this.configurationService.lookup(COLOR_THEME_SETTING); + let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } @@ -126,7 +126,7 @@ class SelectIconThemeAction extends Action { } let target = null; if (applyTheme) { - let confValue = this.configurationService.lookup(ICON_THEME_SETTING); + let confValue = this.configurationService.inspect(ICON_THEME_SETTING); target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } this.themeService.setFileIconTheme(theme && theme.id, target).done(null, diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 5420ab82b04..21c46e71bdd 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -120,13 +120,13 @@ export class WatermarkContribution implements IWorkbenchContribution { lifecycleService.onShutdown(this.dispose, this); this.partService.joinCreation().then(() => { - this.enabled = this.configurationService.lookup('workbench.tips.enabled').value; + this.enabled = this.configurationService.getValue('workbench.tips.enabled'); if (this.enabled) { this.create(); } }); this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - const enabled = this.configurationService.lookup('workbench.tips.enabled').value; + const enabled = this.configurationService.getValue('workbench.tips.enabled'); if (enabled !== this.enabled) { this.enabled = enabled; if (this.enabled) { diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index 93be1d9e534..c54020a8d3f 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -83,9 +83,9 @@ export class WelcomePageContribution implements IWorkbenchContribution { } function isWelcomePageEnabled(configurationService: IConfigurationService) { - const startupEditor = configurationService.lookup(configurationKey); + const startupEditor = configurationService.inspect(configurationKey); if (!startupEditor.user && !startupEditor.workspace) { - const welcomeEnabled = configurationService.lookup(oldConfigurationKey); + const welcomeEnabled = configurationService.inspect(oldConfigurationKey); if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) { return welcomeEnabled.value; } diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts index 3795d6aabd1..173483768ba 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts @@ -285,7 +285,7 @@ export class WalkThroughPart extends BaseEditor { } private getArrowScrollHeight() { - let fontSize = this.configurationService.lookup('editor.fontSize').value; + let fontSize = this.configurationService.getValue('editor.fontSize'); if (typeof fontSize !== 'number' || fontSize < 1) { fontSize = 12; } @@ -510,8 +510,8 @@ export class WalkThroughPart extends BaseEditor { private multiCursorModifier() { const labels = UILabelProvider.modifierLabels[OS]; - const setting = this.configurationService.lookup('editor.multiCursorModifier'); - const modifier = labels[setting.value === 'ctrlCmd' ? (OS === OperatingSystem.Macintosh ? 'metaKey' : 'ctrlKey') : 'altKey']; + const value = this.configurationService.getValue('editor.multiCursorModifier'); + const modifier = labels[value === 'ctrlCmd' ? (OS === OperatingSystem.Macintosh ? 'metaKey' : 'ctrlKey') : 'altKey']; const keys = this.content.querySelectorAll('.multi-cursor-modifier'); Array.prototype.forEach.call(keys, (key: Element) => { while (key.firstChild) { diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 9dffb9cba33..3d4eb1394b2 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IConfigurationService } from 'vs/platform/configuration/common/configuration2'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const CONFIG_DEFAULT_NAME = 'settings'; @@ -13,14 +13,17 @@ export const WORKSPACE_CONFIG_DEFAULT_PATH = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_ export const IWorkspaceConfigurationService = createDecorator('configurationService'); export interface IWorkspaceConfigurationService extends IConfigurationService { - /** * Returns untrusted configuration keys for the current workspace. */ getUnsupportedWorkspaceKeys(): string[]; - } +export const defaultSettingsSchemaId = 'vscode://schemas/settings/default'; +export const userSettingsSchemaId = 'vscode://schemas/settings/user'; +export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; +export const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; + export const TASKS_CONFIGURATION_KEY = 'tasks'; export const LAUNCH_CONFIGURATION_KEY = 'launch'; diff --git a/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts b/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts new file mode 100644 index 00000000000..7614f64f2e3 --- /dev/null +++ b/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts @@ -0,0 +1,212 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as objects from 'vs/base/common/objects'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { workspaceSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; + +const configurationRegistry = Registry.as(Extensions.Configuration); + +const configurationEntrySchema: IJSONSchema = { + type: 'object', + defaultSnippets: [{ body: { title: '', properties: {} } }], + properties: { + title: { + description: nls.localize('vscode.extension.contributes.configuration.title', 'A summary of the settings. This label will be used in the settings file as separating comment.'), + type: 'string' + }, + properties: { + description: nls.localize('vscode.extension.contributes.configuration.properties', 'Description of the configuration properties.'), + type: 'object', + additionalProperties: { + anyOf: [ + { $ref: 'http://json-schema.org/draft-04/schema#' }, + { + type: 'object', + properties: { + isExecutable: { + type: 'boolean' + }, + scope: { + type: 'string', + enum: ['window', 'resource'], + default: 'window', + enumDescriptions: [ + nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."), + nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.") + ], + description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.") + } + } + } + ] + } + } + } +}; + + +// BEGIN VSCode extension point `configuration` +const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configuration', [], { + description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'), + oneOf: [ + configurationEntrySchema, + { + type: 'array', + items: configurationEntrySchema + } + ] +}); +configurationExtPoint.setHandler(extensions => { + const configurations: IConfigurationNode[] = []; + + function handleConfiguration(node: IConfigurationNode, id: string, collector: ExtensionMessageCollector) { + let configuration = objects.clone(node); + + if (configuration.title && (typeof configuration.title !== 'string')) { + collector.error(nls.localize('invalid.title', "'configuration.title' must be a string")); + } + + validateProperties(configuration, collector); + + configuration.id = id; + configurations.push(configuration); + }; + + for (let extension of extensions) { + const collector = extension.collector; + const value = extension.value; + const id = extension.description.id; + if (!Array.isArray(value)) { + handleConfiguration(value, id, collector); + } else { + value.forEach(v => handleConfiguration(v, id, collector)); + } + } + configurationRegistry.registerConfigurations(configurations, false); +}); +// END VSCode extension point `configuration` + +// BEGIN VSCode extension point `configurationDefaults` +const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configurationDefaults', [], { + description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'), + type: 'object', + defaultSnippets: [{ body: {} }], + patternProperties: { + '\\[.*\\]$': { + type: 'object', + default: {}, + $ref: editorConfigurationSchemaId, + } + } +}); +defaultConfigurationExtPoint.setHandler(extensions => { + const defaultConfigurations: IDefaultConfigurationExtension[] = extensions.map(extension => { + const id = extension.description.id; + const name = extension.description.name; + const defaults = objects.clone(extension.value); + return { + id, name, defaults + }; + }); + configurationRegistry.registerDefaultConfigurations(defaultConfigurations); +}); +// END VSCode extension point `configurationDefaults` + +function validateProperties(configuration: IConfigurationNode, collector: ExtensionMessageCollector): void { + let properties = configuration.properties; + if (properties) { + if (typeof properties !== 'object') { + collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); + configuration.properties = {}; + } + for (let key in properties) { + const message = validateProperty(key); + const propertyConfiguration = configuration.properties[key]; + propertyConfiguration.scope = propertyConfiguration.scope && propertyConfiguration.scope.toString() === 'resource' ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW; + propertyConfiguration.isFromExtensions = true; + if (message) { + collector.warn(message); + delete properties[key]; + } + } + } + let subNodes = configuration.allOf; + if (subNodes) { + collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point.")); + for (let node of subNodes) { + validateProperties(node, collector); + } + } +} + +const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); +jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', { + default: { + folders: [ + { + path: '' + } + ], + settings: { + } + }, + required: ['folders'], + properties: { + 'folders': { + minItems: 0, + uniqueItems: true, + description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace."), + items: { + type: 'object', + default: { path: '' }, + oneOf: [{ + properties: { + path: { + type: 'string', + description: nls.localize('workspaceConfig.path.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } + }, + required: ['path'] + }, { + properties: { + uri: { + type: 'string', + description: nls.localize('workspaceConfig.uri.description', "URI of the folder") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } + }, + required: ['uri'] + }] + } + }, + 'settings': { + type: 'object', + default: {}, + description: nls.localize('workspaceConfig.settings.description', "Workspace settings"), + $ref: workspaceSettingsSchemaId + }, + 'extensions': { + type: 'object', + default: {}, + description: nls.localize('workspaceConfig.extensions.description', "Workspace extensions"), + $ref: 'vscode://schemas/extensions' + } + }, + additionalProperties: false, + errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property") +}); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index dd7f73103ed..b23dc396e7c 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -4,13 +4,16 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { clone } from 'vs/base/common/objects'; +import { clone, equals } from 'vs/base/common/objects'; import { CustomConfigurationModel, toValuesTree } from 'vs/platform/configuration/common/model'; -import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel, Configuration as BaseConfiguration, compare } from 'vs/platform/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { StrictResourceMap } from 'vs/base/common/map'; +import URI from 'vs/base/common/uri'; export class WorkspaceConfigurationModel extends CustomConfigurationModel { @@ -178,4 +181,88 @@ export class FolderConfigurationModel extends CustomConfigurationModel { this.workspaceSettingsConfig.reprocess(); this.consolidate(); } +} + +export class Configuration extends BaseConfiguration { + + constructor(defaults: ConfigurationModel, user: ConfigurationModel, workspaceConfiguration: ConfigurationModel, protected folders: StrictResourceMap>, workspace: Workspace) { + super(defaults, user, workspaceConfiguration, folders, workspace); + } + + updateDefaultConfiguration(defaults: ConfigurationModel): void { + this._defaults = defaults; + this.merge(); + } + + updateUserConfiguration(user: ConfigurationModel): string[] { + let changedKeys = []; + const { added, updated, removed } = compare(this._user, user); + changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + + this._user = user; + this.merge(); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this.getValue2(key))); + return changedKeys; + } + return []; + } + + updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): string[] { + let changedKeys = []; + const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration); + changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + + this._workspaceConfiguration = workspaceConfiguration; + this.merge(); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this.getValue2(key))); + return changedKeys; + } + return []; + } + + updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): string[] { + const currentFolderConfiguration = this.folders.get(resource); + + if (currentFolderConfiguration) { + let changedKeys = []; + const { added, updated, removed } = compare(currentFolderConfiguration, configuration); + changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + + this.folders.set(resource, configuration); + this.mergeFolder(resource); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key, { resource }), this.getValue2(key, { resource }))); + return changedKeys; + } + return []; + } + + this.folders.set(resource, configuration); + this.mergeFolder(resource); + return configuration.keys; + } + + deleteFolderConfiguration(folder: URI): string[] { + if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) { + // Do not remove workspace configuration + return []; + } + + const keys = this.folders.get(folder).keys; + this.folders.delete(folder); + this._foldersConsolidatedConfigurations.delete(folder); + return keys; + } + + getFolderConfigurationModel(folder: URI): FolderConfigurationModel { + return >this.folders.get(folder); + } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index 9787cfcbc1c..694c6122734 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -27,7 +27,7 @@ import { IConfigurationService, IConfigurationOverrides } from 'vs/platform/conf import { keyFromOverrideIdentifier } from 'vs/platform/configuration/common/model'; import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; -import { IConfigurationEditingService, ConfigurationEditingErrorCode, ConfigurationEditingError, ConfigurationTarget, IConfigurationValue, IConfigurationEditingOptions } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError, IConfigurationValue, IConfigurationEditingOptions, IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message'; @@ -95,9 +95,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise { const edit = this.getEdits(model, operation)[0]; if (this.applyEditsToBuffer(edit, model) && save) { - return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }) - // Reload the configuration so that we make sure all parties are updated - .then(() => this.configurationService.reloadConfiguration()); + return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }); } return TPromise.as(null); } diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configurationService.ts similarity index 56% rename from src/vs/workbench/services/configuration/node/configuration.ts rename to src/vs/workbench/services/configuration/node/configurationService.ts index 74556f8b5ab..f5b7cef1e68 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -9,8 +9,8 @@ import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; import { StrictResourceMap } from 'vs/base/common/map'; -import * as objects from 'vs/base/common/objects'; import * as errors from 'vs/base/common/errors'; +import { equals } from 'vs/base/common/objects'; import * as collections from 'vs/base/common/collections'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -23,27 +23,23 @@ import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { CustomConfigurationModel } from 'vs/platform/configuration/common/model'; -import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels'; -import { IConfigurationServiceEvent, ConfigurationSource, IConfigurationKeys, IConfigurationValue, ConfigurationModel, IConfigurationOverrides, Configuration as BaseConfiguration, IConfigurationValues, IConfigurationData } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; -import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import * as nls from 'vs/nls'; +import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration } from 'vs/workbench/services/configuration/common/configurationModels'; +import { IConfigurationChangeEvent, ConfigurationTarget, toConfigurationUpdateEvent, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { ConfigurationService as GlobalConfigurationService, isConfigurationOverrides } from 'vs/platform/configuration/node/configurationService'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; -import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; import { createHash } from 'crypto'; import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; - -const defaultSettingsSchemaId = 'vscode://schemas/settings/default'; -const userSettingsSchemaId = 'vscode://schemas/settings/user'; -const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; -const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; +import { distinct, flatten } from 'vs/base/common/arrays'; +import { IConfigurationEditingService, ConfigurationTarget as EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; interface IStat { resource: URI; @@ -56,212 +52,6 @@ interface IContent { value: string; } -interface IWorkspaceConfiguration { - workspace: T; - consolidated: any; -} - -type IWorkspaceFoldersConfiguration = { [rootFolder: string]: { folders: string[]; } }; - -const configurationRegistry = Registry.as(Extensions.Configuration); - -const configurationEntrySchema: IJSONSchema = { - type: 'object', - defaultSnippets: [{ body: { title: '', properties: {} } }], - properties: { - title: { - description: nls.localize('vscode.extension.contributes.configuration.title', 'A summary of the settings. This label will be used in the settings file as separating comment.'), - type: 'string' - }, - properties: { - description: nls.localize('vscode.extension.contributes.configuration.properties', 'Description of the configuration properties.'), - type: 'object', - additionalProperties: { - anyOf: [ - { $ref: 'http://json-schema.org/draft-04/schema#' }, - { - type: 'object', - properties: { - isExecutable: { - type: 'boolean' - }, - scope: { - type: 'string', - enum: ['window', 'resource'], - default: 'window', - enumDescriptions: [ - nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."), - nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.") - ], - description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.") - } - } - } - ] - } - } - } -}; - - -// BEGIN VSCode extension point `configuration` -const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configuration', [], { - description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'), - oneOf: [ - configurationEntrySchema, - { - type: 'array', - items: configurationEntrySchema - } - ] -}); -configurationExtPoint.setHandler(extensions => { - const configurations: IConfigurationNode[] = []; - - function handleConfiguration(node: IConfigurationNode, id: string, collector: ExtensionMessageCollector) { - let configuration = objects.clone(node); - - if (configuration.title && (typeof configuration.title !== 'string')) { - collector.error(nls.localize('invalid.title', "'configuration.title' must be a string")); - } - - validateProperties(configuration, collector); - - configuration.id = id; - configurations.push(configuration); - }; - - for (let extension of extensions) { - const collector = extension.collector; - const value = extension.value; - const id = extension.description.id; - if (!Array.isArray(value)) { - handleConfiguration(value, id, collector); - } else { - value.forEach(v => handleConfiguration(v, id, collector)); - } - } - configurationRegistry.registerConfigurations(configurations, false); -}); -// END VSCode extension point `configuration` - -// BEGIN VSCode extension point `configurationDefaults` -const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configurationDefaults', [], { - description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'), - type: 'object', - defaultSnippets: [{ body: {} }], - patternProperties: { - '\\[.*\\]$': { - type: 'object', - default: {}, - $ref: editorConfigurationSchemaId, - } - } -}); -defaultConfigurationExtPoint.setHandler(extensions => { - const defaultConfigurations: IDefaultConfigurationExtension[] = extensions.map(extension => { - const id = extension.description.id; - const name = extension.description.name; - const defaults = objects.clone(extension.value); - return { - id, name, defaults - }; - }); - configurationRegistry.registerDefaultConfigurations(defaultConfigurations); -}); -// END VSCode extension point `configurationDefaults` - -function validateProperties(configuration: IConfigurationNode, collector: ExtensionMessageCollector): void { - let properties = configuration.properties; - if (properties) { - if (typeof properties !== 'object') { - collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); - configuration.properties = {}; - } - for (let key in properties) { - const message = validateProperty(key); - const propertyConfiguration = configuration.properties[key]; - propertyConfiguration.scope = propertyConfiguration.scope && propertyConfiguration.scope.toString() === 'resource' ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW; - propertyConfiguration.isFromExtensions = true; - if (message) { - collector.warn(message); - delete properties[key]; - } - } - } - let subNodes = configuration.allOf; - if (subNodes) { - collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point.")); - for (let node of subNodes) { - validateProperties(node, collector); - } - } -} - -const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); -contributionRegistry.registerSchema('vscode://schemas/workspaceConfig', { - default: { - folders: [ - { - path: '' - } - ], - settings: { - } - }, - required: ['folders'], - properties: { - 'folders': { - minItems: 0, - uniqueItems: true, - description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace."), - items: { - type: 'object', - default: { path: '' }, - oneOf: [{ - properties: { - path: { - type: 'string', - description: nls.localize('workspaceConfig.path.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") - }, - name: { - type: 'string', - description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") - } - }, - required: ['path'] - }, { - properties: { - uri: { - type: 'string', - description: nls.localize('workspaceConfig.uri.description', "URI of the folder") - }, - name: { - type: 'string', - description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") - } - }, - required: ['uri'] - }] - } - }, - 'settings': { - type: 'object', - default: {}, - description: nls.localize('workspaceConfig.settings.description', "Workspace settings"), - $ref: workspaceSettingsSchemaId - }, - 'extensions': { - type: 'object', - default: {}, - description: nls.localize('workspaceConfig.extensions.description', "Workspace extensions"), - $ref: 'vscode://schemas/extensions' - } - }, - additionalProperties: false, - errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property") -}); - export class WorkspaceService extends Disposable implements IWorkspaceConfigurationService, IWorkspaceContextService { public _serviceBrand: any; @@ -272,8 +62,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private workspaceConfiguration: WorkspaceConfiguration; private cachedFolderConfigs: StrictResourceMap>; - protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; protected readonly _onDidChangeWorkspaceFolders: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; @@ -284,6 +74,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat protected readonly _onDidChangeWorkbenchState: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; + private configurationEditingService: IConfigurationEditingService; + constructor(private environmentService: IEnvironmentService, private workspacesService: IWorkspacesService, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) { super(); @@ -292,9 +84,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); - this._register(configurationRegistry.onDidRegisterConfiguration(e => this.registerConfigurationSchemas())); + this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(e => this.registerConfigurationSchemas())); } + // Workspace Context Service Impl + public getWorkspace(): Workspace { return this.workspace; } @@ -332,64 +126,112 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return false; } - public getConfigurationData(): IConfigurationData { - return this._configuration.toData(); + // Workspace Configuration Service Impl + + getConfiguration(): T + getConfiguration(section: string): T + getConfiguration(overrides: IConfigurationOverrides): T + getConfiguration(section: string, overrides: IConfigurationOverrides): T + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; + const contents = this._configuration.getValue(section, overrides); + return typeof contents === 'object' ? { toJSON: () => this._configuration.toData(), ...contents } + : contents; } - public getConfiguration(section?: string, overrides?: IConfigurationOverrides): C { - return this._configuration.getValue(section, overrides); + getValue(key: string, overrides?: IConfigurationOverrides): T { + return this._configuration.getValue2(key, overrides); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { - return this._configuration.lookup(key, overrides); - } + updateValue(key: string, value: any): TPromise + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise + updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + if (this.configurationEditingService) { + const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; + const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); - public keys(overrides?: IConfigurationOverrides): IConfigurationKeys { - return this._configuration.keys(overrides); - } - - public values(): IConfigurationValues { - return this._configuration.values(); - } - - public reloadConfiguration(section?: string): TPromise { - const current = this._configuration; - // Reload and reinitialize to ensure we are hitting the disk - return this.baseConfigurationService.reloadConfiguration() - .then(() => { - if (this.workspace.configuration) { - return this.workspaceConfiguration.load(this.workspace.configuration) - .then(() => this.initializeConfiguration(false)); + if (target) { + if (target === ConfigurationTarget.MEMORY) { + return TPromise.as(null); + } else { + return this.writeConfigurationValue(key, value, target, overrides); } - return this.initializeConfiguration(false); - }) - .then(() => { - // Check and trigger - if (!this._configuration.equals(current)) { - this.triggerConfigurationChange(); - } - return this.getConfiguration(section); - }); + } + } + return TPromise.as(null); } - public getUnsupportedWorkspaceKeys(): string[] { + reloadConfiguration(folder?: IWorkspaceFolder, key?: string): TPromise { + if (folder) { + return this.reloadWorkspaceFolderConfiguration(folder, key); + } + return this.loadConfiguration(); + } + + inspect(key: string, overrides?: IConfigurationOverrides): { + default: T, + user: T, + workspace: T, + workspaceFolder: T, + value: T + } { + return this._configuration.lookup(key); + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return this._configuration.keys(); + } + + getUnsupportedWorkspaceKeys(): string[] { return this.getWorkbenchState() === WorkbenchState.FOLDER ? this._configuration.getFolderConfigurationModel(this.workspace.folders[0].uri).workspaceSettingsConfig.unsupportedKeys : []; } - public handleWorkspaceFileEvents(event: FileChangesEvent): void { - TPromise.join(this.workspace.folders.map(folder => this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event))) // handle file event for each folder - .then(folderConfigurations => - folderConfigurations.map((configuration, index) => ({ configuration, folder: this.workspace.folders[index] })) - .filter(folderConfiguration => !!folderConfiguration.configuration) // Filter folders which are not impacted by events - .map(folderConfiguration => this.updateFolderConfiguration(folderConfiguration.folder, folderConfiguration.configuration, true)) // Update the configuration of impacted folders - .reduce((result, value) => result || value, false)) // Check if the effective configuration of folder is changed - .then(changed => changed ? this.triggerConfigurationChange() : void 0); // Trigger event if changed + reloadUserConfiguration(key?: string): TPromise { + return this.baseConfigurationService.reloadConfiguration(); } - public initialize(arg: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWindowConfiguration): TPromise { + reloadWorkspaceConfiguration(key?: string): TPromise { + const workbenchState = this.getWorkbenchState(); + if (workbenchState === WorkbenchState.FOLDER) { + return this.onWorkspaceFolderConfigurationChanged(this.workspace.folders[0], key); + } + if (workbenchState === WorkbenchState.WORKSPACE) { + return this.onWorkspaceConfigurationChanged(); + } + return TPromise.as(null); + } + + reloadWorkspaceFolderConfiguration(folder: IWorkspaceFolder, key?: string): TPromise { + return this.onWorkspaceFolderConfigurationChanged(folder, key); + } + + initialize(arg: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWindowConfiguration): TPromise { return this.createWorkspace(arg) .then(workspace => this.setWorkspace(workspace)) - .then(() => this.initializeConfiguration(true)); + .then(() => this.initializeConfiguration()); + } + + aquireDelayedServices(instantiationService: IInstantiationService): void { + this.configurationEditingService = instantiationService.createInstance(ConfigurationEditingService); + } + + handleWorkspaceFileEvents(event: FileChangesEvent): void { + switch (this.getWorkbenchState()) { + case WorkbenchState.FOLDER: + this.onSingleFolderFileChanges(event); + return; + case WorkbenchState.WORKSPACE: + this.onWorkspaceFileChanges(event); + return; + } } private createWorkspace(arg: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWindowConfiguration): TPromise { @@ -470,137 +312,232 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return result; } - private initializeConfiguration(trigger: boolean = true): TPromise { + private initializeConfiguration(): TPromise { this.registerConfigurationSchemas(); - this.resetCaches(); - return this.updateConfiguration() - .then(() => { - if (trigger) { - this.triggerConfigurationChange(); - } + return this.loadConfiguration(); + } + + private loadConfiguration(): TPromise { + // reset caches + this.cachedFolderConfigs = new StrictResourceMap>(); + + const folders = this.workspace.folders; + return this.loadFolderConfigurations(folders) + .then((folderConfigurations) => { + + let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations); + const folderConfigurationModels = new StrictResourceMap>(); + folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration)); + + this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null + // TODO: compare with old values?? + + const keys = this._configuration.keys(); + this.triggerConfigurationChange([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE); }); } - private resetCaches(): void { - this.cachedFolderConfigs = new StrictResourceMap>(); - this._configuration = new Configuration(this.baseConfigurationService.configuration(), new ConfigurationModel(), new StrictResourceMap>(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null - this.initCachesForFolders(this.workspace.folders); - } - - private initCachesForFolders(folders: IWorkspaceFolder[]): void { - for (const folder of folders) { - this.cachedFolderConfigs.set(folder.uri, this._register(new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW))); - this.updateFolderConfiguration(folder, new FolderConfigurationModel(new FolderSettingsModel(null), [], ConfigurationScope.RESOURCE), false); + private getWorkspaceConfigurationModel(folderConfigurations: FolderConfigurationModel[]): ConfigurationModel { + switch (this.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return folderConfigurations[0]; + case WorkbenchState.WORKSPACE: + return this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration; + default: + return new ConfigurationModel(); } } - private updateConfiguration(folders: IWorkspaceFolder[] = this.workspace.folders): TPromise { - return TPromise.join([...folders.map(folder => this.cachedFolderConfigs.get(folder.uri).loadConfiguration() - .then(configuration => this.updateFolderConfiguration(folder, configuration, true)))]) - .then(changed => changed.reduce((result, value) => result || value, false)) - .then(changed => this.updateWorkspaceConfiguration(true) || changed); - } - private registerConfigurationSchemas(): void { if (this.workspace) { - - contributionRegistry.registerSchema(defaultSettingsSchemaId, settingsSchema); - contributionRegistry.registerSchema(userSettingsSchemaId, settingsSchema); + const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); + jsonRegistry.registerSchema(defaultSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(userSettingsSchemaId, settingsSchema); if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { - contributionRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); - contributionRegistry.registerSchema(folderSettingsSchemaId, resourceSettingsSchema); + jsonRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(folderSettingsSchemaId, resourceSettingsSchema); } else { - contributionRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); - contributionRegistry.registerSchema(folderSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(folderSettingsSchemaId, settingsSchema); } } } - private onBaseConfigurationChanged({ source, sourceConfig }: IConfigurationServiceEvent): void { - if (this.workspace) { - if (source === ConfigurationSource.Default) { + private onBaseConfigurationChanged(e: IConfigurationChangeEvent): void { + if (this.workspace && this._configuration) { + if (e.source === ConfigurationTarget.DEFAULT) { this.workspace.folders.forEach(folder => this._configuration.getFolderConfigurationModel(folder.uri).update()); - } - if (this._configuration.updateBaseConfiguration(this.baseConfigurationService.configuration())) { - this._onDidUpdateConfiguration.fire({ source, sourceConfig }); + this._configuration.updateDefaultConfiguration(this.baseConfigurationService.configuration.defaults); + this._onDidUpdateConfiguration.fire(e); + } else { + let keys = this._configuration.updateUserConfiguration(this.baseConfigurationService.configuration.user); + this.triggerConfigurationChange(keys, e.source); } } } - private onWorkspaceConfigurationChanged(): void { - if (this.workspace && this.workspace.configuration) { + private onWorkspaceConfigurationChanged(): TPromise { + if (this.workspace && this.workspace.configuration && this._configuration) { + const changedWorkspaceKeys = this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration); let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.workspaceConfigurationModel.folders, URI.file(paths.dirname(this.workspace.configuration.fsPath))); const changes = this.compareFolders(this.workspace.folders, configuredFolders); - if (changes.added.length || changes.removed.length || changes.changed.length) { // TODO@Sandeep be smarter here about detecting changes + if (changes.added.length || changes.removed.length || changes.changed.length) { this.workspace.folders = configuredFolders; - this.onFoldersChanged() - .then(configurationChanged => { - if (configurationChanged) { - this.triggerConfigurationChange(); - } + return this.onFoldersChanged() + .then(changedFolderKeys => { + this.triggerConfigurationChange([...changedFolderKeys, ...changedWorkspaceKeys], ConfigurationTarget.WORKSPACE_FOLDER); this._onDidChangeWorkspaceFolders.fire(changes); }); } else { - const configurationChanged = this.updateWorkspaceConfiguration(true); - if (configurationChanged) { - this.triggerConfigurationChange(); - } + this.triggerConfigurationChange(changedWorkspaceKeys, ConfigurationTarget.WORKSPACE); } } + return TPromise.as(null); } - private onFoldersChanged(): TPromise { - let configurationChangedOnRemoval = false; + private onWorkspaceFileChanges(event: FileChangesEvent): TPromise { + return TPromise.join(this.workspace.folders.map(folder => + // handle file event for each folder + this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event) + // Update folder configuration if handled + .then(folderConfiguration => folderConfiguration ? this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration) : [])) + ).then(changedKeys => this.triggerConfigurationChange(flatten(changedKeys), ConfigurationTarget.WORKSPACE_FOLDER)); + } + + private onSingleFolderFileChanges(event: FileChangesEvent): TPromise { + const folder = this.workspace.folders[0]; + return this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event) + .then(folderConfiguration => { + if (folderConfiguration) { + // File change handled + this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration); + const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration); + this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE); + } + }); + } + + private onWorkspaceFolderConfigurationChanged(folder: IWorkspaceFolder, key?: string): TPromise { + this.disposeFolderConfiguration(folder); + return this.loadFolderConfigurations([folder]) + .then(([folderConfiguration]) => { + const folderChangedKeys = this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration); + if (this.getWorkbenchState() === WorkbenchState.FOLDER) { + const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration); + this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE); + } else { + this.triggerConfigurationChange(folderChangedKeys, ConfigurationTarget.WORKSPACE_FOLDER); + } + }); + } + + private onFoldersChanged(): TPromise { + let changedKeys = []; // Remove the configurations of deleted folders for (const key of this.cachedFolderConfigs.keys()) { if (!this.workspace.folders.filter(folder => folder.uri.toString() === key.toString())[0]) { this.cachedFolderConfigs.delete(key); - if (this._configuration.deleteFolderConfiguration(key)) { - configurationChangedOnRemoval = true; - } + changedKeys.push(...this._configuration.deleteFolderConfiguration(key)); } } - // Initialize the newly added folders const toInitialize = this.workspace.folders.filter(folder => !this.cachedFolderConfigs.has(folder.uri)); if (toInitialize.length) { - this.initCachesForFolders(toInitialize); - return this.updateConfiguration(toInitialize) - .then(changed => configurationChangedOnRemoval || changed); - } else if (configurationChangedOnRemoval) { - this.updateWorkspaceConfiguration(false); - return TPromise.as(true); + return this.loadFolderConfigurations(toInitialize) + .then(folderConfigurations => { + folderConfigurations.forEach((folderConfiguration, index) => { + changedKeys.push(...this._configuration.updateFolderConfiguration(toInitialize[index].uri, folderConfiguration)); + }); + return changedKeys; + }); } - return TPromise.as(false); + return TPromise.as(changedKeys); } - private updateFolderConfiguration(folder: IWorkspaceFolder, folderConfiguration: FolderConfigurationModel, compare: boolean): boolean { - let configurationChanged = this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration, compare); - if (this.getWorkbenchState() === WorkbenchState.FOLDER) { - // Workspace configuration changed - configurationChanged = this.updateWorkspaceConfiguration(compare) || configurationChanged; - } - return configurationChanged; + private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise[]> { + return TPromise.join([...folders.map(folder => { + const folderConfiguration = new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW); + this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); + return folderConfiguration.loadConfiguration(); + })]); } - private updateWorkspaceConfiguration(compare: boolean): boolean { - const workbennchState = this.getWorkbenchState(); - if (workbennchState === WorkbenchState.EMPTY) { - return false; - } - - const workspaceConfiguration = workbennchState === WorkbenchState.WORKSPACE ? this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration : this._configuration.getFolderConfigurationModel(this.workspace.folders[0].uri); - return this._configuration.updateWorkspaceConfiguration(workspaceConfiguration, compare); + private writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationOverrides): TPromise { + return this.configurationEditingService.writeConfiguration(this.toEditableConfigurationTarget(target), { key, value }, { scopes: overrides }) + .then(() => { + switch (target) { + case ConfigurationTarget.USER: + return this.reloadUserConfiguration(); + case ConfigurationTarget.WORKSPACE: + return this.reloadWorkspaceConfiguration(); + case ConfigurationTarget.WORKSPACE_FOLDER: + const workspaceFolder = overrides && overrides.resource ? this.workspace.getFolder(overrides.resource) : null; + if (workspaceFolder) { + return this.reloadWorkspaceFolderConfiguration(this.workspace.getFolder(overrides.resource), key); + } + } + return null; + }); } - private triggerConfigurationChange(): void { - if (this.getWorkbenchState() === WorkbenchState.EMPTY) { - this._onDidUpdateConfiguration.fire({ source: ConfigurationSource.User, sourceConfig: this._configuration.user.contents }); - } else { - this._onDidUpdateConfiguration.fire({ source: ConfigurationSource.Workspace, sourceConfig: this.workspace.folders.length ? this._configuration.getFolderConfigurationModel(this.workspace.folders[0].uri).contents : void 0 }); // TODO@Sandeep debt? + private deriveConfigurationTarget(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): ConfigurationTarget { + if (target) { + return target; } + + if (value === void 0) { + // Ignore. But expected is to remove the value from all targets + return void 0; + } + + const inspect = this.inspect(key, overrides); + if (equals(value, inspect.value)) { + // No change. So ignore. + return void 0; + } + + if (inspect.workspaceFolder !== void 0) { + return ConfigurationTarget.WORKSPACE_FOLDER; + } + + if (inspect.workspace !== void 0) { + return ConfigurationTarget.WORKSPACE; + } + + return ConfigurationTarget.USER; + } + + private toEditableConfigurationTarget(target: ConfigurationTarget): EditableConfigurationTarget { + switch (target) { + case ConfigurationTarget.USER: + return EditableConfigurationTarget.USER; + case ConfigurationTarget.WORKSPACE: + return EditableConfigurationTarget.WORKSPACE; + case ConfigurationTarget.WORKSPACE_FOLDER: + return EditableConfigurationTarget.FOLDER; + default: + return EditableConfigurationTarget.WORKSPACE; + } + } + + private triggerConfigurationChange(keys: string[], target: ConfigurationTarget): void { + if (keys.length) { + this._onDidUpdateConfiguration.fire(toConfigurationUpdateEvent(distinct(keys), target, this.getTargetConfiguration(target))); + } + } + + private getTargetConfiguration(target: ConfigurationTarget): any { + switch (target) { + case ConfigurationTarget.DEFAULT: + return this._configuration.defaults.contents; + case ConfigurationTarget.USER: + return this._configuration.user.contents; + case ConfigurationTarget.WORKSPACE: + return this._configuration.workspace.contents; + } + return {}; } private pathEquals(path1: string, path2: string): boolean { @@ -611,6 +548,13 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return path1 === path2; } + + private disposeFolderConfiguration(folder: IWorkspaceFolder): void { + const folderConfiguration = this.cachedFolderConfigs.get(folder.uri); + if (folderConfiguration) { + folderConfiguration.dispose(); + } + } } class WorkspaceConfiguration extends Disposable { @@ -622,7 +566,6 @@ class WorkspaceConfiguration extends Disposable { private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; - load(workspaceConfigPath: URI): TPromise { if (this._workspaceConfigPath && this._workspaceConfigPath.fsPath === workspaceConfigPath.fsPath) { return this._reload(); @@ -852,80 +795,6 @@ function resolveStat(resource: URI): TPromise { }); } -export class Configuration extends BaseConfiguration { - - constructor(private _baseConfiguration: BaseConfiguration, workspaceConfiguration: ConfigurationModel, protected folders: StrictResourceMap>, workspace: Workspace) { - super(_baseConfiguration.defaults, _baseConfiguration.user, workspaceConfiguration, folders, workspace); - } - - updateBaseConfiguration(baseConfiguration: BaseConfiguration): boolean { - const current = new Configuration(this._baseConfiguration, this._workspaceConfiguration, this.folders, this._workspace); - - this._baseConfiguration = baseConfiguration; - this._defaults = this._baseConfiguration.defaults; - this._user = this._baseConfiguration.user; - this.merge(); - - return !this.equals(current); - } - - updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel, compare: boolean = true): boolean { - const current = new Configuration(this._baseConfiguration, this._workspaceConfiguration, this.folders, this._workspace); - - this._workspaceConfiguration = workspaceConfiguration; - this.merge(); - - return compare && !this.equals(current); - } - - updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel, compare: boolean): boolean { - const current = this.getValue(null, { resource }); - - this.folders.set(resource, configuration); - this.mergeFolder(resource); - - return compare && !objects.equals(current, this.getValue(null, { resource })); - } - - deleteFolderConfiguration(folder: URI): boolean { - if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) { - // Do not remove workspace configuration - return false; - } - - const changed = this.folders.get(folder).keys.length > 0; - this.folders.delete(folder); - this._foldersConsolidatedConfigurations.delete(folder); - return changed; - } - - getFolderConfigurationModel(folder: URI): FolderConfigurationModel { - return >this.folders.get(folder); - } - - equals(other: any): boolean { - if (!other || !(other instanceof Configuration)) { - return false; - } - - if (!objects.equals(this.getValue(), other.getValue())) { - return false; - } - - if (this._foldersConsolidatedConfigurations.size !== other._foldersConsolidatedConfigurations.size) { - return false; - } - - for (const resource of this._foldersConsolidatedConfigurations.keys()) { - if (!objects.equals(this.getValue(null, { resource }), other.getValue(null, { resource }))) { - return false; - } - } - - return true; - } -} - interface IExportedConfigurationNode { name: string; description: string; @@ -1019,4 +888,4 @@ function versionStringToNumber(versionStr: string): number { } return parseInt(match[1], 10) * 10000 + parseInt(match[2], 10) * 100 + parseInt(match[3], 10); -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index 268e832f7db..b486834f14e 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -21,7 +21,7 @@ import extfs = require('vs/base/node/extfs'); import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; import uuid = require('vs/base/common/uuid'); import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { ConfigurationTarget, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/common/configurationEditing'; @@ -228,7 +228,7 @@ suite('ConfigurationEditingService', () => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); assert.equal(parsed['configurationEditing.service.testSetting'], 'value'); - assert.equal(instantiationService.get(IConfigurationService).lookup('configurationEditing.service.testSetting').value, 'value'); + assert.equal(instantiationService.get(IConfigurationService).getValue('configurationEditing.service.testSetting'), 'value'); }); }); @@ -242,8 +242,8 @@ suite('ConfigurationEditingService', () => { assert.equal(parsed['my.super.setting'], 'my.super.value'); const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('configurationEditing.service.testSetting').value, 'value'); - assert.equal(configurationService.lookup('my.super.setting').value, 'my.super.value'); + assert.equal(configurationService.getValue('configurationEditing.service.testSetting'), 'value'); + assert.equal(configurationService.getValue('my.super.setting'), 'my.super.value'); }); }); @@ -255,7 +255,7 @@ suite('ConfigurationEditingService', () => { const parsed = json.parse(contents); assert.equal(parsed['service.testSetting'], 'value'); const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('tasks.service.testSetting').value, 'value'); + assert.equal(configurationService.getValue('tasks.service.testSetting'), 'value'); }); }); @@ -270,8 +270,8 @@ suite('ConfigurationEditingService', () => { assert.equal(parsed['my.super.setting'], 'my.super.value'); const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('launch.service.testSetting').value, 'value'); - assert.equal(configurationService.lookup('launch.my.super.setting').value, 'my.super.value'); + assert.equal(configurationService.getValue('launch.service.testSetting'), 'value'); + assert.equal(configurationService.getValue('launch.my.super.setting'), 'my.super.value'); }); }); diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts similarity index 90% rename from src/vs/workbench/services/configuration/test/node/configuration.test.ts rename to src/vs/workbench/services/configuration/test/node/configurationService.test.ts index 8073bb82a98..c6fb36f60c9 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -19,7 +19,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv'; import extfs = require('vs/base/node/extfs'); import uuid = require('vs/base/common/uuid'); import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -167,7 +167,7 @@ suite('WorkspaceConfigurationService - Node', () => { return createService(workspaceDir, globalSettingsFile).then(service => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); - service.reloadConfiguration().then(() => { + service.reloadConfiguration(service.getWorkspace().folders[0]).then(() => { const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>(); assert.equal(config.testworkbench.editor.tabs, true); @@ -197,7 +197,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": false }'); // this has to trigger the event since the config changes - service.reloadConfiguration().done(); + service.reloadUserConfiguration().done(); }); }); @@ -229,7 +229,7 @@ suite('WorkspaceConfigurationService - Node', () => { return createService(workspaceDir, globalSettingsFile).then(service => { fs.writeFileSync(globalSettingsFile, '{ "workspace.service.testSetting": "isChanged" }'); - service.reloadConfiguration().then(() => { + service.reloadUserConfiguration().then(() => { const config = service.getConfiguration(); assert.equal(config.workspace.service.testSetting, 'isChanged'); @@ -246,7 +246,7 @@ suite('WorkspaceConfigurationService - Node', () => { return createService(workspaceDir, globalSettingsFile).then(service => { fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); - service.reloadConfiguration().then(() => { + service.reloadWorkspaceConfiguration().then(() => { const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean } } }>(); assert.equal(config.testworkbench.editor.icons, true); @@ -264,7 +264,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.icons": false, "testworkbench.other.setting": true }'); fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); - service.reloadConfiguration().then(() => { + service.reloadWorkspaceConfiguration().then(() => { const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean }, other: { setting: string } } }>(); assert.equal(config.testworkbench.editor.icons, true); assert.equal(config.testworkbench.other.setting, true); @@ -310,7 +310,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": false }'); - service.reloadConfiguration().done(() => { + service.reloadWorkspaceConfiguration().done(() => { assert.ok(target.calledOnce); service.dispose(); @@ -326,11 +326,11 @@ suite('WorkspaceConfigurationService - Node', () => { const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": true }'); - service.reloadConfiguration().done(() => { + service.reloadWorkspaceConfiguration().done(() => { const target = sinon.stub(); service.onDidUpdateConfiguration(event => target()); - service.reloadConfiguration().done(() => { + service.reloadWorkspaceConfiguration().done(() => { assert.ok(!target.called); service.dispose(); @@ -346,7 +346,7 @@ suite('WorkspaceConfigurationService - Node', () => { return createService(workspaceDir, globalSettingsFile).then(service => { const target = sinon.stub(); service.onDidUpdateConfiguration(event => target()); - service.reloadConfiguration().done(() => { + service.reloadUserConfiguration().done(() => { assert.ok(!target.called); service.dispose(); cleanUp(done); @@ -371,13 +371,13 @@ suite('WorkspaceConfigurationService - Node', () => { createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { - let res = service.lookup('something.missing'); + let res = service.inspect('something.missing'); assert.ok(!res.default); assert.ok(!res.user); assert.ok(!res.workspace); assert.ok(!res.value); - res = service.lookup('workspaceLookup.service.testSetting'); + res = service.inspect('workspaceLookup.service.testSetting'); assert.equal(res.default, 'isSet'); assert.equal(res.value, 'isSet'); assert.ok(!res.user); @@ -385,8 +385,8 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - return service.reloadConfiguration().then(() => { - res = service.lookup('workspaceLookup.service.testSetting'); + return service.reloadUserConfiguration().then(() => { + res = service.inspect('workspaceLookup.service.testSetting'); assert.equal(res.default, 'isSet'); assert.equal(res.user, true); assert.equal(res.value, true); @@ -395,8 +395,8 @@ suite('WorkspaceConfigurationService - Node', () => { const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - return service.reloadConfiguration().then(() => { - res = service.lookup('workspaceLookup.service.testSetting'); + return service.reloadWorkspaceConfiguration().then(() => { + res = service.inspect('workspaceLookup.service.testSetting'); assert.equal(res.default, 'isSet'); assert.equal(res.user, true); assert.equal(res.workspace, 55); @@ -444,7 +444,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - return service.reloadConfiguration().then(() => { + return service.reloadUserConfiguration().then(() => { keys = service.keys(); assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); @@ -454,7 +454,7 @@ suite('WorkspaceConfigurationService - Node', () => { const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - return service.reloadConfiguration().then(() => { + return service.reloadWorkspaceConfiguration().then(() => { keys = service.keys(); assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); @@ -464,7 +464,7 @@ suite('WorkspaceConfigurationService - Node', () => { const settingsFile = path.join(workspaceDir, '.vscode', 'tasks.json'); fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.taskTestSetting": 55 }'); - return service.reloadConfiguration().then(() => { + return service.reloadWorkspaceConfiguration().then(() => { keys = service.keys(); assert.ok(!contains(keys.default, 'tasks.workspaceLookup.service.taskTestSetting')); @@ -496,31 +496,31 @@ suite('WorkspaceConfigurationService - Node', () => { createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { - let values = service.values(); - let value = values['workspaceLookup.service.testSetting']; + let values = service.inspect('workspaceLookup.service.testSetting'); + let value = values.value; assert.ok(value); - assert.equal(value.default, 'isSet'); + assert.equal(values.default, 'isSet'); fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - return service.reloadConfiguration().then(() => { - values = service.values(); - value = values['workspaceLookup.service.testSetting']; + return service.reloadUserConfiguration().then(() => { + values = service.inspect('workspaceLookup.service.testSetting'); + value = values.value; assert.ok(value); - assert.equal(value.user, true); + assert.equal(values.user, true); const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - return service.reloadConfiguration().then(() => { - values = service.values(); - value = values['workspaceLookup.service.testSetting']; + return service.reloadWorkspaceConfiguration().then(() => { + values = service.inspect('workspaceLookup.service.testSetting'); + value = values.value; assert.ok(value); - assert.equal(value.user, true); - assert.equal(value.workspace, 55); + assert.equal(values.user, true); + assert.equal(values.workspace, 55); done(); }); diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 7841abf9606..2360f632988 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -7,7 +7,7 @@ import assert = require('assert'); import uri from 'vs/base/common/uri'; import platform = require('vs/base/common/platform'); import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, getConfigurationValue, IConfigurationOverrides, IConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService'; @@ -348,13 +348,14 @@ class MockConfigurationService implements IConfigurationService { public _serviceBrand: any; public serviceId = IConfigurationService; public constructor(private configuration: any = {}) { } - public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; } - public keys() { return { default: [], user: [], workspace: [], folder: [] }; } - public values() { return {}; } + public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspaceFolder: void 0, folder: void 0 }; } + public keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; } public getConfiguration(): any { return this.configuration; } + public getValue(key: string): any { return getConfigurationValue(this.getConfiguration(), key); } + public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } public onDidUpdateConfiguration() { return { dispose() { } }; } + public reloadConfiguration() { return null; } } class MockCommandService implements ICommandService { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index d4b17a7fbc3..553e69ad627 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -360,7 +360,7 @@ export class ExtensionHostProcessWorker { }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace(), extensions: extensionDescriptions, - configuration: this._configurationService.getConfigurationData(), + configuration: this._configurationService.getConfiguration(), telemetryInfo }; return r; diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 7fb9b9a90c8..7d1e3e4382f 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -344,8 +344,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.updateColorCustomizations(false); - let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; - let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; + let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); + let iconThemeSetting = this.configurationService.getValue(ICON_THEME_SETTING) || ''; return Promise.join([ this.findThemeDataBySettingsId(colorThemeSetting, DEFAULT_THEME_ID).then(theme => { @@ -359,7 +359,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private installConfigurationListener() { this.configurationService.onDidUpdateConfiguration(e => { - let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; + let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); if (colorThemeSetting !== this.currentColorTheme.settingsId) { this.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { if (theme) { @@ -368,7 +368,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }); } - let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; + let iconThemeSetting = this.configurationService.getValue(ICON_THEME_SETTING) || ''; if (iconThemeSetting !== this.currentIconTheme.settingsId) { this.findIconThemeBySettingsId(iconThemeSetting).then(theme => { this.setFileIconTheme(theme && theme.id, null); @@ -530,14 +530,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private updateColorCustomizations(notify = true): void { - let newColorCustomizations = this.configurationService.lookup(CUSTOM_WORKBENCH_COLORS_SETTING).value || {}; + let newColorCustomizations = this.configurationService.getValue(CUSTOM_WORKBENCH_COLORS_SETTING) || {}; let newColorIds = Object.keys(newColorCustomizations); if (newColorIds.length === 0) { - newColorCustomizations = this.configurationService.lookup(DEPRECATED_CUSTOM_COLORS_SETTING).value || {}; + newColorCustomizations = this.configurationService.getValue(DEPRECATED_CUSTOM_COLORS_SETTING) || {}; newColorIds = Object.keys(newColorCustomizations); } - let newTokenColorCustomizations = this.configurationService.lookup(CUSTOM_EDITOR_COLORS_SETTING).value || {}; + let newTokenColorCustomizations = this.configurationService.getValue(CUSTOM_EDITOR_COLORS_SETTING) || {}; if (this.hasCustomizationChanged(newColorCustomizations, newColorIds, newTokenColorCustomizations)) { this.colorCustomizations = newColorCustomizations; @@ -962,7 +962,7 @@ class ConfigurationWriter { } public writeConfiguration(key: string, value: any, settingsTarget: ConfigurationTarget): TPromise { - let settings = this.configurationService.lookup(key); + let settings = this.configurationService.inspect(key); if (settingsTarget === ConfigurationTarget.USER) { if (value === settings.user) { return TPromise.as(null); // nothing to do diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index aa99ca9f75a..ea53130e9cb 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -17,7 +17,7 @@ import { dirname } from 'path'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; import { isLinux } from 'vs/base/common/platform'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { StorageService } from 'vs/platform/storage/common/storageService'; @@ -187,7 +187,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const targetWorkspaceConfiguration = {}; for (const key of this.workspaceConfigurationService.keys().workspace) { if (configurationProperties[key] && !configurationProperties[key].isFromExtensions && configurationProperties[key].scope === ConfigurationScope.WINDOW) { - targetWorkspaceConfiguration[key] = this.workspaceConfigurationService.lookup(key).workspace; + targetWorkspaceConfiguration[key] = this.workspaceConfigurationService.inspect(key).workspace; } } diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index b162fb6a023..4844c81d0aa 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -9,6 +9,9 @@ import 'vs/base/common/strings'; import 'vs/base/common/errors'; +// Configuration +import 'vs/workbench/services/configuration/common/configurationExtensionPoint'; + // Editor import 'vs/editor/editor.all'; From 74e07a6f1cd24cd9a342056096b2d3d7d2a648e1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 5 Oct 2017 23:22:55 +0200 Subject: [PATCH 015/303] Populate register configuration event correctly --- src/vs/platform/configuration/common/configurationRegistry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 83d78eda6da..11f9f2cd686 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -114,9 +114,9 @@ class ConfigurationRegistry implements IConfigurationRegistry { } public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void { - const properties = []; + const properties: string[] = []; configurations.forEach(configuration => { - properties.push(this.validateAndRegisterProperties(configuration, validate)); // fills in defaults + properties.push(...this.validateAndRegisterProperties(configuration, validate)); // fills in defaults this.configurationContributors.push(configuration); this.registerJSONConfiguration(configuration); this.updateSchemaForOverrideSettingsConfiguration(configuration); From e1c29b6188971db4d294b05a71984c645f4d759c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 5 Oct 2017 23:30:34 +0200 Subject: [PATCH 016/303] Populate override identifer keys in the event correctly --- src/vs/platform/configuration/common/configuration.ts | 10 +++++++++- src/vs/platform/configuration/common/model.ts | 10 +--------- .../parts/preferences/browser/preferencesRenderers.ts | 2 +- .../configuration/node/configurationEditingService.ts | 3 +-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 20f1b668201..19bcce38e70 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -78,12 +78,20 @@ export interface IConfigurationService { }; } +export function overrideIdentifierFromKey(key: string): string { + return key.substring(1, key.length - 1); +} + +export function keyFromOverrideIdentifier(overrideIdentifier: string): string { + return `[${overrideIdentifier}]`; +} + export function toConfigurationUpdateEvent(udpated: string[], source: ConfigurationTarget, sourceConfig: any): IConfigurationChangeEvent { const overrideIdentifiers = []; const keys: string[] = []; for (const key of udpated) { if (OVERRIDE_PROPERTY_PATTERN.test(key)) { - overrideIdentifiers.push(key); + overrideIdentifiers.push(overrideIdentifierFromKey(key).trim()); } else { keys.push(key); } diff --git a/src/vs/platform/configuration/common/model.ts b/src/vs/platform/configuration/common/model.ts index 53b122efd0e..2eca51661ff 100644 --- a/src/vs/platform/configuration/common/model.ts +++ b/src/vs/platform/configuration/common/model.ts @@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as json from 'vs/base/common/json'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { ConfigurationModel, IOverrides } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel, IOverrides, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; export function getDefaultValues(): any { const valueTreeRoot: any = Object.create(null); @@ -191,12 +191,4 @@ export class CustomConfigurationModel extends ConfigurationModel { this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); this._keys = Object.keys(raw); } -} - -export function overrideIdentifierFromKey(key: string): string { - return key.substring(1, key.length - 1); -} - -export function keyFromOverrideIdentifier(overrideIdentifier: string): string { - return `[${overrideIdentifier}]`; } \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index e3491f2e20a..98996425277 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -24,7 +24,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; import { IConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { overrideIdentifierFromKey } from 'vs/platform/configuration/common/model'; import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; @@ -33,6 +32,7 @@ import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorE import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; export interface IPreferencesRenderer extends IDisposable { preferencesModel: IPreferencesEditorModel; diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index 694c6122734..b264dbd9662 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -23,8 +23,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IConfigurationService, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; -import { keyFromOverrideIdentifier } from 'vs/platform/configuration/common/model'; +import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError, IConfigurationValue, IConfigurationEditingOptions, IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; From 2a8be527e5a773d3bd01ce1c274cdb2cf5138fc4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 5 Oct 2017 23:41:20 +0200 Subject: [PATCH 017/303] :lipstick: --- src/vs/platform/configuration/common/configuration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 19bcce38e70..43da9ac3cfb 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -60,7 +60,7 @@ export interface IConfigurationService { updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; reloadConfiguration(): TPromise; - reloadConfiguration(folder?: IWorkspaceFolder): TPromise; + reloadConfiguration(folder: IWorkspaceFolder): TPromise; inspect(key: string): { default: T, From 7f89b24319054ae22758d046ef33f0b78c5650cc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 5 Oct 2017 23:50:44 +0200 Subject: [PATCH 018/303] Fix usage of getConfiguration --- src/vs/editor/common/services/modelServiceImpl.ts | 2 +- .../workbench/api/electron-browser/mainThreadWorkspace.ts | 2 +- src/vs/workbench/parts/files/browser/views/explorerView.ts | 2 +- .../workbench/parts/files/browser/views/explorerViewer.ts | 2 +- src/vs/workbench/parts/search/common/queryBuilder.ts | 6 +++--- .../services/files/node/watcher/nsfw/watcherService.ts | 2 +- src/vs/workbench/services/history/browser/history.ts | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 7eb325a6761..fe046a165d5 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -272,7 +272,7 @@ export class ModelServiceImpl implements IModelService { public getCreationOptions(language: string, resource: URI): editorCommon.ITextModelCreationOptions { let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource]; if (!creationOptions) { - creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration(null, { overrideIdentifier: language, resource })); + creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration({ overrideIdentifier: language, resource })); this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions; } return creationOptions; diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 69d00f909db..69e09705743 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -68,7 +68,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } const useRipgrep = folderQueries.every(folderQuery => { - const folderConfig = this._configurationService.getConfiguration(undefined, { resource: folderQuery.folder }); + const folderConfig = this._configurationService.getConfiguration({ resource: folderQuery.folder }); return folderConfig.search.useRipgrep; }); diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 1a84751abf2..9db721ab8b4 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -120,7 +120,7 @@ export class ExplorerView extends ViewsViewletPanel { private getFileEventsExcludes(root?: URI): glob.IExpression { const scope = root ? { resource: root } : void 0; - const configuration = this.configurationService.getConfiguration(undefined, scope); + const configuration = this.configurationService.getConfiguration(scope); return (configuration && configuration.files && configuration.files.exclude) || Object.create(null); } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index c088be1988d..329a15b0bf9 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -687,7 +687,7 @@ export class FileFilter implements IFilter { public updateConfiguration(): boolean { let needsRefresh = false; this.contextService.getWorkspace().folders.forEach(folder => { - const configuration = this.configurationService.getConfiguration(undefined, { resource: folder.uri }); + const configuration = this.configurationService.getConfiguration({ resource: folder.uri }); const excludesConfig = (configuration && configuration.files && configuration.files.exclude) || Object.create(null); needsRefresh = needsRefresh || !objects.equals(this.hiddenExpressionPerRoot.get(folder.uri.toString()), excludesConfig); this.hiddenExpressionPerRoot.set(folder.uri.toString(), objects.clone(excludesConfig)); // do not keep the config, as it gets mutated under our hoods diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index 9b3120dcdc6..cf614eeaeb0 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -56,7 +56,7 @@ export class QueryBuilder { } const useRipgrep = !folderResources || folderResources.every(folder => { - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return folderConfig.search.useRipgrep; }); @@ -244,7 +244,7 @@ export class QueryBuilder { private getFolderQueryForSearchPath(searchPath: ISearchPathPattern): IFolderQuery { const folder = searchPath.searchPath; - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return { folder, includePattern: searchPath.pattern && patternListToIExpression([searchPath.pattern]), @@ -253,7 +253,7 @@ export class QueryBuilder { } private getFolderQueryForRoot(folder: uri, options?: IQueryOptions): IFolderQuery { - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return { folder, excludePattern: this.getExcludesForFolder(folderConfig, options), diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts index 9e3744b2638..05a68b0cb7a 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts @@ -95,7 +95,7 @@ export class FileWatcher { this.service.setRoots(this.contextService.getWorkspace().folders.map(folder => { // Fetch the root's watcherExclude setting and return it - const configuration = this.configurationService.getConfiguration(undefined, { + const configuration = this.configurationService.getConfiguration({ resource: folder.uri }); let ignored: string[] = []; diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index f9fafed499d..1a0c498f2dc 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -224,7 +224,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private getExcludes(root?: URI): IExpression { const scope = root ? { resource: root } : void 0; - return getExcludes(this.configurationService.getConfiguration(void 0, scope)); + return getExcludes(this.configurationService.getConfiguration(scope)); } private registerListeners(): void { From 878233682f1f2798ac42a349fc0f194e2fe4678c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 00:36:54 +0200 Subject: [PATCH 019/303] Watermark: Adopt to new configuration update event. Check if key has changed. --- .../watermark/electron-browser/watermark.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 21c46e71bdd..effbdb62019 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -100,6 +100,7 @@ const folderEntries = [ ]; const UNBOUND = nls.localize('watermark.unboundCommand', "unbound"); +const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled'; export class WatermarkContribution implements IWorkbenchContribution { @@ -120,19 +121,21 @@ export class WatermarkContribution implements IWorkbenchContribution { lifecycleService.onShutdown(this.dispose, this); this.partService.joinCreation().then(() => { - this.enabled = this.configurationService.getValue('workbench.tips.enabled'); + this.enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (this.enabled) { this.create(); } }); this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - const enabled = this.configurationService.getValue('workbench.tips.enabled'); - if (enabled !== this.enabled) { - this.enabled = enabled; - if (this.enabled) { - this.create(); - } else { - this.destroy(); + if (e.hasKeyChanged(WORKBENCH_TIPS_ENABLED_KEY)) { + const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); + if (enabled !== this.enabled) { + this.enabled = enabled; + if (this.enabled) { + this.create(); + } else { + this.destroy(); + } } } })); From 3151c10d70814f7346c7a236d0ec74f610b876b3 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 11:38:58 +0200 Subject: [PATCH 020/303] - Ability to write configuration into memory - CLean up: Separate models and interfaces --- .../standalone/browser/simpleServices.ts | 4 +- .../configuration/common/configuration.ts | 339 ++++----------- .../common/configurationModels.ts | 405 ++++++++++++++++++ src/vs/platform/configuration/common/model.ts | 194 --------- .../node/configurationService.ts | 4 +- .../test/common/configuration.model.test.ts | 2 +- ...del.test.ts => configurationModel.test.ts} | 2 +- .../test/common/testConfigurationService.ts | 3 +- .../api/node/extHostConfiguration.ts | 3 +- .../common/configurationModels.ts | 21 +- .../node/configurationService.ts | 46 +- .../api/extHostConfiguration.test.ts | 2 +- 12 files changed, 560 insertions(+), 465 deletions(-) create mode 100644 src/vs/platform/configuration/common/configurationModels.ts delete mode 100644 src/vs/platform/configuration/common/model.ts rename src/vs/platform/configuration/test/common/{model.test.ts => configurationModel.test.ts} (98%) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 75aaa4492f9..a9b23d8d74f 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -8,7 +8,7 @@ import { Schemas } from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, IConfigurationChangeEvent, Configuration, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IEditor, IEditorInput, IEditorOptions, IEditorService, IResourceInput, Position } from 'vs/platform/editor/common/editor'; import { ICommandService, ICommand, ICommandEvent, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -23,7 +23,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; import Event, { Emitter } from 'vs/base/common/event'; -import { DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; +import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 43da9ac3cfb..74fba9962fd 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -5,14 +5,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as arrays from 'vs/base/common/arrays'; -import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; +import * as types from 'vs/base/common/types'; import URI from 'vs/base/common/uri'; -import { StrictResourceMap } from 'vs/base/common/map'; -import { Workspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; -import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; export const IConfigurationService = createDecorator('configurationService'); @@ -66,7 +66,8 @@ export interface IConfigurationService { default: T, user: T, workspace: T, - workspaceFolder: T + workspaceFolder: T, + memory?: T, value: T, }; @@ -75,15 +76,42 @@ export interface IConfigurationService { user: string[]; workspace: string[]; workspaceFolder: string[]; + memory?: string[]; }; } -export function overrideIdentifierFromKey(key: string): string { - return key.substring(1, key.length - 1); +export interface IConfiguraionModel { + contents: T; + keys: string[]; + overrides: IOverrides[]; } -export function keyFromOverrideIdentifier(overrideIdentifier: string): string { - return `[${overrideIdentifier}]`; +export interface IOverrides { + contents: T; + identifiers: string[]; +} + +export interface IConfigurationData { + defaults: IConfiguraionModel; + user: IConfiguraionModel; + workspace: IConfiguraionModel; + folders: { [folder: string]: IConfiguraionModel }; +} + +export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { + const added = to.keys.filter(key => from.keys.indexOf(key) === -1); + const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); + const updated = []; + + for (const key of from.keys) { + const value1 = getConfigurationValue(from.contents, key); + const value2 = getConfigurationValue(to.contents, key); + if (!objects.equals(value1, value2)) { + updated.push(key); + } + } + + return { added, removed, updated }; } export function toConfigurationUpdateEvent(udpated: string[], source: ConfigurationTarget, sourceConfig: any): IConfigurationChangeEvent { @@ -102,6 +130,45 @@ export function toConfigurationUpdateEvent(udpated: string[], source: Configurat return { keys, sections, overrideIdentifiers, source, sourceConfig, hasSectionChanged, hasKeyChanged }; } + +export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any { + const root = Object.create(null); + + for (let key in properties) { + addToValueTree(root, key, properties[key], conflictReporter); + } + + return root; +} + +export function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void { + const segments = key.split('.'); + const last = segments.pop(); + + let curr = settingsTreeRoot; + for (let i = 0; i < segments.length; i++) { + let s = segments[i]; + let obj = curr[s]; + switch (typeof obj) { + case 'undefined': + obj = curr[s] = Object.create(null); + break; + case 'object': + break; + default: + conflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`); + return; + } + curr = obj; + }; + + if (typeof curr === 'object') { + curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606 + } else { + conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`); + } +} + /** * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting) */ @@ -137,245 +204,27 @@ export function merge(base: any, add: any, overwrite: boolean): void { }); } -export interface IConfiguraionModel { - contents: T; - keys: string[]; - overrides: IOverrides[]; +export function getConfigurationKeys(): string[] { + const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + return Object.keys(properties); } -export interface IOverrides { - contents: T; - identifiers: string[]; +export function getDefaultValues(): any { + const valueTreeRoot: any = Object.create(null); + const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + + for (let key in properties) { + let value = properties[key].default; + addToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`)); + } + + return valueTreeRoot; } -export class ConfigurationModel implements IConfiguraionModel { - - constructor(protected _contents: T = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { - } - - public get contents(): T { - return this._contents; - } - - public get overrides(): IOverrides[] { - return this._overrides; - } - - public get keys(): string[] { - return this._keys; - } - - public getContentsFor(section: string): V { - return objects.clone(this.contents[section]); - } - - public override(identifier: string): ConfigurationModel { - const result = new ConfigurationModel(); - const contents = objects.clone(this.contents); - if (this._overrides) { - for (const override of this._overrides) { - if (override.identifiers.indexOf(identifier) !== -1) { - merge(contents, override.contents, true); - } - } - } - result._contents = contents; - return result; - } - - public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { - const mergedModel = new ConfigurationModel(); - this.doMerge(mergedModel, this, overwrite); - this.doMerge(mergedModel, other, overwrite); - return mergedModel; - } - - protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { - merge(source.contents, objects.clone(target.contents), overwrite); - const overrides = objects.clone(source._overrides); - for (const override of target._overrides) { - const [sourceOverride] = overrides.filter(o => arrays.equals(o.identifiers, override.identifiers)); - if (sourceOverride) { - merge(sourceOverride.contents, override.contents, overwrite); - } else { - overrides.push(override); - } - } - source._overrides = overrides; - } +export function overrideIdentifierFromKey(key: string): string { + return key.substring(1, key.length - 1); } -export function compare(from: ConfigurationModel, to: ConfigurationModel): { added: string[], removed: string[], updated: string[] } { - const added = to.keys.filter(key => from.keys.indexOf(key) === -1); - const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); - const updated = []; - - for (const key of from.keys) { - const value1 = getConfigurationValue(from.contents, key); - const value2 = getConfigurationValue(to.contents, key); - if (!objects.equals(value1, value2)) { - updated.push(key); - } - } - - return { added, removed, updated }; -} - -export interface IConfigurationData { - defaults: IConfiguraionModel; - user: IConfiguraionModel; - workspace: IConfiguraionModel; - folders: { [folder: string]: IConfiguraionModel }; -} - -export class Configuration { - - private _globalConfiguration: ConfigurationModel; - private _workspaceConsolidatedConfiguration: ConfigurationModel; - protected _foldersConsolidatedConfigurations: StrictResourceMap>; - - constructor(protected _defaults: ConfigurationModel, protected _user: ConfigurationModel, protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), protected folders: StrictResourceMap> = new StrictResourceMap>(), protected _workspace?: Workspace) { - this.merge(); - } - - get defaults(): ConfigurationModel { - return this._defaults; - } - - get user(): ConfigurationModel { - return this._user; - } - - get workspace(): ConfigurationModel { - return this._workspaceConfiguration; - } - - protected merge(): void { - this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); - this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); - this._foldersConsolidatedConfigurations = new StrictResourceMap>(); - for (const folder of this.folders.keys()) { - this.mergeFolder(folder); - } - } - - protected mergeFolder(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); - } - - getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { - const configModel = this.getConsolidateConfigurationModel(overrides); - return section ? configModel.getContentsFor(section) : configModel.contents; - } - - getValue2(key: string, overrides: IConfigurationOverrides = {}): any { - // make sure to clone the configuration so that the receiver does not tamper with the values - const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); - } - - lookup(key: string, overrides: IConfigurationOverrides = {}): { - default: C, - user: C, - workspace: C, - workspaceFolder: C - value: C, - } { - // make sure to clone the configuration so that the receiver does not tamper with the values - const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); - return { - default: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)), - user: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)), - workspace: objects.clone(this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0), //Check on workspace exists or not because _workspaceConfiguration is never null - workspaceFolder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), - value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) - }; - } - - keys(): { - default: string[]; - user: string[]; - workspace: string[]; - workspaceFolder: string[]; - } { - const folderConfigurationModel = this.getFolderConfigurationModelForResource(); - return { - default: this._defaults.keys, - user: this._user.keys, - workspace: this._workspaceConfiguration.keys, - workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : [] - }; - } - - private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { - let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); - return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; - } - - private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { - if (!this._workspace) { - return this._globalConfiguration; - } - - if (!resource) { - return this._workspaceConsolidatedConfiguration; - } - - const root = this._workspace.getFolder(resource); - if (!root) { - return this._workspaceConsolidatedConfiguration; - } - - return this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration; - } - - private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { - if (!this._workspace || !resource) { - return null; - } - - const root = this._workspace.getFolder(resource); - return root ? this.folders.get(root.uri) : null; - } - - public toData(): IConfigurationData { - return { - defaults: { - contents: this._defaults.contents, - overrides: this._defaults.overrides, - keys: this._defaults.keys - }, - user: { - contents: this._user.contents, - overrides: this._user.overrides, - keys: this._user.keys - }, - workspace: { - contents: this._workspaceConfiguration.contents, - overrides: this._workspaceConfiguration.overrides, - keys: this._workspaceConfiguration.keys - }, - folders: this.folders.keys().reduce((result, folder) => { - const { contents, overrides, keys } = this.folders.get(folder); - result[folder.toString()] = { contents, overrides, keys }; - return result; - }, Object.create({})) - }; - } - - public static parse(data: IConfigurationData, workspace: Workspace): Configuration { - const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); - const userConfiguration = Configuration.parseConfigurationModel(data.user); - const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); - const folders: StrictResourceMap> = Object.keys(data.folders).reduce((result, key) => { - result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); - return result; - }, new StrictResourceMap>()); - return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, workspace); - } - - private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { - return new ConfigurationModel(model.contents, model.keys, model.overrides); - } +export function keyFromOverrideIdentifier(overrideIdentifier: string): string { + return `[${overrideIdentifier}]`; } \ No newline at end of file diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts new file mode 100644 index 00000000000..4d619fbc13b --- /dev/null +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -0,0 +1,405 @@ +/*--------------------------------------------------------------------------------------------- + * 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 json from 'vs/base/common/json'; +import { StrictResourceMap } from 'vs/base/common/map'; +import * as arrays from 'vs/base/common/arrays'; +import * as objects from 'vs/base/common/objects'; +import URI from 'vs/base/common/uri'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys } from 'vs/platform/configuration/common/configuration'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; + +export class ConfigurationModel implements IConfiguraionModel { + + constructor(protected _contents: T = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { + } + + public get contents(): T { + return this._contents; + } + + public get overrides(): IOverrides[] { + return this._overrides; + } + + public get keys(): string[] { + return this._keys; + } + + public getContentsFor(section: string): V { + return objects.clone(this.contents[section]); + } + + public override(identifier: string): ConfigurationModel { + const result = new ConfigurationModel(); + const contents = objects.clone(this.contents); + if (this._overrides) { + for (const override of this._overrides) { + if (override.identifiers.indexOf(identifier) !== -1) { + merge(contents, override.contents, true); + } + } + } + result._contents = contents; + return result; + } + + public setValue(key: string, value: any) { + addToValueTree(this._contents, key, value, e => { throw new Error(e); }); + if (this._keys.indexOf(key) === -1) { + this._keys.push(key); + } + } + + public removeValue(key: string) { + // Remove key from the value tree + const index = this._keys.indexOf(key); + if (index !== -1) { + this._keys.splice(index, 1); + } + } + + public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { + const mergedModel = new ConfigurationModel(); + this.doMerge(mergedModel, this, overwrite); + this.doMerge(mergedModel, other, overwrite); + return mergedModel; + } + + protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { + merge(source.contents, objects.clone(target.contents), overwrite); + const overrides = objects.clone(source._overrides); + for (const override of target._overrides) { + const [sourceOverride] = overrides.filter(o => arrays.equals(o.identifiers, override.identifiers)); + if (sourceOverride) { + merge(sourceOverride.contents, override.contents, overwrite); + } else { + overrides.push(override); + } + } + source._overrides = overrides; + } +} + +export class DefaultConfigurationModel extends ConfigurationModel { + + constructor() { + super(getDefaultValues()); + this._keys = getConfigurationKeys(); + this._overrides = Object.keys(this._contents) + .filter(key => OVERRIDE_PROPERTY_PATTERN.test(key)) + .map(key => { + return >{ + identifiers: [overrideIdentifierFromKey(key).trim()], + contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`)) + }; + }); + } + + public get keys(): string[] { + return this._keys; + } +} + +interface Overrides extends IOverrides { + raw: any; +} + +export class CustomConfigurationModel extends ConfigurationModel { + + protected _parseErrors: any[] = []; + + constructor(content: string = '', private name: string = '') { + super(); + if (content) { + this.update(content); + } + } + + public get errors(): any[] { + return this._parseErrors; + } + + public update(content: string): void { + let parsed: T = {}; + let overrides: Overrides[] = []; + let currentProperty: string = null; + let currentParent: any = []; + let previousParents: any[] = []; + let parseErrors: json.ParseError[] = []; + + function onValue(value: any) { + if (Array.isArray(currentParent)) { + (currentParent).push(value); + } else if (currentProperty) { + currentParent[currentProperty] = value; + } + if (OVERRIDE_PROPERTY_PATTERN.test(currentProperty)) { + onOverrideSettingsValue(currentProperty, value); + } + } + + function onOverrideSettingsValue(property: string, value: any): void { + overrides.push({ + identifiers: [overrideIdentifierFromKey(property).trim()], + raw: value, + contents: null + }); + } + + let visitor: json.JSONVisitor = { + onObjectBegin: () => { + let object = {}; + onValue(object); + previousParents.push(currentParent); + currentParent = object; + currentProperty = null; + }, + onObjectProperty: (name: string) => { + currentProperty = name; + }, + onObjectEnd: () => { + currentParent = previousParents.pop(); + }, + onArrayBegin: () => { + let array: any[] = []; + onValue(array); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: () => { + currentParent = previousParents.pop(); + }, + onLiteralValue: onValue, + onError: (error: json.ParseErrorCode) => { + parseErrors.push({ error: error }); + } + }; + if (content) { + try { + json.visit(content, visitor); + parsed = currentParent[0] || {}; + } catch (e) { + console.error(`Error while parsing settings file ${this.name}: ${e}`); + this._parseErrors = [e]; + } + } + this.processRaw(parsed); + + const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + this._overrides = overrides.map>(override => { + // Filter unknown and non-overridable properties + const raw = {}; + for (const key in override.raw) { + if (configurationProperties[key] && configurationProperties[key].overridable) { + raw[key] = override.raw[key]; + } + } + return { + identifiers: override.identifiers, + contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) + }; + }); + } + + protected processRaw(raw: T): void { + this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); + this._keys = Object.keys(raw); + } +} + +export class Configuration { + + private _globalConfiguration: ConfigurationModel; + private _workspaceConsolidatedConfiguration: ConfigurationModel; + protected _foldersConsolidatedConfigurations: StrictResourceMap>; + protected _memoryConsolidatedConfigurations: StrictResourceMap>; + + constructor(protected _defaults: ConfigurationModel, + protected _user: ConfigurationModel, + protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), + protected folders: StrictResourceMap> = new StrictResourceMap>(), + protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), + protected _memoryConfigurationByResource: StrictResourceMap> = new StrictResourceMap>(), + protected _workspace?: Workspace) { + this.merge(); + } + + get defaults(): ConfigurationModel { + return this._defaults; + } + + get user(): ConfigurationModel { + return this._user; + } + + get workspace(): ConfigurationModel { + return this._workspaceConfiguration; + } + + protected merge(): void { + this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); + this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); + this._foldersConsolidatedConfigurations = new StrictResourceMap>(); + for (const folder of this.folders.keys()) { + this.mergeFolder(folder); + } + } + + protected mergeFolder(folder: URI) { + this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + } + + protected mergeMemory(folder: URI) { + this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + } + + getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { + const configModel = this.getConsolidateConfigurationModel(overrides); + return section ? configModel.getContentsFor(section) : configModel.contents; + } + + getValue2(key: string, overrides: IConfigurationOverrides = {}): any { + // make sure to clone the configuration so that the receiver does not tamper with the values + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); + return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); + } + + updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { + let memoryConfiguration: ConfigurationModel; + if (overrides.resource) { + let memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource); + if (!memoryConfiguration) { + memoryConfiguration = new ConfigurationModel(); + this._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration); + } + } else { + memoryConfiguration = this._memoryConfiguration; + } + if (value === void 0) { + memoryConfiguration.removeValue(key); + } else { + memoryConfiguration.setValue(key, value); + } + } + + lookup(key: string, overrides: IConfigurationOverrides = {}): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + memory?: C + value: C, + } { + // make sure to clone the configuration so that the receiver does not tamper with the values + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); + const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); + const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; + return { + default: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)), + user: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)), + workspace: objects.clone(this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0), //Check on workspace exists or not because _workspaceConfiguration is never null + workspaceFolder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), + memory: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key)), + value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) + }; + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + const folderConfigurationModel = this.getFolderConfigurationModelForResource(); + return { + default: this._defaults.keys, + user: this._user.keys, + workspace: this._workspaceConfiguration.keys, + workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : [] + }; + } + + private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { + let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); + return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; + } + + private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { + if (!this._workspace) { + return this._globalConfiguration; + } + + if (!resource) { + return this._workspaceConsolidatedConfiguration.merge(this._memoryConfiguration); + } + + let consolidateConfiguration = this._workspaceConsolidatedConfiguration; + const root = this._workspace.getFolder(resource); + if (root) { + consolidateConfiguration = this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration; + } + + const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource); + if (memoryConfigurationForResource) { + consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource); + } + + return consolidateConfiguration; + } + + private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { + if (!this._workspace || !resource) { + return null; + } + + const root = this._workspace.getFolder(resource); + return root ? this.folders.get(root.uri) : null; + } + + public toData(): IConfigurationData { + return { + defaults: { + contents: this._defaults.contents, + overrides: this._defaults.overrides, + keys: this._defaults.keys + }, + user: { + contents: this._user.contents, + overrides: this._user.overrides, + keys: this._user.keys + }, + workspace: { + contents: this._workspaceConfiguration.contents, + overrides: this._workspaceConfiguration.overrides, + keys: this._workspaceConfiguration.keys + }, + folders: this.folders.keys().reduce((result, folder) => { + const { contents, overrides, keys } = this.folders.get(folder); + result[folder.toString()] = { contents, overrides, keys }; + return result; + }, Object.create({})) + }; + } + + public static parse(data: IConfigurationData, workspace: Workspace): Configuration { + const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); + const userConfiguration = Configuration.parseConfigurationModel(data.user); + const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); + const folders: StrictResourceMap> = Object.keys(data.folders).reduce((result, key) => { + result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); + return result; + }, new StrictResourceMap>()); + return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap>(), workspace); + } + + private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { + return new ConfigurationModel(model.contents, model.keys, model.overrides); + } +} \ No newline at end of file diff --git a/src/vs/platform/configuration/common/model.ts b/src/vs/platform/configuration/common/model.ts deleted file mode 100644 index 2eca51661ff..00000000000 --- a/src/vs/platform/configuration/common/model.ts +++ /dev/null @@ -1,194 +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 { Registry } from 'vs/platform/registry/common/platform'; -import * as json from 'vs/base/common/json'; -import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { ConfigurationModel, IOverrides, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; - -export function getDefaultValues(): any { - const valueTreeRoot: any = Object.create(null); - const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - - for (let key in properties) { - let value = properties[key].default; - addToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`)); - } - - return valueTreeRoot; -} - -export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any { - const root = Object.create(null); - - for (let key in properties) { - addToValueTree(root, key, properties[key], conflictReporter); - } - - return root; -} - -function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void { - const segments = key.split('.'); - const last = segments.pop(); - - let curr = settingsTreeRoot; - for (let i = 0; i < segments.length; i++) { - let s = segments[i]; - let obj = curr[s]; - switch (typeof obj) { - case 'undefined': - obj = curr[s] = Object.create(null); - break; - case 'object': - break; - default: - conflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`); - return; - } - curr = obj; - }; - - if (typeof curr === 'object') { - curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606 - } else { - conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`); - } -} - -export function getConfigurationKeys(): string[] { - const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - - return Object.keys(properties); -} - -export class DefaultConfigurationModel extends ConfigurationModel { - - constructor() { - super(getDefaultValues()); - this._keys = getConfigurationKeys(); - this._overrides = Object.keys(this._contents) - .filter(key => OVERRIDE_PROPERTY_PATTERN.test(key)) - .map(key => { - return >{ - identifiers: [overrideIdentifierFromKey(key).trim()], - contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`)) - }; - }); - } - - public get keys(): string[] { - return this._keys; - } -} - -interface Overrides extends IOverrides { - raw: any; -} - -export class CustomConfigurationModel extends ConfigurationModel { - - protected _parseErrors: any[] = []; - - constructor(content: string = '', private name: string = '') { - super(); - if (content) { - this.update(content); - } - } - - public get errors(): any[] { - return this._parseErrors; - } - - public update(content: string): void { - let parsed: T = {}; - let overrides: Overrides[] = []; - let currentProperty: string = null; - let currentParent: any = []; - let previousParents: any[] = []; - let parseErrors: json.ParseError[] = []; - - function onValue(value: any) { - if (Array.isArray(currentParent)) { - (currentParent).push(value); - } else if (currentProperty) { - currentParent[currentProperty] = value; - } - if (OVERRIDE_PROPERTY_PATTERN.test(currentProperty)) { - onOverrideSettingsValue(currentProperty, value); - } - } - - function onOverrideSettingsValue(property: string, value: any): void { - overrides.push({ - identifiers: [overrideIdentifierFromKey(property).trim()], - raw: value, - contents: null - }); - } - - let visitor: json.JSONVisitor = { - onObjectBegin: () => { - let object = {}; - onValue(object); - previousParents.push(currentParent); - currentParent = object; - currentProperty = null; - }, - onObjectProperty: (name: string) => { - currentProperty = name; - }, - onObjectEnd: () => { - currentParent = previousParents.pop(); - }, - onArrayBegin: () => { - let array: any[] = []; - onValue(array); - previousParents.push(currentParent); - currentParent = array; - currentProperty = null; - }, - onArrayEnd: () => { - currentParent = previousParents.pop(); - }, - onLiteralValue: onValue, - onError: (error: json.ParseErrorCode) => { - parseErrors.push({ error: error }); - } - }; - if (content) { - try { - json.visit(content, visitor); - parsed = currentParent[0] || {}; - } catch (e) { - console.error(`Error while parsing settings file ${this.name}: ${e}`); - this._parseErrors = [e]; - } - } - this.processRaw(parsed); - - const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - this._overrides = overrides.map>(override => { - // Filter unknown and non-overridable properties - const raw = {}; - for (const key in override.raw) { - if (configurationProperties[key] && configurationProperties[key].overridable) { - raw[key] = override.raw[key]; - } - } - return { - identifiers: override.identifiers, - contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) - }; - }); - } - - protected processRaw(raw: T): void { - this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); - this._keys = Object.keys(raw); - } -} \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 0d97199766b..6cfa5d53fb7 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -8,8 +8,8 @@ import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, toConfigurationUpdateEvent, ConfigurationModel, Configuration, compare } from 'vs/platform/configuration/common/configuration'; -import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, toConfigurationUpdateEvent, compare } from 'vs/platform/configuration/common/configuration'; +import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration } from 'vs/platform/configuration/common/configurationModels'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { onUnexpectedError } from 'vs/base/common/errors'; diff --git a/src/vs/platform/configuration/test/common/configuration.model.test.ts b/src/vs/platform/configuration/test/common/configuration.model.test.ts index 42b52919b33..4b4ff1e3ed1 100644 --- a/src/vs/platform/configuration/test/common/configuration.model.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.model.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; diff --git a/src/vs/platform/configuration/test/common/model.test.ts b/src/vs/platform/configuration/test/common/configurationModel.test.ts similarity index 98% rename from src/vs/platform/configuration/test/common/model.test.ts rename to src/vs/platform/configuration/test/common/configurationModel.test.ts index aa9597b6702..3cc4f519bc2 100644 --- a/src/vs/platform/configuration/test/common/model.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModel.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; +import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 5653f211b14..2410406e261 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -9,8 +9,7 @@ import { TernarySearchTree } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { getConfigurationKeys } from 'vs/platform/configuration/common/model'; -import { IConfigurationOverrides, IConfigurationService, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService extends EventEmitter implements IConfigurationService { public _serviceBrand: any; diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 9e5101340bf..1647e1736ac 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -11,7 +11,8 @@ import { WorkspaceConfiguration } from 'vscode'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; -import { IConfigurationData, Configuration } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { Configuration } from 'vs/platform/configuration/common/configurationModels'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; function lookUp(tree: any, key: string) { diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index b23dc396e7c..85afabd93a7 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,8 +5,8 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { CustomConfigurationModel, toValuesTree } from 'vs/platform/configuration/common/model'; -import { ConfigurationModel, Configuration as BaseConfiguration, compare } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; @@ -185,8 +185,15 @@ export class FolderConfigurationModel extends CustomConfigurationModel { export class Configuration extends BaseConfiguration { - constructor(defaults: ConfigurationModel, user: ConfigurationModel, workspaceConfiguration: ConfigurationModel, protected folders: StrictResourceMap>, workspace: Workspace) { - super(defaults, user, workspaceConfiguration, folders, workspace); + constructor( + defaults: ConfigurationModel, + user: ConfigurationModel, + workspaceConfiguration: ConfigurationModel, + protected folders: StrictResourceMap>, + memoryConfiguration: ConfigurationModel, + memoryConfigurationByResource: StrictResourceMap>, + workspace: Workspace) { + super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource, workspace); } updateDefaultConfiguration(defaults: ConfigurationModel): void { @@ -199,7 +206,7 @@ export class Configuration extends BaseConfiguration { const { added, updated, removed } = compare(this._user, user); changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { - const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); this._user = user; this.merge(); @@ -215,7 +222,7 @@ export class Configuration extends BaseConfiguration { const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration); changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { - const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); this._workspaceConfiguration = workspaceConfiguration; this.merge(); @@ -234,7 +241,7 @@ export class Configuration extends BaseConfiguration { const { added, updated, removed } = compare(currentFolderConfiguration, configuration); changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { - const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._workspace); + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); this.folders.set(resource, configuration); this.mergeFolder(resource); diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index f5b7cef1e68..4e4b99992ee 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -22,9 +22,9 @@ import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { CustomConfigurationModel } from 'vs/platform/configuration/common/model'; +import { CustomConfigurationModel, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { IConfigurationChangeEvent, ConfigurationTarget, toConfigurationUpdateEvent, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration } from 'vs/workbench/services/configuration/common/configurationModels'; -import { IConfigurationChangeEvent, ConfigurationTarget, toConfigurationUpdateEvent, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { ConfigurationService as GlobalConfigurationService, isConfigurationOverrides } from 'vs/platform/configuration/node/configurationService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -152,13 +152,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat if (this.configurationEditingService) { const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); - if (target) { - if (target === ConfigurationTarget.MEMORY) { - return TPromise.as(null); - } else { - return this.writeConfigurationValue(key, value, target, overrides); - } + return this.writeConfigurationValue(key, value, target, overrides); } } return TPromise.as(null); @@ -176,6 +171,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat user: T, workspace: T, workspaceFolder: T, + memory?: T, value: T } { return this._configuration.lookup(key); @@ -329,7 +325,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat const folderConfigurationModels = new StrictResourceMap>(); folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration)); - this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null + this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap>(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null // TODO: compare with old values?? const keys = this._configuration.keys(); @@ -465,6 +461,21 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } private writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationOverrides): TPromise { + if (target === ConfigurationTarget.DEFAULT) { + return TPromise.wrapError(new Error('Invalid configuration target')); + } + + let currentTargetValue = this.getTargetValue(key, target, overrides); + if (equals(currentTargetValue, value)) { + return TPromise.as(null); + } + + if (target === ConfigurationTarget.MEMORY) { + this._configuration.updateValue(key, value, overrides); + this.triggerConfigurationChange([key], target); + return TPromise.as(null); + } + return this.configurationEditingService.writeConfiguration(this.toEditableConfigurationTarget(target), { key, value }, { scopes: overrides }) .then(() => { switch (target) { @@ -528,6 +539,23 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } } + private getTargetValue(key: string, target: ConfigurationTarget, overrides?: IConfigurationOverrides): any { + const inspect = this.inspect(key, overrides); + switch (target) { + case ConfigurationTarget.DEFAULT: + return inspect.default; + case ConfigurationTarget.USER: + return inspect.user; + case ConfigurationTarget.WORKSPACE: + return inspect.workspace; + case ConfigurationTarget.WORKSPACE_FOLDER: + return inspect.workspaceFolder; + case ConfigurationTarget.MEMORY: + return inspect.memory; + } + return void 0; + } + private getTargetConfiguration(target: ConfigurationTarget): any { switch (target) { case ConfigurationTarget.DEFAULT: diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index a935f3c9eed..54fa31a10d4 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -12,7 +12,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration import { MainThreadConfigurationShape } from 'vs/workbench/api/node/extHost.protocol'; import { TPromise } from 'vs/base/common/winjs.base'; import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; From 38f2f142b01dae11ddc56e28b720ad717c4fa836 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 11:48:02 +0200 Subject: [PATCH 021/303] Remove unnecessary generics in configuration area --- src/vs/code/electron-main/app.ts | 2 +- .../standalone/browser/simpleServices.ts | 4 +- .../configuration/common/configuration.ts | 22 ++--- .../common/configurationModels.ts | 96 +++++++++---------- .../node/configurationService.ts | 14 +-- .../test/common/configuration.model.test.ts | 20 ++-- src/vs/workbench/api/node/extHost.protocol.ts | 4 +- .../api/node/extHostConfiguration.ts | 6 +- .../common/configurationModels.ts | 76 +++++++-------- .../node/configurationService.ts | 50 +++++----- 10 files changed, 147 insertions(+), 147 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 789da519ee2..2efd0e0d351 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -76,7 +76,7 @@ export class CodeApplication { @ILogService private logService: ILogService, @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, - @IConfigurationService private configurationService: ConfigurationService, + @IConfigurationService private configurationService: ConfigurationService, @IStorageService private storageService: IStorageService, @IHistoryMainService private historyService: IHistoryMainService ) { diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index a9b23d8d74f..3d84c45b5eb 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -442,13 +442,13 @@ export class SimpleConfigurationService implements IConfigurationService { private _onDidUpdateConfiguration = new Emitter(); public onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; - private _configuration: Configuration; + private _configuration: Configuration; constructor() { this._configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel()); } - private configuration(): Configuration { + private configuration(): Configuration { return this._configuration; } diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 74fba9962fd..b9cbfb0a599 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -80,25 +80,25 @@ export interface IConfigurationService { }; } -export interface IConfiguraionModel { - contents: T; +export interface IConfiguraionModel { + contents: any; keys: string[]; - overrides: IOverrides[]; + overrides: IOverrides[]; } -export interface IOverrides { - contents: T; +export interface IOverrides { + contents: any; identifiers: string[]; } -export interface IConfigurationData { - defaults: IConfiguraionModel; - user: IConfiguraionModel; - workspace: IConfiguraionModel; - folders: { [folder: string]: IConfiguraionModel }; +export interface IConfigurationData { + defaults: IConfiguraionModel; + user: IConfiguraionModel; + workspace: IConfiguraionModel; + folders: { [folder: string]: IConfiguraionModel }; } -export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { +export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { const added = to.keys.filter(key => from.keys.indexOf(key) === -1); const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); const updated = []; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 4d619fbc13b..8a207935c4a 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -14,16 +14,16 @@ import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'v import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; -export class ConfigurationModel implements IConfiguraionModel { +export class ConfigurationModel implements IConfiguraionModel { - constructor(protected _contents: T = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { + constructor(protected _contents: any = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { } - public get contents(): T { + public get contents(): any { return this._contents; } - public get overrides(): IOverrides[] { + public get overrides(): IOverrides[] { return this._overrides; } @@ -35,8 +35,8 @@ export class ConfigurationModel implements IConfiguraionModel { return objects.clone(this.contents[section]); } - public override(identifier: string): ConfigurationModel { - const result = new ConfigurationModel(); + public override(identifier: string): ConfigurationModel { + const result = new ConfigurationModel(); const contents = objects.clone(this.contents); if (this._overrides) { for (const override of this._overrides) { @@ -64,14 +64,14 @@ export class ConfigurationModel implements IConfiguraionModel { } } - public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { - const mergedModel = new ConfigurationModel(); + public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { + const mergedModel = new ConfigurationModel(); this.doMerge(mergedModel, this, overwrite); this.doMerge(mergedModel, other, overwrite); return mergedModel; } - protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { + protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { merge(source.contents, objects.clone(target.contents), overwrite); const overrides = objects.clone(source._overrides); for (const override of target._overrides) { @@ -86,7 +86,7 @@ export class ConfigurationModel implements IConfiguraionModel { } } -export class DefaultConfigurationModel extends ConfigurationModel { +export class DefaultConfigurationModel extends ConfigurationModel { constructor() { super(getDefaultValues()); @@ -94,7 +94,7 @@ export class DefaultConfigurationModel extends ConfigurationModel { this._overrides = Object.keys(this._contents) .filter(key => OVERRIDE_PROPERTY_PATTERN.test(key)) .map(key => { - return >{ + return { identifiers: [overrideIdentifierFromKey(key).trim()], contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`)) }; @@ -106,11 +106,11 @@ export class DefaultConfigurationModel extends ConfigurationModel { } } -interface Overrides extends IOverrides { +interface Overrides extends IOverrides { raw: any; } -export class CustomConfigurationModel extends ConfigurationModel { +export class CustomConfigurationModel extends ConfigurationModel { protected _parseErrors: any[] = []; @@ -126,8 +126,8 @@ export class CustomConfigurationModel extends ConfigurationModel { } public update(content: string): void { - let parsed: T = {}; - let overrides: Overrides[] = []; + let parsed: any = {}; + let overrides: Overrides[] = []; let currentProperty: string = null; let currentParent: any = []; let previousParents: any[] = []; @@ -193,7 +193,7 @@ export class CustomConfigurationModel extends ConfigurationModel { this.processRaw(parsed); const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - this._overrides = overrides.map>(override => { + this._overrides = overrides.map(override => { // Filter unknown and non-overridable properties const raw = {}; for (const key in override.raw) { @@ -203,61 +203,61 @@ export class CustomConfigurationModel extends ConfigurationModel { } return { identifiers: override.identifiers, - contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) + contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) }; }); } - protected processRaw(raw: T): void { + protected processRaw(raw: any): void { this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); this._keys = Object.keys(raw); } } -export class Configuration { +export class Configuration { - private _globalConfiguration: ConfigurationModel; - private _workspaceConsolidatedConfiguration: ConfigurationModel; - protected _foldersConsolidatedConfigurations: StrictResourceMap>; - protected _memoryConsolidatedConfigurations: StrictResourceMap>; + private _globalConfiguration: ConfigurationModel; + private _workspaceConsolidatedConfiguration: ConfigurationModel; + protected _foldersConsolidatedConfigurations: StrictResourceMap; + protected _memoryConsolidatedConfigurations: StrictResourceMap; - constructor(protected _defaults: ConfigurationModel, - protected _user: ConfigurationModel, - protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), - protected folders: StrictResourceMap> = new StrictResourceMap>(), - protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), - protected _memoryConfigurationByResource: StrictResourceMap> = new StrictResourceMap>(), + constructor(protected _defaults: ConfigurationModel, + protected _user: ConfigurationModel, + protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), + protected folders: StrictResourceMap = new StrictResourceMap(), + protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), + protected _memoryConfigurationByResource: StrictResourceMap = new StrictResourceMap(), protected _workspace?: Workspace) { this.merge(); } - get defaults(): ConfigurationModel { + get defaults(): ConfigurationModel { return this._defaults; } - get user(): ConfigurationModel { + get user(): ConfigurationModel { return this._user; } - get workspace(): ConfigurationModel { + get workspace(): ConfigurationModel { return this._workspaceConfiguration; } protected merge(): void { - this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); - this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); - this._foldersConsolidatedConfigurations = new StrictResourceMap>(); + this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); + this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); + this._foldersConsolidatedConfigurations = new StrictResourceMap(); for (const folder of this.folders.keys()) { this.mergeFolder(folder); } } protected mergeFolder(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); } protected mergeMemory(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); } getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { @@ -272,7 +272,7 @@ export class Configuration { } updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { - let memoryConfiguration: ConfigurationModel; + let memoryConfiguration: ConfigurationModel; if (overrides.resource) { let memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource); if (!memoryConfiguration) { @@ -326,12 +326,12 @@ export class Configuration { }; } - private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { + private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); - return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; + return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; } - private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { + private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { if (!this._workspace) { return this._globalConfiguration; } @@ -354,7 +354,7 @@ export class Configuration { return consolidateConfiguration; } - private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { + private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { if (!this._workspace || !resource) { return null; } @@ -363,7 +363,7 @@ export class Configuration { return root ? this.folders.get(root.uri) : null; } - public toData(): IConfigurationData { + public toData(): IConfigurationData { return { defaults: { contents: this._defaults.contents, @@ -388,18 +388,18 @@ export class Configuration { }; } - public static parse(data: IConfigurationData, workspace: Workspace): Configuration { + public static parse(data: IConfigurationData, workspace: Workspace): Configuration { const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); const userConfiguration = Configuration.parseConfigurationModel(data.user); const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); - const folders: StrictResourceMap> = Object.keys(data.folders).reduce((result, key) => { + const folders: StrictResourceMap = Object.keys(data.folders).reduce((result, key) => { result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); return result; - }, new StrictResourceMap>()); - return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap>(), workspace); + }, new StrictResourceMap()); + return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap(), workspace); } - private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { + private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { return new ConfigurationModel(model.contents, model.keys, model.overrides); } } \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 6cfa5d53fb7..d7b5f65f730 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -25,12 +25,12 @@ export function isConfigurationOverrides(thing: any): thing is IConfigurationOve && (!thing.resource || thing.resource instanceof URI); } -export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { +export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { _serviceBrand: any; - private _configuration: Configuration; - private userConfigModelWatcher: ConfigWatcher>; + private _configuration: Configuration; + private userConfigModelWatcher: ConfigWatcher; private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; @@ -41,8 +41,8 @@ export class ConfigurationService extends Disposable implements IConfiguratio super(); this.userConfigModelWatcher = new ConfigWatcher(environmentService.appSettingsPath, { - changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => { - const userConfigModel = new CustomConfigurationModel(content, environmentService.appSettingsPath); + changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => { + const userConfigModel = new CustomConfigurationModel(content, environmentService.appSettingsPath); parseErrors = [...userConfigModel.errors]; return userConfigModel; } @@ -56,7 +56,7 @@ export class ConfigurationService extends Disposable implements IConfiguratio this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(configurationProperties => this.onDidRegisterConfiguration(configurationProperties))); } - get configuration(): Configuration { + get configuration(): Configuration { return this._configuration; } @@ -126,7 +126,7 @@ export class ConfigurationService extends Disposable implements IConfiguratio } private reset(): void { - const defaults = new DefaultConfigurationModel(); + const defaults = new DefaultConfigurationModel(); const user = this.userConfigModelWatcher.getConfig(); this._configuration = new Configuration(defaults, user); } diff --git a/src/vs/platform/configuration/test/common/configuration.model.test.ts b/src/vs/platform/configuration/test/common/configuration.model.test.ts index 4b4ff1e3ed1..65555f8e9f2 100644 --- a/src/vs/platform/configuration/test/common/configuration.model.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.model.test.ts @@ -29,8 +29,8 @@ suite('Configuration', () => { }); test('simple merge', () => { - let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); - let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); + let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); + let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); let result = base.merge(add); assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); }); @@ -43,24 +43,24 @@ suite('Configuration', () => { }); test('simple merge overrides', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': 2 } }]); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'b': 2 } }]); + let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': 2 } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'b': 2 } }]); let result = base.merge(add); assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': 2, 'b': 2 } }]); }); test('recursive merge overrides', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'e': 2 } } }]); + let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'e': 2 } } }]); let result = base.merge(add); assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': { 'd': 1, 'e': 2 } } }]); }); test('merge ignore keys', () => { - let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); - let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); + let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); + let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); let result = base.merge(add); assert.deepEqual(result.keys, []); }); @@ -69,7 +69,7 @@ suite('Configuration', () => { let testObject = new ConfigurationModel({ 'a': 1 }); assert.deepEqual(testObject.getContentsFor('a'), 1); - testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); + testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); assert.deepEqual(testObject.getContentsFor('a'), { 'b': 1 }); }); @@ -80,7 +80,7 @@ suite('Configuration', () => { }); test('Test override gives all content merged with overrides', () => { - const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); + const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1 }); }); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 4016299feed..16f681bddca 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -74,7 +74,7 @@ export interface IInitData { environment: IEnvironment; workspace: IWorkspaceData; extensions: IExtensionDescription[]; - configuration: IConfigurationData; + configuration: IConfigurationData; telemetryInfo: ITelemetryInfo; } @@ -412,7 +412,7 @@ export interface ExtHostCommandsShape { } export interface ExtHostConfigurationShape { - $acceptConfigurationChanged(data: IConfigurationData): void; + $acceptConfigurationChanged(data: IConfigurationData): void; } export interface ExtHostDiagnosticsShape { diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 1647e1736ac..031763f0ff4 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -39,9 +39,9 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { private readonly _onDidChangeConfiguration = new Emitter(); private readonly _proxy: MainThreadConfigurationShape; private readonly _extHostWorkspace: ExtHostWorkspace; - private _configuration: Configuration; + private _configuration: Configuration; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationData) { this._proxy = proxy; this._extHostWorkspace = extHostWorkspace; this._configuration = Configuration.parse(data, extHostWorkspace.workspace); @@ -51,7 +51,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - $acceptConfigurationChanged(data: IConfigurationData) { + $acceptConfigurationChanged(data: IConfigurationData) { this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace); this._onDidChangeConfiguration.fire(undefined); } diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 85afabd93a7..df0c1b196ee 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -15,14 +15,14 @@ import { Workspace } from 'vs/platform/workspace/common/workspace'; import { StrictResourceMap } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; -export class WorkspaceConfigurationModel extends CustomConfigurationModel { +export class WorkspaceConfigurationModel extends CustomConfigurationModel { - private _raw: T; + private _raw: any; private _folders: IStoredWorkspaceFolder[]; - private _worksapaceSettings: ConfigurationModel; - private _tasksConfiguration: ConfigurationModel; - private _launchConfiguration: ConfigurationModel; - private _workspaceConfiguration: ConfigurationModel; + private _worksapaceSettings: ConfigurationModel; + private _tasksConfiguration: ConfigurationModel; + private _launchConfiguration: ConfigurationModel; + private _workspaceConfiguration: ConfigurationModel; public update(content: string): void { super.update(content); @@ -34,11 +34,11 @@ export class WorkspaceConfigurationModel extends CustomConfigurationModel return this._folders; } - get workspaceConfiguration(): ConfigurationModel { + get workspaceConfiguration(): ConfigurationModel { return this._workspaceConfiguration; } - protected processRaw(raw: T): void { + protected processRaw(raw: any): void { this._raw = raw; this._folders = (this._raw['folders'] || []) as IStoredWorkspaceFolder[]; @@ -49,27 +49,27 @@ export class WorkspaceConfigurationModel extends CustomConfigurationModel super.processRaw(raw); } - private parseConfigurationModel(section: string): ConfigurationModel { + private parseConfigurationModel(section: string): ConfigurationModel { const rawSection = this._raw[section] || {}; const contents = toValuesTree(rawSection, message => console.error(`Conflict in section '${section}' of workspace configuration file ${message}`)); - return new ConfigurationModel(contents, Object.keys(rawSection)); + return new ConfigurationModel(contents, Object.keys(rawSection)); } - private consolidate(): ConfigurationModel { + private consolidate(): ConfigurationModel { const keys: string[] = [...this._worksapaceSettings.keys, ...this._tasksConfiguration.keys.map(key => `tasks.${key}`), ...this._launchConfiguration.keys.map(key => `launch.${key}`)]; - const mergedContents = new ConfigurationModel({}, keys) + const mergedContents = new ConfigurationModel({}, keys) .merge(this._worksapaceSettings) .merge(this._tasksConfiguration) .merge(this._launchConfiguration); - return new ConfigurationModel(mergedContents.contents, keys, mergedContents.overrides); + return new ConfigurationModel(mergedContents.contents, keys, mergedContents.overrides); } } -export class ScopedConfigurationModel extends CustomConfigurationModel { +export class ScopedConfigurationModel extends CustomConfigurationModel { constructor(content: string, name: string, public readonly scope: string) { super(null, name); @@ -85,14 +85,14 @@ export class ScopedConfigurationModel extends CustomConfigurationModel { } -export class FolderSettingsModel extends CustomConfigurationModel { +export class FolderSettingsModel extends CustomConfigurationModel { - private _raw: T; + private _raw: any; private _unsupportedKeys: string[]; - protected processRaw(raw: T): void { + protected processRaw(raw: any): void { this._raw = raw; - const processedRaw = {}; + const processedRaw = {}; this._unsupportedKeys = []; const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); for (let key in raw) { @@ -121,16 +121,16 @@ export class FolderSettingsModel extends CustomConfigurationModel { return !propertySchema.isExecutable; } - public createWorkspaceConfigurationModel(): ConfigurationModel { + public createWorkspaceConfigurationModel(): ConfigurationModel { return this.createScopedConfigurationModel(ConfigurationScope.WINDOW); } - public createFolderScopedConfigurationModel(): ConfigurationModel { + public createFolderScopedConfigurationModel(): ConfigurationModel { return this.createScopedConfigurationModel(ConfigurationScope.RESOURCE); } - private createScopedConfigurationModel(scope: ConfigurationScope): ConfigurationModel { - const workspaceRaw = {}; + private createScopedConfigurationModel(scope: ConfigurationScope): ConfigurationModel { + const workspaceRaw = {}; const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); for (let key in this._raw) { if (this.getScope(key, configurationProperties) === scope) { @@ -148,15 +148,15 @@ export class FolderSettingsModel extends CustomConfigurationModel { } } -export class FolderConfigurationModel extends CustomConfigurationModel { +export class FolderConfigurationModel extends CustomConfigurationModel { - constructor(public readonly workspaceSettingsConfig: FolderSettingsModel, private scopedConfigs: ScopedConfigurationModel[], private scope: ConfigurationScope) { + constructor(public readonly workspaceSettingsConfig: FolderSettingsModel, private scopedConfigs: ScopedConfigurationModel[], private scope: ConfigurationScope) { super(); this.consolidate(); } private consolidate(): void { - this._contents = {}; + this._contents = {}; this._overrides = []; this.doMerge(this, ConfigurationScope.WINDOW === this.scope ? this.workspaceSettingsConfig : this.workspaceSettingsConfig.createFolderScopedConfigurationModel()); @@ -183,25 +183,25 @@ export class FolderConfigurationModel extends CustomConfigurationModel { } } -export class Configuration extends BaseConfiguration { +export class Configuration extends BaseConfiguration { constructor( - defaults: ConfigurationModel, - user: ConfigurationModel, - workspaceConfiguration: ConfigurationModel, - protected folders: StrictResourceMap>, - memoryConfiguration: ConfigurationModel, - memoryConfigurationByResource: StrictResourceMap>, + defaults: ConfigurationModel, + user: ConfigurationModel, + workspaceConfiguration: ConfigurationModel, + protected folders: StrictResourceMap, + memoryConfiguration: ConfigurationModel, + memoryConfigurationByResource: StrictResourceMap, workspace: Workspace) { super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource, workspace); } - updateDefaultConfiguration(defaults: ConfigurationModel): void { + updateDefaultConfiguration(defaults: ConfigurationModel): void { this._defaults = defaults; this.merge(); } - updateUserConfiguration(user: ConfigurationModel): string[] { + updateUserConfiguration(user: ConfigurationModel): string[] { let changedKeys = []; const { added, updated, removed } = compare(this._user, user); changedKeys = [...added, ...updated, ...removed]; @@ -217,7 +217,7 @@ export class Configuration extends BaseConfiguration { return []; } - updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): string[] { + updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): string[] { let changedKeys = []; const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration); changedKeys = [...added, ...updated, ...removed]; @@ -233,7 +233,7 @@ export class Configuration extends BaseConfiguration { return []; } - updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): string[] { + updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): string[] { const currentFolderConfiguration = this.folders.get(resource); if (currentFolderConfiguration) { @@ -269,7 +269,7 @@ export class Configuration extends BaseConfiguration { return keys; } - getFolderConfigurationModel(folder: URI): FolderConfigurationModel { - return >this.folders.get(folder); + getFolderConfigurationModel(folder: URI): FolderConfigurationModel { + return this.folders.get(folder); } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 4e4b99992ee..7e8884d88e7 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -57,10 +57,10 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat public _serviceBrand: any; private workspace: Workspace; - private _configuration: Configuration; - private baseConfigurationService: GlobalConfigurationService; + private _configuration: Configuration; + private baseConfigurationService: GlobalConfigurationService; private workspaceConfiguration: WorkspaceConfiguration; - private cachedFolderConfigs: StrictResourceMap>; + private cachedFolderConfigs: StrictResourceMap; protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; @@ -315,17 +315,17 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private loadConfiguration(): TPromise { // reset caches - this.cachedFolderConfigs = new StrictResourceMap>(); + this.cachedFolderConfigs = new StrictResourceMap(); const folders = this.workspace.folders; return this.loadFolderConfigurations(folders) .then((folderConfigurations) => { let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations); - const folderConfigurationModels = new StrictResourceMap>(); + const folderConfigurationModels = new StrictResourceMap(); folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration)); - this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap>(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null + this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null // TODO: compare with old values?? const keys = this._configuration.keys(); @@ -333,14 +333,14 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat }); } - private getWorkspaceConfigurationModel(folderConfigurations: FolderConfigurationModel[]): ConfigurationModel { + private getWorkspaceConfigurationModel(folderConfigurations: FolderConfigurationModel[]): ConfigurationModel { switch (this.getWorkbenchState()) { case WorkbenchState.FOLDER: return folderConfigurations[0]; case WorkbenchState.WORKSPACE: return this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration; default: - return new ConfigurationModel(); + return new ConfigurationModel(); } } @@ -452,7 +452,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return TPromise.as(changedKeys); } - private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise[]> { + private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise { return TPromise.join([...folders.map(folder => { const folderConfiguration = new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); @@ -588,7 +588,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat class WorkspaceConfiguration extends Disposable { private _workspaceConfigPath: URI; - private _workspaceConfigurationWatcher: ConfigWatcher>; + private _workspaceConfigurationWatcher: ConfigWatcher; private _workspaceConfigurationWatcherDisposables: IDisposable[] = []; private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); @@ -618,7 +618,7 @@ class WorkspaceConfiguration extends Disposable { }); } - get workspaceConfigurationModel(): WorkspaceConfigurationModel { + get workspaceConfigurationModel(): WorkspaceConfigurationModel { return this._workspaceConfigurationWatcher ? this._workspaceConfigurationWatcher.getConfig() : new WorkspaceConfigurationModel(); } @@ -632,15 +632,15 @@ class WorkspaceConfiguration extends Disposable { } } -class FolderConfiguration extends Disposable { +class FolderConfiguration extends Disposable { private static RELOAD_CONFIGURATION_DELAY = 50; - private bulkFetchFromWorkspacePromise: TPromise; - private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise> }; + private bulkFetchFromWorkspacePromise: TPromise; + private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise }; private reloadConfigurationScheduler: RunOnceScheduler; - private reloadConfigurationEventEmitter: Emitter> = new Emitter>(); + private reloadConfigurationEventEmitter: Emitter = new Emitter(); constructor(private folder: URI, private configFolderRelativePath: string, private scope: ConfigurationScope) { super(); @@ -649,17 +649,17 @@ class FolderConfiguration extends Disposable { this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configuration => this.reloadConfigurationEventEmitter.fire(configuration), errors.onUnexpectedError), FolderConfiguration.RELOAD_CONFIGURATION_DELAY)); } - loadConfiguration(): TPromise> { + loadConfiguration(): TPromise { // Load workspace locals return this.loadWorkspaceConfigFiles().then(workspaceConfigFiles => { // Consolidate (support *.json files in the workspace settings folder) - const workspaceSettingsConfig = >workspaceConfigFiles[WORKSPACE_CONFIG_DEFAULT_PATH] || new FolderSettingsModel(null); - const otherConfigModels = Object.keys(workspaceConfigFiles).filter(key => key !== WORKSPACE_CONFIG_DEFAULT_PATH).map(key => >workspaceConfigFiles[key]); - return new FolderConfigurationModel(workspaceSettingsConfig, otherConfigModels, this.scope); + const workspaceSettingsConfig = workspaceConfigFiles[WORKSPACE_CONFIG_DEFAULT_PATH] || new FolderSettingsModel(null); + const otherConfigModels = Object.keys(workspaceConfigFiles).filter(key => key !== WORKSPACE_CONFIG_DEFAULT_PATH).map(key => workspaceConfigFiles[key]); + return new FolderConfigurationModel(workspaceSettingsConfig, otherConfigModels, this.scope); }); } - private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModel }> { + private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModel }> { // once: when invoked for the first time we fetch json files that contribute settings if (!this.bulkFetchFromWorkspacePromise) { this.bulkFetchFromWorkspacePromise = resolveStat(this.toResource(this.configFolderRelativePath)).then(stat => { @@ -686,7 +686,7 @@ class FolderConfiguration extends Disposable { return this.bulkFetchFromWorkspacePromise.then(() => TPromise.join(this.workspaceFilePathToConfiguration)); } - public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise> { + public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise { const events = event.changes; let affectedByChanges = false; @@ -744,18 +744,18 @@ class FolderConfiguration extends Disposable { }); } - private createConfigModel(content: IContent): ConfigurationModel { + private createConfigModel(content: IContent): ConfigurationModel { const path = this.toFolderRelativePath(content.resource); if (path === WORKSPACE_CONFIG_DEFAULT_PATH) { - return new FolderSettingsModel(content.value, content.resource.toString()); + return new FolderSettingsModel(content.value, content.resource.toString()); } else { const matches = /\/([^\.]*)*\.json/.exec(path); if (matches && matches[1]) { - return new ScopedConfigurationModel(content.value, content.resource.toString(), matches[1]); + return new ScopedConfigurationModel(content.value, content.resource.toString(), matches[1]); } } - return new CustomConfigurationModel(null); + return new CustomConfigurationModel(null); } private isWorkspaceConfigurationFile(folderRelativePath: string): boolean { From 60688ac08ee7f6e198a39c1a896bd1bf6800b032 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 11:55:21 +0200 Subject: [PATCH 022/303] Do not create a new empty model for merging --- .../platform/configuration/common/configurationModels.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 8a207935c4a..428b3a499a9 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -244,8 +244,8 @@ export class Configuration { } protected merge(): void { - this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); - this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); + this._globalConfiguration = this._defaults.merge(this._user); + this._workspaceConsolidatedConfiguration = this._globalConfiguration.merge(this._workspaceConfiguration); this._foldersConsolidatedConfigurations = new StrictResourceMap(); for (const folder of this.folders.keys()) { this.mergeFolder(folder); @@ -253,11 +253,11 @@ export class Configuration { } protected mergeFolder(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); } protected mergeMemory(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); + this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); } getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { From 4765a8ab173c79d3117217eaa72b199be05ffcb3 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 11:57:21 +0200 Subject: [PATCH 023/303] Configuration: Use proper names for getting sections and values --- src/vs/editor/standalone/browser/simpleServices.ts | 4 ++-- src/vs/platform/configuration/common/configurationModels.ts | 4 ++-- src/vs/platform/configuration/node/configurationService.ts | 6 +++--- src/vs/workbench/api/node/extHostConfiguration.ts | 4 ++-- .../services/configuration/common/configurationModels.ts | 6 +++--- .../services/configuration/node/configurationService.ts | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 3d84c45b5eb..91440df58d0 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -459,11 +459,11 @@ export class SimpleConfigurationService implements IConfigurationService { getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - return this.configuration().getValue(section, overrides); + return this.configuration().getSection(section, overrides); } public getValue(key: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue2(key, options); + return this.configuration().getValue(key, options); } public updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 428b3a499a9..a469c8d7571 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -260,12 +260,12 @@ export class Configuration { this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); } - getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { + getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { const configModel = this.getConsolidateConfigurationModel(overrides); return section ? configModel.getContentsFor(section) : configModel.contents; } - getValue2(key: string, overrides: IConfigurationOverrides = {}): any { + getValue(key: string, overrides: IConfigurationOverrides = {}): any { // make sure to clone the configuration so that the receiver does not tamper with the values const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index d7b5f65f730..893af01e558 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -67,11 +67,11 @@ export class ConfigurationService extends Disposable implements IConfigurationSe getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - return this.configuration.getValue(section, overrides); + return this.configuration.getSection(section, overrides); } getValue(key: string, overrides: IConfigurationOverrides): any { - return this.configuration.getValue2(key, overrides); + return this.configuration.getValue(key, overrides); } updateValue(key: string, value: any): TPromise @@ -113,7 +113,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe if (changedKeys.length) { const oldConfiguartion = this._configuration; this.reset(); - changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this._configuration.getValue2(key))); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this._configuration.getValue(key))); if (changedKeys.length) { this.trigger(changedKeys, ConfigurationTarget.USER); } diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 031763f0ff4..6d3aee7186e 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -58,8 +58,8 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { getConfiguration(section?: string, resource?: URI): WorkspaceConfiguration { const config = section - ? lookUp(this._configuration.getValue(null, { resource }), section) - : this._configuration.getValue(null, { resource }); + ? lookUp(this._configuration.getSection(null, { resource }), section) + : this._configuration.getSection(null, { resource }); function parseConfigurationTarget(arg: boolean | ExtHostConfigurationTarget): ConfigurationTarget { if (arg === void 0 || arg === null) { diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index df0c1b196ee..1223ae638a7 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -211,7 +211,7 @@ export class Configuration extends BaseConfiguration { this._user = user; this.merge(); - changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this.getValue2(key))); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); return changedKeys; } return []; @@ -227,7 +227,7 @@ export class Configuration extends BaseConfiguration { this._workspaceConfiguration = workspaceConfiguration; this.merge(); - changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key), this.getValue2(key))); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); return changedKeys; } return []; @@ -246,7 +246,7 @@ export class Configuration extends BaseConfiguration { this.folders.set(resource, configuration); this.mergeFolder(resource); - changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue2(key, { resource }), this.getValue2(key, { resource }))); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, { resource }), this.getValue(key, { resource }))); return changedKeys; } return []; diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 7e8884d88e7..9a1c04fb4be 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -135,13 +135,13 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - const contents = this._configuration.getValue(section, overrides); + const contents = this._configuration.getSection(section, overrides); return typeof contents === 'object' ? { toJSON: () => this._configuration.toData(), ...contents } : contents; } getValue(key: string, overrides?: IConfigurationOverrides): T { - return this._configuration.getValue2(key, overrides); + return this._configuration.getValue(key, overrides); } updateValue(key: string, value: any): TPromise From cd4ef9fbacbb696a8e3589f0a8d210c906901ac4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 12:04:48 +0200 Subject: [PATCH 024/303] Use freeze instead of clone to prevent users to tamper data --- .../common/configurationModels.ts | 54 +++++++++---------- .../test/common/configuration.model.test.ts | 6 +-- .../test/common/configurationModel.test.ts | 12 ++--- .../test/common/configurationModels.test.ts | 2 +- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index a469c8d7571..fcc05810bdb 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -31,22 +31,8 @@ export class ConfigurationModel implements IConfiguraionModel { return this._keys; } - public getContentsFor(section: string): V { - return objects.clone(this.contents[section]); - } - - public override(identifier: string): ConfigurationModel { - const result = new ConfigurationModel(); - const contents = objects.clone(this.contents); - if (this._overrides) { - for (const override of this._overrides) { - if (override.identifiers.indexOf(identifier) !== -1) { - merge(contents, override.contents, true); - } - } - } - result._contents = contents; - return result; + public getSectionContents(section: string): V { + return this.contents[section]; } public setValue(key: string, value: any) { @@ -64,6 +50,20 @@ export class ConfigurationModel implements IConfiguraionModel { } } + public override(identifier: string): ConfigurationModel { + const result = new ConfigurationModel(); + const contents = objects.clone(this.contents); + if (this._overrides) { + for (const override of this._overrides) { + if (override.identifiers.indexOf(identifier) !== -1) { + merge(contents, override.contents, true); + } + } + } + result._contents = contents; + return result; + } + public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { const mergedModel = new ConfigurationModel(); this.doMerge(mergedModel, this, overwrite); @@ -262,13 +262,12 @@ export class Configuration { getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { const configModel = this.getConsolidateConfigurationModel(overrides); - return section ? configModel.getContentsFor(section) : configModel.contents; + return Object.freeze(section ? configModel.getSectionContents(section) : configModel.contents); } getValue(key: string, overrides: IConfigurationOverrides = {}): any { - // make sure to clone the configuration so that the receiver does not tamper with the values const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); + return Object.freeze(getConfigurationValue(consolidateConfigurationModel.contents, key)); } updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { @@ -297,18 +296,17 @@ export class Configuration { memory?: C value: C, } { - // make sure to clone the configuration so that the receiver does not tamper with the values const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; - return { - default: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)), - user: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)), - workspace: objects.clone(this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0), //Check on workspace exists or not because _workspaceConfiguration is never null - workspaceFolder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), - memory: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key)), - value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) - }; + return Object.freeze({ + default: getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key), + user: getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key), + workspace: this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null + workspaceFolder: folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0, + memory: getConfigurationValue(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key), + value: getConfigurationValue(consolidateConfigurationModel.contents, key) + }); } keys(): { diff --git a/src/vs/platform/configuration/test/common/configuration.model.test.ts b/src/vs/platform/configuration/test/common/configuration.model.test.ts index 65555f8e9f2..ea0266bd500 100644 --- a/src/vs/platform/configuration/test/common/configuration.model.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.model.test.ts @@ -67,16 +67,16 @@ suite('Configuration', () => { test('Test contents while getting an existing property', () => { let testObject = new ConfigurationModel({ 'a': 1 }); - assert.deepEqual(testObject.getContentsFor('a'), 1); + assert.deepEqual(testObject.getSectionContents('a'), 1); testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); - assert.deepEqual(testObject.getContentsFor('a'), { 'b': 1 }); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); }); test('Test contents are undefined for non existing properties', () => { const testObject = new ConfigurationModel({ awesome: true }); - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); }); test('Test override gives all content merged with overrides', () => { diff --git a/src/vs/platform/configuration/test/common/configurationModel.test.ts b/src/vs/platform/configuration/test/common/configurationModel.test.ts index 3cc4f519bc2..b79b8cbadcf 100644 --- a/src/vs/platform/configuration/test/common/configurationModel.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModel.test.ts @@ -61,10 +61,10 @@ suite('Configuration', () => { test('Test contents while getting an existing property', () => { let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 })); - assert.deepEqual(testObject.getContentsFor('a'), 1); + assert.deepEqual(testObject.getSectionContents('a'), 1); testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); - assert.deepEqual(testObject.getContentsFor('a'), { 'b': 1 }); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); }); test('Test contents are undefined for non existing properties', () => { @@ -72,13 +72,13 @@ suite('Configuration', () => { awesome: true })); - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); }); test('Test contents are undefined for undefined config', () => { const testObject = new CustomConfigurationModel(null); - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); }); test('Test configWithOverrides gives all content merged with overrides', () => { @@ -125,7 +125,7 @@ suite('Configuration', () => { } } }); - assert.equal(true, new DefaultConfigurationModel().getContentsFor('a')); + assert.equal(true, new DefaultConfigurationModel().getSectionContents('a')); }); test('Test registering the language property', () => { @@ -142,7 +142,7 @@ suite('Configuration', () => { } } }); - assert.equal(undefined, new DefaultConfigurationModel().getContentsFor('[a]')); + assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]')); }); }); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index a6755918258..14e684e145e 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -17,7 +17,7 @@ suite('ConfigurationService - Model', () => { const testObject = new FolderConfigurationModel(settingsConfig, [], ConfigurationScope.WINDOW); - assert.equal(testObject.getContentsFor('task'), undefined); + assert.equal(testObject.getSectionContents('task'), undefined); }); test('Test consolidate (settings and tasks)', () => { From fd70f31b703f27e8cdff476bb2a69e8ab6b75a53 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 6 Oct 2017 12:31:27 +0200 Subject: [PATCH 025/303] Update workspace configuration with memory configuration --- .../configuration/common/configurationModels.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index fcc05810bdb..c77ec098128 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -219,7 +219,6 @@ export class Configuration { private _globalConfiguration: ConfigurationModel; private _workspaceConsolidatedConfiguration: ConfigurationModel; protected _foldersConsolidatedConfigurations: StrictResourceMap; - protected _memoryConsolidatedConfigurations: StrictResourceMap; constructor(protected _defaults: ConfigurationModel, protected _user: ConfigurationModel, @@ -245,18 +244,18 @@ export class Configuration { protected merge(): void { this._globalConfiguration = this._defaults.merge(this._user); - this._workspaceConsolidatedConfiguration = this._globalConfiguration.merge(this._workspaceConfiguration); + this.updateWorkspaceConsolidateConfiguration(); this._foldersConsolidatedConfigurations = new StrictResourceMap(); for (const folder of this.folders.keys()) { this.mergeFolder(folder); } } - protected mergeFolder(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); + private updateWorkspaceConsolidateConfiguration() { + this._workspaceConsolidatedConfiguration = this._globalConfiguration.merge(this._workspaceConfiguration).merge(this._memoryConfiguration); } - protected mergeMemory(folder: URI) { + protected mergeFolder(folder: URI) { this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); } @@ -281,11 +280,16 @@ export class Configuration { } else { memoryConfiguration = this._memoryConfiguration; } + if (value === void 0) { memoryConfiguration.removeValue(key); } else { memoryConfiguration.setValue(key, value); } + + if (!overrides.resource) { + this.updateWorkspaceConsolidateConfiguration(); + } } lookup(key: string, overrides: IConfigurationOverrides = {}): { @@ -335,7 +339,7 @@ export class Configuration { } if (!resource) { - return this._workspaceConsolidatedConfiguration.merge(this._memoryConfiguration); + return this._workspaceConsolidatedConfiguration; } let consolidateConfiguration = this._workspaceConsolidatedConfiguration; From 0f4fdb82cf14429b35614a82ac8aab336c61ee06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?= Date: Fri, 6 Oct 2017 12:48:17 +0200 Subject: [PATCH 026/303] Remove new context from editorContextKeys and rename --- src/vs/editor/common/editorContextKeys.ts | 1 - src/vs/editor/common/modes/editorModeContext.ts | 5 ----- src/vs/workbench/common/resources.ts | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts index 4283b4e989a..8843cf821d4 100644 --- a/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -28,7 +28,6 @@ export namespace EditorContextKeys { // -- mode context keys export const languageId = new RawContextKey('editorLangId', undefined); - export const editorExtension = new RawContextKey('editorExtension', undefined); export const hasCompletionItemProvider = new RawContextKey('editorHasCompletionItemProvider', undefined); export const hasCodeActionsProvider = new RawContextKey('editorHasCodeActionsProvider', undefined); export const hasCodeLensProvider = new RawContextKey('editorHasCodeLensProvider', undefined); diff --git a/src/vs/editor/common/modes/editorModeContext.ts b/src/vs/editor/common/modes/editorModeContext.ts index b503700f9d7..a22237cf04e 100644 --- a/src/vs/editor/common/modes/editorModeContext.ts +++ b/src/vs/editor/common/modes/editorModeContext.ts @@ -10,14 +10,12 @@ import * as modes from 'vs/editor/common/modes'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { Schemas } from 'vs/base/common/network'; -import * as paths from 'vs/base/common/paths'; export class EditorModeContext extends Disposable { private _editor: ICommonCodeEditor; private _langId: IContextKey; - private _editorExtension: IContextKey; private _hasCompletionItemProvider: IContextKey; private _hasCodeActionsProvider: IContextKey; private _hasCodeLensProvider: IContextKey; @@ -42,7 +40,6 @@ export class EditorModeContext extends Disposable { this._editor = editor; this._langId = EditorContextKeys.languageId.bindTo(contextKeyService); - this._editorExtension = EditorContextKeys.editorExtension.bindTo(contextKeyService); this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService); this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService); @@ -90,7 +87,6 @@ export class EditorModeContext extends Disposable { reset() { this._langId.reset(); - this._editorExtension.reset(); this._hasCompletionItemProvider.reset(); this._hasCodeActionsProvider.reset(); this._hasCodeLensProvider.reset(); @@ -115,7 +111,6 @@ export class EditorModeContext extends Disposable { return; } this._langId.set(model.getLanguageIdentifier().language); - this._editorExtension.set(paths.extname(model.uri.fsPath)); this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model)); this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 67857f78e7c..ec82d07b99b 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -23,7 +23,7 @@ export class ResourceContextKey implements IContextKey { static Filename = new RawContextKey('resourceFilename', undefined); static LangId = new RawContextKey('resourceLangId', undefined); static Resource = new RawContextKey('resource', undefined); - static Extension = new RawContextKey('resourceExtension', undefined); + static Extension = new RawContextKey('resourceExtname', undefined); private _resourceKey: IContextKey; private _schemeKey: IContextKey; From 33779673d74ca685419dc78c1fbbf38436b36de9 Mon Sep 17 00:00:00 2001 From: Ari Miller Date: Sun, 8 Oct 2017 22:27:42 -0400 Subject: [PATCH 027/303] allow hiding explorer arrows via icon theme --- .../parts/files/browser/media/explorerviewlet.css | 4 ++++ .../parts/files/browser/views/explorerView.ts | 1 + .../services/themes/common/workbenchThemeService.ts | 1 + .../themes/electron-browser/fileIconThemeData.ts | 12 ++++++++++-- .../themes/electron-browser/workbenchThemeService.ts | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css index 749714d7782..4ef2be5ab15 100644 --- a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css @@ -106,6 +106,10 @@ background-image: url("collapsed-hc.svg"); } +.explorer-folders-view.hide-arrows .monaco-tree-row .content::before { + display: none; +} + .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row:hover > .content .monaco-action-bar, .explorer-viewlet .explorer-open-editors .monaco-tree.focused .monaco-tree-row.focused > .content .monaco-action-bar, .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row > .content.dirty > .monaco-action-bar { diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index eb9f3dbdc9b..aa33c61269d 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -161,6 +161,7 @@ export class ExplorerView extends ViewsViewletPanel { const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => { DOM.toggleClass(this.treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons); + DOM.toggleClass(this.treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows); }; this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index dfacea5a13c..2334ac25ae4 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -47,6 +47,7 @@ export interface IFileIconTheme { readonly isLoaded: boolean; readonly hasFileIcons?: boolean; readonly hasFolderIcons?: boolean; + readonly hidesExplorerArrows?: boolean; } export interface IWorkbenchThemeService extends IThemeService { diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts index fcdd7f82d21..14bb8048c97 100644 --- a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts @@ -21,6 +21,7 @@ export class FileIconThemeData implements IFileIconTheme { description?: string; hasFileIcons?: boolean; hasFolderIcons?: boolean; + hidesExplorerArrows?: boolean; isLoaded: boolean; path?: string; extensionData: ExtensionData; @@ -38,6 +39,7 @@ export class FileIconThemeData implements IFileIconTheme { this.styleSheetContent = result.content; this.hasFileIcons = result.hasFileIcons; this.hasFolderIcons = result.hasFolderIcons; + this.hidesExplorerArrows = result.hidesExplorerArrows; this.isLoaded = true; return this.styleSheetContent; }); @@ -69,6 +71,7 @@ export class FileIconThemeData implements IFileIconTheme { themeData.settingsId = null; themeData.hasFileIcons = false; themeData.hasFolderIcons = false; + themeData.hidesExplorerArrows = false; themeData.isLoaded = true; themeData.extensionData = null; } @@ -110,6 +113,7 @@ interface IconThemeDocument extends IconsAssociation { fonts: FontDefinition[]; light?: IconsAssociation; highContrast?: IconsAssociation; + hidesExplorerArrows?: boolean; } function _loadIconThemeDocument(fileSetPath: string): TPromise { @@ -123,9 +127,9 @@ function _loadIconThemeDocument(fileSetPath: string): TPromise Date: Sun, 8 Oct 2017 22:58:41 -0400 Subject: [PATCH 028/303] preserve the spacing --- src/vs/workbench/parts/files/browser/media/explorerviewlet.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css index 4ef2be5ab15..fd26c32d640 100644 --- a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css @@ -107,7 +107,7 @@ } .explorer-folders-view.hide-arrows .monaco-tree-row .content::before { - display: none; + background-image: none; } .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row:hover > .content .monaco-action-bar, From b1407a87b05c2e9512eba9f44247dfd64c33cdfe Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 10 Oct 2017 18:04:14 +1100 Subject: [PATCH 029/303] disable lookup for GitHub's version of Git If the classic GitHub for Windows (creatively named github.exe) is installed alongside the new GitHub Desktop (which installs a github.bat file to PATH), we can get into the situation where Code can ask the GUI to authenticate for a private repository, which it doesn't understand. --- extensions/git/src/git.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index bc9ac5398a8..5edc8c6d258 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -118,26 +118,11 @@ function findSystemGitWin32(base: string): Promise { return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe')); } -function findGitHubGitWin32(): Promise { - const github = path.join(process.env['LOCALAPPDATA'], 'GitHub'); - - return readdir(github).then(children => { - const git = children.filter(child => /^PortableGit/.test(child))[0]; - - if (!git) { - return Promise.reject('Not found'); - } - - return findSpecificGit(path.join(github, git, 'cmd', 'git.exe')); - }); -} - function findGitWin32(): Promise { return findSystemGitWin32(process.env['ProgramW6432']) .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'])) .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles'])) - .then(void 0, () => findSpecificGit('git')) - .then(void 0, () => findGitHubGitWin32()); + .then(void 0, () => findSpecificGit('git')); } export function findGit(hint: string | undefined): Promise { From ccb79101280d629dbdfa34e2905de0c3a793b148 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 10 Oct 2017 10:13:26 +0200 Subject: [PATCH 030/303] git content provider checks the wrong cache key fixes #35559 --- extensions/git/src/contentProvider.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index 78852ec6685..4e591c1ae32 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -82,7 +82,7 @@ export class GitContentProvider { const cacheKey = uri.toString(); const timestamp = new Date().getTime(); - const cacheValue = { uri, timestamp }; + const cacheValue: CacheRow = { uri, timestamp }; this.cache[cacheKey] = cacheValue; @@ -108,7 +108,10 @@ export class GitContentProvider { Object.keys(this.cache).forEach(key => { const row = this.cache[key]; - const isOpen = window.visibleTextEditors.some(e => e.document.toString() === row.uri.toString()); + const { path } = fromGitUri(row.uri); + const isOpen = workspace.textDocuments + .filter(d => d.uri.scheme === 'file') + .some(d => d.uri.fsPath === path); if (isOpen || now - row.timestamp < THREE_MINUTES) { cache[row.uri.toString()] = row; From dbcc641f8aa9587e600921e219562158ffbb9204 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 10 Oct 2017 11:18:12 +0200 Subject: [PATCH 031/303] Fix #35903 --- .../extensionManagement/node/extensionManagementService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 5b3bdfe9265..58c2a514205 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -268,7 +268,7 @@ export class ExtensionManagementService implements IExtensionManagementService { const promises = installed .filter(e => e.manifest.publisher === extension.manifest.publisher && e.manifest.name === extension.manifest.name) .map(e => this.checkForDependenciesAndUninstall(e, installed, force)); - return TPromise.join(promises).then(null, errors => TPromise.wrapError(this.joinErrors(errors))); + return TPromise.join(promises).then(null, error => TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error)); })) .then(() => { /* drop resolved value */ }); } From 0b03de632ae66ad24da6d9bb5ce8d2bdbeb0d7c8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 12:20:09 +0200 Subject: [PATCH 032/303] avoid disk search trouble when having workspace folders that aren't on disk --- .../services/search/node/searchService.ts | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 8fdb18b45af..b7adc8e63a9 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -15,13 +15,14 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { IModelService } from 'vs/editor/common/services/modelService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IRawSearch, IFolderSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService, ITelemetryEvent } from './search'; +import { IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService, ITelemetryEvent } from './search'; import { ISearchChannel, SearchChannelClient } from './searchIpc'; import { IEnvironmentService, IDebugParams } from 'vs/platform/environment/common/environment'; import { ResourceMap } from 'vs/base/common/map'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { Schemas } from 'vs/base/common/network'; export class SearchService implements ISearchService { public _serviceBrand: any; @@ -259,15 +260,8 @@ export class DiskSearch implements ISearchResultProvider { let request: PPromise; let rawSearch: IRawSearch = { - folderQueries: query.folderQueries ? query.folderQueries.map(q => { - return { - excludePattern: q.excludePattern, - includePattern: q.includePattern, - fileEncoding: q.fileEncoding, - folder: q.folder.fsPath - }; - }) : [], - extraFiles: query.extraFileResources ? query.extraFileResources.map(r => r.fsPath) : [], + folderQueries: [], + extraFiles: [], filePattern: query.filePattern, excludePattern: query.excludePattern, includePattern: query.includePattern, @@ -278,6 +272,27 @@ export class DiskSearch implements ISearchResultProvider { disregardIgnoreFiles: query.disregardIgnoreFiles }; + if (query.folderQueries) { + for (const q of query.folderQueries) { + if (q.folder.scheme === Schemas.file) { + rawSearch.folderQueries.push({ + excludePattern: q.excludePattern, + includePattern: q.includePattern, + fileEncoding: q.fileEncoding, + folder: q.folder.fsPath + }); + } + } + } + + if (query.extraFileResources) { + for (const r of query.extraFileResources) { + if (r.scheme === Schemas.file) { + rawSearch.extraFiles.push(r.fsPath); + } + } + } + if (query.type === QueryType.Text) { rawSearch.contentPattern = query.contentPattern; } From 51b0bf3c7891fd014fc1508b9f1686c1c5d46355 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 12:20:38 +0200 Subject: [PATCH 033/303] support `findFiles` --- src/vs/vscode.proposed.d.ts | 3 + .../electron-browser/mainThreadFileSystem.ts | 58 ++++++++++++++++--- src/vs/workbench/api/node/extHost.protocol.ts | 3 + .../workbench/api/node/extHostFileSystem.ts | 8 +++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 85ca4a72cd1..0a2e63c7729 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -155,6 +155,9 @@ declare module 'vscode' { // todo@remote // create(resource: Uri): Thenable; + + // find files by names + findFiles?(query: string, progress: Progress, token: CancellationToken): Thenable; } export namespace workspace { diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 76aac923806..5b6ea8b6f3a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -5,7 +5,7 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; +import { TPromise, PPromise } from 'vs/base/common/winjs.base'; import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape } from '../node/extHost.protocol'; import { IFileService, IFileSystemProvider, IStat, IFileChange } from 'vs/platform/files/common/files'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -13,6 +13,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IProgress } from 'vs/platform/progress/common/progress'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService } from 'vs/platform/search/common/search'; @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape { @@ -24,6 +25,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { constructor( extHostContext: IExtHostContext, @IFileService private readonly _fileService: IFileService, + @ISearchService private readonly _searchService: ISearchService, @IWorkspaceEditingService private readonly _workspaceEditService: IWorkspaceEditingService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); @@ -34,7 +36,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $registerFileSystemProvider(handle: number, scheme: string): void { - this._provider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, handle, this._proxy)); + this._provider.set(handle, new RemoteFileSystemProvider(this._fileService, this._searchService, scheme, handle, this._proxy)); } $unregisterFileSystemProvider(handle: number): void { @@ -53,28 +55,38 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { $reportFileChunk(handle: number, resource: URI, chunk: number[]): void { this._provider.get(handle).reportFileChunk(resource, chunk); } + + // --- search + + $handleSearchProgress(handle: number, session: number, resource: URI): void { + this._provider.get(handle).handleSearchProgress(session, resource); + } } -class RemoteFileSystemProvider implements IFileSystemProvider { +class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProvider { private readonly _onDidChange = new Emitter(); - private readonly _registration: IDisposable; private readonly _reads = new Map>(); + private readonly _registrations: IDisposable[]; readonly onDidChange: Event = this._onDidChange.event; constructor( - service: IFileService, + fileService: IFileService, + searchService: ISearchService, scheme: string, private readonly _handle: number, private readonly _proxy: ExtHostFileSystemShape ) { - this._registration = service.registerProvider(scheme, this); + this._registrations = [ + fileService.registerProvider(scheme, this), + searchService.registerSearchResultProvider(this), + ]; } dispose(): void { - this._registration.dispose(); + dispose(this._registrations); this._onDidChange.dispose(); } @@ -115,4 +127,36 @@ class RemoteFileSystemProvider implements IFileSystemProvider { rmdir(resource: URI): TPromise { return this._proxy.$rmdir(this._handle, resource); } + + // --- search + + private _searches = new Map void>(); + private _searchesIdPool = 0; + + search(query: ISearchQuery): PPromise { + if (query.type === QueryType.Text) { + return PPromise.as({ results: [], stats: undefined }); + } + const id = ++this._searchesIdPool; + const matches: IFileMatch[] = []; + return new PPromise((resolve, reject, report) => { + this._proxy.$fileFiles(this._handle, id, query.filePattern).then(() => { + this._searches.delete(id); + resolve({ + results: matches, + stats: undefined + }); + }, reject); + + this._searches.set(id, resource => { + const match: IFileMatch = { resource }; + matches.push(match); + report(match); + }); + }); + } + + handleSearchProgress(session: number, resource: URI): void { + this._searches.get(session)(resource); + } } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 4016299feed..07a65209fe6 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -324,6 +324,8 @@ export interface MainThreadFileSystemShape extends IDisposable { $onDidAddFileSystemRoot(root: URI): void; $onFileSystemChange(handle: number, resource: IFileChange[]): void; $reportFileChunk(handle: number, resource: URI, chunk: number[] | null): void; + + $handleSearchProgress(handle: number, session: number, resource: URI): void; } export interface MainThreadTaskShape extends IDisposable { @@ -489,6 +491,7 @@ export interface ExtHostFileSystemShape { $mkdir(handle: number, resource: URI): TPromise; $readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>; $rmdir(handle: number, resource: URI): TPromise; + $fileFiles(handle: number, session: number, query: string): TPromise; } export interface ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 6b7466381f5..a7b8c787310 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -74,4 +74,12 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { $rmdir(handle: number, resource: URI): TPromise { return asWinJsPromise(token => this._provider.get(handle).rmdir(resource)); } + $fileFiles(handle: number, session: number, query: string): TPromise { + const provider = this._provider.get(handle); + if (!provider.findFiles) { + return TPromise.as(undefined); + } + const progress = { report: (uri) => this._proxy.$handleSearchProgress(handle, session, uri) }; + return asWinJsPromise(token => provider.findFiles(query, progress, token)); + } } From dad2c89e76163971b75d0dc90d38e6d914b7f583 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 10 Oct 2017 12:25:21 +0200 Subject: [PATCH 034/303] fixes #35898 --- src/vs/workbench/parts/debug/browser/debugStatus.ts | 5 +++-- .../parts/debug/browser/media/debug.contribution.css | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugStatus.ts b/src/vs/workbench/parts/debug/browser/debugStatus.ts index 9e575478b01..821b34d783b 100644 --- a/src/vs/workbench/parts/debug/browser/debugStatus.ts +++ b/src/vs/workbench/parts/debug/browser/debugStatus.ts @@ -54,8 +54,9 @@ export class DebugStatus extends Themable implements IStatusbarItem { this.quickOpenService.show('debug ').done(undefined, errors.onUnexpectedError); })); statusBarItem.title = nls.localize('debug', "Debug"); - this.icon = dom.append(statusBarItem, $('.icon')); - this.label = dom.append(statusBarItem, $('span.label')); + const a = dom.append(statusBarItem, $('a')); + this.icon = dom.append(a, $('.icon')); + this.label = dom.append(a, $('span.label')); this.setLabel(); this.updateStyles(); } diff --git a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css index 69bf974a45f..2796a460a0d 100644 --- a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css @@ -103,8 +103,8 @@ } /* Debug status */ -.monaco-workbench .part.statusbar .debug-statusbar-item { - cursor: pointer; +/* A very precise css rule to overwrite the display set in statusbar.css */ +.monaco-workbench > .part.statusbar > .statusbar-item > .debug-statusbar-item > a:not([disabled]):not(.disabled) { display: flex; } From e6df58e5d9a90d27eb4304abdff521e32a58b957 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 12:28:47 +0200 Subject: [PATCH 035/303] debt - additional quick scorer result tweaks --- .../parts/quickopen/common/quickOpenScorer.ts | 306 +++++++++++------- .../test/common/quickOpenScorer.test.ts | 94 +++++- .../browser/parts/editor/editorPicker.ts | 9 +- .../parts/quickopen/quickOpenController.ts | 8 +- .../search/browser/openAnythingHandler.ts | 16 +- 5 files changed, 282 insertions(+), 151 deletions(-) diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 1dce6a05bad..750a6961ca1 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -8,12 +8,103 @@ import { compareAnything } from 'vs/base/common/comparers'; import { matchesPrefix, IMatch, createMatches, matchesCamelCase, isSeparatorAtPos, isUpper } from 'vs/base/common/filters'; import { isEqual, nativeSep } from 'vs/base/common/paths'; +import { isWindows } from 'vs/base/common/platform'; +import { stripWildcards } from 'vs/base/common/strings'; export type Score = [number /* score */, number[] /* match positions */]; export type ScorerCache = { [key: string]: IItemScore }; const NO_SCORE: Score = [0, []]; +/** + * Compute a score for the given string and the given query. + * + * Rules: + * Character score: 1 + * Same case bonus: 1 + * Upper case bonus: 1 + * Consecutive match bonus: 5 + * Start of word/path bonus: 7 + * Start of string bonus: 8 + */ +export function _doScore(target: string, query: string, fuzzy: boolean): Score { + if (!target || !query) { + return NO_SCORE; // return early if target or query are undefined + } + + if (target.length < query.length) { + return NO_SCORE; // impossible for query to be contained in target + } + + // console.group(`Target: ${target}, Query: ${query}`); + + const queryLen = query.length; + const targetLower = target.toLowerCase(); + const queryLower = query.toLowerCase(); + + let res = NO_SCORE; + + // When not searching fuzzy, we require the query to be contained fully + // in the target string. We set the offset to search from to that location. + if (!fuzzy) { + const indexOfQueryInTarget = targetLower.indexOf(queryLower); + if (indexOfQueryInTarget === -1) { + // console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`); + + return NO_SCORE; + } + + res = _doScoreFromOffset(target, query, targetLower, queryLower, queryLen, indexOfQueryInTarget); + } + + // When searching fuzzy we run the scorer for each location of the first query + // character so that we can produce better results in case the pattern matches + // multiple times on the target (prevent scattering of matching positions). + else { + const queryFirstCharacter = queryLower[0]; + + let offset = 0; + while ((offset = targetLower.indexOf(queryFirstCharacter, offset)) !== -1) { + const scoreFromOffset = _doScoreFromOffset(target, query, targetLower, queryLower, queryLen, offset); + if (isBetterScore(res, scoreFromOffset)) { + res = scoreFromOffset; + } + + offset++; + } + } + + // console.log(`%cFinal Score: ${score}`, 'font-weight: bold'); + // console.groupEnd(); + + return res; +} + +function isBetterScore(score: Score, candidate: Score): boolean { + if (candidate[0] > score[0]) { + return true; // candidate has higher score + } + + if (score[0] > candidate[0]) { + return false; // candidate has lower score + } + + // Score is the same, check by match compactness + const matchStart = score[1][0]; + const matchEnd = score[1][score[1].length - 1]; + const matchLength = matchEnd - matchStart; + + const candidateMatchStart = candidate[1][0]; + const candidateMatchEnd = candidate[1][candidate[1].length - 1]; + const candidateMatchLength = candidateMatchEnd - candidateMatchStart; + + if (candidateMatchLength < matchLength) { + return true; // candidate has more compact matches + } + + return false; +} + // Based on material from: /*! BEGIN THIRD PARTY @@ -31,81 +122,18 @@ BEGIN THIRD PARTY * Date: Tue Mar 1 2011 * Updated: Tue Mar 10 2015 */ - -/** - * Compute a score for the given string and the given query. - * - * Rules: - * Character score: 1 - * Same case bonus: 1 - * Upper case bonus: 1 - * Consecutive match bonus: 5 - * Start of word/path bonus: 7 - * Start of string bonus: 8 - */ -export function _doScore(target: string, query: string, fuzzy: boolean, inverse?: boolean): Score { - if (!target || !query) { - return NO_SCORE; // return early if target or query are undefined - } - - if (target.length < query.length) { - return NO_SCORE; // impossible for query to be contained in target - } - - // console.group(`Target: ${target}, Query: ${query}`); - - const queryLen = query.length; - const targetLower = target.toLowerCase(); - const queryLower = query.toLowerCase(); - +export function _doScoreFromOffset(target: string, query: string, targetLower: string, queryLower: string, queryLen: number, offset: number): Score { const matchingPositions: number[] = []; - let index: number; - let startAt: number; - if (!inverse) { - index = 0; - startAt = 0; - } else { - index = queryLen - 1; // inverse: from end of query to beginning - startAt = target.length - 1; // inverse: from end of target to beginning - } - - // When not searching fuzzy, we require the query to be contained fully - // in the target string. - if (!fuzzy) { - let indexOfQueryInTarget: number; - if (!inverse) { - indexOfQueryInTarget = targetLower.indexOf(queryLower); - } else { - indexOfQueryInTarget = targetLower.lastIndexOf(queryLower); - } - - if (indexOfQueryInTarget === -1) { - // console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`); - - return NO_SCORE; - } - - // Adjust the start position with the offset of the query - if (!inverse) { - startAt = indexOfQueryInTarget; - } else { - startAt = indexOfQueryInTarget + query.length; - } - } - + let targetIndex = offset; + let queryIndex = 0; let score = 0; - while (inverse ? index >= 0 : index < queryLen) { + while (queryIndex < queryLen) { // Check for query character being contained in target - let indexOf: number; - if (!inverse) { - indexOf = targetLower.indexOf(queryLower[index], startAt); - } else { - indexOf = targetLower.lastIndexOf(queryLower[index], startAt); // inverse: look from the end - } + const indexOfQueryInTarget = targetLower.indexOf(queryLower[queryIndex], targetIndex); - if (indexOf < 0) { + if (indexOfQueryInTarget < 0) { // console.log(`Character not part of target ${query[index]}`); score = 0; @@ -113,7 +141,7 @@ export function _doScore(target: string, query: string, fuzzy: boolean, inverse? } // Fill into positions array - matchingPositions.push(indexOf); + matchingPositions.push(indexOfQueryInTarget); // Character match bonus score += 1; @@ -121,35 +149,35 @@ export function _doScore(target: string, query: string, fuzzy: boolean, inverse? // console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${query[index]} at index ${indexOf}, total score: ${score})`, 'font-weight: normal'); // Consecutive match bonus - if (startAt === indexOf && index > 0) { + if (targetIndex === indexOfQueryInTarget && queryIndex > 0) { score += 5; // console.log('Consecutive match bonus: +5'); } // Same case bonus - if (target[indexOf] === query[index]) { + if (target[indexOfQueryInTarget] === query[queryIndex]) { score += 1; // console.log('Same case bonus: +1'); } // Start of word bonus - if (indexOf === 0) { + if (indexOfQueryInTarget === 0) { score += 8; // console.log('Start of word bonus: +8'); } // After separator bonus - else if (isSeparatorAtPos(target, indexOf - 1)) { + else if (isSeparatorAtPos(target, indexOfQueryInTarget - 1)) { score += 7; // console.log('After separtor bonus: +7'); } // Inside word upper case bonus - else if (isUpper(target.charCodeAt(indexOf))) { + else if (isUpper(target.charCodeAt(indexOfQueryInTarget))) { score += 1; // console.log('Inside word upper case bonus: +1'); @@ -157,18 +185,8 @@ export function _doScore(target: string, query: string, fuzzy: boolean, inverse? // console.groupEnd(); - if (!inverse) { - startAt = indexOf + 1; - index++; - } else { - startAt = indexOf - 1; // inverse: go to begining from end - index--; // inverse: also for query index - } - } - - // inverse: flip the matching positions so that they appear in order - if (inverse) { - matchingPositions.reverse(); + targetIndex = indexOfQueryInTarget + 1; + queryIndex++; } const res: Score = (score > 0) ? [score, matchingPositions] : NO_SCORE; @@ -266,22 +284,27 @@ function doScoreItem(label: string, description: string, path: string, query: return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0 }; } - // 2.) treat prefix matches on the label second highest - const prefixLabelMatch = matchesPrefix(query, label); - if (prefixLabelMatch) { - return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch }; - } + // We only consider label matches if the query is not including file path separators + const preferLabelMatches = !path || query.indexOf(nativeSep) === -1; + if (preferLabelMatches) { - // 3.) treat camelcase matches on the label third highest - const camelcaseLabelMatch = matchesCamelCase(query, label); - if (camelcaseLabelMatch) { - return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch }; - } + // 2.) treat prefix matches on the label second highest + const prefixLabelMatch = matchesPrefix(query, label); + if (prefixLabelMatch) { + return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch }; + } - // 4.) prefer scores on the label if any - const [labelScore, labelPositions] = _doScore(label, query, fuzzy); - if (labelScore) { - return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) }; + // 3.) treat camelcase matches on the label third highest + const camelcaseLabelMatch = matchesCamelCase(query, label); + if (camelcaseLabelMatch) { + return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch }; + } + + // 4.) prefer scores on the label if any + const [labelScore, labelPositions] = _doScore(label, query, fuzzy); + if (labelScore) { + return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) }; + } } // 5.) finally compute description + label scores if we have a description @@ -294,18 +317,7 @@ function doScoreItem(label: string, description: string, path: string, query: const descriptionPrefixLength = descriptionPrefix.length; const descriptionAndLabel = `${descriptionPrefix}${label}`; - let [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query, fuzzy); - - // Optimize for file paths: score from the back to the beginning to catch more specific folder - // names that match on the end of the file. This yields better results in most cases. - if (!!path) { - const [labelDescriptionScoreInverse, labelDescriptionPositionsInverse] = _doScore(descriptionAndLabel, query, fuzzy, true /* inverse */); - if (labelDescriptionScoreInverse && labelDescriptionScoreInverse > labelDescriptionScore) { - labelDescriptionScore = labelDescriptionScoreInverse; - labelDescriptionPositions = labelDescriptionPositionsInverse; - } - } - + const [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query, fuzzy); if (labelDescriptionScore) { const labelDescriptionMatches = createMatches(labelDescriptionPositions); const labelMatch: IMatch[] = []; @@ -339,8 +351,11 @@ function doScoreItem(label: string, description: string, path: string, query: } export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache, fallbackComparer = fallbackCompare): number { - const scoreA = scoreItem(itemA, query, fuzzy, accessor, cache).score; - const scoreB = scoreItem(itemB, query, fuzzy, accessor, cache).score; + const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache); + const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache); + + const scoreA = itemScoreA.score; + const scoreB = itemScoreB.score; // 1.) check for identity matches if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) { @@ -373,6 +388,12 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: const labelA = accessor.getItemLabel(itemA); const labelB = accessor.getItemLabel(itemB); + // prefer more compact camel case matches over longer + const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch); + if (comparedByMatchLength !== 0) { + return comparedByMatchLength; + } + // prefer shorter names when both match on label camelcase if (labelA.length !== labelB.length) { return labelA.length - labelB.length; @@ -395,10 +416,49 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: return scoreA > scoreB ? -1 : 1; } - // 6.) at this point, scores are identical for both items so we start to use the fallback compare + // 6.) scores are identical, prefer more compact matches (label and description) + const labelMatchCompactness = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch); + if (labelMatchCompactness !== 0) { + return labelMatchCompactness; + } + + const descriptionMatchCompactness = compareByMatchLength(itemScoreA.descriptionMatch, itemScoreB.descriptionMatch); + if (descriptionMatchCompactness !== 0) { + return descriptionMatchCompactness; + } + + // 7.) at this point, scores are identical and match compactness as well + // for both items so we start to use the fallback compare return fallbackComparer(itemA, itemB, query, accessor); } +function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number { + if ((!matchesA && !matchesB) || (!matchesA.length && !matchesB.length)) { + return 0; // make sure to not cause bad comparing when matches are not provided + } + + if (!matchesB || !matchesB.length) { + return -1; + } + + if (!matchesA || !matchesA.length) { + return 1; + } + + // Compute match length of A (first to last match) + const matchStartA = matchesA[0].start; + const matchEndA = matchesA[matchesA.length - 1].end; + const matchLengthA = matchEndA - matchStartA; + + // Compute match length of B (first to last match) + const matchStartB = matchesB[0].start; + const matchEndB = matchesB[matchesB.length - 1].end; + const matchLengthB = matchEndB - matchStartB; + + // Prefer shorter match length + return matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1; +} + export function fallbackCompare(itemA: T, itemB: T, query: string, accessor: IItemAccessor): number { // check for label + description length and prefer shorter @@ -442,4 +502,18 @@ export function fallbackCompare(itemA: T, itemB: T, query: string, accessor: // equal return 0; +} + +/** + * Helper function to prepare a search value for scoring in quick open by removing unwanted characters. + */ +export function massageSearchForScoring(searchValue: string): string { + if (searchValue) { + searchValue = stripWildcards(searchValue).replace(/\s/g, ''); // get rid of all wildcards and whitespace + if (isWindows) { + searchValue = searchValue.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash + } + } + + return searchValue; } \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 5af281048e2..ed47435cbc0 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -57,10 +57,10 @@ suite('Quick Open Scorer', () => { scores.push(scorer._doScore(target, 'hw', true)); // direct mix-case prefix (multiple) scores.push(scorer._doScore(target, 'H', true)); // direct case prefix scores.push(scorer._doScore(target, 'h', true)); // direct mix-case prefix + scores.push(scorer._doScore(target, 'ld', true)); // in-string mix-case match (consecutive, avoids scattered hit) scores.push(scorer._doScore(target, 'W', true)); // direct case word prefix scores.push(scorer._doScore(target, 'w', true)); // direct mix-case word prefix scores.push(scorer._doScore(target, 'Ld', true)); // in-string case match (multiple) - scores.push(scorer._doScore(target, 'ld', true)); // in-string mix-case match scores.push(scorer._doScore(target, 'L', true)); // in-string case match scores.push(scorer._doScore(target, 'l', true)); // in-string mix-case match scores.push(scorer._doScore(target, '4', true)); // no match @@ -93,20 +93,6 @@ suite('Quick Open Scorer', () => { assert.equal(scorer._doScore(target, 'eo', false)[0], 0); }); - test('score (non fuzzy, inverse)', function () { - const target = 'HeLlo-World'; - - assert.ok(scorer._doScore(target, 'HelLo-World', false, true)[0] > 0); - assert.equal(scorer._doScore(target, 'HelLo-World', false, true)[1].length, 'HelLo-World'.length); - - assert.ok(scorer._doScore(target, 'hello-world', false, true)[0] > 0); - assert.equal(scorer._doScore(target, 'HW', false, true)[0], 0); - assert.ok(scorer._doScore(target, 'h', false, true)[0] > 0); - assert.ok(scorer._doScore(target, 'ello', false, true)[0] > 0); - assert.ok(scorer._doScore(target, 'ld', false, true)[0] > 0); - assert.equal(scorer._doScore(target, 'eo', false, true)[0], 0); - }); - test('scoreItem - matches are proper', function () { let res = scorer.scoreItem(null, 'something', true, ResourceAccessor, cache); assert.ok(!res.score); @@ -197,6 +183,22 @@ suite('Quick Open Scorer', () => { assert.equal(pathRes.descriptionMatch[0].end, 26); }); + test('scoreItem - prefers more compact matches', function () { + const resource = URI.file('/1a111d1/11a1d1/something.txt'); + + // expect "ad" to be matched towards the end of the file because the + // match is more compact + const res = scorer.scoreItem(resource, 'ad', true, ResourceAccessor, cache); + assert.ok(res.score); + assert.ok(res.descriptionMatch); + assert.ok(!res.labelMatch.length); + assert.equal(res.descriptionMatch.length, 2); + assert.equal(res.descriptionMatch[0].start, 11); + assert.equal(res.descriptionMatch[0].end, 12); + assert.equal(res.descriptionMatch[1].start, 13); + assert.equal(res.descriptionMatch[1].end, 14); + }); + test('compareItemsByScore - identity', function () { const resourceA = URI.file('/some/path/fileA.txt'); const resourceB = URI.file('/some/path/other/fileB.txt'); @@ -422,4 +424,66 @@ suite('Quick Open Scorer', () => { assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); + + test('compareFilesByScore - prefer more compact camel case matches', function () { + const resourceA = URI.file('config/test/openthisAnythingHandler.js'); + const resourceB = URI.file('config/test/openthisisnotsorelevantforthequeryAnyHand.js'); + + let query = 'AH'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact matches (label)', function () { + const resourceA = URI.file('config/test/examasdaple.js'); + const resourceB = URI.file('config/test/exampleasdaasd.ts'); + + let query = 'xp'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact matches (path)', function () { + const resourceA = URI.file('config/test/examasdaple/file.js'); + const resourceB = URI.file('config/test/exampleasdaasd/file.ts'); + + let query = 'xp'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - avoid match scattering (bug #34210)', function () { + const resourceA = URI.file('node_modules1/bundle/lib/model/modules/ot1/index.js'); + const resourceB = URI.file('node_modules1/bundle/lib/model/modules/un1/index.js'); + const resourceC = URI.file('node_modules1/bundle/lib/model/modules/modu1/index.js'); + const resourceD = URI.file('node_modules1/bundle/lib/model/modules/oddl1/index.js'); + + let query = 'modu1/index.js'; + + let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + + query = 'un1/index.js'; + + res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); }); \ 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 f02a2e68452..f7c63fa7e08 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -22,8 +22,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { EditorInput, toResource, IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor'; -import { stripWildcards } from 'vs/base/common/strings'; -import { compareItemsByScore, scoreItem, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { compareItemsByScore, scoreItem, ScorerCache, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export class EditorPickerEntry extends QuickOpenEntryGroup { private stacks: IEditorStacksModel; @@ -107,9 +106,8 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { return TPromise.as(null); } - const stacks = this.editorGroupService.getStacksModel(); - - searchValue = stripWildcards(searchValue.trim()); + // Massage search for scoring + searchValue = massageSearchForScoring(searchValue); const entries = editorEntries.filter(e => { if (!searchValue) { @@ -127,6 +125,7 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { }); // Sorting + const stacks = this.editorGroupService.getStacksModel(); if (searchValue) { entries.sort((e1, e2) => { if (e1.group !== e2.group) { diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 27b098e9604..00bd2d8d83a 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -55,7 +55,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { FileKind, IFileService } from 'vs/platform/files/common/files'; -import { scoreItem, ScorerCache, compareItemsByScore } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { scoreItem, ScorerCache, compareItemsByScore, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; const HELP_PREFIX = '?'; @@ -1177,9 +1177,9 @@ class EditorHistoryHandler { } public getResults(searchValue?: string): QuickOpenEntry[] { - if (searchValue) { - searchValue = strings.stripWildcards(searchValue.replace(/ /g, '')); // get rid of all whitespace and wildcards - } + + // Massage search for scoring + searchValue = massageSearchForScoring(searchValue); // Just return all if we are not searching const history = this.historyService.getHistory(); diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 1814995bbef..69c76344f67 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -11,8 +11,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import { ThrottledDelayer } from 'vs/base/common/async'; import types = require('vs/base/common/types'); -import { isWindows } from 'vs/base/common/platform'; -import strings = require('vs/base/common/strings'); import { IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen'; import { QuickOpenEntry, QuickOpenModel, QuickOpenItemAccessor } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; @@ -25,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchSearchConfiguration } from 'vs/workbench/parts/search/common/search'; import { IRange } from 'vs/editor/common/core/range'; -import { compareItemsByScore, scoreItem, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { compareItemsByScore, scoreItem, ScorerCache, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export import OpenSymbolHandler = openSymbolHandler.OpenSymbolHandler; // OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load @@ -175,11 +173,8 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.cancelPendingSearch(); this.isClosed = false; // Treat this call as the handler being in use - // Massage search value - searchValue = searchValue.replace(/ /g, ''); // get rid of all whitespace - if (isWindows) { - searchValue = searchValue.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash - } + // Massage search for scoring + searchValue = massageSearchForScoring(searchValue); const searchWithRange = this.extractRange(searchValue); // Find a suitable range from the pattern looking for ":" and "#" if (searchWithRange) { @@ -217,8 +212,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Sort const unsortedResultTime = Date.now(); - const normalizedSearchValue = strings.stripWildcards(searchValue); - const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => compareItemsByScore(elementA, elementB, normalizedSearchValue, true, QuickOpenItemAccessor, this.scorerCache); + const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => compareItemsByScore(elementA, elementB, searchValue, true, QuickOpenItemAccessor, this.scorerCache); const viewResults = arrays.top(mergedResults, compare, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); const sortedResultTime = Date.now(); @@ -227,7 +221,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { if (entry instanceof FileEntry) { entry.setRange(searchWithRange ? searchWithRange.range : null); - const itemScore = scoreItem(entry, normalizedSearchValue, true, QuickOpenItemAccessor, this.scorerCache); + const itemScore = scoreItem(entry, searchValue, true, QuickOpenItemAccessor, this.scorerCache); entry.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); } }); From b862b187499fe549920276b833f130fc67d4986e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 12:45:36 +0200 Subject: [PATCH 036/303] fix tests --- .../base/parts/quickopen/test/common/quickOpenScorer.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index ed47435cbc0..b6d972787d2 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -9,6 +9,7 @@ import * as assert from 'assert'; import * as scorer from 'vs/base/parts/quickopen/common/quickOpenScorer'; import URI from 'vs/base/common/uri'; import { basename, dirname } from 'vs/base/common/paths'; +import { isWindows } from 'vs/base/common/platform'; class ResourceAccessorClass implements scorer.IItemAccessor { @@ -476,12 +477,12 @@ suite('Quick Open Scorer', () => { const resourceC = URI.file('node_modules1/bundle/lib/model/modules/modu1/index.js'); const resourceD = URI.file('node_modules1/bundle/lib/model/modules/oddl1/index.js'); - let query = 'modu1/index.js'; + let query = isWindows ? 'modu1\\index.js' : 'modu1/index.js'; let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceC); - query = 'un1/index.js'; + query = isWindows ? 'un1\\index.js' : 'un1/index.js'; res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); From aef33be94167f5331a689802d68d37476c2e9729 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 15:36:42 +0200 Subject: [PATCH 037/303] Missing workspace prevents start of vscode (fixes #35871) --- .../workspaces/electron-main/workspacesMainService.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index c3b3bb22264..8ac75f1fce2 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -70,7 +70,14 @@ export class WorkspacesMainService implements IWorkspacesMainService { return null; // does not look like a valid workspace config file } - return this.doResolveWorkspace(path, readFileSync(path, 'utf8')); + let contents: string; + try { + contents = readFileSync(path, 'utf8'); + } catch (error) { + return null; // invalid workspace + } + + return this.doResolveWorkspace(path, contents); } private isWorkspacePath(path: string): boolean { From ad42cac7b2cddfa7c6df5bcf8485171ed6c5d0aa Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 15:41:53 +0200 Subject: [PATCH 038/303] New setting "workbench.editor.labelFormat": "default" does not work (Linux) (fixes #35721) --- src/vs/workbench/browser/parts/editor/tabsTitleControl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index fe92a09cb72..3a12c2226cf 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -364,7 +364,7 @@ export class TabsTitleControl extends TitleControl { // Gather duplicate titles, while filtering out invalid descriptions const mapTitleToDuplicates = new Map(); for (const label of labels) { - if (typeof label.description === 'string' && label.description) { + if (typeof label.description === 'string') { getOrSet(mapTitleToDuplicates, label.name, []).push(label); } else { label.description = ''; From 5a8042dbaaa3352f918c50a20d6acd41a6eab0ca Mon Sep 17 00:00:00 2001 From: Beyang Liu Date: Tue, 10 Oct 2017 06:44:39 -0700 Subject: [PATCH 039/303] remove kludge that adds history item when new input is set on an editor (#35682) --- .../parts/files/browser/editors/textFileEditor.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index 4b70527ce55..b60b3bce030 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -24,7 +24,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CancelAction } from 'vs/platform/message/common/message'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -47,7 +46,6 @@ export class TextFileEditor extends BaseTextEditor { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @IHistoryService private historyService: IHistoryService, @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IThemeService themeService: IThemeService, @@ -87,16 +85,6 @@ export class TextFileEditor extends BaseTextEditor { public setInput(input: FileEditorInput, options?: EditorOptions): TPromise { - // We have a current input in this editor and are about to either open a new editor or jump to a different - // selection inside the editor. Thus we store the current selection into the navigation history so that - // a user can navigate back to the exact position he left off. - if (this.input) { - const selection = this.getControl().getSelection(); - if (selection) { - this.historyService.add(this.input, { startLineNumber: selection.startLineNumber, startColumn: selection.startColumn }); - } - } - // Return early for same input unless we force to open const forceOpen = options && options.forceOpen; if (!forceOpen && input.matches(this.input)) { From 4b38a9a5367d7a466ee3043f729fb79e3fc787bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 15:46:48 +0200 Subject: [PATCH 040/303] :lipstick: --- src/vs/workbench/services/history/common/history.ts | 7 +------ src/vs/workbench/test/workbenchTestServices.ts | 5 +---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index 4e262196b68..823f3f5f073 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -5,7 +5,7 @@ 'use strict'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorInput, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IResourceInput } from 'vs/platform/editor/common/editor'; import URI from 'vs/base/common/uri'; export const IHistoryService = createDecorator('historyService'); @@ -19,11 +19,6 @@ export interface IHistoryService { */ reopenLastClosedEditor(): void; - /** - * Add an entry to the navigation stack of the history. - */ - add(input: IEditorInput, selection?: ITextEditorSelection): void; - /** * Navigate forwards in history. * diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index e09df0d1813..18d72e4d754 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -24,7 +24,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput } from 'vs/platform/editor/common/editor'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IMessageService, IConfirmation, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; @@ -271,9 +271,6 @@ export class TestHistoryService implements IHistoryService { public reopenLastClosedEditor(): void { } - public add(input: IEditorInput, selection?: ITextEditorSelection): void { - } - public forward(acrossEditors?: boolean): void { } From dfc3c944a46589bd783aedd0b09ebd2ff861e55a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 10 Oct 2017 16:05:29 +0200 Subject: [PATCH 041/303] remove unused variable --- extensions/git/src/git.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 5edc8c6d258..d0f69123a04 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -13,7 +13,6 @@ import { EventEmitter } from 'events'; import iconv = require('iconv-lite'); import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp } from './util'; -const readdir = denodeify(fs.readdir); const readfile = denodeify(fs.readFile); export interface IGit { From f593206841221da1a3a49cab08ab166ff240400e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 16:29:10 +0200 Subject: [PATCH 042/303] tests --- .../test/common/quickOpenScorer.test.ts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index b6d972787d2..2df8c19f1ac 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -487,4 +487,56 @@ suite('Quick Open Scorer', () => { res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); + + test('compareFilesByScore - avoid match scattering (bug #21019)', function () { + const resourceA = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceLoad/index.js'); + const resourceB = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceDistribution/index.js'); + const resourceC = URI.file('app/containers/Services/NetworkData/ServiceDetailTabs/ServiceTabs/StatVideo/index.js'); + + let query = 'StatVideoindex'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + }); + + test('compareFilesByScore - avoid match scattering (bug #26649)', function () { + const resourceA = URI.file('photobook/src/components/AddPagesButton/index.js'); + const resourceB = URI.file('photobook/src/components/ApprovalPageHeader/index.js'); + const resourceC = URI.file('photobook/src/canvasComponents/BookPage/index.js'); + + let query = 'bookpageIndex'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + }); + + test('compareFilesByScore - avoid match scattering (bug #33247)', function () { + const resourceA = URI.file('ui/src/utils/constants.js'); + const resourceB = URI.file('ui/src/ui/Icons/index.js'); + + let query = isWindows ? 'ui\\icons' : 'ui/icons'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #33247 comment)', function () { + const resourceA = URI.file('ui/src/components/IDInput/index.js'); + const resourceB = URI.file('ui/src/ui/Input/index.js'); + + let query = isWindows ? 'ui\\input\\index' : 'ui/input/index'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - prefer shorter hit (bug #20546)', function () { + const resourceA = URI.file('editor/core/components/tests/list-view-spec.js'); + const resourceB = URI.file('editor/core/components/list-view.js'); + + let query = 'listview'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); }); \ No newline at end of file From a57c8ec73c6a12904323d8047b558d533ce8335c Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 10 Oct 2017 07:38:44 -0700 Subject: [PATCH 043/303] Disable 'new release' --- .github/new_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/new_release.yml b/.github/new_release.yml index 3877cb6f8a2..be3fd91e8b1 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', newReleases: ['1.17'], - perform: true + perform: false } \ No newline at end of file From 7f9ff2b1c89755a408aa43bbd353f2296e3fafd1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 5 Oct 2017 15:35:23 +0200 Subject: [PATCH 044/303] add FileDecorationsService and use it with markers --- .../workbench/electron-browser/workbench.ts | 5 + .../parts/files/browser/views/explorerView.ts | 18 ++- .../files/browser/views/explorerViewer.ts | 7 +- .../markers/browser/markersFileDecorations.ts | 64 +++++++++++ .../browser/markersWorkbenchContributions.ts | 4 +- .../browser/fileDecorations.ts | 53 +++++++++ .../browser/fileDecorationsService.ts | 104 ++++++++++++++++++ 7 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 src/vs/workbench/parts/markers/browser/markersFileDecorations.ts create mode 100644 src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts create mode 100644 src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index c565be4c877..0a894a8df22 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -98,6 +98,8 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; import URI from 'vs/base/common/uri'; +import { FileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorationsService'; +import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); @@ -583,6 +585,9 @@ export class Workbench implements IPartService { // Text File Service serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService)); + // File Decorations + serviceCollection.set(IFileDecorationsService, new SyncDescriptor(FileDecorationsService)); + // SCM Service serviceCollection.set(ISCMService, new SyncDescriptor(SCMService)); diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index eb9f3dbdc9b..20fc00c0ff2 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -45,6 +45,7 @@ import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/th import { isLinux } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { attachListStyler } from 'vs/platform/theme/common/styler'; +import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; export interface IExplorerViewOptions extends IViewletViewOptions { viewletState: FileViewletState; @@ -98,7 +99,8 @@ export class ExplorerView extends ViewsViewletPanel { @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService, @IWorkbenchThemeService private themeService: IWorkbenchThemeService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IFileDecorationsService private fileDecorationsService: IFileDecorationsService ) { super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService); @@ -166,6 +168,7 @@ export class ExplorerView extends ViewsViewletPanel { this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(e => this.refreshFromEvent(e.added))); this.disposables.push(this.contextService.onDidChangeWorkbenchState(e => this.refreshFromEvent())); + this.disposables.push(this.fileDecorationsService.onDidChangeFileDecoration(this.onDidChangeFileDecorations, this)); onFileIconThemeChange(this.themeService.getFileIconTheme()); } @@ -681,6 +684,19 @@ export class ExplorerView extends ViewsViewletPanel { })); } + private onDidChangeFileDecorations(uris: URI[]): void { + let seen = new Set(); + let stack = uris.map(uri => this.model.findClosest(uri)); + while (stack.length > 0) { + let stat = stack.shift(); + if (stat && !seen.has(stat)) { + this.explorerViewer.refresh(stat, false); + stack.push(stat.parent); + seen.add(stat); + } + } + } + private refreshFromEvent(newRoots: IWorkspaceFolder[] = []): void { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index d60aa33d4d8..a2eaf2bdb45 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -58,6 +58,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; export class FileDataSource implements IDataSource { constructor( @@ -290,7 +291,8 @@ export class FileRenderer implements IRenderer { state: FileViewletState, @IContextViewService private contextViewService: IContextViewService, @IInstantiationService private instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @IFileDecorationsService private decorationsService: IFileDecorationsService ) { this.state = state; } @@ -324,6 +326,9 @@ export class FileRenderer implements IRenderer { extraClasses.push('nonexistent-root'); } templateData.label.setFile(stat.resource, { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses }); + + let top = this.decorationsService.getTopDecoration(stat.resource, stat.isDirectory); + templateData.label.element.style.color = top ? top.color.toString() : ''; } // Input Box diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts new file mode 100644 index 00000000000..9030dd7375e --- /dev/null +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; +import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; +import { IFileDecorationsService, DecorationType, IFileDecorationData } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import URI from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { Registry } from 'vs/platform/registry/common/platform'; +import Severity from 'vs/base/common/severity'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; + +class MarkersFileDecorations implements IWorkbenchContribution { + + private readonly _disposables: IDisposable[]; + private readonly _type: DecorationType; + + constructor( + @IMarkerService private _markerService: IMarkerService, + @IFileDecorationsService private _decorationsService: IFileDecorationsService, + @IThemeService private _themeService: IThemeService + ) { + // + this._disposables = [ + this._markerService.onMarkerChanged(this._onDidChangeMarker, this), + this._type = this._decorationsService.registerDecorationType(localize('errorAndWarnings', "Errors & Warnings")) + ]; + } + + dispose(): void { + dispose(this._disposables); + } + + getId(): string { + return 'markers.MarkersFileDecorations'; + } + + private _onDidChangeMarker(resources: URI[]): void { + for (const resource of resources) { + const markers = this._markerService.read({ resource }); + if (!isFalsyOrEmpty(markers)) { + const data = markers.map(this._toFileDecorationData, this); + this._decorationsService.setFileDecorations(this._type, resource, data); + } else { + this._decorationsService.unsetFileDecorations(this._type, resource); + } + } + } + + private _toFileDecorationData(marker: IMarker): IFileDecorationData { + const { message, severity } = marker; + const color = this._themeService.getTheme().getColor(severity === Severity.Error ? editorErrorForeground : editorWarningForeground); + return { message, severity, color }; + } +} + +Registry.as(Extensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations); diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index d6b4f686ffd..5c20e92410b 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -17,6 +17,8 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { MarkersPanel } from 'vs/workbench/parts/markers/browser/markersPanel'; +import './markersFileDecorations'; + export function registerContributions(): void { KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -66,4 +68,4 @@ export function registerContributions(): void { // Retaining old action to show errors and warnings, so that custom bindings to this action for existing users works. registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleErrorsAndWarningsAction, ToggleErrorsAndWarningsAction.ID, ToggleErrorsAndWarningsAction.LABEL), 'Show Errors and Warnings'); -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts new file mode 100644 index 00000000000..3bb20dba223 --- /dev/null +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Color } from 'vs/base/common/color'; +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import Severity from 'vs/base/common/severity'; + +export const IFileDecorationsService = createDecorator('IFileDecorationsService'); + +export interface IFileDecoration { + readonly type: DecorationType; + readonly message: string; + readonly color: Color; + readonly severity: Severity; +} + +export abstract class DecorationType { + readonly label: string; + protected constructor(label: string) { + this.label = label; + } + dispose(): void { + // + } +} + +export interface IFileDecorationData { + message: string; + color: Color; + severity: Severity; +} + +export interface IFileDecorationsService { + + readonly _serviceBrand: any; + + readonly onDidChangeFileDecoration: Event; + + registerDecorationType(label: string): DecorationType; + + setFileDecorations(type: DecorationType, target: URI, data: IFileDecorationData[]): void; + + unsetFileDecorations(type: DecorationType, target: URI): void; + + getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[]; + + getTopDecoration(uri: URI, includeChildren: boolean): IFileDecoration; +} diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts new file mode 100644 index 00000000000..392f6ece311 --- /dev/null +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import Severity from 'vs/base/common/severity'; +import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; +import { IFileDecorationsService, IFileDecoration, DecorationType, IFileDecorationData } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { TernarySearchTree } from 'vs/base/common/map'; +import { mergeSort, isFalsyOrEmpty } from 'vs/base/common/arrays'; + + +export class FileDecorationsService implements IFileDecorationsService { + + readonly _serviceBrand; + + private readonly _onDidChangeFileDecoration = new Emitter(); + private readonly _types = new Map>(); + + readonly onDidChangeFileDecoration: Event = debounceEvent( + this._onDidChangeFileDecoration.event, + (last, current) => { + if (!last) { + last = []; + } + last.push(current); + return last; + } + ); + + registerDecorationType(label: string): DecorationType { + const outer = this; + const type = new class extends DecorationType { + constructor() { + super(label); + } + dispose() { + outer._types.delete(type); + } + }; + this._types.set(type, TernarySearchTree.forPaths()); + return type; + } + + setFileDecorations(type: DecorationType, target: URI, data: IFileDecorationData[]): void { + let decorations = mergeSort(data.map(data => ({ type, ...data })), FileDecorationsService._compareFileDecorationsBySeverity); + this._types.get(type).set(target.toString(), decorations); + this._onDidChangeFileDecoration.fire(target); + } + + unsetFileDecorations(type: DecorationType, target: URI): void { + this._types.get(type).delete(target.toString()); + this._onDidChangeFileDecoration.fire(target); + } + + getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[] { + let ret: IFileDecoration[] = []; + this._someFileDecoration(uri, includeChildren, decoration => { + ret.push(decoration); + return false; + }); + return ret; + } + + getTopDecoration(uri: URI, includeChildren: boolean): IFileDecoration { + let top: IFileDecoration; + this._someFileDecoration(uri, includeChildren, decoration => { + // top is the most severe one, + // stop as soon as an error is found + if (!top || FileDecorationsService._compareFileDecorationsBySeverity(top, decoration) > 0) { + top = decoration; + } + return top.severity === Severity.Error; + }); + return top; + } + + private _someFileDecoration(uri: URI, includeChildren: boolean, callback: (a: IFileDecoration) => boolean): void { + let key = uri.toString(); + let done = false; + this._types.forEach(tree => { + if (done) { + return; + } + if (includeChildren) { + let newTree = tree.findSuperstr(key); + if (newTree) { + newTree.forEach(([, data]) => done = done || data.some(callback)); + } + } else { + let list = tree.get(key); + if (!isFalsyOrEmpty(list)) { + done = list.some(callback); + } + } + }); + } + + private static _compareFileDecorationsBySeverity(a: IFileDecoration, b: IFileDecoration): number { + return Severity.compare(a.severity, b.severity); + } +} From 9fa1f52ac2f33ddf62ec37b093a81a39a00a3162 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 5 Oct 2017 16:48:12 +0200 Subject: [PATCH 045/303] start with scm file decorations --- .../scm/electron-browser/scm.contribution.ts | 4 + .../electron-browser/scmFileDecorations.ts | 94 +++++++++++++++++++ .../browser/fileDecorationsService.ts | 6 +- 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index b5ee2acfc51..93da15cee69 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -17,6 +17,7 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StatusUpdater, StatusBarController } from './scmActivity'; +import { FileDecorations } from './scmFileDecorations'; import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet'; class OpenSCMViewletAction extends ToggleViewletAction { @@ -49,6 +50,9 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(StatusBarController); +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(FileDecorations); + // Register Action to Open Viewlet Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts new file mode 100644 index 00000000000..ff401a62713 --- /dev/null +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; +import URI from 'vs/base/common/uri'; +import Severity from 'vs/base/common/severity'; +import { Color } from 'vs/base/common/color'; + +export class FileDecorations implements IWorkbenchContribution { + + private readonly _disposables: IDisposable[]; + // private readonly _type: DecorationType; + private readonly _repositoryListeners = new Map(); + + constructor( + @IFileDecorationsService private _decorationsService: IFileDecorationsService, + @ISCMService private _scmService: ISCMService, + ) { + this._scmService.repositories.forEach(this._onDidAddRepository, this); + this._disposables = [ + this._scmService.onDidAddRepository(this._onDidAddRepository, this), + this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this), + ]; + } + + dispose(): void { + dispose(this._disposables); + } + + private _onDidAddRepository(repo: ISCMRepository): void { + const type = this._decorationsService.registerDecorationType(repo.provider.label); + const { provider } = repo; + + let oldDecorations = new Map(); + const listener = provider.onDidChangeResources(() => { + + let newDecorations = new Map(); + let baseColor = Color.fromHex('#007acc'); + let factor = 0.0; + for (const group of provider.resources) { + + factor += 0.1; + let color = Color.getDarkerColor(baseColor, Color.black, factor); + + for (const resource of group.resourceCollection.resources) { + + this._decorationsService.setFileDecorations(type, resource.sourceUri, [{ + severity: Severity.Info, + message: resource.decorations.tooltip, + color + }]); + + newDecorations.set(resource.sourceUri.toString(), resource.sourceUri); + } + } + + oldDecorations.forEach((value, key) => { + if (!newDecorations.has(key)) { + this._decorationsService.unsetFileDecorations(type, value); + } + }); + + oldDecorations = newDecorations; + }); + + this._repositoryListeners.set(repo, { + dispose() { + listener.dispose(); + type.dispose(); + } + }); + } + + private _onDidRemoveRepository(repo: ISCMRepository): void { + let listener = this._repositoryListeners.get(repo); + if (listener) { + this._repositoryListeners.delete(repo); + listener.dispose(); + } + } + + + getId(): string { + throw new Error('smc.SCMFileDecorations'); + } + +} diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts index 392f6ece311..a7c225ba106 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts @@ -37,7 +37,11 @@ export class FileDecorationsService implements IFileDecorationsService { super(label); } dispose() { - outer._types.delete(type); + let tree = outer._types.get(type); + if (tree) { + tree.forEach(([key]) => outer._onDidChangeFileDecoration.fire(URI.parse(key))); + outer._types.delete(type); + } } }; this._types.set(type, TernarySearchTree.forPaths()); From b5b3208739386fb151d68313505df4e78255fd4c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 5 Oct 2017 17:12:13 +0200 Subject: [PATCH 046/303] one scm color --- .../parts/scm/electron-browser/scmFileDecorations.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index ff401a62713..13f3ffb8f8e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -42,15 +42,13 @@ export class FileDecorations implements IWorkbenchContribution { const listener = provider.onDidChangeResources(() => { let newDecorations = new Map(); - let baseColor = Color.fromHex('#007acc'); - let factor = 0.0; + let color = Color.fromHex('#007aCC'); + for (const group of provider.resources) { - factor += 0.1; - let color = Color.getDarkerColor(baseColor, Color.black, factor); - for (const resource of group.resourceCollection.resources) { - + // TODO@Joh have a better color and icon which is based + // on the resource decoration this._decorationsService.setFileDecorations(type, resource.sourceUri, [{ severity: Severity.Info, message: resource.decorations.tooltip, From 040f338dda89673e4ce0c13716cfc3a574ca4d84 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 09:40:29 +0200 Subject: [PATCH 047/303] refine service, allow to set only one decoration per type and resource --- .../markers/browser/markersFileDecorations.ts | 10 ++++---- .../electron-browser/scmFileDecorations.ts | 6 ++--- .../browser/fileDecorations.ts | 4 ++-- .../browser/fileDecorationsService.ts | 23 ++++++++----------- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 9030dd7375e..b5dad47b841 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -44,12 +44,14 @@ class MarkersFileDecorations implements IWorkbenchContribution { private _onDidChangeMarker(resources: URI[]): void { for (const resource of resources) { - const markers = this._markerService.read({ resource }); + const markers = this._markerService.read({ resource }) + .sort((a, b) => Severity.compare(a.severity, b.severity)); + if (!isFalsyOrEmpty(markers)) { - const data = markers.map(this._toFileDecorationData, this); - this._decorationsService.setFileDecorations(this._type, resource, data); + const data = this._toFileDecorationData(markers[0]); + this._decorationsService.setFileDecoration(this._type, resource, data); } else { - this._decorationsService.unsetFileDecorations(this._type, resource); + this._decorationsService.unsetFileDecoration(this._type, resource); } } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 13f3ffb8f8e..59509fd3c01 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -49,11 +49,11 @@ export class FileDecorations implements IWorkbenchContribution { for (const resource of group.resourceCollection.resources) { // TODO@Joh have a better color and icon which is based // on the resource decoration - this._decorationsService.setFileDecorations(type, resource.sourceUri, [{ + this._decorationsService.setFileDecoration(type, resource.sourceUri, { severity: Severity.Info, message: resource.decorations.tooltip, color - }]); + }); newDecorations.set(resource.sourceUri.toString(), resource.sourceUri); } @@ -61,7 +61,7 @@ export class FileDecorations implements IWorkbenchContribution { oldDecorations.forEach((value, key) => { if (!newDecorations.has(key)) { - this._decorationsService.unsetFileDecorations(type, value); + this._decorationsService.unsetFileDecoration(type, value); } }); diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts index 3bb20dba223..15e1feb21d4 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts @@ -43,9 +43,9 @@ export interface IFileDecorationsService { registerDecorationType(label: string): DecorationType; - setFileDecorations(type: DecorationType, target: URI, data: IFileDecorationData[]): void; + setFileDecoration(type: DecorationType, target: URI, data: IFileDecorationData): void; - unsetFileDecorations(type: DecorationType, target: URI): void; + unsetFileDecoration(type: DecorationType, target: URI): void; getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[]; diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts index a7c225ba106..e4f2932b524 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts @@ -9,15 +9,13 @@ import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; import { IFileDecorationsService, IFileDecoration, DecorationType, IFileDecorationData } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { mergeSort, isFalsyOrEmpty } from 'vs/base/common/arrays'; - export class FileDecorationsService implements IFileDecorationsService { readonly _serviceBrand; private readonly _onDidChangeFileDecoration = new Emitter(); - private readonly _types = new Map>(); + private readonly _types = new Map>(); readonly onDidChangeFileDecoration: Event = debounceEvent( this._onDidChangeFileDecoration.event, @@ -44,17 +42,16 @@ export class FileDecorationsService implements IFileDecorationsService { } } }; - this._types.set(type, TernarySearchTree.forPaths()); + this._types.set(type, TernarySearchTree.forPaths()); return type; } - setFileDecorations(type: DecorationType, target: URI, data: IFileDecorationData[]): void { - let decorations = mergeSort(data.map(data => ({ type, ...data })), FileDecorationsService._compareFileDecorationsBySeverity); - this._types.get(type).set(target.toString(), decorations); + setFileDecoration(type: DecorationType, target: URI, data: IFileDecorationData): void { + this._types.get(type).set(target.toString(), { type, ...data }); this._onDidChangeFileDecoration.fire(target); } - unsetFileDecorations(type: DecorationType, target: URI): void { + unsetFileDecoration(type: DecorationType, target: URI): void { this._types.get(type).delete(target.toString()); this._onDidChangeFileDecoration.fire(target); } @@ -76,7 +73,7 @@ export class FileDecorationsService implements IFileDecorationsService { if (!top || FileDecorationsService._compareFileDecorationsBySeverity(top, decoration) > 0) { top = decoration; } - return top.severity === Severity.Error; + return top !== undefined && top.severity === Severity.Error; }); return top; } @@ -91,13 +88,11 @@ export class FileDecorationsService implements IFileDecorationsService { if (includeChildren) { let newTree = tree.findSuperstr(key); if (newTree) { - newTree.forEach(([, data]) => done = done || data.some(callback)); + newTree.forEach(([, deco]) => done = done || callback(deco)); } } else { - let list = tree.get(key); - if (!isFalsyOrEmpty(list)) { - done = list.some(callback); - } + let deco = tree.get(key); + done = done || deco && callback(deco); } }); } From e980c39e60bf00a312228905031277278cd17edf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 10:10:40 +0200 Subject: [PATCH 048/303] add setting 'problems.showOnFiles' --- .../markers/browser/markersFileDecorations.ts | 20 +++++++++++++++++-- .../browser/markersWorkbenchContributions.ts | 16 +++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index b5dad47b841..dae31174494 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -16,25 +16,31 @@ import { Registry } from 'vs/platform/registry/common/platform'; import Severity from 'vs/base/common/severity'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; class MarkersFileDecorations implements IWorkbenchContribution { private readonly _disposables: IDisposable[]; private readonly _type: DecorationType; + private _markerListener: IDisposable; constructor( @IMarkerService private _markerService: IMarkerService, @IFileDecorationsService private _decorationsService: IFileDecorationsService, - @IThemeService private _themeService: IThemeService + @IThemeService private _themeService: IThemeService, + @IConfigurationService private _configurationService: IConfigurationService ) { // this._disposables = [ - this._markerService.onMarkerChanged(this._onDidChangeMarker, this), + this._configurationService.onDidUpdateConfiguration(this._updateEnablement, this), this._type = this._decorationsService.registerDecorationType(localize('errorAndWarnings', "Errors & Warnings")) ]; + + this._updateEnablement(); } dispose(): void { + dispose(this._markerListener); dispose(this._disposables); } @@ -42,6 +48,16 @@ class MarkersFileDecorations implements IWorkbenchContribution { return 'markers.MarkersFileDecorations'; } + private _updateEnablement(): void { + let value = this._configurationService.getConfiguration<{ showOnFiles: boolean }>('problems'); + if (value) { + this._markerListener = this._markerService.onMarkerChanged(this._onDidChangeMarker, this); + this._onDidChangeMarker(this._markerService.read().map(marker => marker.resource)); + } else if (this._markerListener) { + this._markerListener.dispose(); + } + } + private _onDidChangeMarker(resources: URI[]): void { for (const resource of resources) { const markers = this._markerService.read({ resource }) diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index 5c20e92410b..45e7ca37718 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -18,6 +18,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { MarkersPanel } from 'vs/workbench/parts/markers/browser/markersPanel'; import './markersFileDecorations'; +import { localize } from 'vs/nls'; export function registerContributions(): void { @@ -50,6 +51,21 @@ export function registerContributions(): void { } }); + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'problems', + 'order': 101, + 'type': 'object', + 'properties': { + 'problems.showOnFiles': { + 'description': localize('markers.showOnFile', "Show Errors & Warnings in the file explorer."), + 'type': 'boolean', + 'default': true + } + } + }); + + + // markers panel Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( MarkersPanel, From 5c109769f0d9a2bf3af51e978f5e4558bf3b9177 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 11:40:24 +0200 Subject: [PATCH 049/303] use ColorIdentifier instead of Color, define some git colors for untracked, modifed, and ignored --- extensions/git/package.json | 33 +++++++++++++++++-- extensions/git/src/repository.ts | 19 +++++++++-- src/vs/vscode.d.ts | 6 ++++ .../api/electron-browser/mainThreadSCM.ts | 5 +-- src/vs/workbench/api/node/extHost.protocol.ts | 3 +- src/vs/workbench/api/node/extHostSCM.ts | 3 +- .../files/browser/views/explorerViewer.ts | 4 ++- .../markers/browser/markersFileDecorations.ts | 4 +-- .../electron-browser/scmFileDecorations.ts | 12 +++---- .../browser/fileDecorations.ts | 6 ++-- src/vs/workbench/services/scm/common/scm.ts | 4 ++- 11 files changed, 76 insertions(+), 23 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 3dbdb6604bf..c8408252664 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -803,7 +803,36 @@ "default": false } } - } + }, + "colors": [ + { + "id": "git.color.untracked", + "description": "Color for untracked resources", + "defaults": { + "light": "#b47d16", + "dark": "#cf9425", + "highContrast": "#cf9425" + } + }, + { + "id": "git.color.modified", + "description": "Color for modified resources", + "defaults": { + "light": "#007acc", + "dark": "#007acc", + "highContrast": "#007acc" + } + }, + { + "id": "git.color.ignored", + "description": "Color for ignored resources", + "defaults": { + "light": "#00000033", + "dark": "#ffffff33", + "highContrast": "#ffffff33" + } + } + ] }, "dependencies": { "byline": "^5.0.0", @@ -816,4 +845,4 @@ "@types/node": "7.0.43", "mocha": "^3.2.0" } -} \ No newline at end of file +} diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index da154939744..465c9211f70 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -5,7 +5,7 @@ 'use strict'; -import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit } from 'vscode'; +import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor } from 'vscode'; import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; import { memoize, throttle, debounce } from './decorators'; @@ -170,14 +170,29 @@ export class Resource implements SourceControlResourceState { // return this.resourceUri.fsPath.substr(0, workspaceRootPath.length) !== workspaceRootPath; } + private get color(): ThemeColor | undefined { + switch (this.type) { + case Status.INDEX_MODIFIED: + case Status.MODIFIED: + return new ThemeColor('git.color.modified'); + case Status.UNTRACKED: + return new ThemeColor('git.color.untracked'); + case Status.IGNORED: + return new ThemeColor('git.color.ignored'); + default: + return undefined; + } + } + get decorations(): SourceControlResourceDecorations { const light = { iconPath: this.getIconPath('light') }; const dark = { iconPath: this.getIconPath('dark') }; const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; + const color = this.color; - return { strikeThrough, faded, tooltip, light, dark }; + return { strikeThrough, faded, tooltip, light, dark, color }; } constructor( diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1a63221b1f9..d81912cebe7 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5630,6 +5630,12 @@ declare module 'vscode' { */ readonly tooltip?: string; + /** + * A color for a specific + * [source control resource state](#SourceControlResourceState). + */ + readonly color?: ThemeColor; + /** * The light theme decorations. */ diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index 64253cfa2d4..69b253930b7 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -182,7 +182,7 @@ class MainThreadSCMProvider implements ISCMProvider { for (const [start, deleteCount, rawResources] of groupSlices) { const resources = rawResources.map(rawResource => { - const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource; + const [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] = rawResource; const icon = icons[0]; const iconDark = icons[1] || icon; const decorations = { @@ -190,7 +190,8 @@ class MainThreadSCMProvider implements ISCMProvider { iconDark: iconDark && URI.parse(iconDark), tooltip, strikeThrough, - faded + faded, + color: color && color.id }; return new MainThreadSCMResource( diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 07a65209fe6..a3d65955516 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -357,7 +357,8 @@ export type SCMRawResource = [ string[] /*icons: light, dark*/, string /*tooltip*/, boolean /*strike through*/, - boolean /*faded*/ + boolean /*faded*/, + { id: string } /*ThemeColor*/ ]; export type SCMRawResourceSplice = [ diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index ec9ad8b38ee..a9c1e63af2e 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -243,8 +243,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG const tooltip = (r.decorations && r.decorations.tooltip) || ''; const strikeThrough = r.decorations && !!r.decorations.strikeThrough; const faded = r.decorations && !!r.decorations.faded; + const color = r.decorations && r.decorations.color; - return [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource; + return [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] as SCMRawResource; }); handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles)); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index a2eaf2bdb45..25f102e95c1 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -328,7 +328,9 @@ export class FileRenderer implements IRenderer { templateData.label.setFile(stat.resource, { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses }); let top = this.decorationsService.getTopDecoration(stat.resource, stat.isDirectory); - templateData.label.element.style.color = top ? top.color.toString() : ''; + templateData.label.element.style.color = top + ? this.themeService.getTheme().getColor(top.color, true).toString() + : ''; } // Input Box diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index dae31174494..b4cb3d739b5 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -14,7 +14,6 @@ import { localize } from 'vs/nls'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { Registry } from 'vs/platform/registry/common/platform'; import Severity from 'vs/base/common/severity'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -27,7 +26,6 @@ class MarkersFileDecorations implements IWorkbenchContribution { constructor( @IMarkerService private _markerService: IMarkerService, @IFileDecorationsService private _decorationsService: IFileDecorationsService, - @IThemeService private _themeService: IThemeService, @IConfigurationService private _configurationService: IConfigurationService ) { // @@ -74,7 +72,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { private _toFileDecorationData(marker: IMarker): IFileDecorationData { const { message, severity } = marker; - const color = this._themeService.getTheme().getColor(severity === Severity.Error ? editorErrorForeground : editorWarningForeground); + const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; return { message, severity, color }; } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 59509fd3c01..d145507ce19 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -11,7 +11,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; -import { Color } from 'vs/base/common/color'; export class FileDecorations implements IWorkbenchContribution { @@ -42,19 +41,18 @@ export class FileDecorations implements IWorkbenchContribution { const listener = provider.onDidChangeResources(() => { let newDecorations = new Map(); - let color = Color.fromHex('#007aCC'); - for (const group of provider.resources) { for (const resource of group.resourceCollection.resources) { - // TODO@Joh have a better color and icon which is based - // on the resource decoration + if (!resource.decorations.color) { + continue; + } + this._decorationsService.setFileDecoration(type, resource.sourceUri, { severity: Severity.Info, message: resource.decorations.tooltip, - color + color: resource.decorations.color }); - newDecorations.set(resource.sourceUri.toString(), resource.sourceUri); } } diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts index 15e1feb21d4..2aa9f04fbe1 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts @@ -5,17 +5,17 @@ 'use strict'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Color } from 'vs/base/common/color'; import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; +import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export const IFileDecorationsService = createDecorator('IFileDecorationsService'); export interface IFileDecoration { readonly type: DecorationType; readonly message: string; - readonly color: Color; + readonly color: ColorIdentifier; readonly severity: Severity; } @@ -31,7 +31,7 @@ export abstract class DecorationType { export interface IFileDecorationData { message: string; - color: Color; + color: ColorIdentifier; severity: Severity; } diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index a9337cf69b8..e5dda8e6e2b 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -11,6 +11,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Command } from 'vs/editor/common/modes'; +import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export interface IBaselineResourceProvider { getBaselineResource(resource: URI): TPromise; @@ -24,6 +25,7 @@ export interface ISCMResourceDecorations { tooltip?: string; strikeThrough?: boolean; faded?: boolean; + color?: ColorIdentifier; } export interface ISCMResourceSplice { @@ -92,4 +94,4 @@ export interface ISCMService { readonly repositories: ISCMRepository[]; registerSCMProvider(provider: ISCMProvider): ISCMRepository; -} \ No newline at end of file +} From 737f55bb2ffebdc3caad9501470d3765adb28ece Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 17:07:07 +0200 Subject: [PATCH 050/303] TST#clear --- src/vs/base/common/map.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 72284c76d1a..894f82082b6 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -323,6 +323,10 @@ export class TernarySearchTree { this._segments = segments; } + clear(): void { + this._root = undefined; + } + set(key: string, element: E): void { const segements = this._segments.reset(key); this._root = this._set(this._root, segements.next(), segements, element); From 5a57f27d5a86cdc90e912cd1bedc5c01af8392c3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 17:16:48 +0200 Subject: [PATCH 051/303] refine interfaces --- .../markers/browser/markersFileDecorations.ts | 12 ++++------- .../electron-browser/scmFileDecorations.ts | 7 +++---- .../browser/fileDecorations.ts | 21 +++++++------------ .../browser/fileDecorationsService.ts | 13 ++++++------ 4 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index b4cb3d739b5..558a0814392 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -61,19 +61,15 @@ class MarkersFileDecorations implements IWorkbenchContribution { const markers = this._markerService.read({ resource }) .sort((a, b) => Severity.compare(a.severity, b.severity)); - if (!isFalsyOrEmpty(markers)) { - const data = this._toFileDecorationData(markers[0]); - this._decorationsService.setFileDecoration(this._type, resource, data); - } else { - this._decorationsService.unsetFileDecoration(this._type, resource); - } + const data = !isFalsyOrEmpty(markers) ? this._toFileDecorationData(markers[0]) : undefined; + this._decorationsService.setFileDecoration(this._type, resource, data); } } private _toFileDecorationData(marker: IMarker): IFileDecorationData { - const { message, severity } = marker; + const { severity } = marker; const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; - return { message, severity, color }; + return { severity, color }; } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index d145507ce19..0e228dc6208 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -15,7 +15,6 @@ import Severity from 'vs/base/common/severity'; export class FileDecorations implements IWorkbenchContribution { private readonly _disposables: IDisposable[]; - // private readonly _type: DecorationType; private readonly _repositoryListeners = new Map(); constructor( @@ -50,8 +49,8 @@ export class FileDecorations implements IWorkbenchContribution { this._decorationsService.setFileDecoration(type, resource.sourceUri, { severity: Severity.Info, - message: resource.decorations.tooltip, - color: resource.decorations.color + color: resource.decorations.color, + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } }); newDecorations.set(resource.sourceUri.toString(), resource.sourceUri); } @@ -59,7 +58,7 @@ export class FileDecorations implements IWorkbenchContribution { oldDecorations.forEach((value, key) => { if (!newDecorations.has(key)) { - this._decorationsService.unsetFileDecoration(type, value); + this._decorationsService.setFileDecoration(type, value); } }); diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts index 2aa9f04fbe1..0f89b41c00f 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts @@ -12,13 +12,6 @@ import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export const IFileDecorationsService = createDecorator('IFileDecorationsService'); -export interface IFileDecoration { - readonly type: DecorationType; - readonly message: string; - readonly color: ColorIdentifier; - readonly severity: Severity; -} - export abstract class DecorationType { readonly label: string; protected constructor(label: string) { @@ -29,10 +22,14 @@ export abstract class DecorationType { } } + +export interface IFileDecoration extends IFileDecorationData { + readonly type: DecorationType; +} export interface IFileDecorationData { - message: string; - color: ColorIdentifier; - severity: Severity; + readonly severity: Severity; + readonly color?: ColorIdentifier; + readonly icon?: URI | { dark: URI, light: URI }; } export interface IFileDecorationsService { @@ -43,9 +40,7 @@ export interface IFileDecorationsService { registerDecorationType(label: string): DecorationType; - setFileDecoration(type: DecorationType, target: URI, data: IFileDecorationData): void; - - unsetFileDecoration(type: DecorationType, target: URI): void; + setFileDecoration(type: DecorationType, target: URI, data?: IFileDecorationData): void; getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[]; diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts index e4f2932b524..39bb9c6de2a 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts +++ b/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts @@ -46,13 +46,12 @@ export class FileDecorationsService implements IFileDecorationsService { return type; } - setFileDecoration(type: DecorationType, target: URI, data: IFileDecorationData): void { - this._types.get(type).set(target.toString(), { type, ...data }); - this._onDidChangeFileDecoration.fire(target); - } - - unsetFileDecoration(type: DecorationType, target: URI): void { - this._types.get(type).delete(target.toString()); + setFileDecoration(type: DecorationType, target: URI, data?: IFileDecorationData): void { + if (data) { + this._types.get(type).set(target.toString(), { type, ...data }); + } else { + this._types.get(type).delete(target.toString()); + } this._onDidChangeFileDecoration.fire(target); } From 6fc89a918e8c6ce127204e5661f1e7bb14df489d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 19:19:04 +0200 Subject: [PATCH 052/303] move render/update logic to file/resource label, rename fileDecorations to decorations etc --- src/vs/workbench/browser/labels.ts | 40 +++++++++++++-- .../workbench/electron-browser/workbench.ts | 6 +-- .../parts/files/browser/views/explorerView.ts | 18 +------ .../files/browser/views/explorerViewer.ts | 19 +++---- .../markers/browser/markersFileDecorations.ts | 8 +-- .../electron-browser/scmFileDecorations.ts | 8 +-- .../browser/decorations.ts} | 22 +++++---- .../browser/decorationsService.ts} | 49 ++++++++++++------- 8 files changed, 102 insertions(+), 68 deletions(-) rename src/vs/workbench/services/{fileDecorations/browser/fileDecorations.ts => decorations/browser/decorations.ts} (60%) rename src/vs/workbench/services/{fileDecorations/browser/fileDecorationsService.ts => decorations/browser/decorationsService.ts} (61%) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 93a7498c27b..2797fec3411 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -20,9 +20,11 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; export interface IResourceLabel { name: string; @@ -32,6 +34,8 @@ export interface IResourceLabel { export interface IResourceLabelOptions extends IIconLabelOptions { fileKind?: FileKind; + showDecorations?: boolean; + showAllDecorations?: boolean; } export class ResourceLabel extends IconLabel { @@ -49,7 +53,9 @@ export class ResourceLabel extends IconLabel { @IConfigurationService private configurationService: IConfigurationService, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, - @IEnvironmentService protected environmentService: IEnvironmentService + @IEnvironmentService protected environmentService: IEnvironmentService, + @IResourceDecorationsService protected decorationsService: IResourceDecorationsService, + @IThemeService private themeService: IThemeService ) { super(container, options); @@ -62,6 +68,7 @@ export class ResourceLabel extends IconLabel { this.extensionService.onReady().then(() => this.render(true /* clear cache */)); // update when extensions are loaded with potentially new languages this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); // react to model mode changes + this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); // react to file decoration changes } private onModelModeChanged(e: { model: IModel; oldModeId: string; }): void { @@ -84,6 +91,18 @@ export class ResourceLabel extends IconLabel { } } + private onFileDecorationsChanges(e: IResourceDecorationChangeEvent): void { + if (!this.options || !this.label || !this.label.resource) { + return; + } + if (!this.options.showAllDecorations && !this.options.showDecorations) { + return; + } + if (e.affectsResource(this.label.resource)) { + this.render(false); + } + } + public setLabel(label: IResourceLabel, options?: IResourceLabelOptions): void { const hasResourceChanged = this.hasResourceChanged(label, options); @@ -159,6 +178,19 @@ export class ResourceLabel extends IconLabel { extraClasses.push(...this.options.extraClasses); } + let deco: IResourceDecoration; + if (this.options) { + if (this.options.showDecorations) { + deco = this.decorationsService.getTopDecoration(resource, false); + } else if (this.options.showAllDecorations) { + deco = this.decorationsService.getTopDecoration(resource, true); + } + } + + // set/unset color from decoration + const color = deco && this.themeService.getTheme().getColor(deco.color, true); + this.element.style.color = color ? color.toString() : ''; + const italic = this.options && this.options.italic; const matches = this.options && this.options.matches; @@ -204,9 +236,11 @@ export class FileLabel extends ResourceLabel { @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IEnvironmentService environmentService: IEnvironmentService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService + @IResourceDecorationsService decorationsService: IResourceDecorationsService, + @IThemeService themeService: IThemeService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, ) { - super(container, options, extensionService, contextService, configurationService, modeService, modelService, environmentService); + super(container, options, extensionService, contextService, configurationService, modeService, modelService, environmentService, decorationsService, themeService); } public setFile(resource: uri, options?: IFileLabelOptions): void { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 0a894a8df22..f6bdc8d057f 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -97,9 +97,9 @@ import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviou import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; +import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { IResourceDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import URI from 'vs/base/common/uri'; -import { FileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorationsService'; -import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); @@ -586,7 +586,7 @@ export class Workbench implements IPartService { serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService)); // File Decorations - serviceCollection.set(IFileDecorationsService, new SyncDescriptor(FileDecorationsService)); + serviceCollection.set(IResourceDecorationsService, new SyncDescriptor(FileDecorationsService)); // SCM Service serviceCollection.set(ISCMService, new SyncDescriptor(SCMService)); diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 20fc00c0ff2..eb9f3dbdc9b 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -45,7 +45,6 @@ import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/th import { isLinux } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { attachListStyler } from 'vs/platform/theme/common/styler'; -import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; export interface IExplorerViewOptions extends IViewletViewOptions { viewletState: FileViewletState; @@ -99,8 +98,7 @@ export class ExplorerView extends ViewsViewletPanel { @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService, @IWorkbenchThemeService private themeService: IWorkbenchThemeService, - @IEnvironmentService private environmentService: IEnvironmentService, - @IFileDecorationsService private fileDecorationsService: IFileDecorationsService + @IEnvironmentService private environmentService: IEnvironmentService ) { super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService); @@ -168,7 +166,6 @@ export class ExplorerView extends ViewsViewletPanel { this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(e => this.refreshFromEvent(e.added))); this.disposables.push(this.contextService.onDidChangeWorkbenchState(e => this.refreshFromEvent())); - this.disposables.push(this.fileDecorationsService.onDidChangeFileDecoration(this.onDidChangeFileDecorations, this)); onFileIconThemeChange(this.themeService.getFileIconTheme()); } @@ -684,19 +681,6 @@ export class ExplorerView extends ViewsViewletPanel { })); } - private onDidChangeFileDecorations(uris: URI[]): void { - let seen = new Set(); - let stack = uris.map(uri => this.model.findClosest(uri)); - while (stack.length > 0) { - let stat = stack.shift(); - if (stat && !seen.has(stat)) { - this.explorerViewer.refresh(stat, false); - stack.push(stat.parent); - seen.add(stat); - } - } - } - private refreshFromEvent(newRoots: IWorkspaceFolder[] = []): void { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 25f102e95c1..f9e8fd1a030 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -58,7 +58,8 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; + export class FileDataSource implements IDataSource { constructor( @@ -291,8 +292,7 @@ export class FileRenderer implements IRenderer { state: FileViewletState, @IContextViewService private contextViewService: IContextViewService, @IInstantiationService private instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService, - @IFileDecorationsService private decorationsService: IFileDecorationsService + @IThemeService private themeService: IThemeService ) { this.state = state; } @@ -325,12 +325,13 @@ export class FileRenderer implements IRenderer { if (!stat.exists && stat.isRoot) { extraClasses.push('nonexistent-root'); } - templateData.label.setFile(stat.resource, { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses }); - - let top = this.decorationsService.getTopDecoration(stat.resource, stat.isDirectory); - templateData.label.element.style.color = top - ? this.themeService.getTheme().getColor(top.color, true).toString() - : ''; + templateData.label.setFile(stat.resource, { + hidePath: true, + fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, + extraClasses, + showAllDecorations: stat.isDirectory, + showDecorations: !stat.isDirectory + }); } // Input Box diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 558a0814392..7ee0b096fb4 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; -import { IFileDecorationsService, DecorationType, IFileDecorationData } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IResourceDecorationsService, DecorationType, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import { localize } from 'vs/nls'; @@ -25,7 +25,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { constructor( @IMarkerService private _markerService: IMarkerService, - @IFileDecorationsService private _decorationsService: IFileDecorationsService, + @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, @IConfigurationService private _configurationService: IConfigurationService ) { // @@ -62,11 +62,11 @@ class MarkersFileDecorations implements IWorkbenchContribution { .sort((a, b) => Severity.compare(a.severity, b.severity)); const data = !isFalsyOrEmpty(markers) ? this._toFileDecorationData(markers[0]) : undefined; - this._decorationsService.setFileDecoration(this._type, resource, data); + this._decorationsService.setDecoration(this._type, resource, data); } } - private _toFileDecorationData(marker: IMarker): IFileDecorationData { + private _toFileDecorationData(marker: IMarker): IResourceDecorationData { const { severity } = marker; const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; return { severity, color }; diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 0e228dc6208..c783b9b4c4d 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -6,7 +6,7 @@ 'use strict'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IFileDecorationsService } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IResourceDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; @@ -18,7 +18,7 @@ export class FileDecorations implements IWorkbenchContribution { private readonly _repositoryListeners = new Map(); constructor( - @IFileDecorationsService private _decorationsService: IFileDecorationsService, + @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, @ISCMService private _scmService: ISCMService, ) { this._scmService.repositories.forEach(this._onDidAddRepository, this); @@ -47,7 +47,7 @@ export class FileDecorations implements IWorkbenchContribution { continue; } - this._decorationsService.setFileDecoration(type, resource.sourceUri, { + this._decorationsService.setDecoration(type, resource.sourceUri, { severity: Severity.Info, color: resource.decorations.color, icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } @@ -58,7 +58,7 @@ export class FileDecorations implements IWorkbenchContribution { oldDecorations.forEach((value, key) => { if (!newDecorations.has(key)) { - this._decorationsService.setFileDecoration(type, value); + this._decorationsService.setDecoration(type, value); } }); diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts similarity index 60% rename from src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts rename to src/vs/workbench/services/decorations/browser/decorations.ts index 0f89b41c00f..af56f65ac86 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -10,7 +10,7 @@ import Event from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; -export const IFileDecorationsService = createDecorator('IFileDecorationsService'); +export const IResourceDecorationsService = createDecorator('IFileDecorationsService'); export abstract class DecorationType { readonly label: string; @@ -22,27 +22,31 @@ export abstract class DecorationType { } } - -export interface IFileDecoration extends IFileDecorationData { +export interface IResourceDecoration extends IResourceDecorationData { readonly type: DecorationType; } -export interface IFileDecorationData { + +export interface IResourceDecorationData { readonly severity: Severity; readonly color?: ColorIdentifier; readonly icon?: URI | { dark: URI, light: URI }; } -export interface IFileDecorationsService { +export interface IResourceDecorationChangeEvent { + affectsResource(uri: URI): boolean; +} + +export interface IResourceDecorationsService { readonly _serviceBrand: any; - readonly onDidChangeFileDecoration: Event; + readonly onDidChangeDecorations: Event; registerDecorationType(label: string): DecorationType; - setFileDecoration(type: DecorationType, target: URI, data?: IFileDecorationData): void; + setDecoration(type: DecorationType, target: URI, data?: IResourceDecorationData): void; - getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[]; + getDecorations(uri: URI, includeChildren: boolean): IResourceDecoration[]; - getTopDecoration(uri: URI, includeChildren: boolean): IFileDecoration; + getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration; } diff --git a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts similarity index 61% rename from src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts rename to src/vs/workbench/services/decorations/browser/decorationsService.ts index 39bb9c6de2a..1d266431590 100644 --- a/src/vs/workbench/services/fileDecorations/browser/fileDecorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,25 +7,36 @@ import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; -import { IFileDecorationsService, IFileDecoration, DecorationType, IFileDecorationData } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IResourceDecorationsService, IResourceDecoration, DecorationType, IResourceDecorationData, IResourceDecorationChangeEvent } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; import { TernarySearchTree } from 'vs/base/common/map'; -export class FileDecorationsService implements IFileDecorationsService { +class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { + + private readonly _data = TernarySearchTree.forPaths(); + + affectsResource(uri: URI): boolean { + return this._data.get(uri.toString()) || this._data.findSuperstr(uri.toString()) !== undefined; + } + + static debouncer(last: FileDecorationChangeEvent, current: URI) { + if (!last) { + last = new FileDecorationChangeEvent(); + } + last._data.set(current.toString(), true); + return last; + } +} + +export class FileDecorationsService implements IResourceDecorationsService { readonly _serviceBrand; private readonly _onDidChangeFileDecoration = new Emitter(); - private readonly _types = new Map>(); + private readonly _types = new Map>(); - readonly onDidChangeFileDecoration: Event = debounceEvent( + readonly onDidChangeDecorations: Event = debounceEvent( this._onDidChangeFileDecoration.event, - (last, current) => { - if (!last) { - last = []; - } - last.push(current); - return last; - } + FileDecorationChangeEvent.debouncer ); registerDecorationType(label: string): DecorationType { @@ -42,11 +53,11 @@ export class FileDecorationsService implements IFileDecorationsService { } } }; - this._types.set(type, TernarySearchTree.forPaths()); + this._types.set(type, TernarySearchTree.forPaths()); return type; } - setFileDecoration(type: DecorationType, target: URI, data?: IFileDecorationData): void { + setDecoration(type: DecorationType, target: URI, data?: IResourceDecorationData): void { if (data) { this._types.get(type).set(target.toString(), { type, ...data }); } else { @@ -55,8 +66,8 @@ export class FileDecorationsService implements IFileDecorationsService { this._onDidChangeFileDecoration.fire(target); } - getDecorations(uri: URI, includeChildren: boolean): IFileDecoration[] { - let ret: IFileDecoration[] = []; + getDecorations(uri: URI, includeChildren: boolean): IResourceDecoration[] { + let ret: IResourceDecoration[] = []; this._someFileDecoration(uri, includeChildren, decoration => { ret.push(decoration); return false; @@ -64,8 +75,8 @@ export class FileDecorationsService implements IFileDecorationsService { return ret; } - getTopDecoration(uri: URI, includeChildren: boolean): IFileDecoration { - let top: IFileDecoration; + getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { + let top: IResourceDecoration; this._someFileDecoration(uri, includeChildren, decoration => { // top is the most severe one, // stop as soon as an error is found @@ -77,7 +88,7 @@ export class FileDecorationsService implements IFileDecorationsService { return top; } - private _someFileDecoration(uri: URI, includeChildren: boolean, callback: (a: IFileDecoration) => boolean): void { + private _someFileDecoration(uri: URI, includeChildren: boolean, callback: (a: IResourceDecoration) => boolean): void { let key = uri.toString(); let done = false; this._types.forEach(tree => { @@ -96,7 +107,7 @@ export class FileDecorationsService implements IFileDecorationsService { }); } - private static _compareFileDecorationsBySeverity(a: IFileDecoration, b: IFileDecoration): number { + private static _compareFileDecorationsBySeverity(a: IResourceDecoration, b: IResourceDecoration): number { return Severity.compare(a.severity, b.severity); } } From 9a8bdad947e10540e783969d8a3270b6b100e490 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 19:36:51 +0200 Subject: [PATCH 053/303] missing labels change --- src/vs/workbench/browser/labels.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 2797fec3411..b2b17617109 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -69,6 +69,7 @@ export class ResourceLabel extends IconLabel { this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); // react to model mode changes this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); // react to file decoration changes + this.toDispose.push(this.themeService.onThemeChange(() => this.render(false))); } private onModelModeChanged(e: { model: IModel; oldModeId: string; }): void { From 46e48b345055c491b09aa77a94eaedeb62650b90 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Oct 2017 19:45:39 +0200 Subject: [PATCH 054/303] yet another missing change... --- .../services/decorations/browser/decorationsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 1d266431590..456c8f5cf40 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; -import { IResourceDecorationsService, IResourceDecoration, DecorationType, IResourceDecorationData, IResourceDecorationChangeEvent } from 'vs/workbench/services/fileDecorations/browser/fileDecorations'; +import { IResourceDecorationsService, IResourceDecoration, DecorationType, IResourceDecorationData, IResourceDecorationChangeEvent } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { From 3cd39eeb2a0e762c02b3b9b4a8414e7f6f1112f2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 10:54:50 +0200 Subject: [PATCH 055/303] use a provider-style api for resource/file decorations --- src/vs/base/common/async.ts | 2 +- .../markers/browser/markersFileDecorations.ts | 61 +++--- .../electron-browser/scmFileDecorations.ts | 116 +++++++----- .../decorations/browser/decorations.ts | 29 +-- .../decorations/browser/decorationsService.ts | 177 +++++++++++------- 5 files changed, 221 insertions(+), 164 deletions(-) diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 983ca30b520..e2120526002 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -13,7 +13,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; -function isThenable(obj: any): obj is Thenable { +export function isThenable(obj: any): obj is Thenable { return obj && typeof (>obj).then === 'function'; } diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 7ee0b096fb4..2a9a05a17a2 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -7,9 +7,10 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; -import { IResourceDecorationsService, DecorationType, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; import { localize } from 'vs/nls'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -17,11 +18,38 @@ import Severity from 'vs/base/common/severity'; import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +class MarkersDecorationsProvider implements IDecorationsProvider { + + readonly label: string = localize('label', "Problems"); + readonly onDidChange: Event; + + constructor( + private readonly _markerService: IMarkerService + ) { + this.onDidChange = _markerService.onMarkerChanged; + } + + provideDecorations(resource: URI): IResourceDecoration { + + const markers = this._markerService.read({ resource }) + .sort((a, b) => Severity.compare(a.severity, b.severity)); + + return !isFalsyOrEmpty(markers) + ? MarkersDecorationsProvider._toFileDecorationData(markers[0]) + : undefined; + } + + private static _toFileDecorationData(marker: IMarker): IResourceDecoration { + const { severity } = marker; + const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; + return { severity, color }; + } +} + class MarkersFileDecorations implements IWorkbenchContribution { private readonly _disposables: IDisposable[]; - private readonly _type: DecorationType; - private _markerListener: IDisposable; + private _provider: IDisposable; constructor( @IMarkerService private _markerService: IMarkerService, @@ -31,14 +59,13 @@ class MarkersFileDecorations implements IWorkbenchContribution { // this._disposables = [ this._configurationService.onDidUpdateConfiguration(this._updateEnablement, this), - this._type = this._decorationsService.registerDecorationType(localize('errorAndWarnings', "Errors & Warnings")) ]; this._updateEnablement(); } dispose(): void { - dispose(this._markerListener); + dispose(this._provider); dispose(this._disposables); } @@ -49,28 +76,12 @@ class MarkersFileDecorations implements IWorkbenchContribution { private _updateEnablement(): void { let value = this._configurationService.getConfiguration<{ showOnFiles: boolean }>('problems'); if (value) { - this._markerListener = this._markerService.onMarkerChanged(this._onDidChangeMarker, this); - this._onDidChangeMarker(this._markerService.read().map(marker => marker.resource)); - } else if (this._markerListener) { - this._markerListener.dispose(); + const provider = new MarkersDecorationsProvider(this._markerService); + this._provider = this._decorationsService.registerDecortionsProvider(provider); + } else if (this._provider) { + this._provider.dispose(); } } - - private _onDidChangeMarker(resources: URI[]): void { - for (const resource of resources) { - const markers = this._markerService.read({ resource }) - .sort((a, b) => Severity.compare(a.severity, b.severity)); - - const data = !isFalsyOrEmpty(markers) ? this._toFileDecorationData(markers[0]) : undefined; - this._decorationsService.setDecoration(this._type, resource, data); - } - } - - private _toFileDecorationData(marker: IMarker): IResourceDecorationData { - const { severity } = marker; - const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; - return { severity, color }; - } } Registry.as(Extensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index c783b9b4c4d..03aacefc190 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -6,16 +6,69 @@ 'use strict'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IResourceDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; +import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; +import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; +import Event, { Emitter } from 'vs/base/common/event'; + +class SCMDecorationsProvider implements IDecorationsProvider { + + private readonly _disposable: IDisposable; + private readonly _onDidChange = new Emitter(); + private _data = new Map(); + + readonly label: string; + readonly onDidChange: Event = this._onDidChange.event; + + constructor( + private readonly _provider: ISCMProvider + ) { + this.label = this._provider.label; + this._disposable = this._provider.onDidChangeResources(this._updateGroups, this); + this._updateGroups(); + } + + dispose(): void { + this._disposable.dispose(); + } + + private _updateGroups(): void { + const uris: URI[] = []; + const newData = new Map(); + for (const group of this._provider.resources) { + for (const resource of group.resourceCollection.resources) { + const { sourceUri } = resource; + if (this._data.get(sourceUri.toString()) !== resource) { + newData.set(sourceUri.toString(), resource); + uris.push(sourceUri); + this._data.delete(sourceUri.toString()); + } + } + } + this._data.forEach(value => uris.push(value.sourceUri)); + this._data = newData; + this._onDidChange.fire(uris); + } + + provideDecorations(uri: URI): IResourceDecoration { + const resource = this._data.get(uri.toString()); + if (!resource) { + return undefined; + } + return { + severity: Severity.Info, + color: resource.decorations.color, + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } + }; + } +} export class FileDecorations implements IWorkbenchContribution { private readonly _disposables: IDisposable[]; - private readonly _repositoryListeners = new Map(); + private readonly _providers = new Map(); constructor( @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, @@ -28,62 +81,25 @@ export class FileDecorations implements IWorkbenchContribution { ]; } + getId(): string { + throw new Error('smc.SCMFileDecorations'); + } + dispose(): void { dispose(this._disposables); } private _onDidAddRepository(repo: ISCMRepository): void { - const type = this._decorationsService.registerDecorationType(repo.provider.label); - const { provider } = repo; - - let oldDecorations = new Map(); - const listener = provider.onDidChangeResources(() => { - - let newDecorations = new Map(); - for (const group of provider.resources) { - - for (const resource of group.resourceCollection.resources) { - if (!resource.decorations.color) { - continue; - } - - this._decorationsService.setDecoration(type, resource.sourceUri, { - severity: Severity.Info, - color: resource.decorations.color, - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } - }); - newDecorations.set(resource.sourceUri.toString(), resource.sourceUri); - } - } - - oldDecorations.forEach((value, key) => { - if (!newDecorations.has(key)) { - this._decorationsService.setDecoration(type, value); - } - }); - - oldDecorations = newDecorations; - }); - - this._repositoryListeners.set(repo, { - dispose() { - listener.dispose(); - type.dispose(); - } - }); + const provider = new SCMDecorationsProvider(repo.provider); + const registration = this._decorationsService.registerDecortionsProvider(provider); + this._providers.set(repo, combinedDisposable([registration, provider])); } private _onDidRemoveRepository(repo: ISCMRepository): void { - let listener = this._repositoryListeners.get(repo); + let listener = this._providers.get(repo); if (listener) { - this._repositoryListeners.delete(repo); + this._providers.delete(repo); listener.dispose(); } } - - - getId(): string { - throw new Error('smc.SCMFileDecorations'); - } - } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index af56f65ac86..ab3e9718f03 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -9,29 +9,22 @@ import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; +import { IDisposable } from 'vs/base/common/lifecycle'; export const IResourceDecorationsService = createDecorator('IFileDecorationsService'); -export abstract class DecorationType { - readonly label: string; - protected constructor(label: string) { - this.label = label; - } - dispose(): void { - // - } -} - -export interface IResourceDecoration extends IResourceDecorationData { - readonly type: DecorationType; -} - -export interface IResourceDecorationData { +export interface IResourceDecoration { readonly severity: Severity; readonly color?: ColorIdentifier; readonly icon?: URI | { dark: URI, light: URI }; } +export interface IDecorationsProvider { + readonly label: string; + readonly onDidChange: Event; + provideDecorations(uri: URI): IResourceDecoration | Thenable; +} + export interface IResourceDecorationChangeEvent { affectsResource(uri: URI): boolean; } @@ -42,11 +35,7 @@ export interface IResourceDecorationsService { readonly onDidChangeDecorations: Event; - registerDecorationType(label: string): DecorationType; - - setDecoration(type: DecorationType, target: URI, data?: IResourceDecorationData): void; - - getDecorations(uri: URI, includeChildren: boolean): IResourceDecoration[]; + registerDecortionsProvider(provider: IDecorationsProvider): IDisposable; getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 456c8f5cf40..6fdc51d1749 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,8 +7,11 @@ import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; -import { IResourceDecorationsService, IResourceDecoration, DecorationType, IResourceDecorationData, IResourceDecorationChangeEvent } from './decorations'; +import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { isThenable } from 'vs/base/common/async'; +import { LinkedList } from 'vs/base/common/linkedList'; class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -18,96 +21,134 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { return this._data.get(uri.toString()) || this._data.findSuperstr(uri.toString()) !== undefined; } - static debouncer(last: FileDecorationChangeEvent, current: URI) { + static debouncer(last: FileDecorationChangeEvent, current: URI | URI[]) { if (!last) { last = new FileDecorationChangeEvent(); } - last._data.set(current.toString(), true); + if (Array.isArray(current)) { + // many + for (const uri of current) { + last._data.set(uri.toString(), true); + } + } else { + // one + last._data.set(current.toString(), true); + } + return last; } } +class DecorationProviderWrapper { + + private readonly _data = TernarySearchTree.forPaths | IResourceDecoration>(); + private readonly _dispoable: IDisposable; + + constructor( + private readonly _provider: IDecorationsProvider, + private readonly _emitter: Emitter + ) { + this._dispoable = this._provider.onDidChange(uris => { + for (const uri of uris) { + this._data.delete(uri.toString()); + this._fetchData(uri); + } + }); + } + + dispose(): void { + this._dispoable.dispose(); + this._data.clear(); + } + + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration) => void): void { + const key = uri.toString(); + const item = this._data.get(key); + + if (isThenable(item)) { + // pending -> still waiting + return; + } + + if (item === undefined && !includeChildren) { + // unknown, a leaf node -> trigger request + this._fetchData(uri); + return; + } + + if (item) { + // leaf node + callback(item); + } + if (includeChildren) { + // (resolved) children + const childTree = this._data.findSuperstr(key); + if (childTree) { + childTree.forEach(([, value]) => { + if (value && !isThenable(value)) { + callback(value); + } + }); + } + } + } + + private _fetchData(uri: URI) { + const request = Promise.resolve(this._provider.provideDecorations(uri)) + .then(data => { + this._data.set(uri.toString(), data || null); + this._emitter.fire(uri); + }) + .catch(_ => this._data.delete(uri.toString())); + + this._data.set(uri.toString(), request); + } +} + export class FileDecorationsService implements IResourceDecorationsService { - readonly _serviceBrand; + _serviceBrand: any; - private readonly _onDidChangeFileDecoration = new Emitter(); - private readonly _types = new Map>(); + private readonly _data = new LinkedList(); + private readonly _onDidChangeFileDecoration = new Emitter(); - readonly onDidChangeDecorations: Event = debounceEvent( + readonly onDidChangeDecorations: Event = debounceEvent( this._onDidChangeFileDecoration.event, FileDecorationChangeEvent.debouncer ); - registerDecorationType(label: string): DecorationType { - const outer = this; - const type = new class extends DecorationType { - constructor() { - super(label); - } - dispose() { - let tree = outer._types.get(type); - if (tree) { - tree.forEach(([key]) => outer._onDidChangeFileDecoration.fire(URI.parse(key))); - outer._types.delete(type); - } + registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { + + const wrapper = new DecorationProviderWrapper(provider, this._onDidChangeFileDecoration); + const remove = this._data.push(wrapper); + // fire for all + return { + dispose: () => { + wrapper.dispose(); + remove(); } }; - this._types.set(type, TernarySearchTree.forPaths()); - return type; - } - - setDecoration(type: DecorationType, target: URI, data?: IResourceDecorationData): void { - if (data) { - this._types.get(type).set(target.toString(), { type, ...data }); - } else { - this._types.get(type).delete(target.toString()); - } - this._onDidChangeFileDecoration.fire(target); - } - - getDecorations(uri: URI, includeChildren: boolean): IResourceDecoration[] { - let ret: IResourceDecoration[] = []; - this._someFileDecoration(uri, includeChildren, decoration => { - ret.push(decoration); - return false; - }); - return ret; } getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { let top: IResourceDecoration; - this._someFileDecoration(uri, includeChildren, decoration => { - // top is the most severe one, - // stop as soon as an error is found - if (!top || FileDecorationsService._compareFileDecorationsBySeverity(top, decoration) > 0) { - top = decoration; - } - return top !== undefined && top.severity === Severity.Error; - }); + for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { + next.value.getOrRetrieve(uri, includeChildren, candidate => { + top = FileDecorationsService._pickBest(top, candidate); + }); + } return top; } - private _someFileDecoration(uri: URI, includeChildren: boolean, callback: (a: IResourceDecoration) => boolean): void { - let key = uri.toString(); - let done = false; - this._types.forEach(tree => { - if (done) { - return; - } - if (includeChildren) { - let newTree = tree.findSuperstr(key); - if (newTree) { - newTree.forEach(([, deco]) => done = done || callback(deco)); - } - } else { - let deco = tree.get(key); - done = done || deco && callback(deco); - } - }); - } - - private static _compareFileDecorationsBySeverity(a: IResourceDecoration, b: IResourceDecoration): number { - return Severity.compare(a.severity, b.severity); + private static _pickBest(a: IResourceDecoration, b: IResourceDecoration): IResourceDecoration { + if (!a) { + return b; + } else if (!b) { + return a; + } else if (Severity.compare(a.severity, b.severity) < 0) { + return a; + } else { + return b; + } } } From 7921c1fe491af7bdddf849a6f92395b4769a0a8a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 13:55:27 +0200 Subject: [PATCH 056/303] add setting for scm, handle de-registration --- .../markers/browser/markersFileDecorations.ts | 4 +-- .../browser/markersWorkbenchContributions.ts | 4 +-- .../scm/electron-browser/scm.contribution.ts | 15 +++++++++ .../electron-browser/scmFileDecorations.ts | 33 ++++++++++++++----- .../decorations/browser/decorationsService.ts | 26 ++++++++++----- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 2a9a05a17a2..c12f87e110f 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -74,8 +74,8 @@ class MarkersFileDecorations implements IWorkbenchContribution { } private _updateEnablement(): void { - let value = this._configurationService.getConfiguration<{ showOnFiles: boolean }>('problems'); - if (value) { + let value = this._configurationService.getConfiguration<{ fileDecorations: { enabled: boolean } }>('problems'); + if (value.fileDecorations.enabled) { const provider = new MarkersDecorationsProvider(this._markerService); this._provider = this._decorationsService.registerDecortionsProvider(provider); } else if (this._provider) { diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index 45e7ca37718..b3dbb714669 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -56,8 +56,8 @@ export function registerContributions(): void { 'order': 101, 'type': 'object', 'properties': { - 'problems.showOnFiles': { - 'description': localize('markers.showOnFile', "Show Errors & Warnings in the file explorer."), + 'problems.fileDecorations.enabled': { + 'description': localize('markers.showOnFile', "Show Errors & Warnings on files and folder."), 'type': 'boolean', 'default': true } diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 93da15cee69..9510db9af9e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -19,6 +19,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { StatusUpdater, StatusBarController } from './scmActivity'; import { FileDecorations } from './scmFileDecorations'; import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; class OpenSCMViewletAction extends ToggleViewletAction { @@ -64,3 +65,17 @@ Registry.as(WorkbenchActionExtensions.WorkbenchActions 'View: Show SCM', localize('view', "View") ); + + +Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'scm', + 'order': 101, + 'type': 'object', + 'properties': { + 'scm.fileDecorations.enabled': { + 'description': localize('scm.fileDecorations.enabled', "Show source control status on files and folders"), + 'type': 'boolean', + 'default': true + } + } +}); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 03aacefc190..332577c07a0 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -12,6 +12,7 @@ import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/work import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter } from 'vs/base/common/event'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; class SCMDecorationsProvider implements IDecorationsProvider { @@ -32,6 +33,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { dispose(): void { this._disposable.dispose(); + this._data.clear(); } private _updateGroups(): void { @@ -67,18 +69,17 @@ class SCMDecorationsProvider implements IDecorationsProvider { export class FileDecorations implements IWorkbenchContribution { - private readonly _disposables: IDisposable[]; - private readonly _providers = new Map(); + private _providers = new Map(); + private _configListener: IDisposable; + private _repoListeners: IDisposable[]; constructor( @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, + @IConfigurationService private _configurationService: IConfigurationService, @ISCMService private _scmService: ISCMService, ) { - this._scmService.repositories.forEach(this._onDidAddRepository, this); - this._disposables = [ - this._scmService.onDidAddRepository(this._onDidAddRepository, this), - this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this), - ]; + this._configListener = this._configurationService.onDidUpdateConfiguration(this._update, this); + this._update(); } getId(): string { @@ -86,7 +87,23 @@ export class FileDecorations implements IWorkbenchContribution { } dispose(): void { - dispose(this._disposables); + this._providers.forEach(value => dispose(value)); + dispose(this._repoListeners); + dispose(this._configListener, this._configListener); + } + + private _update(): void { + const value = this._configurationService.getConfiguration<{ fileDecorations: { enabled: boolean } }>('scm'); + if (value.fileDecorations.enabled) { + this._scmService.repositories.forEach(this._onDidAddRepository, this); + this._repoListeners = [ + this._scmService.onDidAddRepository(this._onDidAddRepository, this), + this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) + ]; + } else { + this._providers.forEach(value => dispose(value)); + this._repoListeners = dispose(this._repoListeners); + } } private _onDidAddRepository(repo: ISCMRepository): void { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 6fdc51d1749..99437905107 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; -import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; +import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -61,6 +61,10 @@ class DecorationProviderWrapper { this._data.clear(); } + knowsAbout(uri: URI): boolean { + return Boolean(this._data.get(uri.toString())) || Boolean(this._data.findSuperstr(uri.toString())); + } + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration) => void): void { const key = uri.toString(); const item = this._data.get(key); @@ -110,22 +114,28 @@ export class FileDecorationsService implements IResourceDecorationsService { _serviceBrand: any; private readonly _data = new LinkedList(); - private readonly _onDidChangeFileDecoration = new Emitter(); + private readonly _onDidChangeDecorationsDelayed = new Emitter(); + private readonly _onDidChangeDecorations = new Emitter(); - readonly onDidChangeDecorations: Event = debounceEvent( - this._onDidChangeFileDecoration.event, - FileDecorationChangeEvent.debouncer + readonly onDidChangeDecorations: Event = any( + this._onDidChangeDecorations.event, + debounceEvent( + this._onDidChangeDecorationsDelayed.event, + FileDecorationChangeEvent.debouncer + ) ); registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { - const wrapper = new DecorationProviderWrapper(provider, this._onDidChangeFileDecoration); + const wrapper = new DecorationProviderWrapper(provider, this._onDidChangeDecorationsDelayed); const remove = this._data.push(wrapper); - // fire for all return { dispose: () => { - wrapper.dispose(); + // fire event that says 'yes' for any resource + // known to this provider. then dispose and remove it. remove(); + this._onDidChangeDecorations.fire({ affectsResource: uri => wrapper.knowsAbout(uri) }); + wrapper.dispose(); } }; } From 9e5bd5fbefa759f4c49a6400b60fffccfc297d12 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 14:08:52 +0200 Subject: [PATCH 057/303] add tooltip, prefix, and suffix text --- .../markers/browser/markersFileDecorations.ts | 19 ++++++++++--------- .../electron-browser/scmFileDecorations.ts | 1 + .../decorations/browser/decorations.ts | 3 +++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index c12f87e110f..e5bf939370a 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -6,7 +6,7 @@ 'use strict'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; -import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; +import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; @@ -34,15 +34,16 @@ class MarkersDecorationsProvider implements IDecorationsProvider { const markers = this._markerService.read({ resource }) .sort((a, b) => Severity.compare(a.severity, b.severity)); - return !isFalsyOrEmpty(markers) - ? MarkersDecorationsProvider._toFileDecorationData(markers[0]) - : undefined; - } + if (isFalsyOrEmpty(markers)) { + return undefined; + } - private static _toFileDecorationData(marker: IMarker): IResourceDecoration { - const { severity } = marker; - const color = severity === Severity.Error ? editorErrorForeground : editorWarningForeground; - return { severity, color }; + const [first] = markers; + return { + severity: first.severity, + tooltip: markers.length > 1 ? localize('tooltip', "{0} and {1} more problems", first.message, markers.length) : first.message, + color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground + }; } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 332577c07a0..c03b44feef8 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -62,6 +62,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, color: resource.decorations.color, + tooltip: resource.decorations.tooltip, icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } }; } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index ab3e9718f03..26a494a4ec6 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -15,6 +15,9 @@ export const IResourceDecorationsService = createDecorator Date: Mon, 9 Oct 2017 14:35:21 +0200 Subject: [PATCH 058/303] tweak label --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 6 ++++- src/vs/workbench/browser/labels.ts | 26 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index fb83ca1d3b1..f41e16128e8 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -13,6 +13,7 @@ import uri from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import { IWorkspaceFolderProvider, getPathLabel, IUserHomeProvider } from 'vs/base/common/labels'; import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { Color } from 'vs/base/common/color'; export interface IIconLabelCreationOptions { supportHighlights?: boolean; @@ -22,6 +23,7 @@ export interface IIconLabelOptions { title?: string; extraClasses?: string[]; italic?: boolean; + color?: Color; matches?: IMatch[]; } @@ -127,6 +129,8 @@ export class IconLabel { if (options.italic) { classes.push('italic'); } + + this.element.style.color = options.color ? options.color.toString() : ''; } this.domNode.className = classes.join(' '); @@ -163,4 +167,4 @@ export class FileLabel extends IconLabel { this.setValue(paths.basename(file.fsPath), parent && parent !== '.' ? getPathLabel(parent, provider, userHome) : '', { title: file.fsPath }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index b2b17617109..3175fa3ad8f 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -25,6 +25,7 @@ import { Schemas } from 'vs/base/common/network'; import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { Color } from 'vs/base/common/color'; export interface IResourceLabel { name: string; @@ -179,23 +180,30 @@ export class ResourceLabel extends IconLabel { extraClasses.push(...this.options.extraClasses); } - let deco: IResourceDecoration; + const italic = this.options && this.options.italic; + const matches = this.options && this.options.matches; + + let color: Color; if (this.options) { + let deco: IResourceDecoration; if (this.options.showDecorations) { deco = this.decorationsService.getTopDecoration(resource, false); } else if (this.options.showAllDecorations) { deco = this.decorationsService.getTopDecoration(resource, true); } + + if (deco) { + color = this.themeService.getTheme().getColor(deco.color); + } } - // set/unset color from decoration - const color = deco && this.themeService.getTheme().getColor(deco.color, true); - this.element.style.color = color ? color.toString() : ''; - - const italic = this.options && this.options.italic; - const matches = this.options && this.options.matches; - - this.setValue(this.label.name, this.label.description, { title, extraClasses, italic, matches }); + this.setValue(this.label.name, this.label.description, { + title, + extraClasses, + italic, + matches, + color + }); } public dispose(): void { From 73164106d581048e293701bdf6585f49f28fb5dd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 14:59:39 +0200 Subject: [PATCH 059/303] simplify git decorations... --- extensions/git/package.json | 22 ++---------- extensions/git/src/repository.ts | 5 +-- .../electron-browser/scmFileDecorations.ts | 36 ++++++++----------- 3 files changed, 18 insertions(+), 45 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index c8408252664..8eeaeb7cace 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -806,31 +806,13 @@ }, "colors": [ { - "id": "git.color.untracked", - "description": "Color for untracked resources", + "id": "git.color.modified", + "description": "Color for modified resources", "defaults": { "light": "#b47d16", "dark": "#cf9425", "highContrast": "#cf9425" } - }, - { - "id": "git.color.modified", - "description": "Color for modified resources", - "defaults": { - "light": "#007acc", - "dark": "#007acc", - "highContrast": "#007acc" - } - }, - { - "id": "git.color.ignored", - "description": "Color for ignored resources", - "defaults": { - "light": "#00000033", - "dark": "#ffffff33", - "highContrast": "#ffffff33" - } } ] }, diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 465c9211f70..efc10d9a6fc 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -174,11 +174,8 @@ export class Resource implements SourceControlResourceState { switch (this.type) { case Status.INDEX_MODIFIED: case Status.MODIFIED: - return new ThemeColor('git.color.modified'); case Status.UNTRACKED: - return new ThemeColor('git.color.untracked'); - case Status.IGNORED: - return new ThemeColor('git.color.ignored'); + return new ThemeColor('git.color.modified'); default: return undefined; } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index c03b44feef8..fae8074a41f 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -8,17 +8,17 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository, ISCMProvider } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { localize } from 'vs/nls'; class SCMDecorationsProvider implements IDecorationsProvider { private readonly _disposable: IDisposable; private readonly _onDidChange = new Emitter(); - private _data = new Map(); readonly label: string; readonly onDidChange: Event = this._onDidChange.event; @@ -33,38 +33,32 @@ class SCMDecorationsProvider implements IDecorationsProvider { dispose(): void { this._disposable.dispose(); - this._data.clear(); } private _updateGroups(): void { const uris: URI[] = []; - const newData = new Map(); for (const group of this._provider.resources) { for (const resource of group.resourceCollection.resources) { - const { sourceUri } = resource; - if (this._data.get(sourceUri.toString()) !== resource) { - newData.set(sourceUri.toString(), resource); - uris.push(sourceUri); - this._data.delete(sourceUri.toString()); - } + uris.push(resource.sourceUri); } } - this._data.forEach(value => uris.push(value.sourceUri)); - this._data = newData; this._onDidChange.fire(uris); } provideDecorations(uri: URI): IResourceDecoration { - const resource = this._data.get(uri.toString()); - if (!resource) { - return undefined; + for (const group of this._provider.resources) { + for (const resource of group.resourceCollection.resources) { + if (resource.sourceUri.toString() === uri.toString()) { + return { + severity: Severity.Info, + color: resource.decorations.color, + tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } + }; + } + } } - return { - severity: Severity.Info, - color: resource.decorations.color, - tooltip: resource.decorations.tooltip, - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } - }; + return undefined; } } From b63319d902135c712c60ddf1e62f829b2d26bb32 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 15:11:16 +0200 Subject: [PATCH 060/303] support suffix/prefix label --- src/vs/workbench/browser/labels.ts | 22 ++++++++++++++++++- .../electron-browser/scmFileDecorations.ts | 3 ++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 3175fa3ad8f..85900b17227 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -26,6 +26,7 @@ import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; +import { localize } from 'vs/nls'; export interface IResourceLabel { name: string; @@ -163,6 +164,7 @@ export class ResourceLabel extends IconLabel { } const resource = this.label.resource; + let label = this.label.name; let title = ''; if (this.options && typeof this.options.title === 'string') { @@ -194,10 +196,28 @@ export class ResourceLabel extends IconLabel { if (deco) { color = this.themeService.getTheme().getColor(deco.color); + + if (deco.tooltip) { + title = localize('deco.tooltip', "{0}, {1}", title, deco.tooltip); + } + + if (deco.prefix) { + label += deco.prefix; + if (matches) { + matches.forEach(match => { + match.start += deco.prefix.length; + match.end += deco.prefix.length; + }); + } + } + + if (deco.suffix) { + label += deco.suffix; + } } } - this.setValue(this.label.name, this.label.description, { + this.setValue(label, this.label.description, { title, extraClasses, italic, diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index fae8074a41f..a4f840ef2e6 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -52,7 +52,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, color: resource.decorations.color, - tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), + suffix: '*', + tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } }; } From 49ed34f8672422bbc5663dce01503950f7ef4635 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 15:14:38 +0200 Subject: [PATCH 061/303] support leafOnly option --- src/vs/workbench/services/decorations/browser/decorations.ts | 1 + .../services/decorations/browser/decorationsService.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 26a494a4ec6..f2e0aa4753c 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -20,6 +20,7 @@ export interface IResourceDecoration { readonly suffix?: string; readonly color?: ColorIdentifier; readonly icon?: URI | { dark: URI, light: URI }; + readonly leafOnly?: boolean; } export interface IDecorationsProvider { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 99437905107..771b353f193 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -89,7 +89,7 @@ class DecorationProviderWrapper { const childTree = this._data.findSuperstr(key); if (childTree) { childTree.forEach(([, value]) => { - if (value && !isThenable(value)) { + if (value && !isThenable(value) && !value.leafOnly) { callback(value); } }); From 88927c9bc5c6fc1888e50cc032ba1530952edef0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 15:41:44 +0200 Subject: [PATCH 062/303] have just 1 option --- src/vs/workbench/browser/labels.ts | 22 +++++++------------ .../files/browser/views/explorerViewer.ts | 3 +-- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 85900b17227..023e27283d1 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -20,7 +20,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; +import { IResourceDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; @@ -36,8 +36,7 @@ export interface IResourceLabel { export interface IResourceLabelOptions extends IIconLabelOptions { fileKind?: FileKind; - showDecorations?: boolean; - showAllDecorations?: boolean; + fileDecorations?: 'mine' | 'all'; } export class ResourceLabel extends IconLabel { @@ -98,10 +97,7 @@ export class ResourceLabel extends IconLabel { if (!this.options || !this.label || !this.label.resource) { return; } - if (!this.options.showAllDecorations && !this.options.showDecorations) { - return; - } - if (e.affectsResource(this.label.resource)) { + if (this.options.fileDecorations && e.affectsResource(this.label.resource)) { this.render(false); } } @@ -186,13 +182,11 @@ export class ResourceLabel extends IconLabel { const matches = this.options && this.options.matches; let color: Color; - if (this.options) { - let deco: IResourceDecoration; - if (this.options.showDecorations) { - deco = this.decorationsService.getTopDecoration(resource, false); - } else if (this.options.showAllDecorations) { - deco = this.decorationsService.getTopDecoration(resource, true); - } + if (this.options && this.options.fileDecorations) { + let deco = this.decorationsService.getTopDecoration( + resource, + this.options.fileDecorations === 'all' + ); if (deco) { color = this.themeService.getTheme().getColor(deco.color); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index f9e8fd1a030..7fd15a4cd5e 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -329,8 +329,7 @@ export class FileRenderer implements IRenderer { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, - showAllDecorations: stat.isDirectory, - showDecorations: !stat.isDirectory + fileDecorations: stat.isDirectory ? 'all' : 'mine' }); } From 9fa1a88b2f4c78061eccfe286bea41c2b4a358d9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 16:19:01 +0200 Subject: [PATCH 063/303] add explorer setting for file decorations --- src/vs/workbench/parts/files/browser/files.contribution.ts | 7 ++++++- .../workbench/parts/files/browser/views/explorerViewer.ts | 7 +++++-- src/vs/workbench/parts/files/common/files.ts | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 173b92b32bd..ecc17a60bdd 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -350,6 +350,11 @@ configurationRegistry.registerConfiguration({ nls.localize('sortOrder.modified', 'Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.') ], 'description': nls.localize({ key: 'sortOrder', comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'] }, "Controls sorting order of files and folders in the explorer. In addition to the default sorting, you can set the order to 'mixed' (files and folders sorted combined), 'type' (by file type), 'modified' (by last modified date) or 'filesFirst' (sort files before folders).") + }, + 'explorer.enableFileDecorations': { + type: 'boolean', + description: nls.localize('enableFileDecorations', "Controls if the explorer should show file decorations, like SCM status or problems."), + default: true } } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 7fd15a4cd5e..5073098d46c 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -292,7 +292,8 @@ export class FileRenderer implements IRenderer { state: FileViewletState, @IContextViewService private contextViewService: IContextViewService, @IInstantiationService private instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @IConfigurationService private configurationService: IConfigurationService ) { this.state = state; } @@ -329,7 +330,9 @@ export class FileRenderer implements IRenderer { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, - fileDecorations: stat.isDirectory ? 'all' : 'mine' + fileDecorations: this.configurationService.getConfiguration().explorer.enableFileDecorations + ? stat.isDirectory ? 'all' : 'mine' + : undefined }); } diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index f2a423c3ce9..150d33372a5 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -71,6 +71,7 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit enableDragAndDrop: boolean; confirmDelete: boolean; sortOrder: SortOrder; + enableFileDecorations: boolean; }; editor: IEditorOptions; } @@ -178,4 +179,4 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { public dispose(): void { this.fileWatcher = dispose(this.fileWatcher); } -} \ No newline at end of file +} From 380616a42c42873a837401fd42387a56a5ea5a8e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 16:27:38 +0200 Subject: [PATCH 064/303] keep scm data around --- .../electron-browser/scmFileDecorations.ts | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index a4f840ef2e6..5996767aa42 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -8,7 +8,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository, ISCMProvider } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter } from 'vs/base/common/event'; @@ -19,6 +19,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { private readonly _disposable: IDisposable; private readonly _onDidChange = new Emitter(); + private _data = new Map(); readonly label: string; readonly onDidChange: Event = this._onDidChange.event; @@ -37,29 +38,39 @@ class SCMDecorationsProvider implements IDecorationsProvider { private _updateGroups(): void { const uris: URI[] = []; + const newData = new Map(); for (const group of this._provider.resources) { for (const resource of group.resourceCollection.resources) { - uris.push(resource.sourceUri); + newData.set(resource.sourceUri.toString(), resource); + + if (!this._data.has(resource.sourceUri.toString())) { + uris.push(resource.sourceUri); // added + } } } + + this._data.forEach((value, key) => { + if (!newData.has(key)) { + uris.push(value.sourceUri); // removed + } + }); + + this._data = newData; this._onDidChange.fire(uris); } provideDecorations(uri: URI): IResourceDecoration { - for (const group of this._provider.resources) { - for (const resource of group.resourceCollection.resources) { - if (resource.sourceUri.toString() === uri.toString()) { - return { - severity: Severity.Info, - color: resource.decorations.color, - suffix: '*', - tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } - }; - } - } + const resource = this._data.get(uri.toString()); + if (!resource) { + return undefined; } - return undefined; + return { + severity: Severity.Info, + color: resource.decorations.color, + suffix: '*', + tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } + }; } } From 3c68560ed851fd04c336b552810b8fb10a6c4028 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 16:38:07 +0200 Subject: [PATCH 065/303] remove icons, use tick as suffix decoration --- .../parts/scm/electron-browser/scmFileDecorations.ts | 5 ++--- src/vs/workbench/services/decorations/browser/decorations.ts | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 5996767aa42..0aa8a1d962d 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -67,9 +67,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, color: resource.decorations.color, - suffix: '*', - tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } + suffix: '\'', + tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label) }; } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index f2e0aa4753c..df65b8429f7 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -19,7 +19,6 @@ export interface IResourceDecoration { readonly prefix?: string; readonly suffix?: string; readonly color?: ColorIdentifier; - readonly icon?: URI | { dark: URI, light: URI }; readonly leafOnly?: boolean; } From e73da33e4fa009a648c241cd3ac1b9b452d30ca5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Oct 2017 18:42:13 +0200 Subject: [PATCH 066/303] add back untracked color, remove suffix for now --- extensions/git/package.json | 9 +++++++++ extensions/git/src/repository.ts | 3 ++- .../parts/scm/electron-browser/scmFileDecorations.ts | 1 - 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 8eeaeb7cace..b10cfa73f31 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -813,6 +813,15 @@ "dark": "#cf9425", "highContrast": "#cf9425" } + }, + { + "id": "git.color.untracked", + "description": "Color for modified resources", + "defaults": { + "light": "#49805b", + "dark": "#73c990", + "highContrast": "#73c990" + } } ] }, diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index efc10d9a6fc..f4dab0e46e5 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -174,8 +174,9 @@ export class Resource implements SourceControlResourceState { switch (this.type) { case Status.INDEX_MODIFIED: case Status.MODIFIED: - case Status.UNTRACKED: return new ThemeColor('git.color.modified'); + case Status.UNTRACKED: + return new ThemeColor('git.color.untracked'); default: return undefined; } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 0aa8a1d962d..d963f462e7e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -67,7 +67,6 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, color: resource.decorations.color, - suffix: '\'', tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label) }; } From 02794bd86a2c464e6359c3e589b93556a0521ae0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 09:55:49 +0200 Subject: [PATCH 067/303] re-use scm icons --- src/vs/workbench/browser/labels.ts | 11 +++++++++++ .../parts/scm/electron-browser/scmFileDecorations.ts | 3 ++- .../services/decorations/browser/decorations.ts | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 023e27283d1..667b934b9c1 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -208,6 +208,17 @@ export class ResourceLabel extends IconLabel { if (deco.suffix) { label += deco.suffix; } + + if (deco.icon) { + const { type } = this.themeService.getTheme(); + const icon = type === 'light' ? deco.icon.light : deco.icon.dark; + + this.element.style.backgroundImage = `url(${icon.toString(true)})`; + this.element.style.backgroundRepeat = 'no-repeat'; + this.element.style.backgroundPosition = 'right center'; + this.element.style.paddingRight = '20px'; + this.element.style.marginRight = '14px'; + } } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index d963f462e7e..0f05f5dbc35 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -67,7 +67,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, color: resource.decorations.color, - tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label) + tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } }; } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index df65b8429f7..6c9cb6743a5 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -19,6 +19,7 @@ export interface IResourceDecoration { readonly prefix?: string; readonly suffix?: string; readonly color?: ColorIdentifier; + readonly icon?: { light: URI, dark: URI }; readonly leafOnly?: boolean; } From d8f20b58eb116d083d6c1d3f96b57a1f09005767 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 11:16:41 +0200 Subject: [PATCH 068/303] error/warning icons --- .../parts/markers/browser/markersFileDecorations.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index e5bf939370a..ab126fb6764 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -23,6 +23,9 @@ class MarkersDecorationsProvider implements IDecorationsProvider { readonly label: string = localize('label', "Problems"); readonly onDidChange: Event; + // private static _warningIcon = { light: URI.parse(require.toUrl('./media/status-warning.svg')), dark: URI.parse(require.toUrl('./media/status-warning-inverse.svg')) }; + // private static _errorIcon = { light: URI.parse(require.toUrl('./media/status-error.svg')), dark: URI.parse(require.toUrl('./media/status-error-inverse.svg')) }; + constructor( private readonly _markerService: IMarkerService ) { @@ -41,8 +44,9 @@ class MarkersDecorationsProvider implements IDecorationsProvider { const [first] = markers; return { severity: first.severity, - tooltip: markers.length > 1 ? localize('tooltip', "{0} and {1} more problems", first.message, markers.length) : first.message, - color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground + tooltip: localize('tooltip', "{0} problems in this file", markers.length), + color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, + // icon: first.severity === Severity.Error ? MarkersDecorationsProvider._errorIcon : MarkersDecorationsProvider._warningIcon }; } } From 7e2d9ee7b32b66e2192bddbc56f79ecad460bc3f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 13:05:04 +0200 Subject: [PATCH 069/303] have markerFileDecorations in one place --- .../markers/browser/markersFileDecorations.ts | 18 ++++++++++++++++-- .../browser/markersWorkbenchContributions.ts | 17 ----------------- .../parts/markers/markers.contribution.ts | 4 +++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index ab126fb6764..4f36dfed113 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -17,6 +17,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import Severity from 'vs/base/common/severity'; import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; class MarkersDecorationsProvider implements IDecorationsProvider { @@ -89,4 +90,17 @@ class MarkersFileDecorations implements IWorkbenchContribution { } } -Registry.as(Extensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations); + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + 'id': 'problems', + 'order': 101, + 'type': 'object', + 'properties': { + 'problems.fileDecorations.enabled': { + 'description': localize('markers.showOnFile', "Show Errors & Warnings on files and folder."), + 'type': 'boolean', + 'default': true + } + } +}); diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index b3dbb714669..39970c806b9 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -17,9 +17,6 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { MarkersPanel } from 'vs/workbench/parts/markers/browser/markersPanel'; -import './markersFileDecorations'; -import { localize } from 'vs/nls'; - export function registerContributions(): void { KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -51,20 +48,6 @@ export function registerContributions(): void { } }); - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'problems', - 'order': 101, - 'type': 'object', - 'properties': { - 'problems.fileDecorations.enabled': { - 'description': localize('markers.showOnFile', "Show Errors & Warnings on files and folder."), - 'type': 'boolean', - 'default': true - } - } - }); - - // markers panel Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( diff --git a/src/vs/workbench/parts/markers/markers.contribution.ts b/src/vs/workbench/parts/markers/markers.contribution.ts index 8e93a5abe41..b7b91dbc852 100644 --- a/src/vs/workbench/parts/markers/markers.contribution.ts +++ b/src/vs/workbench/parts/markers/markers.contribution.ts @@ -5,5 +5,7 @@ import { registerContributions } from 'vs/workbench/parts/markers/browser/markersWorkbenchContributions'; import { registerContributions as registerElectronContributions } from 'vs/workbench/parts/markers/electron-browser/markersElectronContributions'; +import './browser/markersFileDecorations'; + registerContributions(); -registerElectronContributions(); \ No newline at end of file +registerElectronContributions(); From 5c61e7cb860788d8ff377b4a7bbd680efc826959 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 14:52:05 +0200 Subject: [PATCH 070/303] disable markersFileDecorations for now --- src/vs/workbench/parts/markers/markers.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/markers/markers.contribution.ts b/src/vs/workbench/parts/markers/markers.contribution.ts index b7b91dbc852..4ab845211d8 100644 --- a/src/vs/workbench/parts/markers/markers.contribution.ts +++ b/src/vs/workbench/parts/markers/markers.contribution.ts @@ -5,7 +5,7 @@ import { registerContributions } from 'vs/workbench/parts/markers/browser/markersWorkbenchContributions'; import { registerContributions as registerElectronContributions } from 'vs/workbench/parts/markers/electron-browser/markersElectronContributions'; -import './browser/markersFileDecorations'; +// import './browser/markersFileDecorations'; registerContributions(); registerElectronContributions(); From 6796d4105a2d2ddde50cffa336a2a078b246cab8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:05:08 +0200 Subject: [PATCH 071/303] add useColors/useIcons settings --- .../scm/electron-browser/scm.contribution.ts | 10 ++++++++++ .../electron-browser/scmFileDecorations.ts | 19 ++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 9510db9af9e..16f6ce2631c 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -76,6 +76,16 @@ Registry.as(Extensions.Configuration).registerConfigurat 'description': localize('scm.fileDecorations.enabled', "Show source control status on files and folders"), 'type': 'boolean', 'default': true + }, + 'scm.fileDecorations.useIcons': { + 'description': localize('scm.fileDecorations.useIcons', "Use icons when showing source control status on files and folders"), + 'type': 'boolean', + 'default': true + }, + 'scm.fileDecorations.useColors': { + 'description': localize('scm.fileDecorations.useColors', "Use colors when showing source control status on files and folders"), + 'type': 'boolean', + 'default': true } } }); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 0f05f5dbc35..f3ffc823a07 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -25,7 +25,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { readonly onDidChange: Event = this._onDidChange.event; constructor( - private readonly _provider: ISCMProvider + private readonly _provider: ISCMProvider, + private readonly _config: ISCMConfiguration ) { this.label = this._provider.label; this._disposable = this._provider.onDidChangeResources(this._updateGroups, this); @@ -66,13 +67,21 @@ class SCMDecorationsProvider implements IDecorationsProvider { } return { severity: Severity.Info, - color: resource.decorations.color, tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark } + color: this._config.fileDecorations.useColors ? resource.decorations.color : undefined, + icon: this._config.fileDecorations.useIcons ? { light: resource.decorations.icon, dark: resource.decorations.iconDark } : undefined }; } } +interface ISCMConfiguration { + fileDecorations: { + enabled: boolean; + useIcons: boolean; + useColors: boolean; + }; +} + export class FileDecorations implements IWorkbenchContribution { private _providers = new Map(); @@ -99,7 +108,7 @@ export class FileDecorations implements IWorkbenchContribution { } private _update(): void { - const value = this._configurationService.getConfiguration<{ fileDecorations: { enabled: boolean } }>('scm'); + const value = this._configurationService.getConfiguration('scm'); if (value.fileDecorations.enabled) { this._scmService.repositories.forEach(this._onDidAddRepository, this); this._repoListeners = [ @@ -113,7 +122,7 @@ export class FileDecorations implements IWorkbenchContribution { } private _onDidAddRepository(repo: ISCMRepository): void { - const provider = new SCMDecorationsProvider(repo.provider); + const provider = new SCMDecorationsProvider(repo.provider, this._configurationService.getConfiguration('scm')); const registration = this._decorationsService.registerDecortionsProvider(provider); this._providers.set(repo, combinedDisposable([registration, provider])); } From 9159b691005ae10896fadfeb77033d009a1dab55 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:11:41 +0200 Subject: [PATCH 072/303] move extra icon into label --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 17 ++++++++++++++++- src/vs/workbench/browser/labels.ts | 14 ++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index f41e16128e8..80486cc1e34 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -23,8 +23,9 @@ export interface IIconLabelOptions { title?: string; extraClasses?: string[]; italic?: boolean; - color?: Color; matches?: IMatch[]; + color?: Color; + extraIcon?: uri; } class FastLabelNode { @@ -145,6 +146,20 @@ export class IconLabel { this.descriptionNode.textContent = description || ''; this.descriptionNode.empty = !description; + + if (options && options.extraIcon) { + this.element.style.backgroundImage = `url(${options.extraIcon.toString(true)})`; + this.element.style.backgroundRepeat = 'no-repeat'; + this.element.style.backgroundPosition = 'right center'; + this.element.style.paddingRight = '20px'; + this.element.style.marginRight = '14px'; + } else { + this.element.style.backgroundImage = ''; + this.element.style.backgroundRepeat = ''; + this.element.style.backgroundPosition = ''; + this.element.style.paddingRight = ''; + this.element.style.marginRight = ''; + } } public dispose(): void { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 667b934b9c1..58ed73d8fb1 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -181,7 +181,10 @@ export class ResourceLabel extends IconLabel { const italic = this.options && this.options.italic; const matches = this.options && this.options.matches; + + let color: Color; + let extraIcon: uri; if (this.options && this.options.fileDecorations) { let deco = this.decorationsService.getTopDecoration( resource, @@ -211,13 +214,7 @@ export class ResourceLabel extends IconLabel { if (deco.icon) { const { type } = this.themeService.getTheme(); - const icon = type === 'light' ? deco.icon.light : deco.icon.dark; - - this.element.style.backgroundImage = `url(${icon.toString(true)})`; - this.element.style.backgroundRepeat = 'no-repeat'; - this.element.style.backgroundPosition = 'right center'; - this.element.style.paddingRight = '20px'; - this.element.style.marginRight = '14px'; + extraIcon = type === 'light' ? deco.icon.light : deco.icon.dark; } } } @@ -227,7 +224,8 @@ export class ResourceLabel extends IconLabel { extraClasses, italic, matches, - color + color, + extraIcon }); } From 9c4052804d4691e101ee0a88517860bf8a2e79a7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:16:49 +0200 Subject: [PATCH 073/303] adjust git colors --- extensions/git/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index b10cfa73f31..490a7ea49d2 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -809,18 +809,18 @@ "id": "git.color.modified", "description": "Color for modified resources", "defaults": { - "light": "#b47d16", - "dark": "#cf9425", - "highContrast": "#cf9425" + "light": "#007BD0", + "dark": "#1B80B2", + "highContrast": "#1B80B2" } }, { "id": "git.color.untracked", "description": "Color for modified resources", "defaults": { - "light": "#49805b", - "dark": "#73c990", - "highContrast": "#73c990" + "light": "#6C6C6C", + "dark": "#6C6C6C", + "highContrast": "#6C6C6C" } } ] From 1b3011020b449b117b9f61b2b99802e72aeec3ce Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:43:01 +0200 Subject: [PATCH 074/303] sync/async results, add unit test --- .../decorations/browser/decorationsService.ts | 33 ++++++--- .../test/browser/decorationsService.test.ts | 74 +++++++++++++++++++ 2 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 771b353f193..6583632cb89 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -67,7 +67,7 @@ class DecorationProviderWrapper { getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration) => void): void { const key = uri.toString(); - const item = this._data.get(key); + let item = this._data.get(key); if (isThenable(item)) { // pending -> still waiting @@ -76,8 +76,7 @@ class DecorationProviderWrapper { if (item === undefined && !includeChildren) { // unknown, a leaf node -> trigger request - this._fetchData(uri); - return; + item = this._fetchData(uri); } if (item) { @@ -97,15 +96,27 @@ class DecorationProviderWrapper { } } - private _fetchData(uri: URI) { - const request = Promise.resolve(this._provider.provideDecorations(uri)) - .then(data => { - this._data.set(uri.toString(), data || null); - this._emitter.fire(uri); - }) - .catch(_ => this._data.delete(uri.toString())); + private _fetchData(uri: URI): IResourceDecoration { - this._data.set(uri.toString(), request); + const decoOrThenable = this._provider.provideDecorations(uri); + if (!isThenable(decoOrThenable)) { + // sync -> we have a result now + this._data.set(uri.toString(), decoOrThenable || null); + this._emitter.fire(uri); + return decoOrThenable; + + } else { + // async -> we have a result soon + const request = Promise.resolve(decoOrThenable) + .then(data => { + this._data.set(uri.toString(), data || null); + this._emitter.fire(uri); + }) + .catch(_ => this._data.delete(uri.toString())); + + this._data.set(uri.toString(), request); + return undefined; + } } } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts new file mode 100644 index 00000000000..ba79dc94d91 --- /dev/null +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; +import URI from 'vs/base/common/uri'; +import Event, { toPromise } from 'vs/base/common/event'; +import Severity from 'vs/base/common/severity'; + +suite('DecorationsService', function () { + + let service: FileDecorationsService; + + setup(function () { + service = new FileDecorationsService(); + }); + + test('Async provider, async/evented result', function () { + + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + service.registerDecortionsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return new Promise(resolve => { + setTimeout(() => resolve({ + severity: Severity.Info, + color: 'someBlue' + })); + }); + } + }); + + // trigger -> async + assert.equal(service.getTopDecoration(uri, false), undefined); + assert.equal(callCounter, 1); + + // event when result is computed + return toPromise(service.onDidChangeDecorations).then(e => { + assert.equal(e.affectsResource(uri), true); + + // sync result + assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.equal(callCounter, 1); + }); + }); + + test('Sync provider, sync result', function () { + + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + service.registerDecortionsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return { severity: Severity.Info, color: 'someBlue' }; + } + }); + + // trigger -> sync + assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.equal(callCounter, 1); + }); +}); From 3631852e9c94ff920fe550d9a64994a87c1d2a6d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:45:53 +0200 Subject: [PATCH 075/303] provider dispose test --- .../test/browser/decorationsService.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index ba79dc94d91..50cd8982814 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -71,4 +71,32 @@ suite('DecorationsService', function () { assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); assert.equal(callCounter, 1); }); + + test('Clear decorations on provider dispose', function () { + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + let reg = service.registerDecortionsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return { severity: Severity.Info, color: 'someBlue' }; + } + }); + + // trigger -> sync + assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.equal(callCounter, 1); + + const p = toPromise(service.onDidChangeDecorations); + + reg.dispose(); + + p.then(e => { + assert.equal(e.affectsResource(uri), true); + assert.deepEqual(service.getTopDecoration(uri, false), undefined); + assert.equal(callCounter, 1); + }); + }); }); From e013bf881f3c7f1c56594a726d5c68eb3c9abffa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 15:53:29 +0200 Subject: [PATCH 076/303] improve test --- .../test/browser/decorationsService.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 50cd8982814..5c6cf38d5db 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -89,14 +89,15 @@ suite('DecorationsService', function () { assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); assert.equal(callCounter, 1); - const p = toPromise(service.onDidChangeDecorations); - - reg.dispose(); - - p.then(e => { + // un-register -> ensure good event + let didSeeEvent = false; + service.onDidChangeDecorations(e => { assert.equal(e.affectsResource(uri), true); assert.deepEqual(service.getTopDecoration(uri, false), undefined); assert.equal(callCounter, 1); + didSeeEvent = true; }); + reg.dispose(); + assert.equal(didSeeEvent, true); }); }); From a34ee0c5aa91e0565f3adf84d5362c87b261b11b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 16:05:58 +0200 Subject: [PATCH 077/303] label tweak --- extensions/git/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 490a7ea49d2..58779e50bbc 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -816,7 +816,7 @@ }, { "id": "git.color.untracked", - "description": "Color for modified resources", + "description": "Color for untracked resources", "defaults": { "light": "#6C6C6C", "dark": "#6C6C6C", From e7799d19150ec2648a8b4bf4b5dc166846e81869 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 17:10:21 +0200 Subject: [PATCH 078/303] fix merge/rebase hickup --- src/vs/workbench/parts/files/browser/views/explorerViewer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 5073098d46c..a60d36d6116 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -58,8 +58,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; - export class FileDataSource implements IDataSource { constructor( From be10b09e63e86ea2f459627f746622c1c3d930a6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Oct 2017 17:47:17 +0200 Subject: [PATCH 079/303] better matchCompactness computation --- .../parts/quickopen/common/quickOpenScorer.ts | 42 ++++++++-------- .../test/common/quickOpenScorer.test.ts | 48 +++++++++++++++++++ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 750a6961ca1..1b12ae09842 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -16,17 +16,6 @@ export type ScorerCache = { [key: string]: IItemScore }; const NO_SCORE: Score = [0, []]; -/** - * Compute a score for the given string and the given query. - * - * Rules: - * Character score: 1 - * Same case bonus: 1 - * Upper case bonus: 1 - * Consecutive match bonus: 5 - * Start of word/path bonus: 7 - * Start of string bonus: 8 - */ export function _doScore(target: string, query: string, fuzzy: boolean): Score { if (!target || !query) { return NO_SCORE; // return early if target or query are undefined @@ -122,7 +111,7 @@ BEGIN THIRD PARTY * Date: Tue Mar 1 2011 * Updated: Tue Mar 10 2015 */ -export function _doScoreFromOffset(target: string, query: string, targetLower: string, queryLower: string, queryLen: number, offset: number): Score { +function _doScoreFromOffset(target: string, query: string, targetLower: string, queryLower: string, queryLen: number, offset: number): Score { const matchingPositions: number[] = []; let targetIndex = offset; @@ -357,14 +346,14 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: const scoreA = itemScoreA.score; const scoreB = itemScoreB.score; - // 1.) check for identity matches + // 1.) prefer identity matches if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) { if (scoreA !== scoreB) { return scoreA === PATH_IDENTITY_SCORE ? -1 : 1; } } - // 2.) check for label prefix matches + // 2.) prefer label prefix matches if (scoreA === LABEL_PREFIX_SCORE || scoreB === LABEL_PREFIX_SCORE) { if (scoreA !== scoreB) { return scoreA === LABEL_PREFIX_SCORE ? -1 : 1; @@ -379,7 +368,7 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: } } - // 3.) check for camelcase matches + // 3.) prefer camelcase matches if (scoreA === LABEL_CAMELCASE_SCORE || scoreB === LABEL_CAMELCASE_SCORE) { if (scoreA !== scoreB) { return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1; @@ -400,7 +389,7 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: } } - // 4.) check for label scores + // 4.) prefer label scores if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) { if (scoreB < LABEL_SCORE_THRESHOLD) { return -1; @@ -411,20 +400,27 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: } } - // 5.) check for path scores + // 5.) compare by score if (scoreA !== scoreB) { return scoreA > scoreB ? -1 : 1; } // 6.) scores are identical, prefer more compact matches (label and description) - const labelMatchCompactness = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch); - if (labelMatchCompactness !== 0) { - return labelMatchCompactness; + let itemAMatches: IMatch[] = []; + if (itemScoreA.descriptionMatch) { + itemAMatches.push(...itemScoreA.descriptionMatch); } + itemAMatches.push(...itemScoreA.labelMatch); - const descriptionMatchCompactness = compareByMatchLength(itemScoreA.descriptionMatch, itemScoreB.descriptionMatch); - if (descriptionMatchCompactness !== 0) { - return descriptionMatchCompactness; + let itemBMatches: IMatch[] = []; + if (itemScoreB.descriptionMatch) { + itemBMatches.push(...itemScoreB.descriptionMatch); + } + itemBMatches.push(...itemScoreB.labelMatch); + + const matchCompactness = compareByMatchLength(itemAMatches, itemBMatches); + if (matchCompactness !== 0) { + return matchCompactness; } // 7.) at this point, scores are identical and match compactness as well diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 2df8c19f1ac..8aedf7ce3ea 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -166,6 +166,15 @@ suite('Quick Open Scorer', () => { assert.ok(pathRes.score > noRes.score); }); + test('scoreItem - invalid input', function () { + + let res = scorer.scoreItem(null, null, true, ResourceAccessor, cache); + assert.equal(res.score, 0); + + res = scorer.scoreItem(null, 'null', true, ResourceAccessor, cache); + assert.equal(res.score, 0); + }); + test('scoreItem - optimize for file paths', function () { const resource = URI.file('/xyz/others/spath/some/xsp/file123.txt'); @@ -379,6 +388,25 @@ suite('Quick Open Scorer', () => { assert.equal(res[2], resourceC); }); + test('compareFilesByScore - prefer shorter basenames (match on basename)', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileBLonger.txt'); + const resourceC = URI.file('/unrelated/the/path/other/fileC.txt'); + + // Resource A part of path + let query = 'file'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + }); + test('compareFilesByScore - prefer shorter paths', function () { const resourceA = URI.file('/some/path/fileA.txt'); const resourceB = URI.file('/some/path/other/fileB.txt'); @@ -471,6 +499,21 @@ suite('Quick Open Scorer', () => { assert.equal(res[1], resourceA); }); + test('compareFilesByScore - prefer more compact matches (label and path)', function () { + const resourceA = URI.file('config/example/thisfile.ts'); + const resourceB = URI.file('config/24234243244/example/file.js'); + + let query = 'exfile'; + + let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + test('compareFilesByScore - avoid match scattering (bug #34210)', function () { const resourceA = URI.file('node_modules1/bundle/lib/model/modules/ot1/index.js'); const resourceB = URI.file('node_modules1/bundle/lib/model/modules/un1/index.js'); @@ -539,4 +582,9 @@ suite('Quick Open Scorer', () => { let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); + + test('massageSearchForScoring', function () { + assert.equal(scorer.massageSearchForScoring(' f*a '), 'fa'); + assert.equal(scorer.massageSearchForScoring('model tester.ts'), 'modeltester.ts'); + }); }); \ No newline at end of file From fd92bc6a3d22a4f839eb8e31ecec45f6cb72a278 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Oct 2017 18:09:31 +0200 Subject: [PATCH 080/303] fix scm.fileDecorations.enabled setting --- .../electron-browser/scmFileDecorations.ts | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index f3ffc823a07..021d06178e2 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -14,6 +14,7 @@ import Severity from 'vs/base/common/severity'; import Event, { Emitter } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; +import { equals } from 'vs/base/common/objects'; class SCMDecorationsProvider implements IDecorationsProvider { @@ -87,6 +88,7 @@ export class FileDecorations implements IWorkbenchContribution { private _providers = new Map(); private _configListener: IDisposable; private _repoListeners: IDisposable[]; + private _currentConfig: ISCMConfiguration; constructor( @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, @@ -108,16 +110,21 @@ export class FileDecorations implements IWorkbenchContribution { } private _update(): void { - const value = this._configurationService.getConfiguration('scm'); - if (value.fileDecorations.enabled) { - this._scmService.repositories.forEach(this._onDidAddRepository, this); - this._repoListeners = [ - this._scmService.onDidAddRepository(this._onDidAddRepository, this), - this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) - ]; - } else { - this._providers.forEach(value => dispose(value)); - this._repoListeners = dispose(this._repoListeners); + const config = this._configurationService.getConfiguration('scm'); + if (!equals(config, this._currentConfig)) { + this._currentConfig = config; + + if (this._currentConfig.fileDecorations.enabled) { + this._scmService.repositories.forEach(this._onDidAddRepository, this); + this._repoListeners = [ + this._scmService.onDidAddRepository(this._onDidAddRepository, this), + this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) + ]; + } else { + this._repoListeners = dispose(this._repoListeners); + this._providers.forEach(value => dispose(value)); + this._providers.clear(); + } } } From 06e1699b241a5f9ae15bdf8014a73a0c9da4a7cb Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 10 Oct 2017 18:13:20 +0200 Subject: [PATCH 081/303] debugStatus: only style icon if it is constructed --- src/vs/workbench/parts/debug/browser/debugStatus.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/debugStatus.ts b/src/vs/workbench/parts/debug/browser/debugStatus.ts index 821b34d783b..58ad52104db 100644 --- a/src/vs/workbench/parts/debug/browser/debugStatus.ts +++ b/src/vs/workbench/parts/debug/browser/debugStatus.ts @@ -43,7 +43,9 @@ export class DebugStatus extends Themable implements IStatusbarItem { protected updateStyles(): void { super.updateStyles(); - this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND); + if (this.icon) { + this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND); + } } public render(container: HTMLElement): IDisposable { From a91bad463a4a90409fd6012e4e31a63364cca44b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 10 Oct 2017 12:22:59 -0700 Subject: [PATCH 082/303] Only set LANG env var in term if setLocaleVariables is true Fixes #35550 --- .../parts/terminal/electron-browser/terminalInstance.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 4ba392d7be8..e00375c131d 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -780,7 +780,9 @@ export class TerminalInstance implements ITerminalInstance { } } env['PTYCWD'] = cwd; - env['LANG'] = TerminalInstance._getLangEnvVariable(locale); + if (locale) { + env['LANG'] = TerminalInstance._getLangEnvVariable(locale); + } if (cols && rows) { env['PTYCOLS'] = cols.toString(); env['PTYROWS'] = rows.toString(); From 63ecf01397911435229dcf47d6f9f84c74bdb44f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 10 Oct 2017 15:01:51 -0700 Subject: [PATCH 083/303] Use unique grammar and scope for JavaScript react to avoid conflicts when overriding plain old javascript grammar Fixes #35532 --- .../syntaxes/JavaScript.tmLanguage.json | 4 +- .../syntaxes/JavaScriptReact.tmLanguage.json | 4275 +++++++++++++++++ .../test/colorize-results/test_jsx.json | 436 +- .../typescript/build/update-grammars.js | 10 +- .../syntaxes/TypeScript.tmLanguage.json | 4 +- .../syntaxes/TypeScriptReact.tmLanguage.json | 4 +- 6 files changed, 4505 insertions(+), 228 deletions(-) create mode 100644 extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 990df29f8b3..466cb34a314 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d6ee336bf6047594768a56f955563ba5ce86e7c9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -3332,7 +3332,7 @@ "name": "punctuation.definition.group.regexp" }, "1": { - "name": "punctuation.definition.group.capture.regexp" + "name": "punctuation.definition.group.no-capture.regexp" } }, "end": "\\)", diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json new file mode 100644 index 00000000000..29aa8b6a2a2 --- /dev/null +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -0,0 +1,4275 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", + "name": "JavaScript (with React support)", + "scopeName": "source.js.jsx", + "fileTypes": [ + ".js", + ".jsx", + ".es6", + ".mjs" + ], + "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js.jsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.readwrite.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.js.jsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js.jsx", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "variable.parameter.js.jsx" + } + } + }, + { + "name": "meta.arrow.js.jsx", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js.jsx", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + }, + "1": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.js.jsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js.jsx", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.js.jsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.js.jsx", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js.jsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js.jsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js.jsx", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.js.jsx", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.js.jsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js.jsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.js.jsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js.jsx", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.js.jsx" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.js.jsx", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "support.constant.dom.js.jsx" + }, + "3": { + "name": "support.variable.property.dom.js.jsx" + } + } + }, + { + "name": "support.class.node.js.jsx", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.property.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.property.js.jsx" + } + } + }, + { + "name": "variable.other.constant.js.jsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.object.property.js.jsx" + }, + "3": { + "name": "variable.other.object.property.js.jsx" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js.jsx" + }, + "2": { + "name": "variable.other.object.js.jsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js.jsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js.jsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js.jsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.js.jsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js.jsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js.jsx", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "keyword.other.js.jsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js.jsx", + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.js.jsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js.jsx" + }, + "2": { + "name": "entity.name.tag.directive.js.jsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js.jsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js.jsx", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js.jsx" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js.jsx" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + }, + { + "include": "#jsx-tag-invalid" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js.jsx", + "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "contentName": "meta.jsx.children.tsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-child-tag": { + "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js.jsx", + "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(?=(/>)|(?:()))", + "patterns": [ + { + "begin": "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + } + }, + "end": "(?=[/]?>)", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attributes" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "end": "(?=" + }, + "jsx-children": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + }, + { + "include": "#jsx-child-tag" + }, + { + "include": "#jsx-tag-invalid" + }, + { + "include": "#jsx-evaluated-code" + }, + { + "include": "#jsx-entities" + } + ] + }, + "jsx-evaluated-code": { + "name": "meta.embedded.expression.js.jsx", + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "jsx-entities": { + "patterns": [ + { + "name": "constant.character.entity.js.jsx", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.js.jsx" + }, + "3": { + "name": "punctuation.definition.entity.js.jsx" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.js.jsx", + "match": "&" + } + ] + }, + "jsx-tag-attributes": { + "patterns": [ + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js.jsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js.jsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js.jsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js.jsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js.jsx", + "match": "\\S+" + } + } +} \ No newline at end of file diff --git a/extensions/javascript/test/colorize-results/test_jsx.json b/extensions/javascript/test/colorize-results/test_jsx.json index f12ab38729b..80d1d740615 100644 --- a/extensions/javascript/test/colorize-results/test_jsx.json +++ b/extensions/javascript/test/colorize-results/test_jsx.json @@ -1,7 +1,7 @@ [ { "c": "var", - "t": "source.js meta.var.expr.js storage.type.js", + "t": "source.js.jsx meta.var.expr.js.jsx storage.type.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -12,7 +12,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -23,7 +23,7 @@ }, { "c": "ToggleText", - "t": "source.js meta.var.expr.js meta.var-single-variable.expr.js meta.definition.variable.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx meta.definition.variable.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -34,7 +34,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.var-single-variable.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -45,7 +45,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -56,7 +56,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -67,7 +67,7 @@ }, { "c": "React", - "t": "source.js meta.var.expr.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -78,7 +78,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -89,7 +89,7 @@ }, { "c": "createClass", - "t": "source.js meta.var.expr.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -100,7 +100,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -111,7 +111,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -122,7 +122,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -133,7 +133,7 @@ }, { "c": "getInitialState", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -144,7 +144,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -155,7 +155,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -166,7 +166,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -177,7 +177,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -188,7 +188,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -199,7 +199,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -210,7 +210,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -221,7 +221,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -232,7 +232,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -243,7 +243,7 @@ }, { "c": "return", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.flow.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.flow.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -254,7 +254,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -265,7 +265,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -276,7 +276,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -287,7 +287,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -298,7 +298,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -309,7 +309,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -320,7 +320,7 @@ }, { "c": "true", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js constant.language.boolean.true.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx constant.language.boolean.true.js.jsx", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -331,7 +331,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -342,7 +342,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -353,7 +353,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -364,7 +364,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -375,7 +375,7 @@ }, { "c": ",", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.separator.comma.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -386,7 +386,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -397,7 +397,7 @@ }, { "c": "toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -408,7 +408,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -419,7 +419,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +430,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -441,7 +441,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -452,7 +452,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -463,7 +463,7 @@ }, { "c": "e", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js variable.parameter.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx variable.parameter.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -474,7 +474,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -485,7 +485,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -496,7 +496,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -507,7 +507,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -518,7 +518,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -529,7 +529,7 @@ }, { "c": " Prevent following the link.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.tsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -540,7 +540,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -551,7 +551,7 @@ }, { "c": "e", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -562,7 +562,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -573,7 +573,7 @@ }, { "c": "preventDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js support.function.dom.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx support.function.dom.js.jsx", "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", @@ -584,7 +584,7 @@ }, { "c": "()", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -595,7 +595,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -606,7 +606,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -617,7 +617,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -628,7 +628,7 @@ }, { "c": " Invert the chosen default.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.tsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -639,7 +639,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -650,7 +650,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -661,7 +661,7 @@ }, { "c": " This will trigger an intelligent re-render of the component.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.tsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -672,7 +672,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -683,7 +683,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -694,7 +694,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -705,7 +705,7 @@ }, { "c": "setState", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -716,7 +716,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -727,7 +727,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -738,7 +738,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -749,7 +749,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -760,7 +760,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -771,7 +771,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -782,7 +782,7 @@ }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js keyword.operator.logical.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx keyword.operator.logical.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -793,7 +793,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -804,7 +804,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -815,7 +815,7 @@ }, { "c": "state", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -826,7 +826,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -837,7 +837,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -848,7 +848,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -859,7 +859,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -870,7 +870,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -881,7 +881,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -892,7 +892,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -903,7 +903,7 @@ }, { "c": ",", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.separator.comma.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -914,7 +914,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -925,7 +925,7 @@ }, { "c": "render", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -936,7 +936,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -947,7 +947,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -958,7 +958,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -969,7 +969,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -980,7 +980,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -991,7 +991,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1002,7 +1002,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1013,7 +1013,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1024,7 +1024,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1035,7 +1035,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1046,7 +1046,7 @@ }, { "c": " Default to the default message.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.tsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1057,7 +1057,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1068,7 +1068,7 @@ }, { "c": "var", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js storage.type.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx storage.type.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1079,7 +1079,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1090,7 +1090,7 @@ }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js meta.var-single-variable.expr.js meta.definition.variable.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx meta.definition.variable.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1101,7 +1101,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js meta.var-single-variable.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1112,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1123,7 +1123,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1134,7 +1134,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1145,7 +1145,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1156,7 +1156,7 @@ }, { "c": "props", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1167,7 +1167,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1178,7 +1178,7 @@ }, { "c": "default", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1189,7 +1189,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1200,7 +1200,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1211,7 +1211,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1222,7 +1222,7 @@ }, { "c": " If toggled, show the alternate message.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.tsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1233,7 +1233,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1244,7 +1244,7 @@ }, { "c": "if", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.conditional.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.conditional.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1255,7 +1255,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1266,7 +1266,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1277,7 +1277,7 @@ }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.operator.logical.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.operator.logical.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1288,7 +1288,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1299,7 +1299,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1310,7 +1310,7 @@ }, { "c": "state", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1321,7 +1321,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1332,7 +1332,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1343,7 +1343,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1354,7 +1354,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1365,7 +1365,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1376,7 +1376,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1387,7 +1387,7 @@ }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1398,7 +1398,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1409,7 +1409,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1420,7 +1420,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1431,7 +1431,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1442,7 +1442,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1453,7 +1453,7 @@ }, { "c": "props", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1464,7 +1464,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1475,7 +1475,7 @@ }, { "c": "alt", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js support.variable.property.dom.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx support.variable.property.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -1486,7 +1486,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1497,7 +1497,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1508,7 +1508,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1519,7 +1519,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1530,7 +1530,7 @@ }, { "c": "return", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.flow.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.flow.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1541,7 +1541,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1552,7 +1552,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1563,7 +1563,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1574,7 +1574,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1585,7 +1585,7 @@ }, { "c": "div", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1596,7 +1596,7 @@ }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1607,7 +1607,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1618,7 +1618,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1629,7 +1629,7 @@ }, { "c": "h1", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1640,7 +1640,7 @@ }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1651,7 +1651,7 @@ }, { "c": "Hello ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1662,7 +1662,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js punctuation.section.embedded.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1673,7 +1673,7 @@ }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1684,7 +1684,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js punctuation.section.embedded.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1695,7 +1695,7 @@ }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1706,7 +1706,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1739,7 +1739,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1750,7 +1750,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1761,7 +1761,7 @@ }, { "c": "a", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1772,7 +1772,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1783,7 @@ }, { "c": "href", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1794,7 +1794,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1805,7 +1805,7 @@ }, { "c": "\"", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1816,7 +1816,7 @@ }, { "c": "\"", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1827,7 +1827,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1838,7 +1838,7 @@ }, { "c": "onClick", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1849,7 +1849,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1860,7 +1860,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.section.embedded.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1871,7 +1871,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1882,7 +1882,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "meta.embedded: #D4D4D4", "light_plus": "meta.embedded: #000000", @@ -1893,7 +1893,7 @@ }, { "c": "toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1904,7 +1904,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.section.embedded.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1915,7 +1915,7 @@ }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1926,7 +1926,7 @@ }, { "c": "Toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1937,7 +1937,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1970,7 +1970,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1981,7 +1981,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2014,7 +2014,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2025,7 +2025,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2036,7 +2036,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2047,7 +2047,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2058,7 +2058,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2069,7 +2069,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2080,7 +2080,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2091,7 +2091,7 @@ }, { "c": ";", - "t": "source.js punctuation.terminator.statement.js", + "t": "source.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2102,7 +2102,7 @@ }, { "c": "React", - "t": "source.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2113,7 +2113,7 @@ }, { "c": ".", - "t": "source.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2124,7 +2124,7 @@ }, { "c": "render", - "t": "source.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -2135,7 +2135,7 @@ }, { "c": "(", - "t": "source.js meta.brace.round.js", + "t": "source.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2146,7 +2146,7 @@ }, { "c": "<", - "t": "source.js meta.tag.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2157,7 +2157,7 @@ }, { "c": "ToggleText", - "t": "source.js meta.tag.js entity.name.tag.js support.class.component.js", + "t": "source.js.jsx meta.tag.js.jsx entity.name.tag.js.jsx support.class.component.js.jsx", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -2168,7 +2168,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2179,7 +2179,7 @@ }, { "c": "default", - "t": "source.js meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2190,7 +2190,7 @@ }, { "c": "=", - "t": "source.js meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2201,7 +2201,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2212,7 +2212,7 @@ }, { "c": "World", - "t": "source.js meta.tag.js string.quoted.double.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2223,7 +2223,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2234,7 +2234,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2245,7 +2245,7 @@ }, { "c": "alt", - "t": "source.js meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2256,7 +2256,7 @@ }, { "c": "=", - "t": "source.js meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2267,7 +2267,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2278,7 +2278,7 @@ }, { "c": "Mars", - "t": "source.js meta.tag.js string.quoted.double.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2289,7 +2289,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2300,7 +2300,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2311,7 +2311,7 @@ }, { "c": "/>", - "t": "source.js meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2322,7 +2322,7 @@ }, { "c": ",", - "t": "source.js punctuation.separator.comma.js", + "t": "source.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2333,7 +2333,7 @@ }, { "c": " ", - "t": "source.js", + "t": "source.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2344,7 +2344,7 @@ }, { "c": "document", - "t": "source.js support.variable.dom.js", + "t": "source.js.jsx support.variable.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -2355,7 +2355,7 @@ }, { "c": ".", - "t": "source.js punctuation.accessor.js", + "t": "source.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2366,7 +2366,7 @@ }, { "c": "body", - "t": "source.js support.variable.property.dom.js", + "t": "source.js.jsx support.variable.property.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -2377,7 +2377,7 @@ }, { "c": ")", - "t": "source.js meta.brace.round.js", + "t": "source.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2388,7 +2388,7 @@ }, { "c": ";", - "t": "source.js punctuation.terminator.statement.js", + "t": "source.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/typescript/build/update-grammars.js b/extensions/typescript/build/update-grammars.js index c38d6f10510..e82549b4eef 100644 --- a/extensions/typescript/build/update-grammars.js +++ b/extensions/typescript/build/update-grammars.js @@ -6,14 +6,14 @@ var updateGrammar = require('../../../build/npm/update-grammar'); -function adaptToJavaScript(grammar) { +function adaptToJavaScript(grammar, replacementScope) { grammar.name = 'JavaScript (with React support)'; grammar.fileTypes = ['.js', '.jsx', '.es6', '.mjs' ]; - grammar.scopeName = 'source.js'; + grammar.scopeName = `source${replacementScope}`; var fixScopeNames = function(rule) { if (typeof rule.name === 'string') { - rule.name = rule.name.replace(/\.tsx/g, '.js'); + rule.name = rule.name.replace(/\.tsx/g, replacementScope); } for (var property in rule) { var value = rule[property]; @@ -32,7 +32,9 @@ function adaptToJavaScript(grammar) { var tsGrammarRepo = 'Microsoft/TypeScript-TmLanguage'; updateGrammar.update(tsGrammarRepo, 'TypeScript.tmLanguage', './syntaxes/TypeScript.tmLanguage.json'); updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', './syntaxes/TypeScriptReact.tmLanguage.json'); -updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', adaptToJavaScript); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', grammar => adaptToJavaScript(grammar, '.js')); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScriptReact.tmLanguage.json', grammar => adaptToJavaScript(grammar, '.js.jsx')); + diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index 28b955a0742..ba5c664ccf4 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/cd202a57fd738d6d2c712c2ed63f5f41a11eb558", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -3363,7 +3363,7 @@ "name": "punctuation.definition.group.regexp" }, "1": { - "name": "punctuation.definition.group.capture.regexp" + "name": "punctuation.definition.group.no-capture.regexp" } }, "end": "\\)", diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json index 52273319c2e..8266fec39bb 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d6ee336bf6047594768a56f955563ba5ce86e7c9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", "name": "TypeScriptReact", "scopeName": "source.tsx", "fileTypes": [ @@ -3329,7 +3329,7 @@ "name": "punctuation.definition.group.regexp" }, "1": { - "name": "punctuation.definition.group.capture.regexp" + "name": "punctuation.definition.group.no-capture.regexp" } }, "end": "\\)", From 00dbc4541cb07f33c32a2c55a1fd76a3831e375e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 10 Oct 2017 18:05:14 -0700 Subject: [PATCH 084/303] Autoshow intellisense for import with no side effects Fixes #35691 --- extensions/typescript/src/features/completionItemProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 1d7b35cd4e2..77fe1015a32 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -177,7 +177,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { // make sure we are in something that looks like the start of an import const line = document.lineAt(position.line).text.slice(0, position.character); - if (!line.match(/\bfrom\s*["']$/) && !line.match(/\b(import|require)\(['"]$/)) { + if (!line.match(/\b(from|import)\s*["']$/) && !line.match(/\b(import|require)\(['"]$/)) { return Promise.resolve([]); } } From a627a95c4d78684e3285107c428b9cd2a151761d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 10 Oct 2017 18:13:47 -0700 Subject: [PATCH 085/303] Use consistent style for inline code in hover/suggest/parameter hints Fixes #35813 --- src/vs/editor/contrib/hover/browser/hover.ts | 1 - .../contrib/parameterHints/browser/parameterHints.css | 5 +++++ .../contrib/parameterHints/browser/parameterHintsWidget.ts | 7 ++++++- src/vs/editor/contrib/suggest/browser/media/suggest.css | 4 ++++ src/vs/editor/contrib/suggest/browser/suggestWidget.ts | 7 ++++++- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index c973826bfa7..179eb9d2973 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -219,5 +219,4 @@ registerThemingParticipant((theme, collector) => { if (codeBackground) { collector.addRule(`.monaco-editor .monaco-editor-hover code { background-color: ${codeBackground}; }`); } - }); diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHints.css b/src/vs/editor/contrib/parameterHints/browser/parameterHints.css index 812bff41e87..2f89fb1658c 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHints.css +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHints.css @@ -56,6 +56,11 @@ white-space: pre-wrap; } +.monaco-editor .parameter-hints-widget .docs code { + border-radius: 3px; + padding: 0 0.4em; +} + .monaco-editor .parameter-hints-widget .buttons { position: absolute; display: none; diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts index fd7fe899f0d..2d022f949a3 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts @@ -25,7 +25,7 @@ import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; -import { editorHoverBackground, editorHoverBorder, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IModeService } from 'vs/editor/common/services/modeService'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; @@ -511,4 +511,9 @@ registerThemingParticipant((theme, collector) => { if (link) { collector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`); } + + let codeBackground = theme.getColor(textCodeBlockBackground); + if (codeBackground) { + collector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`); + } }); diff --git a/src/vs/editor/contrib/suggest/browser/media/suggest.css b/src/vs/editor/contrib/suggest/browser/media/suggest.css index 2cd4a1b4896..f51c70d511a 100644 --- a/src/vs/editor/contrib/suggest/browser/media/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/media/suggest.css @@ -244,6 +244,10 @@ display: none; } +.monaco-editor .suggest-widget .details code { + border-radius: 3px; + padding: 0 0.4em; +} /* High Contrast and Dark Theming */ diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index ebd0216c50a..f7a076a2780 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -28,7 +28,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { registerColor, editorWidgetBackground, listFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorWidgetBackground, listFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -1117,4 +1117,9 @@ registerThemingParticipant((theme, collector) => { if (link) { collector.addRule(`.monaco-editor .suggest-widget a { color: ${link}; }`); } + + let codeBackground = theme.getColor(textCodeBlockBackground); + if (codeBackground) { + collector.addRule(`.monaco-editor .suggest-widget code { background-color: ${codeBackground}; }`); + } }); From 3ffa14e5ed86b3489f86d9f8d966ae3076f94a61 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 10 Oct 2017 21:24:19 -0700 Subject: [PATCH 086/303] Revert "Only set LANG env var in term if setLocaleVariables is true" This reverts commit a91bad463a4a90409fd6012e4e31a63364cca44b. --- .../parts/terminal/electron-browser/terminalInstance.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index e00375c131d..4ba392d7be8 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -780,9 +780,7 @@ export class TerminalInstance implements ITerminalInstance { } } env['PTYCWD'] = cwd; - if (locale) { - env['LANG'] = TerminalInstance._getLangEnvVariable(locale); - } + env['LANG'] = TerminalInstance._getLangEnvVariable(locale); if (cols && rows) { env['PTYCOLS'] = cols.toString(); env['PTYROWS'] = rows.toString(); From 2b99699e36b81dfd2d1c3c00c502483ff5aef44b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 10 Oct 2017 22:29:45 -0700 Subject: [PATCH 087/303] Fix blurry terminal fonts particularly on low dpi screens Fixes #35991 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 17ee6622a1e..db4d423bbcd 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#b49fe4a329ca792e1eb59d647042e0460e860b4d" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#24fff1743b18ac7291e43c0ba547c7e2681efe65" }, "yauzl": { "version": "2.8.0", From 4cfb2487331b643f13d2409340e9ed9695a68f8c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 09:30:07 +0200 Subject: [PATCH 088/303] fixes #36010 --- src/vs/workbench/api/node/extHost.api.impl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index b5423526507..52629733171 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -346,9 +346,9 @@ export function createApiFactory( get state() { return extHostWindow.state; }, - onDidChangeWindowState: proposedApiFunction(extension, (listener, thisArg?, disposables?) => { + onDidChangeWindowState(listener, thisArg?, disposables?) { return extHostWindow.onDidChangeWindowState(listener, thisArg, disposables); - }), + }, showInformationMessage(message, first, ...rest) { return extHostMessageService.showMessage(extension, Severity.Info, message, first, rest); }, From 88a6e81055577e8e7cfc2a5957b0fa9f157b6b24 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 09:53:32 +0200 Subject: [PATCH 089/303] remote - don't read another time when encoding guessing already read the while file --- .../files/electron-browser/remoteFileService.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 1b4f1bcd61d..676358b5598 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -283,12 +283,19 @@ export class RemoteFileService extends FileService { stream.write(chunk); offset += chunk.length; } - provider.read(resource, offset, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { + if (offset < count) { + // we didn't read enough the first time which means + // that we are done stream.end(); - }, err => { - stream.emit('error', err); - stream.end(); - }); + } else { + // there is more to read + provider.read(resource, offset, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { + stream.end(); + }, err => { + stream.emit('error', err); + stream.end(); + }); + } return { encoding: preferredEncoding, From e03163d9a8c330bba80a368af47ce9f0cddfc26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Tar?= Date: Wed, 11 Oct 2017 10:02:55 +0200 Subject: [PATCH 090/303] Fix wrong placement of 'e.g.'s in the description of `window.title` setting (#35986) * Fix wrong placement of 'e.g.'s in the description of `window.title` setting * Fix the same error in configuration-editing --- .../configuration-editing/src/settingsDocumentHelper.ts | 6 +++--- src/vs/workbench/electron-browser/main.contribution.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index 86db16eb4f9..c0067652e9a 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -43,9 +43,9 @@ export class SettingsDocument { private provideWindowTitleCompletionItems(location: Location, range: vscode.Range): vscode.ProviderResult { const completions: vscode.CompletionItem[] = []; - completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "e.g. the file name (myFile.txt)"))); - completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "e.g. the path of the file relative to the workspace folder (myFolder/myFile.txt)"))); - completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "e.g. the full path of the file (/Users/Development/myProject/myFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "the file name (e.g. myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "the path of the file relative to the workspace folder (e.g. myFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "the full path of the file (e.g. /Users/Development/myProject/myFolder/myFile.txt)"))); completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "name of the workspace (e.g. myFolder or myWorkspace)"))); completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "file path of the workspace (e.g. /Users/Development/myWorkspace)"))); completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)"))); diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index dc469437580..704135c3b57 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -322,9 +322,9 @@ Note that there can still be cases where this setting is ignored (e.g. when usin 'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}', 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'title' }, `Controls the window title based on the active editor. Variables are substituted based on the context: -\${activeEditorShort}: e.g. the file name (myFile.txt) -\${activeEditorMedium}: e.g. the path of the file relative to the workspace folder (myFolder/myFile.txt) -\${activeEditorLong}: e.g. the full path of the file (/Users/Development/myProject/myFolder/myFile.txt) +\${activeEditorShort}: the file name (e.g. myFile.txt) +\${activeEditorMedium}: the path of the file relative to the workspace folder (e.g. myFolder/myFile.txt) +\${activeEditorLong}: the full path of the file (e.g. /Users/Development/myProject/myFolder/myFile.txt) \${folderName}: name of the workspace folder the file is contained in (e.g. myFolder) \${folderPath}: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder) \${rootName}: name of the workspace (e.g. myFolder or myWorkspace) From 0770006e2235d40a52bc077f2196f97556269ae4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Oct 2017 10:17:34 +0200 Subject: [PATCH 091/303] :lipstick: --- .../parts/editor/editor.contribution.ts | 2 +- .../files/browser/fileActions.contribution.ts | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index e5161192096..376a4c15c0d 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -336,7 +336,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInGroupThre registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextEditor, OpenNextEditor.ID, OpenNextEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditor, OpenPreviousEditor.ID, OpenPreviousEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'View: Clear Recently Opened', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'File: Clear Recently Opened', nls.localize('file', "File")); registry.registerWorkbenchAction(new SyncActionDescriptor(KeepEditorAction, KeepEditorAction.ID, KeepEditorAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter) }), 'View: Keep Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left', category); diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index aa587300cc4..3d0cad00246 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -189,33 +189,33 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, FilesViewerActionCo actionBarRegistry.registerActionBarContributor(Scope.VIEWER, ExplorerViewersActionContributor); // Contribute Global Actions -const category = nls.localize('filesCategory', "Files"); +const category = nls.localize('filesCategory', "File"); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCopyPathAction, GlobalCopyPathAction.ID, GlobalCopyPathAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P) }), 'Files: Copy Path of Active File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'Files: Save', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: void 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'Files: Save All', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, SaveFilesAction.LABEL), 'Files: Save All Files', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'Files: Revert File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'Files: New File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFolderAction, GlobalNewFolderAction.ID, GlobalNewFolderAction.LABEL), 'Files: New Folder', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'Files: Compare Active File With...', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusOpenEditorsView, FocusOpenEditorsView.ID, FocusOpenEditorsView.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_E) }), 'Files: Focus on Open Editors View', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'Files: Focus on Files Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'Files: Reveal Active File in Side Bar', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'Files: Collapse Folders in Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'Files: Refresh Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAsAction, SaveFileAsAction.ID, SaveFileAsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S }), 'Files: Save As...', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'Files: New Untitled File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'Files: Reveal Active File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'Files: Open Active File in New Window', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'Files: Compare Active File with Saved', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCopyPathAction, GlobalCopyPathAction.ID, GlobalCopyPathAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P) }), 'File: Copy Path of Active File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'File: Save', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: void 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, SaveFilesAction.LABEL), 'File: Save All Files', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'File: Revert File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'File: New File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFolderAction, GlobalNewFolderAction.ID, GlobalNewFolderAction.LABEL), 'File: New Folder', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'File: Compare Active File With...', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusOpenEditorsView, FocusOpenEditorsView.ID, FocusOpenEditorsView.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_E) }), 'File: Focus on Open Editors View', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'File: Focus on Files Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'File: Reveal Active File in Side Bar', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'File: Refresh Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAsAction, SaveFileAsAction.ID, SaveFileAsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S }), 'File: Save As...', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'File: New Untitled File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'File: Reveal Active File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'File: Compare Active File with Saved', category); if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'Files: Open...', category); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', category); } else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'Files: Open File...', category); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'Files: Open Folder...', category); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', category); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', category); } // Commands From 75f1acb5f4ca0819cf57ff33f135a3dbacafc55f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 10:28:37 +0200 Subject: [PATCH 092/303] fix dirty diff widget positioning --- .../scm/electron-browser/dirtydiffDecorator.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 6d53ce9c9c1..750bf407169 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -63,6 +63,14 @@ function getChangeHeight(change: common.IChange): number { } } +function getModifiedEndLineNumber(change: common.IChange): number { + if (change.modifiedEndLineNumber === 0) { + return change.modifiedStartLineNumber; + } else { + return change.modifiedEndLineNumber; + } +} + function getModifiedMiddleLineNumber(change: common.IChange): number { if (change.modifiedEndLineNumber === 0) { return change.modifiedStartLineNumber; @@ -109,7 +117,7 @@ class DirtyDiffWidget extends PeekViewWidget { this.diffEditor.setModel(this.model); - const position = new Position(change.modifiedEndLineNumber, 1); + const position = new Position(getModifiedEndLineNumber(change), 1); const height = getChangeHeight(change) + /* padding */ 8; this.show(position, height); @@ -117,7 +125,7 @@ class DirtyDiffWidget extends PeekViewWidget { protected _fillBody(container: HTMLElement): void { const options: IDiffEditorOptions = { - scrollBeyondLastLine: false, + scrollBeyondLastLine: true, scrollbar: { verticalScrollbarSize: 14, horizontal: 'auto', @@ -355,7 +363,7 @@ export class DirtyDiffController implements common.IEditorContribution { for (let i = 0; i < this.model.changes.length; i++) { const change = this.model.changes[i]; - if (change.modifiedEndLineNumber >= lineNumber) { + if (getModifiedEndLineNumber(change) >= lineNumber) { return i; } } From eac4d3c749c1da2c1e25953cfc12af35dcca829e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 10:34:36 +0200 Subject: [PATCH 093/303] decorations - only bubble up color status --- .../decorations/browser/decorationsService.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 6583632cb89..5cb5e5cb6f9 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -65,7 +65,7 @@ class DecorationProviderWrapper { return Boolean(this._data.get(uri.toString())) || Boolean(this._data.findSuperstr(uri.toString())); } - getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration) => void): void { + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration, isChild: boolean) => void): void { const key = uri.toString(); let item = this._data.get(key); @@ -81,7 +81,7 @@ class DecorationProviderWrapper { if (item) { // leaf node - callback(item); + callback(item, false); } if (includeChildren) { // (resolved) children @@ -89,7 +89,7 @@ class DecorationProviderWrapper { if (childTree) { childTree.forEach(([, value]) => { if (value && !isThenable(value) && !value.leafOnly) { - callback(value); + callback(value, true); } }); } @@ -154,8 +154,15 @@ export class FileDecorationsService implements IResourceDecorationsService { getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { let top: IResourceDecoration; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { - next.value.getOrRetrieve(uri, includeChildren, candidate => { + next.value.getOrRetrieve(uri, includeChildren, (candidate, isChild) => { top = FileDecorationsService._pickBest(top, candidate); + if (isChild && top === candidate) { + // only bubble up color + top = { + severity: top.severity, + color: top.color + }; + } }); } return top; From 0e488cc2bc73187d3c488a9a25307c329edebb7e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 10:41:50 +0200 Subject: [PATCH 094/303] dirty diff actions --- .../scm/electron-browser/dirtydiffDecorator.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 750bf407169..11bf7ede11a 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -170,14 +170,13 @@ class DirtyDiffWidget extends PeekViewWidget { } @editorAction -export class ReferenceAction2 extends EditorAction { +export class ShowPreviousChangeAction extends EditorAction { constructor() { super({ - id: 'editor.action.dirtydiff.trigger2', - // TODO@joao come up with better name - label: nls.localize('dirtydiff.action.label', "Trigger Dirty Diff"), - alias: 'Trigger Dirty Diff', + id: 'editor.action.dirtydiff.previous', + label: nls.localize('show previous change', "Show Previous Change"), + alias: 'Show Previous Change', precondition: ContextKeyExpr.and(EditorContextKeys.isInEmbeddedEditor.toNegated()), kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_S } }); @@ -195,14 +194,13 @@ export class ReferenceAction2 extends EditorAction { } @editorAction -export class ReferenceAction3 extends EditorAction { +export class ShowNextChangeAction extends EditorAction { constructor() { super({ - id: 'editor.action.dirtydiff.trigger3', - // TODO@joao come up with better name - label: nls.localize('dirtydiff.action.label', "Trigger Dirty Diff"), - alias: 'Trigger Dirty Diff', + id: 'editor.action.dirtydiff.next', + label: nls.localize('show next change', "Show Next Change"), + alias: 'Show Next Change', precondition: ContextKeyExpr.and(EditorContextKeys.isInEmbeddedEditor.toNegated()), kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F } }); From 00f0766b0f50e006d2cdfd65c37274fa8b0150a2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 10:51:48 +0200 Subject: [PATCH 095/303] deco - expect icon uris with spaces --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 80486cc1e34..f97f73653d8 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -148,7 +148,7 @@ export class IconLabel { this.descriptionNode.empty = !description; if (options && options.extraIcon) { - this.element.style.backgroundImage = `url(${options.extraIcon.toString(true)})`; + this.element.style.backgroundImage = `url("${options.extraIcon.toString(true)}")`; this.element.style.backgroundRepeat = 'no-repeat'; this.element.style.backgroundPosition = 'right center'; this.element.style.paddingRight = '20px'; From 4310b14f669698917ed468b3443165f21d9032e2 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 11:32:11 +0200 Subject: [PATCH 096/303] dirty diff: previous/next changes --- .../base/browser/ui/actionbar/actionbar.css | 4 +++ src/vs/base/browser/ui/actionbar/actionbar.ts | 36 +++++++++++++++---- .../browser/media/peekViewWidget.css | 27 +++++++++++--- .../referenceSearch/browser/peekViewWidget.ts | 13 ++++--- .../electron-browser/dirtydiffDecorator.ts | 35 ++++++++++++++++++ .../media/dirtydiffDecorator.css | 2 +- 6 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 930ab74fd19..06e582d642e 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -21,6 +21,10 @@ display: inline-block; } +.monaco-action-bar.reverse .actions-container { + flex-direction: row-reverse; +} + .monaco-action-bar .action-item { cursor: pointer; display: inline-block; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 688cb903a45..de30d225bc9 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -350,8 +350,10 @@ export class ActionItem extends BaseActionItem { } export enum ActionsOrientation { - HORIZONTAL = 1, - VERTICAL = 2 + HORIZONTAL, + HORIZONTAL_REVERSE, + VERTICAL, + VERTICAL_REVERSE, } export interface IActionItemProvider { @@ -420,18 +422,38 @@ export class ActionBar extends EventEmitter implements IActionRunner { DOM.addClass(this.domNode, 'animated'); } - let isVertical = this.options.orientation === ActionsOrientation.VERTICAL; - if (isVertical) { - this.domNode.className += ' vertical'; + let previousKey: KeyCode; + let nextKey: KeyCode; + + switch (this.options.orientation) { + case ActionsOrientation.HORIZONTAL: + previousKey = KeyCode.LeftArrow; + nextKey = KeyCode.RightArrow; + break; + case ActionsOrientation.HORIZONTAL_REVERSE: + previousKey = KeyCode.RightArrow; + nextKey = KeyCode.LeftArrow; + this.domNode.className += ' reverse'; + break; + case ActionsOrientation.VERTICAL: + previousKey = KeyCode.UpArrow; + nextKey = KeyCode.DownArrow; + this.domNode.className += ' vertical'; + break; + case ActionsOrientation.VERTICAL_REVERSE: + previousKey = KeyCode.DownArrow; + nextKey = KeyCode.UpArrow; + this.domNode.className += ' vertical reverse'; + break; } $(this.domNode).on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { let event = new StandardKeyboardEvent(e); let eventHandled = true; - if (event.equals(isVertical ? KeyCode.UpArrow : KeyCode.LeftArrow)) { + if (event.equals(previousKey)) { this.focusPrevious(); - } else if (event.equals(isVertical ? KeyCode.DownArrow : KeyCode.RightArrow)) { + } else if (event.equals(nextKey)) { this.focusNext(); } else if (event.equals(KeyCode.Escape)) { this.cancel(); diff --git a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css index 8ef899a7815..8a3041ee368 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css @@ -9,6 +9,7 @@ -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; + display: flex; } .monaco-editor .peekview-widget .head .peekview-title { @@ -24,16 +25,32 @@ } .monaco-editor .peekview-widget .head .peekview-actions { + flex: 1; + text-align: right; + padding-right: 2px; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar { display: inline-block; - position: absolute; - right: 2px; - top: 2px; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar, +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar > .actions-container { + height: 100%; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label { + line-height: inherit; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label.octicon { + margin: 0; } .monaco-editor .peekview-widget .head .peekview-actions .action-label { width: 16px; - height: 16px; - margin: 2px 0; + height: 100%; + margin: 0; } .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action { diff --git a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts index 5332768c677..09aab8dcdcd 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts @@ -13,7 +13,7 @@ import * as objects from 'vs/base/common/objects'; import { $ } from 'vs/base/browser/builder'; import Event, { Emitter } from 'vs/base/common/event'; import * as dom from 'vs/base/browser/dom'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; @@ -132,10 +132,9 @@ export abstract class PeekViewWidget extends ZoneWidget { this._secondaryHeading = $('span.dirname').appendTo(titleElement).getHTMLElement(); this._metaHeading = $('span.meta').appendTo(titleElement).getHTMLElement(); - this._actionbarWidget = new ActionBar( - $('.peekview-actions'). - appendTo(this._headElement) - ); + const actionsContainer = $('.peekview-actions').appendTo(this._headElement); + const actionBarOptions = this._getActionBarOptions(); + this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions); this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), 'close-peekview-action', true, () => { this.dispose(); @@ -143,6 +142,10 @@ export abstract class PeekViewWidget extends ZoneWidget { }), { label: false, icon: true }); } + protected _getActionBarOptions(): IActionBarOptions { + return {}; + } + protected _onTitleClick(event: MouseEvent): void { // implement me } diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 11bf7ede11a..d33619ffd49 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -43,6 +43,8 @@ import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRe import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { Action } from 'vs/base/common/actions'; +import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -79,6 +81,22 @@ function getModifiedMiddleLineNumber(change: common.IChange): number { } } +class UIEditorAction extends Action { + + constructor( + private editor: common.ICommonCodeEditor, + private action: EditorAction, + cssClass: string, + @IInstantiationService private instantiationService: IInstantiationService + ) { + super(action.id, action.label, cssClass); + } + + run(): TPromise { + return TPromise.wrap(this.instantiationService.invokeFunction(accessor => this.action.run(accessor, this.editor, null))); + } +} + class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; @@ -123,6 +141,23 @@ class DirtyDiffWidget extends PeekViewWidget { this.show(position, height); } + protected _fillHead(container: HTMLElement): void { + super._fillHead(container); + + const previous = new UIEditorAction(this.editor, new ShowPreviousChangeAction(), 'show-previous-change octicon octicon-chevron-up', this.instantiationService); + const next = new UIEditorAction(this.editor, new ShowNextChangeAction(), 'show-next-change octicon octicon-chevron-down', this.instantiationService); + + this._disposables.push(previous); + this._disposables.push(next); + this._actionbarWidget.push([previous, next], { label: false, icon: true }); + } + + protected _getActionBarOptions(): IActionBarOptions { + return { + orientation: ActionsOrientation.HORIZONTAL_REVERSE + }; + } + protected _fillBody(container: HTMLElement): void { const options: IDiffEditorOptions = { scrollBeyondLastLine: true, diff --git a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css index beaf772629e..b188403907e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css @@ -17,4 +17,4 @@ width: 4px; height: 0; z-index: 9; -} \ No newline at end of file +} From 26f78f8da1bd7221e6763b4bd8c5994acbb27311 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 11:37:04 +0200 Subject: [PATCH 097/303] remote - tweak read call --- .../services/files/electron-browser/remoteFileService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 676358b5598..6de890c430f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -289,7 +289,7 @@ export class RemoteFileService extends FileService { stream.end(); } else { // there is more to read - provider.read(resource, offset, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { + provider.read(resource, offset, -1, new Progress(chunk => stream.write(chunk))).then(() => { stream.end(); }, err => { stream.emit('error', err); From 0b57f9ee91f3f7c7a21e422cf7f6ef6523fe8aa3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Oct 2017 11:47:59 +0200 Subject: [PATCH 098/303] scorer - better distance compute --- .../parts/quickopen/common/quickOpenScorer.ts | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 1b12ae09842..fe804a29d1f 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -406,21 +406,10 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: } // 6.) scores are identical, prefer more compact matches (label and description) - let itemAMatches: IMatch[] = []; - if (itemScoreA.descriptionMatch) { - itemAMatches.push(...itemScoreA.descriptionMatch); - } - itemAMatches.push(...itemScoreA.labelMatch); - - let itemBMatches: IMatch[] = []; - if (itemScoreB.descriptionMatch) { - itemBMatches.push(...itemScoreB.descriptionMatch); - } - itemBMatches.push(...itemScoreB.labelMatch); - - const matchCompactness = compareByMatchLength(itemAMatches, itemBMatches); - if (matchCompactness !== 0) { - return matchCompactness; + const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor); + const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor); + if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) { + return itemBMatchDistance > itemAMatchDistance ? -1 : 1; } // 7.) at this point, scores are identical and match compactness as well @@ -428,6 +417,44 @@ export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: return fallbackComparer(itemA, itemB, query, accessor); } +function computeLabelAndDescriptionMatchDistance(item: T, score: IItemScore, accessor: IItemAccessor): number { + const hasLabelMatches = (score.labelMatch && score.labelMatch.length); + const hasDescriptionMatches = (score.descriptionMatch && score.descriptionMatch.length); + + let matchStart: number = -1; + let matchEnd: number = -1; + + // If we have description matches, the start is first of description match + if (hasDescriptionMatches) { + matchStart = score.descriptionMatch[0].start; + } + + // Otherwise, the start is the first label match + else if (hasLabelMatches) { + matchStart = score.labelMatch[0].start; + } + + // If we have label match, the end is the last label match + // If we had a description match, we add the length of the description + // as offset to the end to indicate this. + if (hasLabelMatches) { + matchEnd = score.labelMatch[score.labelMatch.length - 1].end; + if (hasDescriptionMatches) { + const itemDescription = accessor.getItemDescription(item); + if (itemDescription) { + matchEnd += itemDescription.length; + } + } + } + + // If we have just a description match, the end is the last description match + else if (hasDescriptionMatches) { + matchEnd = score.descriptionMatch[score.descriptionMatch.length - 1].end; + } + + return matchEnd - matchStart; +} + function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number { if ((!matchesA && !matchesB) || (!matchesA.length && !matchesB.length)) { return 0; // make sure to not cause bad comparing when matches are not provided From 4c50ac73723231001e8286c468fda0868970343a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Oct 2017 12:16:28 +0200 Subject: [PATCH 099/303] enable multi root in all releases --- src/vs/code/electron-main/menus.ts | 10 ++++------ src/vs/code/electron-main/windows.ts | 6 +++--- src/vs/platform/environment/node/argv.ts | 6 ------ .../electron-browser/main.contribution.ts | 17 +++++++---------- .../files/browser/fileActions.contribution.ts | 3 ++- .../parts/files/browser/views/explorerViewer.ts | 4 ---- .../workspace/node/workspaceEditingService.ts | 6 +----- 7 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 0accad12c78..327dcba23b3 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -403,8 +403,6 @@ export class CodeMenu { this.setOpenRecentMenu(openRecentMenu); const openRecent = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent")), submenu: openRecentMenu, enabled: openRecentMenu.items.length > 0 }); - const isMultiRootEnabled = (product.quality !== 'stable'); // TODO@Ben multi root - const saveWorkspaceAs = this.createMenuItem(nls.localize({ key: 'miSaveWorkspaceAs', comment: ['&& denotes a mnemonic'] }, "&&Save Workspace As..."), 'workbench.action.saveWorkspaceAs'); const addFolder = this.createMenuItem(nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Add Folder to Workspace..."), 'workbench.action.addRootFolder'); @@ -437,11 +435,11 @@ export class CodeMenu { isMacintosh ? open : null, !isMacintosh ? openFile : null, !isMacintosh ? openFolder : null, - isMultiRootEnabled ? openWorkspace : null, + openWorkspace, openRecent, - isMultiRootEnabled ? __separator__() : null, - isMultiRootEnabled ? addFolder : null, - isMultiRootEnabled ? saveWorkspaceAs : null, + __separator__(), + addFolder, + saveWorkspaceAs, __separator__(), saveFile, saveFileAs, diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 1262489e565..0698760579e 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -362,7 +362,7 @@ export class WindowsManager implements IWindowsMainService { // When run with --add, take the folders that are to be opened as // folders that should be added to the currently active window. let foldersToAdd: IPath[] = []; - if (openConfig.addMode && product.quality !== 'stable') { // TODO@Ben multi root + if (openConfig.addMode) { foldersToAdd = pathsToOpen.filter(path => !!path.folderPath).map(path => ({ filePath: path.folderPath })); pathsToOpen = pathsToOpen.filter(path => !path.folderPath); } @@ -792,7 +792,7 @@ export class WindowsManager implements IWindowsMainService { // This will ensure to open these folders in one window instead of multiple // If we are in addMode, we should not do this because in that case all // folders should be added to the existing window. - if (!openConfig.addMode && isCommandLineOrAPICall && product.quality !== 'stable') { // TODO@Ben multi root + if (!openConfig.addMode && isCommandLineOrAPICall) { const foldersToOpen = windowsToOpen.filter(path => !!path.folderPath); if (foldersToOpen.length > 1) { const workspace = this.workspacesService.createWorkspaceSync(foldersToOpen.map(folder => folder.folderPath)); @@ -937,7 +937,7 @@ export class WindowsManager implements IWindowsMainService { restoreWindows = ((windowConfig && windowConfig.restoreWindows) || 'one') as RestoreWindowsSetting; if (restoreWindows === 'one' /* default */ && windowConfig && windowConfig.reopenFolders) { - restoreWindows = windowConfig.reopenFolders; // TODO@Ben migration + restoreWindows = windowConfig.reopenFolders; // TODO@Ben migration from deprecated window.reopenFolders setting } if (['all', 'folders', 'one', 'none'].indexOf(restoreWindows) === -1) { diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 2396982a61f..b0ee81d6fc6 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -9,7 +9,6 @@ import * as assert from 'assert'; import { firstIndex } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; import { ParsedArgs } from '../common/environment'; -import product from 'vs/platform/node/product'; const options: minimist.Opts = { string: [ @@ -146,11 +145,6 @@ export const optionsHelp: { [name: string]: string; } = { '-h, --help': localize('help', "Print usage.") }; -// TODO@Ben multi root -if (product.quality === 'stable') { - delete optionsHelp['-a, --add']; -} - export function formatOptions(options: { [name: string]: string; }, columns: number): string { let keys = Object.keys(options); let argLength = Math.max.apply(null, keys.map(k => k.length)) + 2/*left padding*/ + 1/*right padding*/; diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 704135c3b57..f56ae229cbe 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -84,16 +84,13 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Naviga workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, null), 'View: Increase Current View Size', viewCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, null), 'View: Decrease Current View Size', viewCategory); -// TODO@Ben multi root -if (product.quality !== 'stable') { - const workspacesCategory = nls.localize('workspaces', "Workspaces"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAsWorkspaceInNewWindowAction, OpenFolderAsWorkspaceInNewWindowAction.ID, OpenFolderAsWorkspaceInNewWindowAction.LABEL), 'Workspaces: Open Folder as Workspace in New Window', workspacesCategory); -} +const workspacesCategory = nls.localize('workspaces', "Workspaces"); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAsWorkspaceInNewWindowAction, OpenFolderAsWorkspaceInNewWindowAction.ID, OpenFolderAsWorkspaceInNewWindowAction.LABEL), 'Workspaces: Open Folder as Workspace in New Window', workspacesCategory); // Developer related actions const developerCategory = nls.localize('developer', "Developer"); diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 3d0cad00246..b05ba76285d 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -91,7 +91,8 @@ class FilesViewerActionContributor extends ActionBarContributor { actions.push(new Separator(null, 100)); } - if (stat.isRoot && this.environmentService.appQuality !== 'stable') { + // Workspace Root Folder Actions + if (stat.isRoot) { const addRootFolderAction: Action = this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL); addRootFolderAction.order = 52; actions.push(addRootFolderAction); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index a60d36d6116..291052f6ac0 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -918,10 +918,6 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // Handle folders by adding to workspace if we are in workspace context const folders = result.filter(result => result.stat.isDirectory).map(result => result.stat.resource); if (folders.length > 0) { - if (this.environmentService.appQuality === 'stable') { - return void 0; // TODO@Ben multi root - } - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { return this.workspaceEditingService.addFolders(folders); } diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index 934b4c70a19..0a684c69b28 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -116,11 +116,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } private isSupported(): boolean { - // TODO@Ben multi root - return ( - this.environmentService.appQuality !== 'stable' // not yet enabled in stable - && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE // we need a multi folder workspace to begin with - ); + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; // we need a multi folder workspace to begin with; } private contains(resources: URI[], toCheck: URI): boolean { From c076ea2e0f392798601d0e1f7ed6f2692e8f1055 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Oct 2017 12:17:16 +0200 Subject: [PATCH 100/303] remove some todos --- .../platform/history/electron-main/historyMainService.ts | 9 --------- src/vs/workbench/common/actions.ts | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 8e8519b730f..129df5fabce 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -154,15 +154,6 @@ export class HistoryMainService implements IHistoryMainService { files.unshift(...currentFiles.map(f => f.filePath)); } - // TODO@Ben migration to new workspace ID - workspaces.forEach(workspaceOrFile => { - if (isSingleFolderWorkspaceIdentifier(workspaceOrFile)) { - return; - } - - workspaceOrFile.id = this.workspacesService.getWorkspaceId(workspaceOrFile.configPath); - }); - // Clear those dupes workspaces = arrays.distinct(workspaces, workspace => this.distinctFn(workspace)); files = arrays.distinct(files, file => this.distinctFn(file)); diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index d1b8e840b46..63643d4d95a 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -61,8 +61,8 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR }); // menu item - // TODO@Ben slightly weird if-check required because of - // https://github.com/Microsoft/vscode/blob/d28ace31aa147596e35adf101a27768a048c79ec/src/vs/workbench/parts/files/browser/fileActions.contribution.ts#L194 + // TODO@Rob slightly weird if-check required because of + // https://github.com/Microsoft/vscode/blob/master/src/vs/workbench/parts/search/browser/search.contribution.ts#L266 if (descriptor.label) { const command = { From 355d49ff2e00c1287941428495a3126ce3449fb9 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 11 Oct 2017 12:18:05 +0200 Subject: [PATCH 101/303] debug: fix guess adapter fixes #36045 --- .../parts/debug/electron-browser/debugService.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index a47e5a09be6..b5fef6e3f4c 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -701,14 +701,16 @@ export class DebugService implements debug.IDebugService { config.noDebug = true; } - return this.configurationManager.resolveDebugConfiguration(launch ? launch.workspace.uri : undefined, type, config).then(config => { - // a falsy config indicates an aborted launch - if (config && config.type) { - return this.createProcess(root, config); - } + return (type ? TPromise.as(null) : this.configurationManager.guessAdapter().then(a => type = a && a.type)).then(() => + this.configurationManager.resolveDebugConfiguration(launch ? launch.workspace.uri : undefined, type, config).then(config => { + // a falsy config indicates an aborted launch + if (config && config.type) { + return this.createProcess(root, config); + } - return undefined; // ignore weird compile error - }); + return launch.openConfigFile(false, type); // cast to ignore weird compile error + }) + ); }) ))); } From 71cdb6afbc6ccee52e70ff9266cca62e92a72a13 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Oct 2017 12:22:06 +0200 Subject: [PATCH 102/303] promote showWorkspaceFolderPick to stable API --- src/vs/vscode.d.ts | 25 ++++++++++++++++ src/vs/vscode.proposed.d.ts | 29 ------------------- src/vs/workbench/api/node/extHost.api.impl.ts | 4 +-- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index d81912cebe7..f158ca9f725 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1504,6 +1504,22 @@ declare module 'vscode' { onDidSelectItem?(item: QuickPickItem | string): any; } + /** + * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. + */ + export interface WorkspaceFolderPickOptions { + + /** + * An optional string to show as place holder in the input box to guide the user what to pick on. + */ + placeHolder?: string; + + /** + * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; + } + /** * Options to configure the behaviour of a file open dialog. * @@ -4586,6 +4602,15 @@ declare module 'vscode' { */ export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + /** + * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. + * Returns `undefined` if no folder is open. + * + * @param options Configures the behavior of the workspace folder list. + * @return A promise that resolves to the workspace folder or `undefined`. + */ + export function showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions): Thenable; + /** * Shows a file open dialog to the user which allows to select a file * for opening-purposes. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 0a2e63c7729..fd6f8cf68e3 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -7,35 +7,6 @@ declare module 'vscode' { - export namespace window { - - /** - * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. - * Returns `undefined` if no folder is open. - * - * @param options Configures the behavior of the workspace folder list. - * @return A promise that resolves to the workspace folder or `undefined`. - */ - export function showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions): Thenable; - } - - /** - * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. - */ - export interface WorkspaceFolderPickOptions { - - /** - * An optional string to show as place holder in the input box to guide the user what to pick on. - */ - placeHolder?: string; - - /** - * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. - */ - ignoreFocusOut?: boolean; - } - - // export enum FileErrorCodes { // /** // * Not owner. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 52629733171..4e7b51fb5a5 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -361,9 +361,9 @@ export function createApiFactory( showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showQuickPick(items, options, token); }, - showWorkspaceFolderPick: proposedApiFunction(extension, (options: vscode.WorkspaceFolderPickOptions) => { + showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { return extHostQuickOpen.showWorkspaceFolderPick(options); - }), + }, showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showInput(options, token); }, From e96a35fa05cc389ce0606d885bd25304c602774a Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 11 Oct 2017 12:40:27 +0200 Subject: [PATCH 103/303] panel has to be expanded in order for the actions to be visible fixes #35923 --- src/vs/base/browser/ui/splitview/panelview.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css index e4853977a88..50a7d87499a 100644 --- a/src/vs/base/browser/ui/splitview/panelview.css +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -53,8 +53,8 @@ } /* TODO: actions should be part of the panel, but they aren't yet */ -.monaco-panel-view .panel:hover > .panel-header > .actions, -.monaco-panel-view .panel > .panel-header.focused > .actions { +.monaco-panel-view .panel:hover > .panel-header.expanded > .actions, +.monaco-panel-view .panel > .panel-header.focused.expanded > .actions { display: initial; } From 12439dfbb6f8ba446f4b88281c8d9bca88e1b70e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 12:59:38 +0200 Subject: [PATCH 104/303] debt - remove obsolete URI casts --- src/vs/workbench/api/electron-browser/mainThreadEditors.ts | 2 +- src/vs/workbench/api/node/extHost.api.impl.ts | 4 ++-- src/vs/workbench/api/node/extHostDebugService.ts | 4 ++-- src/vs/workbench/api/node/extHostDiagnostics.ts | 4 ++-- src/vs/workbench/api/node/extHostDocumentContentProviders.ts | 4 ++-- src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts | 2 +- src/vs/workbench/api/node/extHostLanguageFeatures.ts | 2 +- src/vs/workbench/api/node/extHostTextEditors.ts | 5 ++--- src/vs/workbench/api/node/extHostTypeConverters.ts | 2 +- src/vs/workbench/api/node/extHostTypes.ts | 2 +- 10 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts index 40d2943f7e6..df3174ae67c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts @@ -243,7 +243,7 @@ export class MainThreadEditors implements MainThreadEditorsShape { const edit = edits[j]; resourceEdits.push({ - resource: uri, + resource: uri, newText: edit.newText, newEol: edit.newEol, range: edit.range diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 4e7b51fb5a5..87c5a26ce68 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -453,7 +453,7 @@ export function createApiFactory( if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); } else if (uriOrFileNameOrOptions instanceof URI) { - uriPromise = TPromise.as(uriOrFileNameOrOptions); + uriPromise = TPromise.as(uriOrFileNameOrOptions); } else if (!options || typeof options === 'object') { uriPromise = extHostDocuments.createDocumentData(options); } else { @@ -486,7 +486,7 @@ export function createApiFactory( return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); }, getConfiguration: (section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration => { - return extHostConfiguration.getConfiguration(section, resource); + return extHostConfiguration.getConfiguration(section, resource); }, registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) { return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 1e7a6c0d3df..0e27ea89109 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -95,11 +95,11 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise { - return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig); + return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig); } public startDebugSession(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): TPromise { - return this._debugServiceProxy.$startDebugSession(folder ? folder.uri : undefined, config).then((id: DebugSessionUUID) => { + return this._debugServiceProxy.$startDebugSession(folder ? folder.uri : undefined, config).then((id: DebugSessionUUID) => { const debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, config.type, config.name); this._debugSessions.set(id, debugSession); return debugSession; diff --git a/src/vs/workbench/api/node/extHostDiagnostics.ts b/src/vs/workbench/api/node/extHostDiagnostics.ts index 1a200433765..8b44277e384 100644 --- a/src/vs/workbench/api/node/extHostDiagnostics.ts +++ b/src/vs/workbench/api/node/extHostDiagnostics.ts @@ -133,7 +133,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { } } - entries.push([uri, marker]); + entries.push([uri, marker]); } this._proxy.$changeMany(this.name, entries); @@ -142,7 +142,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { delete(uri: vscode.Uri): void { this._checkDisposed(); this._data.delete(uri.toString()); - this._proxy.$changeMany(this.name, [[uri, undefined]]); + this._proxy.$changeMany(this.name, [[uri, undefined]]); } clear(): void { diff --git a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts index c3d6e39536e..dc53c36fcc8 100644 --- a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts +++ b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts @@ -47,7 +47,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro if (typeof provider.onDidChange === 'function') { subscription = provider.onDidChange(uri => { if (this._documentsAndEditors.getDocument(uri.toString())) { - this.$provideTextDocumentContent(handle, uri).then(value => { + this.$provideTextDocumentContent(handle, uri).then(value => { const document = this._documentsAndEditors.getDocument(uri.toString()); if (!document) { @@ -60,7 +60,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro // broadcast event when content changed if (!document.equalLines(textSource)) { - return this._proxy.$onVirtualDocumentChange(uri, textSource); + return this._proxy.$onVirtualDocumentChange(uri, textSource); } }, onUnexpectedError); diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 3be0250cf70..16d2ed87ccd 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -129,7 +129,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic }).then(values => { let workspaceResourceEdit: IWorkspaceResourceEdit = { - resource: document.uri, + resource: document.uri, edits: [] }; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 1b9211584d8..c3764b060d5 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -437,7 +437,7 @@ class RenameAdapter { let [uri, textEdits] = entry; for (let textEdit of textEdits) { result.edits.push({ - resource: uri, + resource: uri, newText: textEdit.newText, range: TypeConverters.fromRange(textEdit.range) }); diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts index d1f70271a48..d3ca9b8edc8 100644 --- a/src/vs/workbench/api/node/extHostTextEditors.ts +++ b/src/vs/workbench/api/node/extHostTextEditors.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { toThenable } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -77,7 +76,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { }; } - return this._proxy.$tryShowTextDocument(document.uri, options).then(id => { + return this._proxy.$tryShowTextDocument(document.uri, options).then(id => { let editor = this._extHostDocumentsAndEditors.getEditor(id); if (editor) { return editor; @@ -106,7 +105,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { } let workspaceResourceEdit: IWorkspaceResourceEdit = { - resource: uri, + resource: uri, modelVersionId: docVersion, edits: [] }; diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 47010f07757..54c80ba84c4 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -284,7 +284,7 @@ export const location = { from(value: vscode.Location): modes.Location { return { range: value.range && fromRange(value.range), - uri: value.uri + uri: value.uri }; }, to(value: modes.Location): types.Location { diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index c0044aa87a9..616ce83c24c 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -794,7 +794,7 @@ export class SymbolInformation { if (locationOrUri instanceof Location) { this.location = locationOrUri; } else if (rangeOrContainer instanceof Range) { - this.location = new Location(locationOrUri, rangeOrContainer); + this.location = new Location(locationOrUri, rangeOrContainer); } } From 7286bce88c3b3ab4b591da7b6590e72d480c3013 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 14:20:48 +0200 Subject: [PATCH 105/303] dirtydiff: reveal zone in center --- src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index f2ebd600999..0e3cc650b70 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -395,7 +395,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // Reveal the line above or below the zone widget, to get the zone widget in the viewport const revealLineNumber = Math.min(this.editor.getModel().getLineCount(), Math.max(1, where.endLineNumber + 1)); - this.editor.revealLine(revealLineNumber, ScrollType.Smooth); + this.editor.revealLineInCenterIfOutsideViewport(revealLineNumber, ScrollType.Smooth); } protected setCssClass(className: string, classToReplace?: string): void { From e1f3a1f8632c0ac56c53c179f743133deea1f447 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 14:21:03 +0200 Subject: [PATCH 106/303] dirtydiff: show keybindings in command label --- .../electron-browser/dirtydiffDecorator.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index d33619ffd49..543e2fddd93 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -45,6 +45,7 @@ import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeE import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; import { Action } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -83,13 +84,25 @@ function getModifiedMiddleLineNumber(change: common.IChange): number { class UIEditorAction extends Action { + private editor: common.ICommonCodeEditor; + private action: EditorAction; + private instantiationService: IInstantiationService; + constructor( - private editor: common.ICommonCodeEditor, - private action: EditorAction, + editor: common.ICommonCodeEditor, + action: EditorAction, cssClass: string, - @IInstantiationService private instantiationService: IInstantiationService + @IKeybindingService keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService ) { - super(action.id, action.label, cssClass); + const keybinding = keybindingService.lookupKeybinding(action.id); + const label = action.label + (keybinding ? ` (${keybinding.getLabel()})` : ''); + + super(action.id, label, cssClass); + + this.instantiationService = instantiationService; + this.action = action; + this.editor = editor; } run(): TPromise { @@ -144,8 +157,8 @@ class DirtyDiffWidget extends PeekViewWidget { protected _fillHead(container: HTMLElement): void { super._fillHead(container); - const previous = new UIEditorAction(this.editor, new ShowPreviousChangeAction(), 'show-previous-change octicon octicon-chevron-up', this.instantiationService); - const next = new UIEditorAction(this.editor, new ShowNextChangeAction(), 'show-next-change octicon octicon-chevron-down', this.instantiationService); + const previous = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowPreviousChangeAction(), 'show-previous-change octicon octicon-chevron-up'); + const next = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowNextChangeAction(), 'show-next-change octicon octicon-chevron-down'); this._disposables.push(previous); this._disposables.push(next); From 6038070f88f37000533ccfd3a941c29b1b985ddb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 14:33:12 +0200 Subject: [PATCH 107/303] zone widget: dont grow markers --- src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index 0e3cc650b70..24acb8e2eba 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -17,7 +17,7 @@ import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { ScrollType } from 'vs/editor/common/editorCommon'; +import { ScrollType, TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; export interface IOptions { showFrame?: boolean; @@ -147,7 +147,7 @@ class Arrow { show(where: IPosition): void { this._decorations = this._editor.deltaDecorations( this._decorations, - [{ range: Range.fromPositions(where), options: { className: this._ruleName } }] + [{ range: Range.fromPositions(where), options: { className: this._ruleName, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } }] ); } From 3acbab74db239baf8e9dcc7e88ca9ac8033bcee4 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 14:34:12 +0200 Subject: [PATCH 108/303] dirtydiff: title --- .../scm/electron-browser/dirtydiffDecorator.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 543e2fddd93..0876a78b162 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -46,6 +46,7 @@ import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; import { Action } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { basename } from 'vs/base/common/paths'; export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -113,6 +114,7 @@ class UIEditorAction extends Action { class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; + private title: string; private change: common.IChange; private didLayout = false; @@ -128,10 +130,13 @@ class DirtyDiffWidget extends PeekViewWidget { this._applyTheme(themeService.getTheme()); this.create(); - this.setTitle('Diff'); + + this.title = basename(editor.getModel().uri.fsPath); + this.setTitle(this.title); } - showChange(change: common.IChange): void { + showChange(index: number): void { + const change = this.model.changes[index]; this.change = change; const originalModel = this.model.original; @@ -151,6 +156,9 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(getModifiedEndLineNumber(change), 1); const height = getChangeHeight(change) + /* padding */ 8; + const detail = localize('changes', "Changes ({0} of {1})", index + 1, this.model.changes.length); + this.setTitle(this.title, detail); + this.show(position, height); } @@ -328,7 +336,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = rot(this.changeIndex + 1, this.model.changes.length); } - this.widget.showChange(this.model.changes[this.changeIndex]); + this.widget.showChange(this.changeIndex); } previous(): void { @@ -342,7 +350,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = rot(this.changeIndex - 1, this.model.changes.length); } - this.widget.showChange(this.model.changes[this.changeIndex]); + this.widget.showChange(this.changeIndex); } close(): void { From c5e3aace450cbff45c1437a1c12c67bcff740b57 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 14:37:58 +0200 Subject: [PATCH 109/303] diff: fix title --- .../parts/scm/electron-browser/dirtydiffDecorator.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 0876a78b162..9174eb7626d 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -156,7 +156,10 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(getModifiedEndLineNumber(change), 1); const height = getChangeHeight(change) + /* padding */ 8; - const detail = localize('changes', "Changes ({0} of {1})", index + 1, this.model.changes.length); + const detail = this.model.changes.length > 1 + ? localize('changes', "{0} of {1} changes", index + 1, this.model.changes.length) + : localize('change', "{0} of {1} change", index + 1, this.model.changes.length); + this.setTitle(this.title, detail); this.show(position, height); From 81d87edb3bac53bd0bb94ecd2d807552f2203275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=AB=E7=A7=91=E9=BE=99?= <974985526@qq.com> Date: Wed, 11 Oct 2017 21:15:25 +0800 Subject: [PATCH 110/303] Correct the EBNF for snippets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I reviewed the parse's code and think that `${sn:-else}` and `${sn:else}` may have the same function and should share the same status,which means that the pattern should be something like `'${' int ':-' else '}' | '${' int ':' else '}'` or not '${' int ':-' else '}' '${' int ':' else '}'. --- src/vs/editor/contrib/snippet/browser/snippet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/snippet/browser/snippet.md b/src/vs/editor/contrib/snippet/browser/snippet.md index df77dd8f821..c0de625a589 100644 --- a/src/vs/editor/contrib/snippet/browser/snippet.md +++ b/src/vs/editor/contrib/snippet/browser/snippet.md @@ -71,7 +71,7 @@ format ::= '$' int | '${' int '}' | '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}' | '${' int ':+' if '}' | '${' int ':?' if ':' else '}' - | '${' int ':-' else '}' '${' int ':' else '}' + | '${' int ':-' else '}' | '${' int ':' else '}' regex ::= JavaScript Regular Expression value (ctor-string) options ::= JavaScript Regular Expression option (ctor-options) var ::= [_a-zA-Z] [_a-zA-Z0-9]* From 7d729c9d17b36d59638e049c4b731ecb59425ec3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 15:16:47 +0200 Subject: [PATCH 111/303] diff: inline actions --- extensions/git/package.json | 30 +++++++++- extensions/git/package.nls.json | 2 + extensions/git/src/commands.ts | 16 +++++- .../browser/media/peekViewWidget.css | 15 +++-- src/vs/platform/actions/common/actions.ts | 1 + .../electron-browser/menusExtensionPoint.ts | 1 + .../electron-browser/dirtydiffDecorator.ts | 55 ++++++++++++++++--- 7 files changed, 102 insertions(+), 18 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 58779e50bbc..b333ac40918 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -101,6 +101,24 @@ "title": "%command.revertSelectedRanges%", "category": "Git" }, + { + "command": "git.stageChange", + "title": "%command.stageChange%", + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } + }, + { + "command": "git.revertChange", + "title": "%command.revertChange%", + "category": "Git", + "icon": { + "light": "resources/icons/light/clean.svg", + "dark": "resources/icons/dark/clean.svg" + } + }, { "command": "git.unstage", "title": "%command.unstage%", @@ -722,6 +740,16 @@ "group": "2_git@3", "when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff" } + ], + "scm/change/title": [ + { + "command": "git.stageChange", + "when": "config.git.enabled && originalResourceScheme == git" + }, + { + "command": "git.revertChange", + "when": "config.git.enabled && originalResourceScheme == git" + } ] }, "configuration": { @@ -836,4 +864,4 @@ "@types/node": "7.0.43", "mocha": "^3.2.0" } -} +} \ No newline at end of file diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index da2c9210fd1..d191adfadf4 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -10,6 +10,8 @@ "command.stageAll": "Stage All Changes", "command.stageSelectedRanges": "Stage Selected Ranges", "command.revertSelectedRanges": "Revert Selected Ranges", + "command.stageChange": "Stage Change", + "command.revertChange": "Revert Change", "command.unstage": "Unstage Changes", "command.unstageAll": "Unstage All Changes", "command.unstageSelectedRanges": "Unstage Selected Ranges", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index c41d60d2fbb..d23b9cd3738 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -556,8 +556,13 @@ export class CommandCenter { await repository.add([]); } + @command('git.stageChange') + async stageChange(change: LineChange): Promise { + await this.stageChanges([change]); + } + @command('git.stageSelectedRanges', { diff: true }) - async stageSelectedRanges(diffs: LineChange[]): Promise { + async stageChanges(changes: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { @@ -574,7 +579,7 @@ export class CommandCenter { const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); - const selectedDiffs = diffs + const selectedDiffs = changes .map(diff => selectedLines.reduce((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null)) .filter(d => !!d) as LineChange[]; @@ -587,8 +592,13 @@ export class CommandCenter { await this.runByRepository(modifiedUri, async (repository, resource) => await repository.stage(resource, result)); } + @command('git.revertChange') + async revertChange(change: LineChange): Promise { + await this.revertChanges([change]); + } + @command('git.revertSelectedRanges', { diff: true }) - async revertSelectedRanges(diffs: LineChange[]): Promise { + async revertChanges(diffs: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { diff --git a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css index 8a3041ee368..3e253ab57b7 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css @@ -39,20 +39,23 @@ height: 100%; } +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-item { + margin-left: 4px; +} + .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label { + width: 16px; + height: 100%; + margin: 0; line-height: inherit; + background-repeat: no-repeat; + background-position: center center; } .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label.octicon { margin: 0; } -.monaco-editor .peekview-widget .head .peekview-actions .action-label { - width: 16px; - height: 100%; - margin: 0; -} - .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action { background: url('close.svg') center center no-repeat; } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 0ebbab71551..4f7f950ec97 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -53,6 +53,7 @@ export class MenuId { static readonly SCMSourceControl = new MenuId(); static readonly SCMResourceGroupContext = new MenuId(); static readonly SCMResourceContext = new MenuId(); + static readonly SCMChangeContext = new MenuId(); static readonly CommandPalette = new MenuId(); static readonly ViewTitle = new MenuId(); static readonly ViewItemContext = new MenuId(); diff --git a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts index 184962e9227..ca45e187101 100644 --- a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts @@ -40,6 +40,7 @@ namespace schema { case 'scm/sourceControl': return MenuId.SCMSourceControl; case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext; case 'scm/resourceState/context': return MenuId.SCMResourceContext; + case 'scm/change/title': return MenuId.SCMChangeContext; case 'view/title': return MenuId.ViewTitle; case 'view/item/context': return MenuId.ViewItemContext; } diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 9174eb7626d..e1b14714357 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -16,7 +16,7 @@ import * as ext from 'vs/workbench/common/contributions'; import * as common from 'vs/editor/common/editorCommon'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -43,10 +43,27 @@ import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRe import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { Action } from 'vs/base/common/actions'; -import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Action, IAction } from 'vs/base/common/actions'; +import { IActionBarOptions, ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { basename } from 'vs/base/common/paths'; +import { MenuId, IMenuService, IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { fillInActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; + +// TODO@Joao +// Need to subclass MenuItemActionItem in order to respect +// the action context coming from any action bar, without breaking +// existing users +class DiffMenuItemActionItem extends MenuItemActionItem { + + onClick(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + + this.actionRunner.run(this._commandAction, this._context) + .done(undefined, err => this._messageService.show(Severity.Error, err)); + } +} export interface IModelRegistry { getModel(editorModel: common.IEditorModel): DirtyDiffModel; @@ -115,22 +132,31 @@ class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; private title: string; + private menu: IMenu; private change: common.IChange; private didLayout = false; + private contextKeyService: IContextKeyService; constructor( editor: ICodeEditor, private model: DirtyDiffModel, - themeService: IThemeService, - private instantiationService: IInstantiationService + @IThemeService themeService: IThemeService, + @IInstantiationService private instantiationService: IInstantiationService, + @IMenuService private menuService: IMenuService, + @IKeybindingService private keybindingService: IKeybindingService, + @IMessageService private messageService: IMessageService, + @IContextKeyService contextKeyService: IContextKeyService ) { super(editor, { isResizeable: true }); themeService.onThemeChange(this._applyTheme, this, this._disposables); this._applyTheme(themeService.getTheme()); - this.create(); + this.contextKeyService = contextKeyService.createScoped(); + this.contextKeyService.createKey('originalResourceScheme', this.model.original.uri.scheme); + this.menu = menuService.createMenu(MenuId.SCMChangeContext, this.contextKeyService); + this.create(); this.title = basename(editor.getModel().uri.fsPath); this.setTitle(this.title); } @@ -161,7 +187,7 @@ class DirtyDiffWidget extends PeekViewWidget { : localize('change', "{0} of {1} change", index + 1, this.model.changes.length); this.setTitle(this.title, detail); - + this._actionbarWidget.context = change; this.show(position, height); } @@ -174,14 +200,27 @@ class DirtyDiffWidget extends PeekViewWidget { this._disposables.push(previous); this._disposables.push(next); this._actionbarWidget.push([previous, next], { label: false, icon: true }); + + const actions: IAction[] = []; + fillInActions(this.menu, { shouldForwardArgs: true }, actions); + this._actionbarWidget.push(actions, { label: false, icon: true }); } protected _getActionBarOptions(): IActionBarOptions { return { + actionItemProvider: action => this.getActionItem(action), orientation: ActionsOrientation.HORIZONTAL_REVERSE }; } + getActionItem(action: IAction): IActionItem { + if (!(action instanceof MenuItemAction)) { + return undefined; + } + + return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService); + } + protected _fillBody(container: HTMLElement): void { const options: IDiffEditorOptions = { scrollBeyondLastLine: true, @@ -395,7 +434,7 @@ export class DirtyDiffController implements common.IEditorContribution { this.changeIndex = -1; this.model = model; - this.widget = new DirtyDiffWidget(this.editor, model, this.themeService, this.instantiationService); + this.widget = this.instantiationService.createInstance(DirtyDiffWidget, this.editor, model); this.isDirtyDiffVisible.set(true); // TODO react on model changes From 45fa36902ead1189c6d55ece66a8c0ba767ef419 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 15:27:37 +0200 Subject: [PATCH 112/303] diff: snappier stage --- extensions/git/src/contentProvider.ts | 19 ++++++++++++++----- extensions/git/src/model.ts | 12 ++++++++++++ extensions/git/src/repository.ts | 4 ++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index 4e591c1ae32..4363c80af8e 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -7,8 +7,8 @@ import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode'; import { debounce, throttle } from './decorators'; -import { fromGitUri } from './uri'; -import { Model, ModelChangeEvent } from './model'; +import { fromGitUri, toGitUri } from './uri'; +import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model'; import { filterEvent, eventToPromise } from './util'; interface CacheRow { @@ -25,8 +25,8 @@ const FIVE_MINUTES = 1000 * 60 * 5; export class GitContentProvider { - private onDidChangeEmitter = new EventEmitter(); - get onDidChange(): Event { return this.onDidChangeEmitter.event; } + private _onDidChange = new EventEmitter(); + get onDidChange(): Event { return this._onDidChange.event; } private changedRepositoryRoots = new Set(); private cache: Cache = Object.create(null); @@ -35,6 +35,7 @@ export class GitContentProvider { constructor(private model: Model) { this.disposables.push( model.onDidChangeRepository(this.onDidChangeRepository, this), + model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this), workspace.registerTextDocumentContentProvider('git', this) ); @@ -46,6 +47,14 @@ export class GitContentProvider { this.eventuallyFireChangeEvents(); } + private onDidChangeOriginalResource({ uri }: OriginalResourceChangeEvent): void { + if (uri.scheme !== 'file') { + return; + } + + this._onDidChange.fire(toGitUri(uri, '', true)); + } + @debounce(1100) private eventuallyFireChangeEvents(): void { this.fireChangeEvents(); @@ -64,7 +73,7 @@ export class GitContentProvider { for (const root of this.changedRepositoryRoots) { if (fsPath.startsWith(root)) { - this.onDidChangeEmitter.fire(uri); + this._onDidChange.fire(uri); return; } } diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 93a809a20fe..be87561ae9a 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -35,6 +35,11 @@ export interface ModelChangeEvent { uri: Uri; } +export interface OriginalResourceChangeEvent { + repository: Repository; + uri: Uri; +} + interface OpenRepository extends Disposable { repository: Repository; } @@ -54,6 +59,9 @@ export class Model { private _onDidChangeRepository = new EventEmitter(); readonly onDidChangeRepository: Event = this._onDidChangeRepository.event; + private _onDidChangeOriginalResource = new EventEmitter(); + readonly onDidChangeOriginalResource: Event = this._onDidChangeOriginalResource.event; + private openRepositories: OpenRepository[] = []; get repositories(): Repository[] { return this.openRepositories.map(r => r.repository); } @@ -217,10 +225,14 @@ export class Model { const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === RepositoryState.Disposed); const disappearListener = onDidDisappearRepository(() => dispose()); const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri })); + const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri })); + const dispose = () => { disappearListener.dispose(); changeListener.dispose(); + originalResourceChangeListener.dispose(); repository.dispose(); + this.openRepositories = this.openRepositories.filter(e => e !== openRepository); this._onDidCloseRepository.fire(repository); }; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index f4dab0e46e5..6c9f781c58f 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -315,6 +315,9 @@ export class Repository implements Disposable { private _onDidChangeStatus = new EventEmitter(); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + private _onDidChangeOriginalResource = new EventEmitter(); + readonly onDidChangeOriginalResource: Event = this._onDidChangeOriginalResource.event; + private _onRunOperation = new EventEmitter(); readonly onRunOperation: Event = this._onRunOperation.event; @@ -460,6 +463,7 @@ export class Repository implements Disposable { async stage(resource: Uri, contents: string): Promise { const relativePath = path.relative(this.repository.root, resource.fsPath).replace(/\\/g, '/'); await this.run(Operation.Stage, () => this.repository.stage(relativePath, contents)); + this._onDidChangeOriginalResource.fire(resource); } async revert(resources: Uri[]): Promise { From 0ff01981c745656853558cf51b783214bc530bd8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 15:34:43 +0200 Subject: [PATCH 113/303] diff: model change --- .../electron-browser/dirtydiffDecorator.ts | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e1b14714357..bceeb5d30ce 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -13,7 +13,6 @@ import { IDisposable, dispose, toDisposable, empty as EmptyDisposable, combinedD import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter, any as anyEvent, filterEvent, once } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; -import * as common from 'vs/editor/common/editorCommon'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; @@ -49,6 +48,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { basename } from 'vs/base/common/paths'; import { MenuId, IMenuService, IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; import { fillInActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; +import { IChange, ICommonCodeEditor, IEditorModel, ScrollType, IEditorContribution, OverviewRulerLane, IModel } from 'vs/editor/common/editorCommon'; // TODO@Joao // Need to subclass MenuItemActionItem in order to respect @@ -66,12 +66,12 @@ class DiffMenuItemActionItem extends MenuItemActionItem { } export interface IModelRegistry { - getModel(editorModel: common.IEditorModel): DirtyDiffModel; + getModel(editorModel: IEditorModel): DirtyDiffModel; } export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', false); -function getChangeHeight(change: common.IChange): number { +function getChangeHeight(change: IChange): number { const modified = change.modifiedEndLineNumber - change.modifiedStartLineNumber + 1; const original = change.originalEndLineNumber - change.originalStartLineNumber + 1; @@ -84,7 +84,7 @@ function getChangeHeight(change: common.IChange): number { } } -function getModifiedEndLineNumber(change: common.IChange): number { +function getModifiedEndLineNumber(change: IChange): number { if (change.modifiedEndLineNumber === 0) { return change.modifiedStartLineNumber; } else { @@ -92,7 +92,7 @@ function getModifiedEndLineNumber(change: common.IChange): number { } } -function getModifiedMiddleLineNumber(change: common.IChange): number { +function getModifiedMiddleLineNumber(change: IChange): number { if (change.modifiedEndLineNumber === 0) { return change.modifiedStartLineNumber; } else { @@ -102,12 +102,12 @@ function getModifiedMiddleLineNumber(change: common.IChange): number { class UIEditorAction extends Action { - private editor: common.ICommonCodeEditor; + private editor: ICommonCodeEditor; private action: EditorAction; private instantiationService: IInstantiationService; constructor( - editor: common.ICommonCodeEditor, + editor: ICommonCodeEditor, action: EditorAction, cssClass: string, @IKeybindingService keybindingService: IKeybindingService, @@ -133,7 +133,7 @@ class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; private title: string; private menu: IMenu; - private change: common.IChange; + private change: IChange; private didLayout = false; private contextKeyService: IContextKeyService; @@ -159,6 +159,12 @@ class DirtyDiffWidget extends PeekViewWidget { this.create(); this.title = basename(editor.getModel().uri.fsPath); this.setTitle(this.title); + + model.onDidChange(this.onDidChange, this, this._disposables); + } + + private onDidChange(changes: IChange[]): void { + // need to update! } showChange(index: number): void { @@ -250,9 +256,9 @@ class DirtyDiffWidget extends PeekViewWidget { } } - private revealChange(change: common.IChange): void { + private revealChange(change: IChange): void { const position = new Position(getModifiedMiddleLineNumber(this.change), 1); - this.diffEditor.revealPositionInCenter(position, common.ScrollType.Immediate); + this.diffEditor.revealPositionInCenter(position, ScrollType.Immediate); } private _applyTheme(theme: ITheme) { @@ -280,7 +286,7 @@ export class ShowPreviousChangeAction extends EditorAction { }); } - run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { + run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { const controller = DirtyDiffController.get(editor); if (!controller) { @@ -304,7 +310,7 @@ export class ShowNextChangeAction extends EditorAction { }); } - run(accessor: ServicesAccessor, editor: common.ICommonCodeEditor): void { + run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { const controller = DirtyDiffController.get(editor); if (!controller) { @@ -338,11 +344,11 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ }); @editorContribution -export class DirtyDiffController implements common.IEditorContribution { +export class DirtyDiffController implements IEditorContribution { private static ID = 'editor.contrib.dirtydiff'; - static get(editor: common.ICommonCodeEditor): DirtyDiffController { + static get(editor: ICommonCodeEditor): DirtyDiffController { return editor.getContribution(DirtyDiffController.ID); } @@ -437,13 +443,9 @@ export class DirtyDiffController implements common.IEditorContribution { this.widget = this.instantiationService.createInstance(DirtyDiffWidget, this.editor, model); this.isDirtyDiffVisible.set(true); - // TODO react on model changes - - // const range = editor.getSelection(); - // this.widget.show(range, 18); - const disposables: IDisposable[] = []; once(this.widget.onDidClose)(this.close, this, disposables); + model.onDidChange(this.onDidModelChange, this, disposables); disposables.push( this.widget, @@ -455,6 +457,11 @@ export class DirtyDiffController implements common.IEditorContribution { return true; } + private onDidModelChange(changes: IChange[]): void { + // TODO + console.log('model changed!'); + } + private findNextClosestChange(lineNumber: number): number { for (let i = 0; i < this.model.changes.length; i++) { const change = this.model.changes[i]; @@ -516,7 +523,7 @@ class DirtyDiffDecorator { overviewRuler: { color: themeColorFromId(overviewRulerModifiedForeground), darkColor: themeColorFromId(overviewRulerModifiedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); @@ -526,7 +533,7 @@ class DirtyDiffDecorator { overviewRuler: { color: themeColorFromId(overviewRulerAddedForeground), darkColor: themeColorFromId(overviewRulerAddedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); @@ -536,7 +543,7 @@ class DirtyDiffDecorator { overviewRuler: { color: themeColorFromId(overviewRulerDeletedForeground), darkColor: themeColorFromId(overviewRulerDeletedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); @@ -544,13 +551,13 @@ class DirtyDiffDecorator { private disposables: IDisposable[] = []; constructor( - private editorModel: common.IModel, + private editorModel: IModel, private model: DirtyDiffModel ) { model.onDidChange(this.onDidChange, this, this.disposables); } - private onDidChange(diff: common.IChange[]): void { + private onDidChange(diff: IChange[]): void { const decorations = diff.map((change) => { const startLineNumber = change.modifiedStartLineNumber; const endLineNumber = change.modifiedEndLineNumber || startLineNumber; @@ -604,25 +611,25 @@ class DirtyDiffDecorator { export class DirtyDiffModel { - private _originalModel: common.IModel; - get original(): common.IModel { return this._originalModel; } - get modified(): common.IModel { return this._editorModel; } + private _originalModel: IModel; + get original(): IModel { return this._originalModel; } + get modified(): IModel { return this._editorModel; } - private diffDelayer: ThrottledDelayer; + private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; private repositoryDisposables = new Set(); private disposables: IDisposable[] = []; - private _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private _onDidChange = new Emitter(); + readonly onDidChange: Event = this._onDidChange.event; - private _changes: common.IChange[] = []; - get changes(): common.IChange[] { + private _changes: IChange[] = []; + get changes(): IChange[] { return this._changes; } constructor( - private _editorModel: common.IModel, + private _editorModel: IModel, @ISCMService private scmService: ISCMService, @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, @@ -630,7 +637,7 @@ export class DirtyDiffModel { @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextModelService private textModelResolverService: ITextModelService ) { - this.diffDelayer = new ThrottledDelayer(200); + this.diffDelayer = new ThrottledDelayer(200); this.disposables.push(_editorModel.onDidChangeContent(() => this.triggerDiff())); scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); @@ -661,7 +668,7 @@ export class DirtyDiffModel { return this.diffDelayer .trigger(() => this.diff()) - .then((changes: common.IChange[]) => { + .then((changes: IChange[]) => { if (!this._editorModel || this._editorModel.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) { return undefined; // disposed } @@ -675,7 +682,7 @@ export class DirtyDiffModel { }); } - private diff(): TPromise { + private diff(): TPromise { return this.getOriginalURIPromise().then(originalURI => { if (!this._editorModel || this._editorModel.isDisposed() || !originalURI) { return TPromise.as([]); // disposed @@ -757,7 +764,7 @@ class DirtyDiffItem { export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, IModelRegistry { - private models: common.IModel[] = []; + private models: IModel[] = []; private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); private disposables: IDisposable[] = []; @@ -808,19 +815,19 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, this.models = models; } - private onModelVisible(editorModel: common.IModel): void { + private onModelVisible(editorModel: IModel): void { const model = this.instantiationService.createInstance(DirtyDiffModel, editorModel); const decorator = new DirtyDiffDecorator(editorModel, model); this.items[editorModel.id] = new DirtyDiffItem(model, decorator); } - private onModelInvisible(editorModel: common.IModel): void { + private onModelInvisible(editorModel: IModel): void { this.items[editorModel.id].dispose(); delete this.items[editorModel.id]; } - getModel(editorModel: common.IModel): DirtyDiffModel | null { + getModel(editorModel: IModel): DirtyDiffModel | null { const item = this.items[editorModel.id]; if (!item) { From c6ac991a52fd19f0c7712439eb0300febfdaf788 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 15:40:35 +0200 Subject: [PATCH 114/303] debt - remove apiUsage telemetry --- src/vs/workbench/api/node/extHost.api.impl.ts | 45 ------------------- .../api/node/extHostLanguageFeatures.ts | 4 +- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 87c5a26ce68..0df38e8773f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -81,8 +81,6 @@ export function createApiFactory( extensionService: ExtHostExtensionService ): IExtensionApiFactory { - const mainThreadTelemetry = threadService.get(MainContext.MainThreadTelemetry); - // Addressable instances const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService()); const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService)); @@ -140,29 +138,6 @@ export function createApiFactory( } } - const apiUsage = new class { - private _seen = new Set(); - publicLog(apiName: string) { - if (this._seen.has(apiName)) { - return undefined; - } - this._seen.add(apiName); - /* __GDPR__ - "apiUsage" : { - "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ - "${MainThreadData}" - ] - } - */ - return mainThreadTelemetry.$publicLog('apiUsage', { - name: apiName, - extension: extension.id - }); - } - }; - // namespace: commands const commands: typeof vscode.commands = { registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { @@ -407,22 +382,18 @@ export function createApiFactory( // namespace: workspace const workspace: typeof vscode.workspace = { get rootPath() { - apiUsage.publicLog('workspace#rootPath'); return extHostWorkspace.getPath(); }, set rootPath(value) { throw errors.readonly(); }, getWorkspaceFolder(resource) { - apiUsage.publicLog('workspace#getWorkspaceFolder'); return extHostWorkspace.getWorkspaceFolder(resource); }, get workspaceFolders() { - apiUsage.publicLog('workspace#workspaceFolders'); return extHostWorkspace.getWorkspaceFolders(); }, onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { - apiUsage.publicLog('workspace#onDidChangeWorkspaceFolders'); return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); }, asRelativePath: (pathOrUri, includeWorkspace) => { @@ -505,22 +476,6 @@ export function createApiFactory( return extHostSCM.getLastInputBox(extension); }, createSourceControl(id: string, label: string, rootUri?: vscode.Uri) { - /* __GDPR__ - "registerSCMProvider" : { - "extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "providerId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, - "providerLabel": { "classification": "PublicPersonalData", "purpose": "FeatureInsight" }, - "${include}": [ - "${MainThreadData}" - ] - } - */ - mainThreadTelemetry.$publicLog('registerSCMProvider', { - extensionId: extension.id, - providerId: id, - providerLabel: label - }); - return extHostSCM.createSourceControl(extension, id, label, rootUri); } }; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index c3764b060d5..4a6a22e86f0 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -18,7 +18,7 @@ import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHos import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadTelemetryShape, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion } from './extHost.protocol'; +import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion } from './extHost.protocol'; import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; @@ -748,7 +748,6 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; private _proxy: MainThreadLanguageFeaturesShape; - private _telemetry: MainThreadTelemetryShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; private _heapService: ExtHostHeapService; @@ -764,7 +763,6 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { diagnostics: ExtHostDiagnostics ) { this._proxy = mainContext.get(MainContext.MainThreadLanguageFeatures); - this._telemetry = mainContext.get(MainContext.MainThreadTelemetry); this._documents = documents; this._commands = commands; this._heapService = heapMonitor; From 08597e3aaf98622098e983512b92dc7faea9e270 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 6 Oct 2017 11:18:11 +0200 Subject: [PATCH 115/303] [css] update service & server --- extensions/css/npm-shrinkwrap.json | 23 ++++++++++---------- extensions/css/package.json | 3 +-- extensions/css/server/npm-shrinkwrap.json | 26 +++++++++++------------ extensions/css/server/package.json | 5 ++--- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/extensions/css/npm-shrinkwrap.json b/extensions/css/npm-shrinkwrap.json index 0cb7377ce6d..2a022a155e1 100644 --- a/extensions/css/npm-shrinkwrap.json +++ b/extensions/css/npm-shrinkwrap.json @@ -2,26 +2,25 @@ "name": "css", "version": "0.1.0", "dependencies": { - "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageclient": { - "version": "3.4.2", + "version": "3.5.0-next.3", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.3.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.3 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/package.json b/extensions/css/package.json index c9b0c82f1de..d124a1430f7 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -720,8 +720,7 @@ ] }, "dependencies": { - "vscode-languageclient": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2", + "vscode-languageclient": "^3.5.0-next.3", "vscode-nls": "^2.0.2" }, "devDependencies": { diff --git a/extensions/css/server/npm-shrinkwrap.json b/extensions/css/server/npm-shrinkwrap.json index 1b647cda8c7..8325a987e91 100644 --- a/extensions/css/server/npm-shrinkwrap.json +++ b/extensions/css/server/npm-shrinkwrap.json @@ -3,29 +3,29 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.9", + "version": "2.1.10", "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.9.tgz" + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.10.tgz" }, "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageserver": { - "version": "3.4.2", + "version": "3.5.0-next.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.2 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/server/package.json b/extensions/css/server/package.json index 841cb4d9cf4..1feda7d7f9d 100644 --- a/extensions/css/server/package.json +++ b/extensions/css/server/package.json @@ -8,9 +8,8 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.9", - "vscode-languageserver": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2" + "vscode-css-languageservice": "^2.1.10", + "vscode-languageserver": "^3.5.0-next.2" }, "devDependencies": { "@types/node": "7.0.43" From c6b980c67233860e0b4e2cd33ca65322c0e31240 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 6 Oct 2017 11:27:57 +0200 Subject: [PATCH 116/303] [html] update server --- extensions/html/npm-shrinkwrap.json | 27 +++++++++------------- extensions/html/package.json | 8 +++---- extensions/html/server/npm-shrinkwrap.json | 26 ++++++++++----------- extensions/html/server/package.json | 6 ++--- 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/extensions/html/npm-shrinkwrap.json b/extensions/html/npm-shrinkwrap.json index 97c20854f46..ab1071727c3 100644 --- a/extensions/html/npm-shrinkwrap.json +++ b/extensions/html/npm-shrinkwrap.json @@ -7,35 +7,30 @@ "from": "applicationinsights@0.18.0", "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz" }, - "color-convert": { - "version": "0.5.3", - "from": "color-convert@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz" - }, "vscode-extension-telemetry": { "version": "0.0.8", "from": "vscode-extension-telemetry@>=0.0.8 <0.0.9", "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageclient": { - "version": "3.4.2", + "version": "3.5.0-next.3", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.3.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@3.4.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.3 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@3.4.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/html/package.json b/extensions/html/package.json index 7b7fe521038..b197a2c386f 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -17,8 +17,8 @@ "compile": "gulp compile-extension:html-client && gulp compile-extension:html-server", "postinstall": "cd server && npm install", "update-grammar": "node ../../build/npm/update-grammar.js textmate/html.tmbundle Syntaxes/HTML.plist ./syntaxes/html.json", - "install-client-next": "npm install vscode-languageserver-types -f -S && npm install vscode-languageclient@next -f -S", - "install-client-local": "npm install ../../../vscode-languageserver-node/types -f -S && npm install ../../../vscode-languageserver-node/client -f -S" + "install-client-next": "npm install vscode-languageclient@next -f -S", + "install-client-local": "npm install ../../../vscode-languageserver-node/client -f -S" }, "contributes": { "languages": [ @@ -216,9 +216,7 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2", - "vscode-languageserver-types": "^3.4.0", + "vscode-languageclient": "^3.5.0-next.3", "vscode-nls": "2.0.2" }, "devDependencies": { diff --git a/extensions/html/server/npm-shrinkwrap.json b/extensions/html/server/npm-shrinkwrap.json index e293aa9b417..3658a9a092c 100644 --- a/extensions/html/server/npm-shrinkwrap.json +++ b/extensions/html/server/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.9", + "version": "2.1.10", "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.9.tgz" + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.10.tgz" }, "vscode-html-languageservice": { "version": "2.0.10", @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.10.tgz" }, "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageserver": { - "version": "3.4.2", + "version": "3.5.0-next.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@3.4.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.2 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@3.4.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json index 6fdf5cfc678..e0c26108be7 100644 --- a/extensions/html/server/package.json +++ b/extensions/html/server/package.json @@ -8,11 +8,9 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.9", + "vscode-css-languageservice": "^2.1.10", "vscode-html-languageservice": "^2.0.10", - "vscode-languageserver": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2", - "vscode-languageserver-types": "^3.4.0", + "vscode-languageserver": "^3.5.0-next.2", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" }, From 4a170ddebcddaf417292b1fd36fe1c8832baf3dd Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 6 Oct 2017 12:08:14 +0200 Subject: [PATCH 117/303] iconTheme: null shouldn't show a warning. Fixes #35692 --- .../services/themes/electron-browser/workbenchThemeService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 6766e10bc34..ebfa30130f3 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -153,8 +153,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { configurationRegistry.notifyConfigurationSchemaUpdated(colorThemeSettingSchema); }); this.iconThemeStore.onDidChange(themes => { - iconThemeSettingSchema.enum = themes.map(t => t.settingsId); - iconThemeSettingSchema.enumDescriptions = themes.map(t => themeData.description || ''); + iconThemeSettingSchema.enum = [null, ...themes.map(t => t.settingsId)]; + iconThemeSettingSchema.enumDescriptions = [iconThemeSettingSchema.enumDescriptions[0], ...themes.map(t => themeData.description || '')]; configurationRegistry.notifyConfigurationSchemaUpdated(iconThemeSettingSchema); }); } From a5f49516c1a0b070ed14b2d8073067fa71592ee5 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 11 Oct 2017 16:01:39 +0200 Subject: [PATCH 118/303] [json] update server & service --- extensions/json/npm-shrinkwrap.json | 24 ++++++++++---------- extensions/json/package.json | 3 +-- extensions/json/server/npm-shrinkwrap.json | 26 +++++++++++----------- extensions/json/server/package.json | 6 ++--- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/extensions/json/npm-shrinkwrap.json b/extensions/json/npm-shrinkwrap.json index 2b10b555249..edf04fe0a48 100644 --- a/extensions/json/npm-shrinkwrap.json +++ b/extensions/json/npm-shrinkwrap.json @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageclient": { - "version": "3.4.2", + "version": "3.5.0-next.3", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.3.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@3.4.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.3 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", @@ -43,4 +43,4 @@ "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz" } } -} \ No newline at end of file +} diff --git a/extensions/json/package.json b/extensions/json/package.json index c27ae547702..b85adbd6fad 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -133,8 +133,7 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2", + "vscode-languageclient": "^3.5.0-next.3", "vscode-nls": "2.0.2" }, "devDependencies": { diff --git a/extensions/json/server/npm-shrinkwrap.json b/extensions/json/server/npm-shrinkwrap.json index 31c46482d9a..13925889795 100644 --- a/extensions/json/server/npm-shrinkwrap.json +++ b/extensions/json/server/npm-shrinkwrap.json @@ -43,29 +43,29 @@ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz" }, "vscode-json-languageservice": { - "version": "2.0.20", + "version": "2.0.21", "from": "vscode-json-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.20.tgz" + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.21.tgz" }, "vscode-jsonrpc": { - "version": "3.4.0", - "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-jsonrpc@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.1.tgz" }, "vscode-languageserver": { - "version": "3.4.2", + "version": "3.5.0-next.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.4.2", - "from": "vscode-languageserver-protocol@3.4.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" + "version": "3.5.0-next.3", + "from": "vscode-languageserver-protocol@>=3.5.0-next.2 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" }, "vscode-languageserver-types": { - "version": "3.4.0", - "from": "vscode-languageserver-types@3.4.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 8c9a7a3f113..3e4dfd6508f 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -10,10 +10,8 @@ "dependencies": { "jsonc-parser": "^1.0.0", "request-light": "^0.2.1", - "vscode-json-languageservice": "^2.0.20", - "vscode-languageserver": "^3.4.2", - "vscode-languageserver-protocol": "^3.4.2", - "vscode-languageserver-types": "^3.4.0", + "vscode-json-languageservice": "^2.0.21", + "vscode-languageserver": "^3.5.0-next.2", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" }, From 90fc26ca2cea6a0036c9d2d723d67e7536e00613 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 16:05:14 +0200 Subject: [PATCH 119/303] diff: react to changes --- .../electron-browser/dirtydiffDecorator.ts | 79 ++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index bceeb5d30ce..a68eb675d73 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -49,6 +49,7 @@ import { basename } from 'vs/base/common/paths'; import { MenuId, IMenuService, IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; import { fillInActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; import { IChange, ICommonCodeEditor, IEditorModel, ScrollType, IEditorContribution, OverviewRulerLane, IModel } from 'vs/editor/common/editorCommon'; +import { sortedDiff, Splice } from 'vs/base/common/arrays'; // TODO@Joao // Need to subclass MenuItemActionItem in order to respect @@ -133,6 +134,7 @@ class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; private title: string; private menu: IMenu; + private index: number; private change: IChange; private didLayout = false; private contextKeyService: IContextKeyService; @@ -160,15 +162,12 @@ class DirtyDiffWidget extends PeekViewWidget { this.title = basename(editor.getModel().uri.fsPath); this.setTitle(this.title); - model.onDidChange(this.onDidChange, this, this._disposables); - } - - private onDidChange(changes: IChange[]): void { - // need to update! + model.onDidChange(this.renderTitle, this, this._disposables); } showChange(index: number): void { const change = this.model.changes[index]; + this.index = index; this.change = change; const originalModel = this.model.original; @@ -188,15 +187,19 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(getModifiedEndLineNumber(change), 1); const height = getChangeHeight(change) + /* padding */ 8; - const detail = this.model.changes.length > 1 - ? localize('changes', "{0} of {1} changes", index + 1, this.model.changes.length) - : localize('change', "{0} of {1} change", index + 1, this.model.changes.length); - - this.setTitle(this.title, detail); + this.renderTitle(); this._actionbarWidget.context = change; this.show(position, height); } + private renderTitle(): void { + const detail = this.model.changes.length > 1 + ? localize('changes', "{0} of {1} changes", this.index + 1, this.model.changes.length) + : localize('change', "{0} of {1} change", this.index + 1, this.model.changes.length); + + this.setTitle(this.title, detail); + } + protected _fillHead(container: HTMLElement): void { super._fillHead(container); @@ -356,7 +359,8 @@ export class DirtyDiffController implements IEditorContribution { private model: DirtyDiffModel | null = null; private widget: DirtyDiffWidget | null = null; - private changeIndex: number = -1; + private currentLineNumber: number = -1; + private currentIndex: number = -1; private readonly isDirtyDiffVisible: IContextKey; private session: IDisposable = EmptyDisposable; @@ -378,13 +382,16 @@ export class DirtyDiffController implements IEditorContribution { return; } - if (this.changeIndex === -1) { - this.changeIndex = this.findNextClosestChange(this.editor.getPosition().lineNumber); + if (this.currentIndex === -1) { + this.currentIndex = this.findNextClosestChange(this.editor.getPosition().lineNumber); } else { - this.changeIndex = rot(this.changeIndex + 1, this.model.changes.length); + this.currentIndex = rot(this.currentIndex + 1, this.model.changes.length); } - this.widget.showChange(this.changeIndex); + const change = this.model.changes[this.currentIndex]; + this.currentLineNumber = change.modifiedStartLineNumber; + + this.widget.showChange(this.currentIndex); } previous(): void { @@ -392,13 +399,16 @@ export class DirtyDiffController implements IEditorContribution { return; } - if (this.changeIndex === -1) { - this.changeIndex = this.findPreviousClosestChange(this.editor.getPosition().lineNumber); + if (this.currentIndex === -1) { + this.currentIndex = this.findPreviousClosestChange(this.editor.getPosition().lineNumber); } else { - this.changeIndex = rot(this.changeIndex - 1, this.model.changes.length); + this.currentIndex = rot(this.currentIndex - 1, this.model.changes.length); } - this.widget.showChange(this.changeIndex); + const change = this.model.changes[this.currentIndex]; + this.currentLineNumber = change.modifiedStartLineNumber; + + this.widget.showChange(this.currentIndex); } close(): void { @@ -438,7 +448,7 @@ export class DirtyDiffController implements IEditorContribution { return false; } - this.changeIndex = -1; + this.currentIndex = -1; this.model = model; this.widget = this.instantiationService.createInstance(DirtyDiffWidget, this.editor, model); this.isDirtyDiffVisible.set(true); @@ -457,9 +467,18 @@ export class DirtyDiffController implements IEditorContribution { return true; } - private onDidModelChange(changes: IChange[]): void { - // TODO - console.log('model changed!'); + private onDidModelChange(splices: Splice[]): void { + for (const splice of splices) { + if (splice.start <= this.currentIndex) { + if (this.currentIndex < splice.start + splice.deleteCount) { + this.currentIndex = -1; + this.next(); + } else { + this.currentIndex = rot(this.currentIndex + splice.inserted.length - splice.deleteCount - 1, this.model.changes.length); + this.next(); + } + } + } } private findNextClosestChange(lineNumber: number): number { @@ -557,8 +576,8 @@ class DirtyDiffDecorator { model.onDidChange(this.onDidChange, this, this.disposables); } - private onDidChange(diff: IChange[]): void { - const decorations = diff.map((change) => { + private onDidChange(): void { + const decorations = this.model.changes.map((change) => { const startLineNumber = change.modifiedStartLineNumber; const endLineNumber = change.modifiedEndLineNumber || startLineNumber; @@ -620,8 +639,8 @@ export class DirtyDiffModel { private repositoryDisposables = new Set(); private disposables: IDisposable[] = []; - private _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private _onDidChange = new Emitter[]>(); + readonly onDidChange: Event[]> = this._onDidChange.event; private _changes: IChange[] = []; get changes(): IChange[] { @@ -677,8 +696,12 @@ export class DirtyDiffModel { changes = []; } + const diff = sortedDiff(this._changes, changes, (a, b) => b.modifiedStartLineNumber - a.modifiedStartLineNumber); this._changes = changes; - this._onDidChange.fire(changes); + + if (diff.length > 0) { + this._onDidChange.fire(diff); + } }); } From 240b0cb4c9e97112c7602bba765025714a6aabbf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 16:20:55 +0200 Subject: [PATCH 120/303] fix typo --- src/vs/editor/contrib/snippet/browser/snippet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/snippet/browser/snippet.md b/src/vs/editor/contrib/snippet/browser/snippet.md index c0de625a589..458cccbdb96 100644 --- a/src/vs/editor/contrib/snippet/browser/snippet.md +++ b/src/vs/editor/contrib/snippet/browser/snippet.md @@ -34,7 +34,7 @@ Variable-Transform Transformations allow to modify the value of a variable before it is being inserted. The definition of a transformation consists of three parts: 1. A regular expression that is matched against the value of a variable, or the empty string when the variable cannot be resolved. -2. A "format string" that allows to reference matching groups from the regular expression. The format string also for conditional inserts and simple modifications. +2. A "format string" that allows to reference matching groups from the regular expression. The format string allows for conditional inserts and simple modifications. 3. Options that are passed to the regular expression The following sample inserts the name of the current file without its ending, so from `foo.txt` it makes `foo`. From 1f058ae1cbf64c5c669b49026ceef71a4fb37441 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 17:17:10 +0200 Subject: [PATCH 121/303] diff: fix stage/revert ranges --- extensions/git/src/commands.ts | 85 ++++++++++++------- .../electron-browser/dirtydiffDecorator.ts | 16 +++- 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index d23b9cd3738..64dd80ceaa3 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5,7 +5,7 @@ 'use strict'; -import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation } from 'vscode'; +import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor } from 'vscode'; import { Ref, RefType, Git, GitErrorCodes, Branch } from './git'; import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository'; import { Model } from './model'; @@ -557,18 +557,38 @@ export class CommandCenter { } @command('git.stageChange') - async stageChange(change: LineChange): Promise { - await this.stageChanges([change]); + async stageChange(uri: Uri, changes: LineChange[], index: number): Promise { + const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0]; + + if (!textEditor) { + return; + } + + await this._stageChanges(textEditor, [changes[index]]); } @command('git.stageSelectedRanges', { diff: true }) - async stageChanges(changes: LineChange[]): Promise { + async stageSelectedChanges(changes: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { return; } + const modifiedDocument = textEditor.document; + const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); + const selectedChanges = changes + .map(diff => selectedLines.reduce((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null)) + .filter(d => !!d) as LineChange[]; + + if (!selectedChanges.length) { + return; + } + + await this._stageChanges(textEditor, selectedChanges); + } + + private async _stageChanges(textEditor: TextEditor, changes: LineChange[]): Promise { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; @@ -578,33 +598,48 @@ export class CommandCenter { const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); - const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); - const selectedDiffs = changes - .map(diff => selectedLines.reduce((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null)) - .filter(d => !!d) as LineChange[]; - - if (!selectedDiffs.length) { - return; - } - - const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs); + const result = applyLineChanges(originalDocument, modifiedDocument, changes); await this.runByRepository(modifiedUri, async (repository, resource) => await repository.stage(resource, result)); } @command('git.revertChange') - async revertChange(change: LineChange): Promise { - await this.revertChanges([change]); + async revertChange(uri: Uri, changes: LineChange[], index: number): Promise { + const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0]; + + if (!textEditor) { + return; + } + + await this._revertChanges(textEditor, [...changes.slice(0, index), ...changes.slice(index + 1)]); } @command('git.revertSelectedRanges', { diff: true }) - async revertChanges(diffs: LineChange[]): Promise { + async revertSelectedRanges(changes: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { return; } + const modifiedDocument = textEditor.document; + const selections = textEditor.selections; + const selectedChanges = changes.filter(change => { + const modifiedRange = change.modifiedEndLineNumber === 0 + ? new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(change.modifiedStartLineNumber).range.start) + : new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(change.modifiedEndLineNumber - 1).range.end); + + return selections.every(selection => !selection.intersection(modifiedRange)); + }); + + if (selectedChanges.length === changes.length) { + return; + } + + await this._revertChanges(textEditor, selectedChanges); + } + + private async _revertChanges(textEditor: TextEditor, changes: LineChange[]): Promise { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; @@ -614,19 +649,6 @@ export class CommandCenter { const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); - const selections = textEditor.selections; - const selectedDiffs = diffs.filter(diff => { - const modifiedRange = diff.modifiedEndLineNumber === 0 - ? new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(diff.modifiedStartLineNumber).range.start) - : new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end); - - return selections.every(selection => !selection.intersection(modifiedRange)); - }); - - if (selectedDiffs.length === diffs.length) { - return; - } - const basename = path.basename(modifiedUri.fsPath); const message = localize('confirm revert', "Are you sure you want to revert the selected changes in {0}?", basename); const yes = localize('revert', "Revert Changes"); @@ -636,10 +658,11 @@ export class CommandCenter { return; } - const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs); + const result = applyLineChanges(originalDocument, modifiedDocument, changes); const edit = new WorkspaceEdit(); edit.replace(modifiedUri, new Range(new Position(0, 0), modifiedDocument.lineAt(modifiedDocument.lineCount - 1).range.end), result); workspace.applyEdit(edit); + await modifiedDocument.save(); } @command('git.unstage') diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index a68eb675d73..e029cd2df54 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -42,7 +42,7 @@ import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRe import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { Action, IAction } from 'vs/base/common/actions'; +import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { basename } from 'vs/base/common/paths'; @@ -66,6 +66,17 @@ class DiffMenuItemActionItem extends MenuItemActionItem { } } +class DiffActionRunner extends ActionRunner { + + runAction(action: IAction, context: any): TPromise { + if (action instanceof MenuItemAction) { + return action.run(...context); + } + + return super.runAction(action, context); + } +} + export interface IModelRegistry { getModel(editorModel: IEditorModel): DirtyDiffModel; } @@ -188,7 +199,7 @@ class DirtyDiffWidget extends PeekViewWidget { const height = getChangeHeight(change) + /* padding */ 8; this.renderTitle(); - this._actionbarWidget.context = change; + this._actionbarWidget.context = [this.model.modified.uri, this.model.changes, index]; this.show(position, height); } @@ -217,6 +228,7 @@ class DirtyDiffWidget extends PeekViewWidget { protected _getActionBarOptions(): IActionBarOptions { return { + actionRunner: new DiffActionRunner(), actionItemProvider: action => this.getActionItem(action), orientation: ActionsOrientation.HORIZONTAL_REVERSE }; From 1fb361861f8a5420b13b275f1e3899aac4a9cc1d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 11 Oct 2017 17:26:33 +0200 Subject: [PATCH 122/303] [folding] add work boundries to folding markers --- extensions/cpp/language-configuration.json | 4 ++-- extensions/csharp/language-configuration.json | 4 ++-- extensions/fsharp/language-configuration.json | 4 ++-- extensions/javascript/javascript-language-configuration.json | 4 ++-- extensions/powershell/language-configuration.json | 4 ++-- extensions/python/language-configuration.json | 4 ++-- extensions/typescript/language-configuration.json | 4 ++-- extensions/vb/language-configuration.json | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 2888f3edea9..9c297115ac4 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -28,8 +28,8 @@ }, "folding": { "markers": { - "start": "^\\s*#pragma\\s+region", - "end": "^\\s*#pragma\\s+endregion" + "start": "^\\s*#pragma\\s+region\b", + "end": "^\\s*#pragma\\s+endregion\b" } } } \ No newline at end of file diff --git a/extensions/csharp/language-configuration.json b/extensions/csharp/language-configuration.json index 17f3fb0caf6..32378524b53 100644 --- a/extensions/csharp/language-configuration.json +++ b/extensions/csharp/language-configuration.json @@ -26,8 +26,8 @@ ], "folding": { "markers": { - "start": "^\\s*#region", - "end": "^\\s*#endregion" + "start": "^\\s*#region\b", + "end": "^\\s*#endregion\b" } } } \ No newline at end of file diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index 9cdb97d7912..a24a9da3233 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -24,8 +24,8 @@ "folding": { "offSide": true, "markers": { - "start": "^\\s*//\\s*#region|^\\s*\\(\\*\\s*#region(.*)\\*\\)", - "end": "^\\s*//\\s*#endregion|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" + "start": "^\\s*//\\s*#region\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)", + "end": "^\\s*//\\s*#endregion\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" } } } diff --git a/extensions/javascript/javascript-language-configuration.json b/extensions/javascript/javascript-language-configuration.json index ad48834d04a..d8659c6bacf 100644 --- a/extensions/javascript/javascript-language-configuration.json +++ b/extensions/javascript/javascript-language-configuration.json @@ -27,8 +27,8 @@ ], "folding": { "markers": { - "start": "^\\s*//\\s*#?region", - "end": "^\\s*//\\s*#?endregion" + "start": "^\\s*//\\s*#?region\b", + "end": "^\\s*//\\s*#?endregion\b" } } } \ No newline at end of file diff --git a/extensions/powershell/language-configuration.json b/extensions/powershell/language-configuration.json index 1227fef697d..5c5ae4c2917 100644 --- a/extensions/powershell/language-configuration.json +++ b/extensions/powershell/language-configuration.json @@ -25,8 +25,8 @@ ], "folding": { "markers": { - "start": "^\\s*#region", - "end": "^\\s*#endregion" + "start": "^\\s*#region\b", + "end": "^\\s*#endregion\b" } } } \ No newline at end of file diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index 51892242cc4..e709d275791 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -25,8 +25,8 @@ "folding": { "offSide": true, "markers": { - "start": "^\\s*#region", - "end": "^\\s*#endregion" + "start": "^\\s*#region\b", + "end": "^\\s*#endregion\b" } } } diff --git a/extensions/typescript/language-configuration.json b/extensions/typescript/language-configuration.json index ad48834d04a..d8659c6bacf 100644 --- a/extensions/typescript/language-configuration.json +++ b/extensions/typescript/language-configuration.json @@ -27,8 +27,8 @@ ], "folding": { "markers": { - "start": "^\\s*//\\s*#?region", - "end": "^\\s*//\\s*#?endregion" + "start": "^\\s*//\\s*#?region\b", + "end": "^\\s*//\\s*#?endregion\b" } } } \ No newline at end of file diff --git a/extensions/vb/language-configuration.json b/extensions/vb/language-configuration.json index 6ef9c3c4d48..d87841c6872 100644 --- a/extensions/vb/language-configuration.json +++ b/extensions/vb/language-configuration.json @@ -23,8 +23,8 @@ ], "folding": { "markers": { - "start": "^\\s*#Region", - "end": "^\\s*#End Region" + "start": "^\\s*#Region\b", + "end": "^\\s*#End Region\b" } } } \ No newline at end of file From 27e7423ae240417dc54d29a7c87c9bb46e7685b9 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 11 Oct 2017 17:27:36 +0200 Subject: [PATCH 123/303] [folding] breaks when a particular sequence of text is entered. Fixes #35981 --- src/vs/editor/common/model/indentRanges.ts | 50 ++-- .../test/common/model/indentRanges.test.ts | 247 ++++++++++-------- 2 files changed, 164 insertions(+), 133 deletions(-) diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index 3a7773f592e..21a5311146b 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -61,41 +61,47 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol // folding pattern match if (m[1]) { // start pattern match // discard all regions until the folding pattern - while (previous.indent >= 0 && !previous.marker) { - previousRegions.pop(); - previous = previousRegions[previousRegions.length - 1]; + let i = previousRegions.length - 1; + while (i > 0 && !previousRegions[i].marker) { + i--; } - if (previous.marker) { + if (i > 0) { + previousRegions.length = i + 1; + previous = previousRegions[i]; + // new folding range from pattern, includes the end line result.push(new IndentRange(line, previous.line, indent, true)); previous.marker = false; previous.indent = indent; previous.line = line; + continue; + } else { + // no end marker found, treat line as a regular line } } else { // end pattern match previousRegions.push({ indent: -2, line, marker: true }); + continue; } - } else { - if (previous.indent > indent) { - // discard all regions with larger indent - do { - previousRegions.pop(); - previous = previousRegions[previousRegions.length - 1]; - } while (previous.indent > indent); + } + if (previous.indent > indent) { + // discard all regions with larger indent + do { + previousRegions.pop(); + previous = previousRegions[previousRegions.length - 1]; + } while (previous.indent > indent); - // new folding range - let endLineNumber = previous.line - 1; - if (endLineNumber - line >= minimumRangeSize) { - result.push(new IndentRange(line, endLineNumber, indent)); - } - } - if (previous.indent === indent) { - previous.line = line; - } else { // previous.indent < indent - // new region with a bigger indent - previousRegions.push({ indent, line, marker: false }); + // new folding range + let endLineNumber = previous.line - 1; + if (endLineNumber - line >= minimumRangeSize) { + result.push(new IndentRange(line, endLineNumber, indent)); } } + if (previous.indent === indent) { + previous.line = line; + } else { // previous.indent < indent + // new region with a bigger indent + previousRegions.push({ indent, line, marker: false }); + } } return result.reverse(); diff --git a/src/vs/editor/test/common/model/indentRanges.test.ts b/src/vs/editor/test/common/model/indentRanges.test.ts index 8d90c5a2635..6d09f3f1ce2 100644 --- a/src/vs/editor/test/common/model/indentRanges.test.ts +++ b/src/vs/editor/test/common/model/indentRanges.test.ts @@ -29,125 +29,125 @@ function r(startLineNumber: number, endLineNumber: number, indent: number, marke return { startLineNumber, endLineNumber, indent, marker }; } -// suite('Indentation Folding', () => { +suite('Indentation Folding', () => { -// test('Fold one level', () => { -// let range = [ -// 'A', -// ' A', -// ' A', -// ' A' -// ]; -// assertRanges(range, [r(1, 4, 0)], true); -// assertRanges(range, [r(1, 4, 0)], false); -// }); + test('Fold one level', () => { + let range = [ + 'A', + ' A', + ' A', + ' A' + ]; + assertRanges(range, [r(1, 4, 0)], true); + assertRanges(range, [r(1, 4, 0)], false); + }); -// test('Fold two levels', () => { -// let range = [ -// 'A', -// ' A', -// ' A', -// ' A', -// ' A' -// ]; -// assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); -// assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); -// }); + test('Fold two levels', () => { + let range = [ + 'A', + ' A', + ' A', + ' A', + ' A' + ]; + assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); + assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); + }); -// test('Fold three levels', () => { -// let range = [ -// 'A', -// ' A', -// ' A', -// ' A', -// 'A' -// ]; -// assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); -// assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); -// }); + test('Fold three levels', () => { + let range = [ + 'A', + ' A', + ' A', + ' A', + 'A' + ]; + assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); + assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); + }); -// test('Fold decreasing indent', () => { -// let range = [ -// ' A', -// ' A', -// 'A' -// ]; -// assertRanges(range, [], true); -// assertRanges(range, [], false); -// }); + test('Fold decreasing indent', () => { + let range = [ + ' A', + ' A', + 'A' + ]; + assertRanges(range, [], true); + assertRanges(range, [], false); + }); -// test('Fold Java', () => { -// assertRanges([ -// /* 1*/ 'class A {', -// /* 2*/ ' void foo() {', -// /* 3*/ ' console.log();', -// /* 4*/ ' console.log();', -// /* 5*/ ' }', -// /* 6*/ '', -// /* 7*/ ' void bar() {', -// /* 8*/ ' console.log();', -// /* 9*/ ' }', -// /*10*/ '}', -// /*11*/ 'interface B {', -// /*12*/ ' void bar();', -// /*13*/ '}', -// ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); -// }); + test('Fold Java', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ ' void foo() {', + /* 3*/ ' console.log();', + /* 4*/ ' console.log();', + /* 5*/ ' }', + /* 6*/ '', + /* 7*/ ' void bar() {', + /* 8*/ ' console.log();', + /* 9*/ ' }', + /*10*/ '}', + /*11*/ 'interface B {', + /*12*/ ' void bar();', + /*13*/ '}', + ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); + }); -// test('Fold Javadoc', () => { -// assertRanges([ -// /* 1*/ '/**', -// /* 2*/ ' * Comment', -// /* 3*/ ' */', -// /* 4*/ 'class A {', -// /* 5*/ ' void foo() {', -// /* 6*/ ' }', -// /* 7*/ '}', -// ], [r(1, 3, 0), r(4, 6, 0)], false); -// }); -// test('Fold Whitespace Java', () => { -// assertRanges([ -// /* 1*/ 'class A {', -// /* 2*/ '', -// /* 3*/ ' void foo() {', -// /* 4*/ ' ', -// /* 5*/ ' return 0;', -// /* 6*/ ' }', -// /* 7*/ ' ', -// /* 8*/ '}', -// ], [r(1, 7, 0), r(3, 5, 2)], false); -// }); + test('Fold Javadoc', () => { + assertRanges([ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' }', + /* 7*/ '}', + ], [r(1, 3, 0), r(4, 6, 0)], false); + }); + test('Fold Whitespace Java', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ '', + /* 3*/ ' void foo() {', + /* 4*/ ' ', + /* 5*/ ' return 0;', + /* 6*/ ' }', + /* 7*/ ' ', + /* 8*/ '}', + ], [r(1, 7, 0), r(3, 5, 2)], false); + }); -// test('Fold Whitespace Python', () => { -// assertRanges([ -// /* 1*/ 'def a:', -// /* 2*/ ' pass', -// /* 3*/ ' ', -// /* 4*/ ' def b:', -// /* 5*/ ' pass', -// /* 6*/ ' ', -// /* 7*/ ' ', -// /* 8*/ 'def c: # since there was a deintent here' -// ], [r(1, 5, 0), r(4, 5, 2)], true); -// }); + test('Fold Whitespace Python', () => { + assertRanges([ + /* 1*/ 'def a:', + /* 2*/ ' pass', + /* 3*/ ' ', + /* 4*/ ' def b:', + /* 5*/ ' pass', + /* 6*/ ' ', + /* 7*/ ' ', + /* 8*/ 'def c: # since there was a deintent here' + ], [r(1, 5, 0), r(4, 5, 2)], true); + }); -// test('Fold Tabs', () => { -// assertRanges([ -// /* 1*/ 'class A {', -// /* 2*/ '\t\t', -// /* 3*/ '\tvoid foo() {', -// /* 4*/ '\t \t//hello', -// /* 5*/ '\t return 0;', -// /* 6*/ ' \t}', -// /* 7*/ ' ', -// /* 8*/ '}', -// ], [r(1, 7, 0), r(3, 5, 4)], false); -// }); -// }); + test('Fold Tabs', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ '\t\t', + /* 3*/ '\tvoid foo() {', + /* 4*/ '\t \t//hello', + /* 5*/ '\t return 0;', + /* 6*/ ' \t}', + /* 7*/ ' ', + /* 8*/ '}', + ], [r(1, 7, 0), r(3, 5, 4)], false); + }); +}); let markers: FoldingMarkers = { - start: /^\s*#region/, - end: /^\s*#endregion/ + start: /^\s*#region\b/, + end: /^\s*#endregion\b/ }; suite('Folding with regions', () => { @@ -216,9 +216,9 @@ suite('Folding with regions', () => { /* 2*/ '#region', /* 3*/ ' // comment', /* 4*/ '}', - ], [], false, markers); + ], [r(2, 3, 0)], false, markers); }); - test('Incomplete Regions', () => { + test('Incomplete Regions 2', () => { assertRanges([ /* 1*/ '', /* 2*/ '#region', @@ -291,4 +291,29 @@ suite('Folding with regions', () => { /* 8*/ '', ], [r(1, 7, 0, true), r(3, 5, 0, true)], true, markers); }); + test('Issue 35981', () => { + assertRanges([ + /* 1*/ 'function thisFoldsToEndOfPage() {', + /* 2*/ ' const variable = []', + /* 3*/ ' // #region', + /* 4*/ ' .reduce((a, b) => a,[]);', + /* 5*/ '}', + /* 6*/ '', + /* 7*/ 'function thisFoldsProperly() {', + /* 8*/ ' const foo = "bar"', + /* 9*/ '}', + ], [r(1, 4, 0), r(2, 4, 2), r(7, 8, 0)], false, markers); + }); + test('Misspelled Markers', () => { + assertRanges([ + /* 1*/ '#Region', + /* 2*/ '#endregion', + /* 3*/ '#regionsandmore', + /* 4*/ '#endregion', + /* 5*/ '#region', + /* 6*/ '#end region', + /* 7*/ '#region', + /* 8*/ '#endregionff', + ], [], true, markers); + }); }); \ No newline at end of file From 63fd0e4900b8c0d79cfd2201c934d8a9fcdc48d4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Oct 2017 17:58:48 +0200 Subject: [PATCH 124/303] remove prefix/suffix from decoration --- src/vs/workbench/browser/labels.ts | 14 -------------- .../services/decorations/browser/decorations.ts | 2 -- 2 files changed, 16 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 58ed73d8fb1..cd57469d795 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -198,20 +198,6 @@ export class ResourceLabel extends IconLabel { title = localize('deco.tooltip', "{0}, {1}", title, deco.tooltip); } - if (deco.prefix) { - label += deco.prefix; - if (matches) { - matches.forEach(match => { - match.start += deco.prefix.length; - match.end += deco.prefix.length; - }); - } - } - - if (deco.suffix) { - label += deco.suffix; - } - if (deco.icon) { const { type } = this.themeService.getTheme(); extraIcon = type === 'light' ? deco.icon.light : deco.icon.dark; diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 6c9cb6743a5..8a1740ffd80 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -16,8 +16,6 @@ export const IResourceDecorationsService = createDecorator Date: Wed, 11 Oct 2017 17:59:36 +0200 Subject: [PATCH 125/303] diff: hover decorations --- .../electron-browser/dirtydiffDecorator.ts | 43 +++++++++++++------ .../media/dirtydiffDecorator.css | 21 +++++++++ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e029cd2df54..5858e6845f9 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -523,24 +523,23 @@ export class DirtyDiffController implements IEditorContribution { } export const editorGutterModifiedBackground = registerColor('editorGutter.modifiedBackground', { - dark: Color.fromHex('#00bcf2').transparent(0.6), - light: Color.fromHex('#007acc').transparent(0.6), - hc: Color.fromHex('#007acc').transparent(0.6) + dark: new Color(new RGBA(12, 125, 157)), + light: new Color(new RGBA(102, 175, 224)), + hc: new Color(new RGBA(0, 73, 122)) }, localize('editorGutterModifiedBackground', "Editor gutter background color for lines that are modified.")); export const editorGutterAddedBackground = registerColor('editorGutter.addedBackground', { - dark: Color.fromHex('#7fba00').transparent(0.6), - light: Color.fromHex('#2d883e').transparent(0.6), - hc: Color.fromHex('#2d883e').transparent(0.6) + dark: new Color(new RGBA(88, 124, 12)), + light: new Color(new RGBA(129, 184, 139)), + hc: new Color(new RGBA(27, 82, 37)) }, localize('editorGutterAddedBackground', "Editor gutter background color for lines that are added.")); export const editorGutterDeletedBackground = registerColor('editorGutter.deletedBackground', { - dark: Color.fromHex('#b9131a').transparent(0.76), - light: Color.fromHex('#b9131a').transparent(0.76), - hc: Color.fromHex('#b9131a').transparent(0.76) + dark: new Color(new RGBA(148, 21, 27)), + light: new Color(new RGBA(202, 75, 81)), + hc: new Color(new RGBA(141, 14, 20)) }, localize('editorGutterDeletedBackground', "Editor gutter background color for lines that are deleted.")); - const overviewRulerDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerModifiedForeground = registerColor('editorOverviewRuler.modifiedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerModifiedForeground', 'Overview ruler marker color for modified content.')); export const overviewRulerAddedForeground = registerColor('editorOverviewRuler.addedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerAddedForeground', 'Overview ruler marker color for added content.')); @@ -550,6 +549,7 @@ class DirtyDiffDecorator { static MODIFIED_DECORATION_OPTIONS = ModelDecorationOptions.register({ linesDecorationsClassName: 'dirty-diff-modified-glyph', + marginClassName: 'dirty-diff-modified-margin', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerModifiedForeground), @@ -560,6 +560,7 @@ class DirtyDiffDecorator { static ADDED_DECORATION_OPTIONS = ModelDecorationOptions.register({ linesDecorationsClassName: 'dirty-diff-added-glyph', + marginClassName: 'dirty-diff-added-margin', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerAddedForeground), @@ -570,6 +571,7 @@ class DirtyDiffDecorator { static DELETED_DECORATION_OPTIONS = ModelDecorationOptions.register({ linesDecorationsClassName: 'dirty-diff-deleted-glyph', + marginClassName: 'dirty-diff-deleted-margin', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerDeletedForeground), @@ -884,12 +886,26 @@ export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutterModifiedBackgroundColor = theme.getColor(editorGutterModifiedBackground); if (editorGutterModifiedBackgroundColor) { - collector.addRule(`.monaco-editor .dirty-diff-modified-glyph { border-left: 3px solid ${editorGutterModifiedBackgroundColor}; }`); + collector.addRule(` + .monaco-editor .dirty-diff-modified-glyph { + border-left: 3px solid ${editorGutterModifiedBackgroundColor}; + } + .monaco-editor .dirty-diff-modified-margin { + background: ${editorGutterModifiedBackgroundColor}; + } + `); } const editorGutterAddedBackgroundColor = theme.getColor(editorGutterAddedBackground); if (editorGutterAddedBackgroundColor) { - collector.addRule(`.monaco-editor .dirty-diff-added-glyph { border-left: 3px solid ${editorGutterAddedBackgroundColor}; }`); + collector.addRule(` + .monaco-editor .dirty-diff-added-glyph { + border-left: 3px solid ${editorGutterAddedBackgroundColor}; + } + .monaco-editor .dirty-diff-added-margin { + background: ${editorGutterAddedBackgroundColor}; + } + `); } const editorGutteDeletedBackgroundColor = theme.getColor(editorGutterDeletedBackground); @@ -900,6 +916,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { border-bottom: 4px solid transparent; border-left: 4px solid ${editorGutteDeletedBackgroundColor}; } + .monaco-editor .dirty-diff-deleted-margin { + background: ${editorGutteDeletedBackgroundColor}; + } `); } }); diff --git a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css index b188403907e..cf7de4274c6 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css @@ -18,3 +18,24 @@ height: 0; z-index: 9; } + +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-modified-glyph, +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-added-glyph, +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-deleted-glyph { + opacity: 0; +} + +.monaco-editor .margin-view-overlays .cmdr.dirty-diff-modified-margin, +.monaco-editor .margin-view-overlays .cmdr.dirty-diff-added-margin, +.monaco-editor .margin-view-overlays .cmdr.dirty-diff-deleted-margin { + left: inherit; + right: 0; + width: 0; + transition: width 80ms linear; +} + +.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-modified-margin, +.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-added-margin, +.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-deleted-margin { + width: 100%; +} \ No newline at end of file From 8f279bec057a1b367ee651337899526192c2385a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 11 Oct 2017 18:20:34 +0200 Subject: [PATCH 126/303] diff: use border color per change type --- .../electron-browser/dirtydiffDecorator.ts | 86 ++++++++++++------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 5858e6845f9..cae9a0c8b2b 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -140,6 +140,30 @@ class UIEditorAction extends Action { } } +enum ChangeType { + Modify, + Add, + Delete +} + +function getChangeType(change: IChange): ChangeType { + if (change.originalEndLineNumber === 0) { + return ChangeType.Add; + } else if (change.modifiedEndLineNumber === 0) { + return ChangeType.Delete; + } else { + return ChangeType.Modify; + } +} + +function getChangeTypeColor(theme: ITheme, changeType: ChangeType): Color { + switch (changeType) { + case ChangeType.Modify: return theme.getColor(editorGutterModifiedBackground); + case ChangeType.Add: return theme.getColor(editorGutterAddedBackground); + case ChangeType.Delete: return theme.getColor(editorGutterDeletedBackground); + } +} + class DirtyDiffWidget extends PeekViewWidget { private diffEditor: EmbeddedDiffEditorWidget; @@ -153,7 +177,7 @@ class DirtyDiffWidget extends PeekViewWidget { constructor( editor: ICodeEditor, private model: DirtyDiffModel, - @IThemeService themeService: IThemeService, + @IThemeService private themeService: IThemeService, @IInstantiationService private instantiationService: IInstantiationService, @IMenuService private menuService: IMenuService, @IKeybindingService private keybindingService: IKeybindingService, @@ -199,6 +223,11 @@ class DirtyDiffWidget extends PeekViewWidget { const height = getChangeHeight(change) + /* padding */ 8; this.renderTitle(); + + const changeType = getChangeType(change); + const changeTypeColor = getChangeTypeColor(this.themeService.getTheme(), changeType); + this.style({ frameColor: changeTypeColor }); + this._actionbarWidget.context = [this.model.modified.uri, this.model.changes, index]; this.show(position, height); } @@ -592,39 +621,36 @@ class DirtyDiffDecorator { private onDidChange(): void { const decorations = this.model.changes.map((change) => { + const changeType = getChangeType(change); const startLineNumber = change.modifiedStartLineNumber; const endLineNumber = change.modifiedEndLineNumber || startLineNumber; - // Added - if (change.originalEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffDecorator.ADDED_DECORATION_OPTIONS - }; + switch (changeType) { + case ChangeType.Add: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.ADDED_DECORATION_OPTIONS + }; + case ChangeType.Delete: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: startLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.DELETED_DECORATION_OPTIONS + }; + case ChangeType.Modify: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.MODIFIED_DECORATION_OPTIONS + }; } - - // Removed - if (change.modifiedEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: startLineNumber, endColumn: 1 - }, - options: DirtyDiffDecorator.DELETED_DECORATION_OPTIONS - }; - } - - // Modified - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffDecorator.MODIFIED_DECORATION_OPTIONS - }; }); this.decorations = this.editorModel.deltaDecorations(this.decorations, decorations); From 11b4f3d87395d39c16917d265c4a04be442b52af Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Wed, 11 Oct 2017 10:18:15 -0700 Subject: [PATCH 127/303] Enable for 1.17.1 (#34432) --- .github/new_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/new_release.yml b/.github/new_release.yml index be3fd91e8b1..1a0465c011d 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', - newReleases: ['1.17'], - perform: false + newReleases: ['1.17.1'], + perform: true } \ No newline at end of file From fd77f04352aa75d4e4121f109d7c755784a5bb2a Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Wed, 11 Oct 2017 10:26:15 -0700 Subject: [PATCH 128/303] Include recent emmet preferences in settings suggestions Fixes #35676 --- extensions/emmet/package.json | 25 +++++++++++++++++++++++++ extensions/emmet/package.nls.json | 7 ++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index b768d3c1d90..9a8c21d3892 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -130,6 +130,31 @@ "type": "string", "default": " ", "description": "%emmetPreferencesStylusBetween%" + }, + "bem.elementSeparator": { + "type": "string", + "default": "__", + "description": "%emmetPreferencesBemElementSeparator%" + }, + "bem.modifierSeparator": { + "type": "string", + "default": "_", + "description": "%emmetPreferencesBemModifierSeparator%" + }, + "filter.commentBefore": { + "type": "string", + "default": "", + "description": "%emmetPreferencesFilterCommentBefore%" + }, + "filter.commentAfter": { + "type": "string", + "default": "\n", + "description": "%emmetPreferencesFilterCommentAfter%" + }, + "filter.commentTrigger": { + "type": "array", + "default": ["id", "class"], + "description": "%emmetPreferencesFilterCommentTrigger%" } } }, diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 4d63301d0ac..837b936b5b1 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -39,5 +39,10 @@ "emmetPreferencesCssBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations", "emmetPreferencesSassBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Sass files", "emmetPreferencesStylusBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Stylus files", - "emmetShowSuggestionsAsSnippets": "If true, then emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting." + "emmetShowSuggestionsAsSnippets": "If true, then emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.", + "emmetPreferencesBemElementSeparator": "Element separator used for classes when using the bem filter", + "emmetPreferencesBemModifierSeparator": "Modifer separator used for classes when using the bem filter", + "emmetPreferencesFilterCommentBefore": "A definition of comment that should be placed before after element when comment filter is applied.", + "emmetPreferencesFilterCommentAfter": "A definition of comment that should be placed before matched element when comment filter is applied.", + "emmetPreferencesFilterCommentTrigger": "A comma-separated list of attribute names that should exist in abbreviation for the comment filter to be applied" } \ No newline at end of file From f6456c295c41e40df586300b050248f34bda6218 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Wed, 11 Oct 2017 10:52:18 -0700 Subject: [PATCH 129/303] Auto-assign markdown and html labels --- .github/classifier.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/classifier.yml b/.github/classifier.yml index 348242d802a..2ac44c447f4 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -26,14 +26,14 @@ extensions: [], git: [ joaomoreno ], hot-exit: [ Tyriar ], - html: [], + html: [ aeschli ], i18n: [], install-update: [], integrated-terminal: [ Tyriar ], javascript: [ mjbvz ], json: [], languages basic: [], - markdown: [], + markdown: [ mjbvz ], merge-conflict: [ chrmarti ], perf-profile: [], php: [ roblourens ], From d6e9f1e7b6a9ce3f15a921d129ca95ac3b38a97c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 11 Oct 2017 15:41:30 -0700 Subject: [PATCH 130/303] Fix findwidget blocking pointer events on webviews Fixes #36051 --- src/vs/editor/contrib/find/browser/simpleFindWidget.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/editor/contrib/find/browser/simpleFindWidget.css b/src/vs/editor/contrib/find/browser/simpleFindWidget.css index 28987124e4b..526b08a05b1 100644 --- a/src/vs/editor/contrib/find/browser/simpleFindWidget.css +++ b/src/vs/editor/contrib/find/browser/simpleFindWidget.css @@ -11,6 +11,7 @@ right: 28px; width: 220px; max-width: calc(100% - 28px - 28px - 8px); + pointer-events: none; } .monaco-workbench .simple-find-part { @@ -20,6 +21,7 @@ display: flex; padding: 4px; align-items: center; + pointer-events: all; -webkit-transition: top 200ms linear; -o-transition: top 200ms linear; From 4f9983bd6490ca454ffed757663f4a7d182c307b Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Wed, 11 Oct 2017 17:22:39 -0700 Subject: [PATCH 131/303] Track source of extension install for dependencies --- .../extensionManagement/node/extensionGalleryService.ts | 2 +- .../parts/extensions/electron-browser/extensionsViews.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 7ee13df86d6..4453efbc64d 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -528,7 +528,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { for (let index = 0; index < result.galleryExtensions.length; index++) { const rawExtension = result.galleryExtensions[index]; if (ids.indexOf(rawExtension.extensionId) === -1) { - dependencies.push(toExtension(rawExtension, this.extensionsGalleryUrl, index, query)); + dependencies.push(toExtension(rawExtension, this.extensionsGalleryUrl, index, query, 'dependencies')); ids.push(rawExtension.extensionId); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index 481df3dfc08..eaa33074295 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -253,13 +253,15 @@ export class ExtensionsListView extends ViewsViewletPanel { }); if (names.length) { - const namesOptions = assign({}, options, { names }); + const namesOptions = assign({}, options, { names, source: 'extRegex' }); pagerPromises.push(this.extensionsWorkbenchService.queryGallery(namesOptions)); } } if (text) { options = assign(options, { text: text.substr(0, 350) }); + } else { + options.source = 'viewlet'; } pagerPromises.push(this.extensionsWorkbenchService.queryGallery(options)); From b811aa6c4044f9e6962609d424fab8dd3964cc84 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 11 Oct 2017 18:12:40 -0700 Subject: [PATCH 132/303] Fix all javascript being tagged as the javascript react language --- extensions/javascript/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 8cc0db74250..4d7fa6dff20 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -63,8 +63,8 @@ "grammars": [ { "language": "javascriptreact", - "scopeName": "source.js", - "path": "./syntaxes/JavaScript.tmLanguage.json", + "scopeName": "source.js.jsx", + "path": "./syntaxes/JavaScriptReact.tmLanguage.json", "embeddedLanguages": { "meta.tag.js": "jsx-tags", "meta.tag.without-attributes.js": "jsx-tags", From a60a5515820532f4d05c586cabcf59315ddec272 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 11 Oct 2017 18:27:45 -0700 Subject: [PATCH 133/303] add new typescript.tsc.autoDetectType to enable either detection of build or watch tasks Fixes #35067 --- extensions/typescript/package.json | 11 +++ extensions/typescript/package.nls.json | 1 + .../typescript/src/features/taskProvider.ts | 83 ++++++++++++------- 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 11b93b77e10..f06d40c27fa 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -390,6 +390,17 @@ ], "description": "%typescript.tsc.autoDetect%", "scope": "resource" + }, + "typescript.tsc.autoDetectType": { + "type": "string", + "default": "both", + "enum": [ + "both", + "build", + "watch" + ], + "description": "%typescript.tsc.autoDetectType%", + "scope": "resource" } } }, diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index b25953666f6..ba466ec0252 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -40,6 +40,7 @@ "typescript.check.npmIsInstalled": "Check if NPM is installed for Automatic Type Acquisition.", "javascript.nameSuggestions": "Enable/disable including unique names from the file in JavaScript suggestion lists.", "typescript.tsc.autoDetect": "Controls whether auto detection of tsc tasks is on or off.", + "typescript.tsc.autoDetectType": "Controls detection of tsc tasks. 'build' only creates single run compile tasks. 'watch' only creates compile and watch tasks. 'both' creates both build and watch tasks. Default is 'both'.", "typescript.problemMatchers.tsc.label": "TypeScript problems", "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)" } diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 46dce9fa311..9545828cd45 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -17,6 +17,10 @@ import { isImplicitProjectConfigFile } from '../utils/tsconfig'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); +type AutoDetect = 'on' | 'off'; + +type AutoDetectType = 'both' | 'build' | 'watch'; + const exists = (file: string): Promise => new Promise((resolve, _reject) => { @@ -35,12 +39,21 @@ interface TypeScriptTaskDefinition extends vscode.TaskDefinition { * Provides tasks for building `tsconfig.json` files in a project. */ class TscTaskProvider implements vscode.TaskProvider { + private autoDetectType: AutoDetectType = 'both'; private readonly tsconfigProvider: TsConfigProvider; + private readonly disposables: vscode.Disposable[] = []; public constructor( private readonly lazyClient: () => TypeScriptServiceClient ) { this.tsconfigProvider = new TsConfigProvider(); + + vscode.workspace.onDidChangeConfiguration(this.onConfigurationChanged, this, this.disposables); + this.onConfigurationChanged(); + } + + dispose() { + this.disposables.forEach(x => x.dispose()); } public async provideTasks(token: vscode.CancellationToken): Promise { @@ -149,8 +162,40 @@ class TscTaskProvider implements vscode.TaskProvider { private async getTasksForProject(project: TSConfig): Promise { const command = await this.getCommand(project); + const label = this.getLabelForTasks(project); - let label: string = project.path; + const tasks: vscode.Task[] = []; + + if (this.autoDetectType === 'build' || this.autoDetectType === 'both') { + const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; + const buildTask = new vscode.Task( + buildTaskidentifier, + localize('buildTscLabel', 'build - {0}', label), + 'tsc', + new vscode.ShellExecution(`${command} -p "${project.path}"`), + '$tsc'); + buildTask.group = vscode.TaskGroup.Build; + buildTask.isBackground = false; + tasks.push(buildTask); + } + + if (this.autoDetectType === 'watch' || this.autoDetectType === 'both') { + const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; + const watchTask = new vscode.Task( + watchTaskidentifier, + localize('buildAndWatchTscLabel', 'watch - {0}', label), + 'tsc', + new vscode.ShellExecution(`${command} --watch -p "${project.path}"`), + '$tsc-watch'); + watchTask.group = vscode.TaskGroup.Build; + watchTask.isBackground = true; + tasks.push(watchTask); + } + + return tasks; + } + + private getLabelForTasks(project: TSConfig): string { if (project.workspaceFolder) { const projectFolder = project.workspaceFolder; const workspaceFolders = vscode.workspace.workspaceFolders; @@ -158,41 +203,23 @@ class TscTaskProvider implements vscode.TaskProvider { if (workspaceFolders && workspaceFolders.length > 1) { // Use absolute path when we have multiple folders with the same name if (workspaceFolders.filter(x => x.name === projectFolder.name).length > 1) { - label = path.join(project.workspaceFolder.uri.fsPath, relativePath); + return path.join(project.workspaceFolder.uri.fsPath, relativePath); } else { - label = path.join(project.workspaceFolder.name, relativePath); + return path.join(project.workspaceFolder.name, relativePath); } } else { - label = relativePath; + return relativePath; } } + return project.path; + } - const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; - const buildTask = new vscode.Task( - buildTaskidentifier, - localize('buildTscLabel', 'build - {0}', label), - 'tsc', - new vscode.ShellExecution(`${command} -p "${project.path}"`), - '$tsc'); - buildTask.group = vscode.TaskGroup.Build; - buildTask.isBackground = false; - - const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; - const watchTask = new vscode.Task( - watchTaskidentifier, - localize('buildAndWatchTscLabel', 'watch - {0}', label), - 'tsc', - new vscode.ShellExecution(`${command} --watch -p "${project.path}"`), - '$tsc-watch'); - watchTask.group = vscode.TaskGroup.Build; - watchTask.isBackground = true; - - return [buildTask, watchTask]; + private onConfigurationChanged(): void { + const type = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetectType'); + this.autoDetectType = typeof type === 'undefined' ? 'both' : type; } } -type AutoDetect = 'on' | 'off'; - /** * Manages registrations of TypeScript task provides with VScode. */ @@ -216,7 +243,7 @@ export default class TypeScriptTaskProviderManager { } private onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); + const autoDetect = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); if (this.taskProviderSub && autoDetect === 'off') { this.taskProviderSub.dispose(); this.taskProviderSub = undefined; From c098b394b07afbb58975ab609117a0e115c5a3fa Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 11 Oct 2017 18:45:31 -0700 Subject: [PATCH 134/303] Use single setting to control autodetect of tasks #35067 --- extensions/typescript/package.json | 13 ++----------- extensions/typescript/package.nls.json | 3 +-- .../typescript/src/features/taskProvider.ts | 16 +++++++--------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index f06d40c27fa..6934e4221bd 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -386,20 +386,11 @@ "default": "on", "enum": [ "on", - "off" - ], - "description": "%typescript.tsc.autoDetect%", - "scope": "resource" - }, - "typescript.tsc.autoDetectType": { - "type": "string", - "default": "both", - "enum": [ - "both", + "off", "build", "watch" ], - "description": "%typescript.tsc.autoDetectType%", + "description": "%typescript.tsc.autoDetect%", "scope": "resource" } } diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index ba466ec0252..f23e78bf4e1 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -39,8 +39,7 @@ "typescript.npm": "Specifies the path to the NPM executable used for Automatic Type Acquisition. Requires TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Check if NPM is installed for Automatic Type Acquisition.", "javascript.nameSuggestions": "Enable/disable including unique names from the file in JavaScript suggestion lists.", - "typescript.tsc.autoDetect": "Controls whether auto detection of tsc tasks is on or off.", - "typescript.tsc.autoDetectType": "Controls detection of tsc tasks. 'build' only creates single run compile tasks. 'watch' only creates compile and watch tasks. 'both' creates both build and watch tasks. Default is 'both'.", + "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks. 'off' disables this feature. 'build' only creates single run compile tasks. 'watch' only creates compile and watch tasks. 'on' creates both build and watch tasks. Default is 'on'.", "typescript.problemMatchers.tsc.label": "TypeScript problems", "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)" } diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 9545828cd45..290c07a7709 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -17,9 +17,7 @@ import { isImplicitProjectConfigFile } from '../utils/tsconfig'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -type AutoDetect = 'on' | 'off'; - -type AutoDetectType = 'both' | 'build' | 'watch'; +type AutoDetect = 'on' | 'off' | 'build' | 'watch'; const exists = (file: string): Promise => @@ -39,7 +37,7 @@ interface TypeScriptTaskDefinition extends vscode.TaskDefinition { * Provides tasks for building `tsconfig.json` files in a project. */ class TscTaskProvider implements vscode.TaskProvider { - private autoDetectType: AutoDetectType = 'both'; + private autoDetect: AutoDetect = 'on'; private readonly tsconfigProvider: TsConfigProvider; private readonly disposables: vscode.Disposable[] = []; @@ -166,7 +164,7 @@ class TscTaskProvider implements vscode.TaskProvider { const tasks: vscode.Task[] = []; - if (this.autoDetectType === 'build' || this.autoDetectType === 'both') { + if (this.autoDetect === 'build' || this.autoDetect === 'on') { const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; const buildTask = new vscode.Task( buildTaskidentifier, @@ -179,7 +177,7 @@ class TscTaskProvider implements vscode.TaskProvider { tasks.push(buildTask); } - if (this.autoDetectType === 'watch' || this.autoDetectType === 'both') { + if (this.autoDetect === 'watch' || this.autoDetect === 'on') { const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; const watchTask = new vscode.Task( watchTaskidentifier, @@ -215,8 +213,8 @@ class TscTaskProvider implements vscode.TaskProvider { } private onConfigurationChanged(): void { - const type = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetectType'); - this.autoDetectType = typeof type === 'undefined' ? 'both' : type; + const type = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); + this.autoDetect = typeof type === 'undefined' ? 'on' : type; } } @@ -247,7 +245,7 @@ export default class TypeScriptTaskProviderManager { if (this.taskProviderSub && autoDetect === 'off') { this.taskProviderSub.dispose(); this.taskProviderSub = undefined; - } else if (!this.taskProviderSub && autoDetect === 'on') { + } else if (!this.taskProviderSub && autoDetect !== 'off') { this.taskProviderSub = vscode.workspace.registerTaskProvider('typescript', new TscTaskProvider(this.lazyClient)); } } From ed9fe0c1823a8decaf6297fae2cd3f2215c5a4e8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 11 Oct 2017 22:41:12 -0700 Subject: [PATCH 135/303] Fix ansi bright being bold without bold flag Fixes #35677 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index db4d423bbcd..a3b4ae130d4 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#24fff1743b18ac7291e43c0ba547c7e2681efe65" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#14b0137accaf350565a005d68e91f03c96a241be" }, "yauzl": { "version": "2.8.0", From b4de6e87e4832d85a6dfaf370dcd229d23a198b8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 Oct 2017 00:14:43 -0700 Subject: [PATCH 136/303] Relayout terminals when they are set to visible This fixes an issue where background terminals were created while not visible. This caused the internal charMeasure object to have 0 width and height so nothing would render. Fixes #34554 --- .../parts/terminal/electron-browser/terminalInstance.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 4ba392d7be8..da798434930 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -511,6 +511,14 @@ export class TerminalInstance implements ITerminalInstance { // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. this._xterm.emit('scroll', this._xterm.buffer.ydisp); + // Force a layout when the instance becomes invisible. This is particularly important + // for ensuring that terminals that are created in the background by an extension will + // correctly get correct character measurements in order to render to the screen (see + // #34554). + const computedStyle = window.getComputedStyle(this._container); + const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); + const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); + this.layout(new Dimension(width, height)); } } From 1ab63ddad5d7a390c337bfdc51cb6a82918a70c9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2017 09:55:57 +0200 Subject: [PATCH 137/303] Adding "base" to files.exclude breaks VS Code (fixes #36081) --- src/vs/base/common/glob.ts | 8 +++++++- src/vs/base/test/node/glob.test.ts | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 67f5ce6ade6..3571fb9c33e 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -450,7 +450,7 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG } // Glob with String - if (typeof arg1 === 'string' || (arg1 as IRelativePattern).base) { + if (typeof arg1 === 'string' || isRelativePattern(arg1)) { const parsedPattern = parsePattern(arg1 as string | IRelativePattern, options); if (parsedPattern === NULL) { return FALSE; @@ -471,6 +471,12 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG return parsedExpression(arg1, options); } +function isRelativePattern(obj: any): obj is IRelativePattern { + const rp = obj as IRelativePattern; + + return typeof rp.base === 'string' && typeof rp.pattern === 'string'; +} + /** * Same as `parse`, but the ParsedExpression is guaranteed to return a Promise */ diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index 0e61295fdb8..301762e6130 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -933,4 +933,8 @@ suite('Glob', () => { assert(!glob.match(p, '/DNXConsoleApp/foo/Program.cs')); } }); + + test('pattern with "base" does not explode - #36081', function () { + assert.ok(glob.match({ 'base': true }, 'base')); + }); }); \ No newline at end of file From 4aef58c70bf09da25d7902c378493d5ab77b9dfa Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 12 Oct 2017 10:22:29 +0200 Subject: [PATCH 138/303] better handling of roots that can not be resolved fixes #35106 --- .../files/browser/fileActions.contribution.ts | 2 +- .../parts/files/browser/views/explorerView.ts | 50 +++++++++---------- .../files/browser/views/explorerViewer.ts | 11 ++-- .../parts/files/common/explorerModel.ts | 6 ++- 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index b05ba76285d..478d1d9ef84 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -65,7 +65,7 @@ class FilesViewerActionContributor extends ActionBarContributor { } // Directory Actions - if (stat.isDirectory && stat.exists) { + if (stat.isDirectory && !stat.nonexistentRoot) { // New File actions.push(this.instantiationService.createInstance(NewFileAction, tree, stat)); diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index aa33c61269d..eb2239c2b3a 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -765,33 +765,33 @@ export class ExplorerView extends ViewsViewletPanel { } // Load Root Stat with given target path configured - const promise = TPromise.join(targetsToResolve.map((target, index) => this.fileService.resolveFile(target.resource, target.options).then(result => { - // Convert to model - const modelStat = FileStat.create(result, target.root, target.options.resolveTo); - // Subsequent refresh: Merge stat into our local model and refresh tree - FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index]); + const promise = TPromise.join(targetsToResolve.map((target, index) => this.fileService.resolveFile(target.resource, target.options) + .then(result => FileStat.create(result, target.root, target.options.resolveTo), err => FileStat.create({ + resource: target.resource, + name: resources.basenameOrAuthority(target.resource), + mtime: 0, + etag: undefined, + isDirectory: true, + hasChildren: false + }, target.root)) + .then(modelStat => { + // Subsequent refresh: Merge stat into our local model and refresh tree + FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index]); - const input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; - let statsToExpand: FileStat[] = this.explorerViewer.getExpandedElements().concat(targetsToExpand.map(target => this.model.findClosest(target))); - if (input === this.explorerViewer.getInput()) { - return this.explorerViewer.refresh().then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); - } + const input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; + let statsToExpand: FileStat[] = this.explorerViewer.getExpandedElements().concat(targetsToExpand.map(target => this.model.findClosest(target))); + if (input === this.explorerViewer.getInput()) { + return this.explorerViewer.refresh().then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); + } - // Display roots only when multi folder workspace - // Make sure to expand all folders that where expanded in the previous session - if (input === this.model) { - // We have transitioned into workspace view -> expand all roots - statsToExpand = this.model.roots.concat(statsToExpand); - } - return this.explorerViewer.setInput(input).then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); - }, e => FileStat.create({ - resource: target.resource, - name: resources.basenameOrAuthority(target.resource), - mtime: 0, - etag: undefined, - isDirectory: true, - hasChildren: false - }, target.root)))); + // Display roots only when multi folder workspace + // Make sure to expand all folders that where expanded in the previous session + if (input === this.model) { + // We have transitioned into workspace view -> expand all roots + statsToExpand = this.model.roots.concat(statsToExpand); + } + return this.explorerViewer.setInput(input).then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); + }))); this.progressService.showWhile(promise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 291052f6ac0..10a815aebac 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -108,14 +108,8 @@ export class FileDataSource implements IDataSource { return stat.children; }, (e: any) => { - stat.exists = false; stat.hasChildren = false; - if (!stat.isRoot) { - this.messageService.show(Severity.Error, e); - } else { - // We render the roots that do not exist differently, nned to do a refresh - tree.refresh(stat, false); - } + this.messageService.show(Severity.Error, e); return []; // we could not resolve any children because of an error }); @@ -321,11 +315,12 @@ export class FileRenderer implements IRenderer { if (!editableData) { templateData.label.element.style.display = 'block'; const extraClasses = ['explorer-item']; - if (!stat.exists && stat.isRoot) { + if (stat.nonexistentRoot) { extraClasses.push('nonexistent-root'); } templateData.label.setFile(stat.resource, { hidePath: true, + title: stat.nonexistentRoot ? nls.localize('canNotResolve', "Can not resolve folder {0}", stat.resource.toString()) : undefined, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, fileDecorations: this.configurationService.getConfiguration().explorer.enableFileDecorations diff --git a/src/vs/workbench/parts/files/common/explorerModel.ts b/src/vs/workbench/parts/files/common/explorerModel.ts index fe3198bbf79..e20b9c1921e 100644 --- a/src/vs/workbench/parts/files/common/explorerModel.ts +++ b/src/vs/workbench/parts/files/common/explorerModel.ts @@ -82,7 +82,6 @@ export class FileStat implements IFileStat { public children: FileStat[]; public parent: FileStat; - public exists: boolean; public isDirectoryResolved: boolean; constructor(resource: URI, public root: FileStat, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mtime?: number, etag?: string) { @@ -102,7 +101,10 @@ export class FileStat implements IFileStat { } this.isDirectoryResolved = false; - this.exists = true; + } + + public get nonexistentRoot(): boolean { + return this.isRoot && !this.isDirectoryResolved; } public getId(): string { From 5f2bd928ebed59926b273ae20ba1acfe1f73794c Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 12 Oct 2017 10:31:36 +0200 Subject: [PATCH 139/303] debug translation --- src/vs/workbench/parts/debug/browser/debugViewlet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewlet.ts b/src/vs/workbench/parts/debug/browser/debugViewlet.ts index 6b93bdeaf8b..af6801d50c5 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewlet.ts @@ -110,7 +110,7 @@ export class DebugViewlet extends PersistentViewsViewlet { export class FocusVariablesViewAction extends Action { static ID = 'workbench.debug.action.focusVariablesView'; - static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusVariablesView' }, 'Focus Variables'); + static LABEL = nls.localize('debugFocusVariablesView', 'Focus Variables'); constructor(id: string, label: string, @IViewletService private viewletService: IViewletService From 819db21f2c33875b7a4fa83fffff6a60804727fc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 10:34:34 +0200 Subject: [PATCH 140/303] remove 'rebornix' from autoAssignees --- .github/classifier.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/classifier.yml b/.github/classifier.yml index 2ac44c447f4..c2666691dc8 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -9,14 +9,14 @@ debug: [ isidorn ], editor: [], editor-brackets: [], - editor-clipboard: [ rebornix ], + editor-clipboard: [], editor-colors: [], - editor-contrib: [ rebornix ], + editor-contrib: [], editor-core: [], - editor-find-widget: [ rebornix ], + editor-find-widget: [], editor-folding: [], - editor-ime: [ rebornix ], - editor-indentation: [ rebornix ], + editor-ime: [], + editor-indentation: [], editor-input: [], editor-minimap: [], editor-multicursor: [], From 20d7f8ab155925e8cb22f41e020d730c052c0273 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2017 10:39:30 +0200 Subject: [PATCH 141/303] test for showWorkspaceFolderPick --- .../vscode-api-tests/src/window.test.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/extensions/vscode-api-tests/src/window.test.ts b/extensions/vscode-api-tests/src/window.test.ts index df08d550a58..c197808fd9e 100644 --- a/extensions/vscode-api-tests/src/window.test.ts +++ b/extensions/vscode-api-tests/src/window.test.ts @@ -349,17 +349,17 @@ suite('window namespace tests', () => { return Promise.all([a, b]); }); - // test('showWorkspaceFolderPick', function () { - // const p = (window).showWorkspaceFolderPick(undefined); + test('showWorkspaceFolderPick', function () { + const p = (window).showWorkspaceFolderPick(undefined); - // return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { - // return p.then(workspace => { - // assert.ok(true); - // }, error => { - // assert.ok(false); - // }); - // }); - // }); + return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { + return p.then(workspace => { + assert.ok(true); + }, error => { + assert.ok(false); + }); + }); + }); test('Default value for showInput Box accepted even if fails validateInput, #33691', function () { const result = window.showInputBox({ From f8098c686641958fc761f08622c5a119e825f9b9 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 12 Oct 2017 11:14:31 +0200 Subject: [PATCH 142/303] diff: better animations --- .../electron-browser/dirtydiffDecorator.ts | 23 ++++----- .../media/dirtydiffDecorator.css | 51 +++++++++++-------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index cae9a0c8b2b..2a703c5f4ab 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -577,8 +577,7 @@ export const overviewRulerDeletedForeground = registerColor('editorOverviewRuler class DirtyDiffDecorator { static MODIFIED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-modified-glyph', - marginClassName: 'dirty-diff-modified-margin', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-modified', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerModifiedForeground), @@ -588,8 +587,7 @@ class DirtyDiffDecorator { }); static ADDED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-added-glyph', - marginClassName: 'dirty-diff-added-margin', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-added', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerAddedForeground), @@ -599,8 +597,7 @@ class DirtyDiffDecorator { }); static DELETED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-deleted-glyph', - marginClassName: 'dirty-diff-deleted-margin', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-deleted', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerDeletedForeground), @@ -913,10 +910,10 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutterModifiedBackgroundColor = theme.getColor(editorGutterModifiedBackground); if (editorGutterModifiedBackgroundColor) { collector.addRule(` - .monaco-editor .dirty-diff-modified-glyph { + .monaco-editor .dirty-diff-modified { border-left: 3px solid ${editorGutterModifiedBackgroundColor}; } - .monaco-editor .dirty-diff-modified-margin { + .monaco-editor .dirty-diff-modified:before { background: ${editorGutterModifiedBackgroundColor}; } `); @@ -925,10 +922,10 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutterAddedBackgroundColor = theme.getColor(editorGutterAddedBackground); if (editorGutterAddedBackgroundColor) { collector.addRule(` - .monaco-editor .dirty-diff-added-glyph { + .monaco-editor .dirty-diff-added { border-left: 3px solid ${editorGutterAddedBackgroundColor}; } - .monaco-editor .dirty-diff-added-margin { + .monaco-editor .dirty-diff-added:before { background: ${editorGutterAddedBackgroundColor}; } `); @@ -937,12 +934,10 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutteDeletedBackgroundColor = theme.getColor(editorGutterDeletedBackground); if (editorGutteDeletedBackgroundColor) { collector.addRule(` - .monaco-editor .dirty-diff-deleted-glyph:after { - border-top: 4px solid transparent; - border-bottom: 4px solid transparent; + .monaco-editor .dirty-diff-deleted:after { border-left: 4px solid ${editorGutteDeletedBackgroundColor}; } - .monaco-editor .dirty-diff-deleted-margin { + .monaco-editor .dirty-diff-deleted:before { background: ${editorGutteDeletedBackgroundColor}; } `); diff --git a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css index cf7de4274c6..e55cb63c612 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css @@ -3,13 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .dirty-diff-modified-glyph, -.monaco-editor .dirty-diff-added-glyph, -.monaco-editor .dirty-diff-deleted-glyph:after { +.monaco-editor .dirty-diff-glyph { margin-left: 5px; + cursor: pointer; } -.monaco-editor .dirty-diff-deleted-glyph:after { +.monaco-editor .dirty-diff-deleted:after { content: ''; position: absolute; bottom: -4px; @@ -17,25 +16,37 @@ width: 4px; height: 0; z-index: 9; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + transition: border-top-width 80ms linear, border-bottom-width 80ms linear, bottom 80ms linear; } -.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-modified-glyph, -.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-added-glyph, -.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-deleted-glyph { - opacity: 0; -} - -.monaco-editor .margin-view-overlays .cmdr.dirty-diff-modified-margin, -.monaco-editor .margin-view-overlays .cmdr.dirty-diff-added-margin, -.monaco-editor .margin-view-overlays .cmdr.dirty-diff-deleted-margin { - left: inherit; - right: 0; +.monaco-editor .dirty-diff-glyph:before { + position: absolute; + content: ''; + height: 100%; width: 0; - transition: width 80ms linear; + left: -2px; + transition: width 80ms linear, left 80ms linear; } -.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-modified-margin, -.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-added-margin, -.monaco-editor .margin-view-overlays > div:hover > .cmdr.dirty-diff-deleted-margin { - width: 100%; +.monaco-editor .dirty-diff-deleted:before { + margin-left: 3px; + height: 0; + bottom: 0; + transition: height 80ms linear; +} + +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-glyph:before { + position: absolute; + content: ''; + height: 100%; + width: 9px; + left: -6px; +} + +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-deleted:after { + bottom: 0; + border-top-width: 0; + border-bottom-width: 0; } \ No newline at end of file From 5d68e6764272fa74f1c9412f7d1af1fb8a5aab76 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 12 Oct 2017 11:29:40 +0200 Subject: [PATCH 143/303] hide exporer arrows improvements (for #35856) --- .../workbench/parts/files/browser/media/explorerviewlet.css | 2 +- .../workbench/services/themes/common/fileIconThemeSchema.ts | 4 ++++ .../services/themes/electron-browser/fileIconThemeData.ts | 6 +----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css index fd26c32d640..4ef2be5ab15 100644 --- a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css @@ -107,7 +107,7 @@ } .explorer-folders-view.hide-arrows .monaco-tree-row .content::before { - background-image: none; + display: none; } .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row:hover > .content .monaco-action-bar, diff --git a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts index 263f48a9b35..f04fc317d19 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts @@ -209,6 +209,10 @@ const schema: IJSONSchema = { highContrast: { $ref: '#/definitions/associations', description: nls.localize('schema.highContrast', 'Optional associations for file icons in high contrast color themes.') + }, + hidesExplorerArrows: { + type: 'boolean', + description: nls.localize('schema.hidesExplorerArrows', 'Configures whether the file explorer\'s arrows should be hidden when this theme is active.') } } }; diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts index 14bb8048c97..286627526d4 100644 --- a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts @@ -129,7 +129,7 @@ function _loadIconThemeDocument(fileSetPath: string): TPromise Date: Thu, 12 Oct 2017 11:44:08 +0200 Subject: [PATCH 144/303] diff: click action --- .../electron-browser/dirtydiffDecorator.ts | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 2a703c5f4ab..cdb0a5ab4a4 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -29,7 +29,7 @@ import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromI import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { PeekViewWidget, getOuterEditor } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; @@ -184,7 +184,7 @@ class DirtyDiffWidget extends PeekViewWidget { @IMessageService private messageService: IMessageService, @IContextKeyService contextKeyService: IContextKeyService ) { - super(editor, { isResizeable: true }); + super(editor, { isResizeable: true, frameWidth: 1 }); themeService.onThemeChange(this._applyTheme, this, this._disposables); this._applyTheme(themeService.getTheme()); @@ -404,6 +404,8 @@ export class DirtyDiffController implements IEditorContribution { private currentIndex: number = -1; private readonly isDirtyDiffVisible: IContextKey; private session: IDisposable = EmptyDisposable; + private mouseDownInfo: { lineNumber: number } | null = null; + private disposables: IDisposable[] = []; constructor( private editor: ICodeEditor, @@ -412,19 +414,21 @@ export class DirtyDiffController implements IEditorContribution { @IInstantiationService private instantiationService: IInstantiationService ) { this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); + this.disposables.push(editor.onMouseDown(e => this.onEditorMouseDown(e))); + this.disposables.push(editor.onMouseUp(e => this.onEditorMouseUp(e))); } getId(): string { return DirtyDiffController.ID; } - next(): void { + next(lineNumber?: number): void { if (!this.assertWidget()) { return; } - if (this.currentIndex === -1) { - this.currentIndex = this.findNextClosestChange(this.editor.getPosition().lineNumber); + if (typeof lineNumber === 'number' || this.currentIndex === -1) { + this.currentIndex = this.findNextClosestChange(typeof lineNumber === 'number' ? lineNumber : this.editor.getPosition().lineNumber); } else { this.currentIndex = rot(this.currentIndex + 1, this.model.changes.length); } @@ -435,13 +439,13 @@ export class DirtyDiffController implements IEditorContribution { this.widget.showChange(this.currentIndex); } - previous(): void { + previous(lineNumber?: number): void { if (!this.assertWidget()) { return; } - if (this.currentIndex === -1) { - this.currentIndex = this.findPreviousClosestChange(this.editor.getPosition().lineNumber); + if (typeof lineNumber === 'number' || this.currentIndex === -1) { + this.currentIndex = this.findPreviousClosestChange(typeof lineNumber === 'number' ? lineNumber : this.editor.getPosition().lineNumber); } else { this.currentIndex = rot(this.currentIndex - 1, this.model.changes.length); } @@ -465,8 +469,6 @@ export class DirtyDiffController implements IEditorContribution { } return true; - // this.widget.dispose(); - // this.widget = null; } if (!this.modelRegistry) { @@ -522,6 +524,57 @@ export class DirtyDiffController implements IEditorContribution { } } + private onEditorMouseDown(e: IEditorMouseEvent): void { + this.mouseDownInfo = null; + + // if (!this.model) { + // return; + // } + + // if (this.model.changes.length === 0) { + // return; + // } + + const range = e.target.range; + + if (!range) { + return; + } + + if (!e.event.leftButton) { + return; + } + + if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) { + return; + } + + this.mouseDownInfo = { lineNumber: range.startLineNumber }; + } + + private onEditorMouseUp(e: IEditorMouseEvent): void { + if (!this.mouseDownInfo) { + return; + } + + const { lineNumber } = this.mouseDownInfo; + this.mouseDownInfo = null; + + const range = e.target.range; + + if (!range || range.startLineNumber !== lineNumber) { + return; + } + + if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) { + return; + } + + // const closestChangeIndex = this.findNextClosestChange(lineNumber); + // this.currentIndex = rot(closestChangeIndex - 1, this.model.changes.length); + this.next(lineNumber); + } + private findNextClosestChange(lineNumber: number): number { for (let i = 0; i < this.model.changes.length; i++) { const change = this.model.changes[i]; From 193980e0baba336e63f892297942144bbc86844e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 12 Oct 2017 12:48:00 +0200 Subject: [PATCH 145/303] Aquire instantiation service after workbench is intialized --- src/vs/workbench/electron-browser/workbench.ts | 2 ++ .../configuration/node/configurationService.ts | 16 +++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 59b300fc28b..128753dedd6 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -624,6 +624,8 @@ export class Workbench implements IPartService { Registry.as(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService); this.instantiationService.createInstance(DefaultConfigurationExportHelper); + + this.configurationService.setInstantiationService(this.getInstantiationService()); } private initSettings(): void { diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 9a1c04fb4be..6edf38685bb 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -7,6 +7,7 @@ import URI from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; +import * as assert from 'vs/base/common/assert'; import Event, { Emitter } from 'vs/base/common/event'; import { StrictResourceMap } from 'vs/base/common/map'; import * as errors from 'vs/base/common/errors'; @@ -149,14 +150,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat updateValue(key: string, value: any, target: ConfigurationTarget): TPromise updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { - if (this.configurationEditingService) { - const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; - const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); - if (target) { - return this.writeConfigurationValue(key, value, target, overrides); - } - } - return TPromise.as(null); + assert.ok(this.configurationEditingService, 'Workbench is not initialized yet'); + const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; + const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); + return target ? this.writeConfigurationValue(key, value, target, overrides) + : TPromise.as(null); } reloadConfiguration(folder?: IWorkspaceFolder, key?: string): TPromise { @@ -215,7 +213,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat .then(() => this.initializeConfiguration()); } - aquireDelayedServices(instantiationService: IInstantiationService): void { + setInstantiationService(instantiationService: IInstantiationService): void { this.configurationEditingService = instantiationService.createInstance(ConfigurationEditingService); } From 6021c19a0bf196efcca70c44628b0ee1b9c6bd05 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2017 13:52:20 +0200 Subject: [PATCH 146/303] api - make sure RelativePattern is exported --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index f158ca9f725..4c7756fbfcb 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1685,7 +1685,7 @@ declare module 'vscode' { * relatively to a base path. The base path can either be an absolute file path * or a [workspace folder](#WorkspaceFolder). */ - class RelativePattern { + export class RelativePattern { /** * A base file path to which this pattern will be matched against relatively. From 6111b83cb1ed601b9f2e8c4990d7cd0740a25ed7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 12:07:03 +0200 Subject: [PATCH 147/303] use a single letter and render that --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 31 +++++++----- .../base/browser/ui/iconLabel/iconlabel.css | 15 +++++- src/vs/workbench/browser/labels.ts | 47 ++++++------------- .../electron-browser/scmFileDecorations.ts | 3 +- .../decorations/browser/decorations.ts | 3 +- 5 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index f97f73653d8..d7f7a42413e 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -25,7 +25,7 @@ export interface IIconLabelOptions { italic?: boolean; matches?: IMatch[]; color?: Color; - extraIcon?: uri; + badge?: { letter: string, title: string }; } class FastLabelNode { @@ -87,6 +87,7 @@ export class IconLabel { private domNode: FastLabelNode; private labelNode: FastLabelNode | HighlightedLabel; private descriptionNode: FastLabelNode; + private badgeNode: HTMLSpanElement; constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { this.domNode = new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label'))); @@ -147,18 +148,22 @@ export class IconLabel { this.descriptionNode.textContent = description || ''; this.descriptionNode.empty = !description; - if (options && options.extraIcon) { - this.element.style.backgroundImage = `url("${options.extraIcon.toString(true)}")`; - this.element.style.backgroundRepeat = 'no-repeat'; - this.element.style.backgroundPosition = 'right center'; - this.element.style.paddingRight = '20px'; - this.element.style.marginRight = '14px'; - } else { - this.element.style.backgroundImage = ''; - this.element.style.backgroundRepeat = ''; - this.element.style.backgroundPosition = ''; - this.element.style.paddingRight = ''; - this.element.style.marginRight = ''; + if (options && options.badge) { + if (!this.badgeNode) { + this.badgeNode = document.createElement('span'); + this.badgeNode.className = 'label-badge'; + this.badgeNode.style.backgroundColor = options.color.toString(); + this.badgeNode.style.color = (options.color.isDarker() ? Color.white : Color.black).toString(); + this.element.style.display = 'flex'; + this.element.appendChild(this.badgeNode); + } + const { letter, title } = options.badge; + this.badgeNode.innerHTML = letter; + this.badgeNode.title = title; + dom.show(this.badgeNode); + + } else if (this.badgeNode) { + dom.hide(this.badgeNode); } } diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 43078b1706b..a1dda94d93e 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -42,4 +42,17 @@ .monaco-icon-label.italic > .label-name, .monaco-icon-label.italic > .label-description { font-style: italic; -} \ No newline at end of file +} + +.monaco-icon-label > .label-badge { + align-self: center; + height: 12px; + min-width: 10px; + line-height: 12px; + font-size: 80%; + margin: 1px 15px 1px auto; + padding: 2px 4px; + border-radius: 14px; + font-weight: normal; + text-align: center; +} diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index cd57469d795..2f147796c63 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -25,8 +25,6 @@ import { Schemas } from 'vs/base/common/network'; import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { Color } from 'vs/base/common/color'; -import { localize } from 'vs/nls'; export interface IResourceLabel { name: string; @@ -159,60 +157,43 @@ export class ResourceLabel extends IconLabel { return; } + const iconLabelOptions: IIconLabelOptions = { + title: '', + italic: this.options && this.options.italic, + matches: this.options && this.options.matches, + }; + const resource = this.label.resource; let label = this.label.name; - let title = ''; + if (this.options && typeof this.options.title === 'string') { - title = this.options.title; + iconLabelOptions.title = this.options.title; } else if (resource) { - title = getPathLabel(resource, void 0, this.environmentService); + iconLabelOptions.title = getPathLabel(resource, void 0, this.environmentService); } if (!this.computedIconClasses) { this.computedIconClasses = getIconClasses(this.modelService, this.modeService, resource, this.options && this.options.fileKind); } - let extraClasses = this.computedIconClasses.slice(0); + iconLabelOptions.extraClasses = this.computedIconClasses.slice(0); if (this.options && this.options.extraClasses) { - extraClasses.push(...this.options.extraClasses); + iconLabelOptions.extraClasses.push(...this.options.extraClasses); } - const italic = this.options && this.options.italic; - const matches = this.options && this.options.matches; - - - - let color: Color; - let extraIcon: uri; if (this.options && this.options.fileDecorations) { let deco = this.decorationsService.getTopDecoration( resource, this.options.fileDecorations === 'all' ); - if (deco) { - color = this.themeService.getTheme().getColor(deco.color); - - if (deco.tooltip) { - title = localize('deco.tooltip', "{0}, {1}", title, deco.tooltip); - } - - if (deco.icon) { - const { type } = this.themeService.getTheme(); - extraIcon = type === 'light' ? deco.icon.light : deco.icon.dark; - } + iconLabelOptions.color = this.themeService.getTheme().getColor(deco.color); + iconLabelOptions.badge = deco.letter && { letter: deco.letter, title: deco.tooltip }; } } - this.setValue(label, this.label.description, { - title, - extraClasses, - italic, - matches, - color, - extraIcon - }); + this.setValue(label, this.label.description, iconLabelOptions); } public dispose(): void { diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 021d06178e2..4d774279bf8 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -70,7 +70,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { severity: Severity.Info, tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), color: this._config.fileDecorations.useColors ? resource.decorations.color : undefined, - icon: this._config.fileDecorations.useIcons ? { light: resource.decorations.icon, dark: resource.decorations.iconDark } : undefined + icon: this._config.fileDecorations.useIcons ? { light: resource.decorations.icon, dark: resource.decorations.iconDark } : undefined, + letter: resource.decorations.tooltip.charAt(0), }; } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 8a1740ffd80..2c177fb78f6 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -15,8 +15,9 @@ export const IResourceDecorationsService = createDecorator Date: Thu, 12 Oct 2017 12:10:41 +0200 Subject: [PATCH 148/303] deco - update settings --- .../parts/files/browser/files.contribution.ts | 4 ++-- .../parts/files/browser/views/explorerViewer.ts | 2 +- src/vs/workbench/parts/files/common/files.ts | 5 ++++- .../parts/scm/electron-browser/scm.contribution.ts | 10 ---------- .../parts/scm/electron-browser/scmFileDecorations.ts | 6 ++---- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index ecc17a60bdd..a0134692e4f 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -351,9 +351,9 @@ configurationRegistry.registerConfiguration({ ], 'description': nls.localize({ key: 'sortOrder', comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'] }, "Controls sorting order of files and folders in the explorer. In addition to the default sorting, you can set the order to 'mixed' (files and folders sorted combined), 'type' (by file type), 'modified' (by last modified date) or 'filesFirst' (sort files before folders).") }, - 'explorer.enableFileDecorations': { + 'explorer.fileDecorations.enabled': { type: 'boolean', - description: nls.localize('enableFileDecorations', "Controls if the explorer should show file decorations, like SCM status or problems."), + description: nls.localize('explorer.fileDecorations.enabled', "Controls if the explorer should show file decorations, like SCM status or problems."), default: true } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 10a815aebac..fb698179935 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -323,7 +323,7 @@ export class FileRenderer implements IRenderer { title: stat.nonexistentRoot ? nls.localize('canNotResolve', "Can not resolve folder {0}", stat.resource.toString()) : undefined, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, - fileDecorations: this.configurationService.getConfiguration().explorer.enableFileDecorations + fileDecorations: this.configurationService.getConfiguration().explorer.fileDecorations.enabled ? stat.isDirectory ? 'all' : 'mine' : undefined }); diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 150d33372a5..5a632e8d448 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -71,7 +71,10 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit enableDragAndDrop: boolean; confirmDelete: boolean; sortOrder: SortOrder; - enableFileDecorations: boolean; + fileDecorations: { + enabled: boolean; + + }; }; editor: IEditorOptions; } diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 16f6ce2631c..9510db9af9e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -76,16 +76,6 @@ Registry.as(Extensions.Configuration).registerConfigurat 'description': localize('scm.fileDecorations.enabled', "Show source control status on files and folders"), 'type': 'boolean', 'default': true - }, - 'scm.fileDecorations.useIcons': { - 'description': localize('scm.fileDecorations.useIcons', "Use icons when showing source control status on files and folders"), - 'type': 'boolean', - 'default': true - }, - 'scm.fileDecorations.useColors': { - 'description': localize('scm.fileDecorations.useColors', "Use colors when showing source control status on files and folders"), - 'type': 'boolean', - 'default': true } } }); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 4d774279bf8..cfef09270ad 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -69,9 +69,9 @@ class SCMDecorationsProvider implements IDecorationsProvider { return { severity: Severity.Info, tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), - color: this._config.fileDecorations.useColors ? resource.decorations.color : undefined, - icon: this._config.fileDecorations.useIcons ? { light: resource.decorations.icon, dark: resource.decorations.iconDark } : undefined, + color: resource.decorations.color, letter: resource.decorations.tooltip.charAt(0), + icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark }, }; } } @@ -79,8 +79,6 @@ class SCMDecorationsProvider implements IDecorationsProvider { interface ISCMConfiguration { fileDecorations: { enabled: boolean; - useIcons: boolean; - useColors: boolean; }; } From f813a949c11b8107918d77a7651db09ea1c2b585 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 12:27:37 +0200 Subject: [PATCH 149/303] adjust scm colors --- extensions/git/package.json | 12 ++++++------ src/vs/base/browser/ui/iconLabel/iconLabel.ts | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 58779e50bbc..36c197ba17c 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -809,18 +809,18 @@ "id": "git.color.modified", "description": "Color for modified resources", "defaults": { - "light": "#007BD0", - "dark": "#1B80B2", - "highContrast": "#1B80B2" + "light": "#D58809", + "dark": "#E2C08D", + "highContrast": "#E2C08D" } }, { "id": "git.color.untracked", "description": "Color for untracked resources", "defaults": { - "light": "#6C6C6C", - "dark": "#6C6C6C", - "highContrast": "#6C6C6C" + "light": "#00B333", + "dark": "#73C991", + "highContrast": "#73C991" } } ] diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index d7f7a42413e..ac6681f441f 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -153,7 +153,8 @@ export class IconLabel { this.badgeNode = document.createElement('span'); this.badgeNode.className = 'label-badge'; this.badgeNode.style.backgroundColor = options.color.toString(); - this.badgeNode.style.color = (options.color.isDarker() ? Color.white : Color.black).toString(); + // this.badgeNode.style.color = (options.color.isDarker() ? Color.white : Color.black).toString(); + this.badgeNode.style.color = Color.white.toString(); this.element.style.display = 'flex'; this.element.appendChild(this.badgeNode); } From ed7c83363cb7fa384f5004dbc184c777a5cf5fd1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 12:34:02 +0200 Subject: [PATCH 150/303] update colors on every update --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index ac6681f441f..aebc82519d8 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -152,15 +152,14 @@ export class IconLabel { if (!this.badgeNode) { this.badgeNode = document.createElement('span'); this.badgeNode.className = 'label-badge'; - this.badgeNode.style.backgroundColor = options.color.toString(); - // this.badgeNode.style.color = (options.color.isDarker() ? Color.white : Color.black).toString(); - this.badgeNode.style.color = Color.white.toString(); this.element.style.display = 'flex'; this.element.appendChild(this.badgeNode); } const { letter, title } = options.badge; this.badgeNode.innerHTML = letter; this.badgeNode.title = title; + this.badgeNode.style.backgroundColor = options.color.toString(); + this.badgeNode.style.color = Color.white.toString(); dom.show(this.badgeNode); } else if (this.badgeNode) { From 3023049fda06e383cb9a66374bb181da2dd1d7b8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 12:41:48 +0200 Subject: [PATCH 151/303] deco - explorer item should use flex --- src/vs/workbench/parts/files/browser/views/explorerViewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index fb698179935..dfd4b4601f7 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -313,7 +313,7 @@ export class FileRenderer implements IRenderer { // File Label if (!editableData) { - templateData.label.element.style.display = 'block'; + templateData.label.element.style.display = 'flex'; const extraClasses = ['explorer-item']; if (stat.nonexistentRoot) { extraClasses.push('nonexistent-root'); From 5970abcfc080d2de4aca6e499b463dc19bcbd465 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 13:50:10 +0200 Subject: [PATCH 152/303] make use badges, use colors an explorer setting --- src/vs/workbench/browser/labels.ts | 8 ++++---- .../parts/files/browser/files.contribution.ts | 12 +++++++++++- .../parts/files/browser/views/explorerViewer.ts | 4 +--- src/vs/workbench/parts/files/common/files.ts | 3 ++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 2f147796c63..90f75564dad 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -34,7 +34,7 @@ export interface IResourceLabel { export interface IResourceLabelOptions extends IIconLabelOptions { fileKind?: FileKind; - fileDecorations?: 'mine' | 'all'; + fileDecorations?: { useColors: boolean, useBadges: boolean }; } export class ResourceLabel extends IconLabel { @@ -185,11 +185,11 @@ export class ResourceLabel extends IconLabel { if (this.options && this.options.fileDecorations) { let deco = this.decorationsService.getTopDecoration( resource, - this.options.fileDecorations === 'all' + this.options.fileKind !== FileKind.FILE ); if (deco) { - iconLabelOptions.color = this.themeService.getTheme().getColor(deco.color); - iconLabelOptions.badge = deco.letter && { letter: deco.letter, title: deco.tooltip }; + iconLabelOptions.color = this.options.fileDecorations.useColors ? this.themeService.getTheme().getColor(deco.color) : undefined; + iconLabelOptions.badge = this.options.fileDecorations.useBadges ? deco.letter && { letter: deco.letter, title: deco.tooltip } : undefined; } } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index a0134692e4f..c9afa393d06 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -355,6 +355,16 @@ configurationRegistry.registerConfiguration({ type: 'boolean', description: nls.localize('explorer.fileDecorations.enabled', "Controls if the explorer should show file decorations, like SCM status or problems."), default: true - } + }, + 'explorer.fileDecorations.useColors': { + type: 'boolean', + description: nls.localize('explorer.fileDecorations.useColors', "Controls if file decorations should use colors."), + default: true + }, + 'explorer.fileDecorations.useBadges': { + type: 'boolean', + description: nls.localize('explorer.fileDecorations.useBadges', "Controls if file decorations should use badges."), + default: true + }, } }); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index dfd4b4601f7..d1bfd069259 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -323,9 +323,7 @@ export class FileRenderer implements IRenderer { title: stat.nonexistentRoot ? nls.localize('canNotResolve', "Can not resolve folder {0}", stat.resource.toString()) : undefined, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, - fileDecorations: this.configurationService.getConfiguration().explorer.fileDecorations.enabled - ? stat.isDirectory ? 'all' : 'mine' - : undefined + fileDecorations: this.configurationService.getConfiguration().explorer.fileDecorations.enabled ? this.configurationService.getConfiguration().explorer.fileDecorations : undefined }); } diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 5a632e8d448..c77f34767ba 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -73,7 +73,8 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit sortOrder: SortOrder; fileDecorations: { enabled: boolean; - + useColors: boolean; + useBadges: boolean; }; }; editor: IEditorOptions; From 91c6bf04ef77affafdf651ca592aab7ef7ab7347 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 14:46:49 +0200 Subject: [PATCH 153/303] update marker decorations --- .../parts/markers/browser/markersFileDecorations.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 4f36dfed113..9559c096924 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -24,9 +24,6 @@ class MarkersDecorationsProvider implements IDecorationsProvider { readonly label: string = localize('label', "Problems"); readonly onDidChange: Event; - // private static _warningIcon = { light: URI.parse(require.toUrl('./media/status-warning.svg')), dark: URI.parse(require.toUrl('./media/status-warning-inverse.svg')) }; - // private static _errorIcon = { light: URI.parse(require.toUrl('./media/status-error.svg')), dark: URI.parse(require.toUrl('./media/status-error-inverse.svg')) }; - constructor( private readonly _markerService: IMarkerService ) { @@ -46,8 +43,8 @@ class MarkersDecorationsProvider implements IDecorationsProvider { return { severity: first.severity, tooltip: localize('tooltip', "{0} problems in this file", markers.length), + letter: markers.length.toString(), color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, - // icon: first.severity === Severity.Error ? MarkersDecorationsProvider._errorIcon : MarkersDecorationsProvider._warningIcon }; } } From 2ea56837772b5a2cd75f57e96e216036545abc75 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 12 Oct 2017 15:23:49 +0200 Subject: [PATCH 154/303] debug: use an array for providers since it is easier to manipulate with --- src/vs/workbench/parts/debug/common/debug.ts | 1 + .../debugConfigurationManager.ts | 39 ++++++------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index f8b008d29c0..43212992fa4 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -387,6 +387,7 @@ export interface IRawAdapter extends IRawEnvAdapter { export interface IDebugConfigurationProvider { type: string; + handle: number; resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig): TPromise; provideDebugConfigurations?(folderUri: uri | undefined): TPromise; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index 4d2ba8ef44d..3cb95c98074 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -213,7 +213,7 @@ export class ConfigurationManager implements IConfigurationManager { private _selectedLaunch: ILaunch; private toDispose: IDisposable[]; private _onDidSelectConfigurationName = new Emitter(); - private _providers: Map; + private providers: IDebugConfigurationProvider[]; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @@ -228,7 +228,7 @@ export class ConfigurationManager implements IConfigurationManager { @IStorageService private storageService: IStorageService, @ILifecycleService lifecycleService: ILifecycleService ) { - this._providers = new Map(); + this.providers = []; this.adapters = []; this.toDispose = []; this.registerListeners(lifecycleService); @@ -242,7 +242,10 @@ export class ConfigurationManager implements IConfigurationManager { if (!debugConfigurationProvider) { return; } - this._providers.set(handle, debugConfigurationProvider); + + debugConfigurationProvider.handle = handle; + this.providers = this.providers.filter(p => p.handle !== handle); + this.providers.push(debugConfigurationProvider); const adapter = this.getAdapter(debugConfigurationProvider.type); // Check if the provider contributes provideDebugConfigurations method if (adapter && debugConfigurationProvider.provideDebugConfigurations) { @@ -250,22 +253,13 @@ export class ConfigurationManager implements IConfigurationManager { } } - public unregisterDebugConfigurationProvider(handle: number): boolean { - return this._providers.delete(handle); + public unregisterDebugConfigurationProvider(handle: number): void { + this.providers = this.providers.filter(p => p.handle !== handle); } public resolveDebugConfiguration(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): TPromise { - - // collect all candidates - const providers: IDebugConfigurationProvider[] = []; - this._providers.forEach(provider => { - if (provider.type === type && provider.resolveDebugConfiguration) { - providers.push(provider); - } - }); - // pipe the config through the promises sequentially - return providers.reduce((promise, provider) => { + return this.providers.filter(p => p.type === type && p.resolveDebugConfiguration).reduce((promise, provider) => { return promise.then(config => { if (config) { return provider.resolveDebugConfiguration(folderUri, config); @@ -277,19 +271,8 @@ export class ConfigurationManager implements IConfigurationManager { } public provideDebugConfigurations(folderUri: uri | undefined, type: string): TPromise { - - // collect all candidates - const configs: TPromise[] = []; - this._providers.forEach(provider => { - if (provider.type === type && provider.provideDebugConfigurations) { - configs.push(provider.provideDebugConfigurations(folderUri)); - } - }); - - // combine all configs into one array - return TPromise.join(configs).then(results => { - return [].concat.apply([], results); - }); + return TPromise.join(this.providers.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations(folderUri))) + .then(results => results.reduce((first, second) => first.concat(second), [])); } private registerListeners(lifecycleService: ILifecycleService): void { From c053a4b4ab762cad5be906c50b35dfb2e6cf1c13 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 12 Oct 2017 15:43:29 +0200 Subject: [PATCH 155/303] debug: go into initialize state earlier fixes #36044 --- src/vs/workbench/parts/debug/common/debug.ts | 2 +- .../debugConfigurationManager.ts | 2 +- .../parts/debug/electron-browser/debugService.ts | 16 +++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 43212992fa4..f226ca69b2b 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -416,7 +416,7 @@ export interface IConfigurationManager { registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void; unregisterDebugConfigurationProvider(handle: number): void; - resolveDebugConfiguration(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise; + resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise; } export interface ILaunch { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index 3cb95c98074..d303e2417ff 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -257,7 +257,7 @@ export class ConfigurationManager implements IConfigurationManager { this.providers = this.providers.filter(p => p.handle !== handle); } - public resolveDebugConfiguration(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): TPromise { + public resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): TPromise { // pipe the config through the promises sequentially return this.providers.filter(p => p.type === type && p.resolveDebugConfiguration).reduce((promise, provider) => { return promise.then(config => { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index b5fef6e3f4c..b5f6a854f91 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -701,13 +701,16 @@ export class DebugService implements debug.IDebugService { config.noDebug = true; } + const sessionId = generateUuid(); + this.updateStateAndEmit(sessionId, debug.State.Initializing); return (type ? TPromise.as(null) : this.configurationManager.guessAdapter().then(a => type = a && a.type)).then(() => - this.configurationManager.resolveDebugConfiguration(launch ? launch.workspace.uri : undefined, type, config).then(config => { + this.configurationManager.resolveConfigurationByProviders(launch ? launch.workspace.uri : undefined, type, config).then(config => { // a falsy config indicates an aborted launch if (config && config.type) { - return this.createProcess(root, config); + return this.createProcess(root, config, sessionId); } + this.updateStateAndEmit(sessionId, debug.State.Inactive); return launch.openConfigFile(false, type); // cast to ignore weird compile error }) ); @@ -724,7 +727,7 @@ export class DebugService implements debug.IDebugService { return null; } - public createProcess(root: IWorkspaceFolder, config: debug.IConfig): TPromise { + public createProcess(root: IWorkspaceFolder, config: debug.IConfig, sessionId?: string): TPromise { return this.textFileService.saveAll().then(() => (this.configurationManager.selectedLaunch ? this.configurationManager.selectedLaunch.resolveConfiguration(config) : TPromise.as(config)).then(resolvedConfig => { if (!resolvedConfig) { @@ -746,8 +749,10 @@ export class DebugService implements debug.IDebugService { return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] })); } - const sessionId = generateUuid(); - this.updateStateAndEmit(sessionId, debug.State.Initializing); + if (!sessionId) { + sessionId = generateUuid(); + this.updateStateAndEmit(sessionId, debug.State.Initializing); + } return this.runPreLaunchTask(root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0; @@ -783,6 +788,7 @@ export class DebugService implements debug.IDebugService { }); }); }, err => { + this.updateStateAndEmit(sessionId, debug.State.Inactive); if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(severity.Error, nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type.")); return undefined; From c65fde819e5cc8f852d431f2c2b5f331af5f9b5f Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 12 Oct 2017 15:18:48 +0200 Subject: [PATCH 156/303] arrows not showing anymore (for #35856) --- src/vs/workbench/parts/files/browser/views/explorerView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index eb2239c2b3a..c9680dc41f9 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -161,7 +161,7 @@ export class ExplorerView extends ViewsViewletPanel { const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => { DOM.toggleClass(this.treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons); - DOM.toggleClass(this.treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows); + DOM.toggleClass(this.treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true); }; this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); From cf70385df5022740fee61d8015278c5675227565 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 12 Oct 2017 16:55:08 +0200 Subject: [PATCH 157/303] Folding regions broken --- extensions/cpp/language-configuration.json | 4 ++-- extensions/csharp/language-configuration.json | 4 ++-- extensions/fsharp/language-configuration.json | 4 ++-- extensions/javascript/javascript-language-configuration.json | 4 ++-- extensions/powershell/language-configuration.json | 4 ++-- extensions/python/language-configuration.json | 4 ++-- extensions/typescript/language-configuration.json | 4 ++-- extensions/vb/language-configuration.json | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 9c297115ac4..a4f6c85aeab 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -28,8 +28,8 @@ }, "folding": { "markers": { - "start": "^\\s*#pragma\\s+region\b", - "end": "^\\s*#pragma\\s+endregion\b" + "start": "^\\s*#pragma\\s+region\\b", + "end": "^\\s*#pragma\\s+endregion\\b" } } } \ No newline at end of file diff --git a/extensions/csharp/language-configuration.json b/extensions/csharp/language-configuration.json index 32378524b53..88107685266 100644 --- a/extensions/csharp/language-configuration.json +++ b/extensions/csharp/language-configuration.json @@ -26,8 +26,8 @@ ], "folding": { "markers": { - "start": "^\\s*#region\b", - "end": "^\\s*#endregion\b" + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" } } } \ No newline at end of file diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index a24a9da3233..e4affc8deaa 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -24,8 +24,8 @@ "folding": { "offSide": true, "markers": { - "start": "^\\s*//\\s*#region\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)", - "end": "^\\s*//\\s*#endregion\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" + "start": "^\\s*//\\s*#region\\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)", + "end": "^\\s*//\\s*#endregion\\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" } } } diff --git a/extensions/javascript/javascript-language-configuration.json b/extensions/javascript/javascript-language-configuration.json index d8659c6bacf..1e8f440a420 100644 --- a/extensions/javascript/javascript-language-configuration.json +++ b/extensions/javascript/javascript-language-configuration.json @@ -27,8 +27,8 @@ ], "folding": { "markers": { - "start": "^\\s*//\\s*#?region\b", - "end": "^\\s*//\\s*#?endregion\b" + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" } } } \ No newline at end of file diff --git a/extensions/powershell/language-configuration.json b/extensions/powershell/language-configuration.json index 5c5ae4c2917..b03aa5cd42e 100644 --- a/extensions/powershell/language-configuration.json +++ b/extensions/powershell/language-configuration.json @@ -25,8 +25,8 @@ ], "folding": { "markers": { - "start": "^\\s*#region\b", - "end": "^\\s*#endregion\b" + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" } } } \ No newline at end of file diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index e709d275791..14ad98220b4 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -25,8 +25,8 @@ "folding": { "offSide": true, "markers": { - "start": "^\\s*#region\b", - "end": "^\\s*#endregion\b" + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" } } } diff --git a/extensions/typescript/language-configuration.json b/extensions/typescript/language-configuration.json index d8659c6bacf..1e8f440a420 100644 --- a/extensions/typescript/language-configuration.json +++ b/extensions/typescript/language-configuration.json @@ -27,8 +27,8 @@ ], "folding": { "markers": { - "start": "^\\s*//\\s*#?region\b", - "end": "^\\s*//\\s*#?endregion\b" + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" } } } \ No newline at end of file diff --git a/extensions/vb/language-configuration.json b/extensions/vb/language-configuration.json index d87841c6872..d9a6b21014a 100644 --- a/extensions/vb/language-configuration.json +++ b/extensions/vb/language-configuration.json @@ -23,8 +23,8 @@ ], "folding": { "markers": { - "start": "^\\s*#Region\b", - "end": "^\\s*#End Region\b" + "start": "^\\s*#Region\\b", + "end": "^\\s*#End Region\\b" } } } \ No newline at end of file From 49a3a359c0afb35901b39c3e83a77f2e9d1a5303 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 16:52:21 +0200 Subject: [PATCH 158/303] deco - use css classes for label colors, enabled proper selection colors --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 2 - src/vs/workbench/browser/labels.ts | 1 + .../decorations/browser/decorations.ts | 2 + .../decorations/browser/decorationsService.ts | 57 +++++++++++++++++++ .../test/browser/decorationsService.test.ts | 6 +- 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index aebc82519d8..716368f4562 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -131,8 +131,6 @@ export class IconLabel { if (options.italic) { classes.push('italic'); } - - this.element.style.color = options.color ? options.color.toString() : ''; } this.domNode.className = classes.join(' '); diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 90f75564dad..1de7dc08b3e 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -188,6 +188,7 @@ export class ResourceLabel extends IconLabel { this.options.fileKind !== FileKind.FILE ); if (deco) { + iconLabelOptions.extraClasses.push(deco.labelClasses); iconLabelOptions.color = this.options.fileDecorations.useColors ? this.themeService.getTheme().getColor(deco.color) : undefined; iconLabelOptions.badge = this.options.fileDecorations.useBadges ? deco.letter && { letter: deco.letter, title: deco.tooltip } : undefined; } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 2c177fb78f6..b2df4127a5a 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -20,6 +20,8 @@ export interface IResourceDecoration { readonly tooltip?: string; readonly icon?: { light: URI, dark: URI }; readonly leafOnly?: boolean; + + labelClasses?: string; } export interface IDecorationsProvider { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 5cb5e5cb6f9..ffdb4239add 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -12,6 +12,10 @@ import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; +import { createStyleSheet, createCSSRule } from 'vs/base/browser/dom'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IdGenerator } from 'vs/base/common/idGenerator'; +import { listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -120,6 +124,49 @@ class DecorationProviderWrapper { } } +class DecorationColors { + + private readonly _styleElement = createStyleSheet(); + private readonly _themeListener: IDisposable; + private readonly _classNames = new IdGenerator('decoration-'); + private readonly _classNames2ColorIds = new Map(); + + constructor( + @IThemeService private _themeService: IThemeService, + ) { + this._themeListener = this._themeService.onThemeChange(this._onThemeChange, this); + } + + dispose(): void { + this._themeListener.dispose(); + this._styleElement.innerHTML = ''; + } + + ensureCssStyles(decoration: IResourceDecoration): void { + if (!decoration || !decoration.color) { + return; + } + let className = this._classNames2ColorIds.get(decoration.color); + if (!className) { + className = this._classNames.nextId(); + this._classNames2ColorIds.set(decoration.color, className); + + createCSSRule(`.${className}`, `color: ${this._themeService.getTheme().getColor(decoration.color)}`, this._styleElement); + createCSSRule(`.selected .${className}`, `color: ${this._themeService.getTheme().getColor(listActiveSelectionForeground)}`, this._styleElement); + } + + decoration.labelClasses = className; + } + + private _onThemeChange(): void { + this._styleElement.innerHTML = ''; + this._classNames2ColorIds.forEach((className, color) => { + createCSSRule(`.${className}`, `color: ${this._themeService.getTheme().getColor(color)}`, this._styleElement); + createCSSRule(`.selected .${className}`, `color: ${this._themeService.getTheme().getColor(listActiveSelectionForeground)}`, this._styleElement); + }); + } +} + export class FileDecorationsService implements IResourceDecorationsService { _serviceBrand: any; @@ -127,6 +174,7 @@ export class FileDecorationsService implements IResourceDecorationsService { private readonly _data = new LinkedList(); private readonly _onDidChangeDecorationsDelayed = new Emitter(); private readonly _onDidChangeDecorations = new Emitter(); + private readonly _decorationStyles: DecorationColors; readonly onDidChangeDecorations: Event = any( this._onDidChangeDecorations.event, @@ -136,6 +184,14 @@ export class FileDecorationsService implements IResourceDecorationsService { ) ); + constructor( @IThemeService themeService: IThemeService) { + this._decorationStyles = new DecorationColors(themeService); + } + + dispose(): void { + this._decorationStyles.dispose(); + } + registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { const wrapper = new DecorationProviderWrapper(provider, this._onDidChangeDecorationsDelayed); @@ -165,6 +221,7 @@ export class FileDecorationsService implements IResourceDecorationsService { } }); } + this._decorationStyles.ensureCssStyles(top); return top; } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 5c6cf38d5db..3f5e430ac97 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -11,13 +11,17 @@ import { IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services import URI from 'vs/base/common/uri'; import Event, { toPromise } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; +import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; suite('DecorationsService', function () { let service: FileDecorationsService; setup(function () { - service = new FileDecorationsService(); + if (service) { + service.dispose(); + } + service = new FileDecorationsService(new TestThemeService()); }); test('Async provider, async/evented result', function () { From dcff484b718069afe6b80cc8c43169f276413f38 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 16:53:04 +0200 Subject: [PATCH 159/303] deco - stronger className --- .../services/decorations/browser/decorationsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index ffdb4239add..ae3f3eca617 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -128,7 +128,7 @@ class DecorationColors { private readonly _styleElement = createStyleSheet(); private readonly _themeListener: IDisposable; - private readonly _classNames = new IdGenerator('decoration-'); + private readonly _classNames = new IdGenerator('monaco-decoration-styles-'); private readonly _classNames2ColorIds = new Map(); constructor( From f7298698cc4ac586d65d195fa076dcf7371de514 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 17:22:27 +0200 Subject: [PATCH 160/303] deco - also use className for badge --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 13 +++--- src/vs/workbench/browser/labels.ts | 7 +++- .../decorations/browser/decorations.ts | 1 + .../decorations/browser/decorationsService.ts | 41 +++++++++++++------ 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 716368f4562..34f285e8c56 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -13,19 +13,23 @@ import uri from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import { IWorkspaceFolderProvider, getPathLabel, IUserHomeProvider } from 'vs/base/common/labels'; import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { Color } from 'vs/base/common/color'; export interface IIconLabelCreationOptions { supportHighlights?: boolean; } +export interface ILabelBadgeOptions { + letter: string; + title: string; + className: string; +} + export interface IIconLabelOptions { title?: string; extraClasses?: string[]; italic?: boolean; matches?: IMatch[]; - color?: Color; - badge?: { letter: string, title: string }; + badge?: ILabelBadgeOptions; } class FastLabelNode { @@ -156,8 +160,7 @@ export class IconLabel { const { letter, title } = options.badge; this.badgeNode.innerHTML = letter; this.badgeNode.title = title; - this.badgeNode.style.backgroundColor = options.color.toString(); - this.badgeNode.style.color = Color.white.toString(); + dom.addClass(this.badgeNode, options.badge.className); dom.show(this.badgeNode); } else if (this.badgeNode) { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 1de7dc08b3e..44862848b46 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -189,8 +189,11 @@ export class ResourceLabel extends IconLabel { ); if (deco) { iconLabelOptions.extraClasses.push(deco.labelClasses); - iconLabelOptions.color = this.options.fileDecorations.useColors ? this.themeService.getTheme().getColor(deco.color) : undefined; - iconLabelOptions.badge = this.options.fileDecorations.useBadges ? deco.letter && { letter: deco.letter, title: deco.tooltip } : undefined; + iconLabelOptions.badge = deco.letter ? { + letter: deco.letter, + title: deco.tooltip, + className: deco.badgeClassName, + } : undefined; } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index b2df4127a5a..0e229c103d6 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -22,6 +22,7 @@ export interface IResourceDecoration { readonly leafOnly?: boolean; labelClasses?: string; + badgeClassName?: string; } export interface IDecorationsProvider { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index ae3f3eca617..3a8c06338c3 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -15,7 +15,7 @@ import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule } from 'vs/base/browser/dom'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; +import { listActiveSelectionForeground, ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -129,7 +129,7 @@ class DecorationColors { private readonly _styleElement = createStyleSheet(); private readonly _themeListener: IDisposable; private readonly _classNames = new IdGenerator('monaco-decoration-styles-'); - private readonly _classNames2ColorIds = new Map(); + private readonly _classNames2ColorIds = new Map(); constructor( @IThemeService private _themeService: IThemeService, @@ -146,25 +146,42 @@ class DecorationColors { if (!decoration || !decoration.color) { return; } - let className = this._classNames2ColorIds.get(decoration.color); - if (!className) { - className = this._classNames.nextId(); - this._classNames2ColorIds.set(decoration.color, className); - createCSSRule(`.${className}`, `color: ${this._themeService.getTheme().getColor(decoration.color)}`, this._styleElement); - createCSSRule(`.selected .${className}`, `color: ${this._themeService.getTheme().getColor(listActiveSelectionForeground)}`, this._styleElement); + const tuple = this._classNames2ColorIds.get(decoration.color); + if (tuple) { + // from cache + decoration.labelClasses = tuple[0]; + decoration.badgeClassName = tuple[1]; + return; } - decoration.labelClasses = className; + let labelClassName = this._classNames.nextId(); + let badgeClassName = this._classNames.nextId(); + + this._classNames2ColorIds.set(decoration.color, [labelClassName, badgeClassName]); + decoration.labelClasses = labelClassName; + decoration.badgeClassName = badgeClassName; + + this._createCssRules(labelClassName, badgeClassName, decoration.color); } private _onThemeChange(): void { this._styleElement.innerHTML = ''; - this._classNames2ColorIds.forEach((className, color) => { - createCSSRule(`.${className}`, `color: ${this._themeService.getTheme().getColor(color)}`, this._styleElement); - createCSSRule(`.selected .${className}`, `color: ${this._themeService.getTheme().getColor(listActiveSelectionForeground)}`, this._styleElement); + this._classNames2ColorIds.forEach((tuple, color) => { + const [labelClassName, badgeClassName] = tuple; + this._createCssRules(labelClassName, badgeClassName, color); }); } + + private _createCssRules(labelClassName: string, badgeClassName: string, color: ColorIdentifier): void { + const theme = this._themeService.getTheme(); + // label + createCSSRule(`.${labelClassName}`, `color: ${theme.getColor(color)}`, this._styleElement); + createCSSRule(`.selected .${labelClassName}`, `color: ${theme.getColor(listActiveSelectionForeground)}`, this._styleElement); + + // badge + createCSSRule(`.${badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, this._styleElement); + } } export class FileDecorationsService implements IResourceDecorationsService { From 7088898d4487ebacb4d2cee79db992caf537a6f5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 12 Oct 2017 17:32:44 +0200 Subject: [PATCH 161/303] Use a configuration event that can answer if a configuration has changed or not given a resource and override identifier. Requested configuration can be full key or section --- .../configuration/common/configuration.ts | 32 ++--- .../common/configurationModels.ts | 109 +++++++++++++++++- .../node/configurationService.ts | 6 +- .../parts/debug/browser/debugActionItems.ts | 2 +- .../watermark/electron-browser/watermark.ts | 2 +- .../common/configurationModels.ts | 70 +++++++---- .../node/configurationService.ts | 47 ++++---- 7 files changed, 193 insertions(+), 75 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index b9cbfb0a599..a2132efea12 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import * as arrays from 'vs/base/common/arrays'; import * as objects from 'vs/base/common/objects'; import * as types from 'vs/base/common/types'; import URI from 'vs/base/common/uri'; @@ -12,7 +11,7 @@ import Event from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; export const IConfigurationService = createDecorator('configurationService'); @@ -30,12 +29,12 @@ export enum ConfigurationTarget { } export interface IConfigurationChangeEvent { - keys: string[]; - sections: string[]; - overrideIdentifiers?: string[]; + affectedKeys: string[]; - hasSectionChanged(section: string): boolean; - hasKeyChanged(key: string): boolean; + affectsConfiugration(configuration: string): boolean; + affectsConfiugration(configuration: string, overrideIdentifier: string): boolean; + affectsConfiugration(configuration: string, resource: URI): boolean; + affectsConfiugration(configuration: string, overrideIdentifier: string, resource: URI): boolean; // Following data is used for telemetry source: ConfigurationTarget; @@ -114,23 +113,6 @@ export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { add return { added, removed, updated }; } -export function toConfigurationUpdateEvent(udpated: string[], source: ConfigurationTarget, sourceConfig: any): IConfigurationChangeEvent { - const overrideIdentifiers = []; - const keys: string[] = []; - for (const key of udpated) { - if (OVERRIDE_PROPERTY_PATTERN.test(key)) { - overrideIdentifiers.push(overrideIdentifierFromKey(key).trim()); - } else { - keys.push(key); - } - } - const sections = arrays.distinct(keys.map(key => key.split('.')[0])); - const hasSectionChanged = (section) => sections.indexOf(section) !== -1; - const hasKeyChanged = (key) => keys.indexOf(key) !== -1; - - return { keys, sections, overrideIdentifiers, source, sourceConfig, hasSectionChanged, hasKeyChanged }; -} - export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any { const root = Object.create(null); @@ -227,4 +209,4 @@ export function overrideIdentifierFromKey(key: string): string { export function keyFromOverrideIdentifier(overrideIdentifier: string): string { return `[${overrideIdentifier}]`; -} \ No newline at end of file +} diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index c77ec098128..f86a10ee7d1 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys } from 'vs/platform/configuration/common/configuration'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; export class ConfigurationModel implements IConfiguraionModel { @@ -42,6 +42,15 @@ export class ConfigurationModel implements IConfiguraionModel { } } + public setValueInOverrides(overrideIdentifier: string, key: string, value: any): void { + let override = this._overrides.filter(override => override.identifiers.indexOf(overrideIdentifier) !== -1)[0]; + if (!override) { + override = { identifiers: [overrideIdentifier], contents: {} }; + this._overrides.push(override); + } + addToValueTree(override.contents, key, value, e => { throw new Error(e); }); + } + public removeValue(key: string) { // Remove key from the value tree const index = this._keys.indexOf(key); @@ -272,7 +281,7 @@ export class Configuration { updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { let memoryConfiguration: ConfigurationModel; if (overrides.resource) { - let memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource); + memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource); if (!memoryConfiguration) { memoryConfiguration = new ConfigurationModel(); this._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration); @@ -404,4 +413,100 @@ export class Configuration { private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { return new ConfigurationModel(model.contents, model.keys, model.overrides); } +} + +export class ConfigurationChangeEvent implements IConfigurationChangeEvent { + + private changedConfiguration: ConfigurationModel = new ConfigurationModel(); + private changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); + private resources: URI[] = []; + + private _source: ConfigurationTarget; + private _sourceConfig: any; + + change(event: ConfigurationChangeEvent): ConfigurationChangeEvent + change(keys: string[], resource?: URI): ConfigurationChangeEvent + change(arg1: any, arg2?: any): ConfigurationChangeEvent { + if (arg1 instanceof ConfigurationChangeEvent) { + this.changedConfiguration = this.changedConfiguration.merge(arg1.changedConfiguration); + for (const resource of arg1.resources) { + let changedConfigurationByResource = this.getOrSetChangedConfigurationForResource(resource); + changedConfigurationByResource = changedConfigurationByResource.merge(arg1.changedConfigurationByResource.get(resource)); + this.changedConfigurationByResource.set(resource, changedConfigurationByResource); + } + } + return this.changeWithKeys(arg1, arg2); + } + + telemetryData(source: ConfigurationTarget, sourceConfig: any): ConfigurationChangeEvent { + this._source = source; + this._sourceConfig = sourceConfig; + return this; + } + + get affectedKeys(): string[] { + const keys = [...this.changedConfiguration.keys]; + this.changedConfigurationByResource.forEach(model => keys.push(...model.keys)); + return keys; + } + + get source(): ConfigurationTarget { + return this._source; + } + + get sourceConfig(): any { + return this._sourceConfig; + } + + affectsConfiugration(config: string): boolean + affectsConfiugration(config: string, overrideIdentifier: string): boolean + affectsConfiugration(config: string, resource: URI): boolean + affectsConfiugration(config: string, overrideIdentifier: string, resource: URI): boolean + affectsConfiugration(config: string, arg1?: any, arg2?: any): boolean { + let resource = arg1 instanceof URI ? arg1 : arg2 instanceof URI ? arg2 : void 0; + let overrideIdentifier = resource && arg1 !== resource ? arg1 : void 0; + let model = resource ? this.changedConfigurationByResource.get(resource) : this.changedConfiguration; + if (model) { + + if (overrideIdentifier) { + return model.overrides.some(override => override.identifiers.indexOf(overrideIdentifier) !== -1); + } + + let changedKeysTree = model.contents; + let requestedTree = toValuesTree({ [config]: true }, () => { }); + + let key; + while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property + changedKeysTree = changedKeysTree[key]; + if (!changedKeysTree) { + return false; // Requested tree is not found + } + requestedTree = requestedTree[key]; + } + return true; + } + return false; + } + + private changeWithKeys(keys: string[], resource?: URI): ConfigurationChangeEvent { + let changedConfiguration = resource ? this.getOrSetChangedConfigurationForResource(resource) : this.changedConfiguration; + for (const key of keys) { + if (OVERRIDE_PROPERTY_PATTERN.test(key)) { + changedConfiguration.setValueInOverrides(overrideIdentifierFromKey(key), 'key'/* any key */, true); + } else { + changedConfiguration.setValue(key, true); + } + } + return this; + } + + private getOrSetChangedConfigurationForResource(resource: URI): ConfigurationModel { + let changedConfigurationByResource = this.changedConfigurationByResource.get(resource); + if (!changedConfigurationByResource) { + changedConfigurationByResource = new ConfigurationModel(); + this.changedConfigurationByResource.set(resource, changedConfigurationByResource); + this.resources.push(resource); + } + return changedConfigurationByResource; + } } \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 893af01e558..035060db7de 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -8,8 +8,8 @@ import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, toConfigurationUpdateEvent, compare } from 'vs/platform/configuration/common/configuration'; -import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration } from 'vs/platform/configuration/common/configurationModels'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare } from 'vs/platform/configuration/common/configuration'; +import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -132,7 +132,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe } private trigger(keys: string[], source: ConfigurationTarget): void { - this._onDidUpdateConfiguration.fire(toConfigurationUpdateEvent(keys, source, this.getTargetConfiguration(source))); + this._onDidUpdateConfiguration.fire(new ConfigurationChangeEvent().change(keys).telemetryData(source, this.getTargetConfiguration(source))); } private getTargetConfiguration(target: ConfigurationTarget): any { diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index 18b677b7f61..4cba52bfbcc 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -55,7 +55,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { private registerListeners(): void { this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.hasSectionChanged('launch')) { + if (e.affectsConfiugration('launch')) { this.updateOptions(); } })); diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index effbdb62019..11538b93dad 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -127,7 +127,7 @@ export class WatermarkContribution implements IWorkbenchContribution { } }); this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.hasKeyChanged(WORKBENCH_TIPS_ENABLED_KEY)) { + if (e.affectsConfiugration(WORKBENCH_TIPS_ENABLED_KEY)) { const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (enabled !== this.enabled) { this.enabled = enabled; diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 1223ae638a7..b4518c06965 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,8 +5,8 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; @@ -201,10 +201,9 @@ export class Configuration extends BaseConfiguration { this.merge(); } - updateUserConfiguration(user: ConfigurationModel): string[] { - let changedKeys = []; + updateUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent { const { added, updated, removed } = compare(this._user, user); - changedKeys = [...added, ...updated, ...removed]; + let changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); @@ -212,15 +211,13 @@ export class Configuration extends BaseConfiguration { this.merge(); changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); - return changedKeys; } - return []; + return new ConfigurationChangeEvent().change(changedKeys); } - updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): string[] { - let changedKeys = []; + updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): ConfigurationChangeEvent { const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration); - changedKeys = [...added, ...updated, ...removed]; + let changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); @@ -228,18 +225,16 @@ export class Configuration extends BaseConfiguration { this.merge(); changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); - return changedKeys; } - return []; + return new ConfigurationChangeEvent().change(changedKeys); } - updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): string[] { + updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): ConfigurationChangeEvent { const currentFolderConfiguration = this.folders.get(resource); if (currentFolderConfiguration) { - let changedKeys = []; const { added, updated, removed } = compare(currentFolderConfiguration, configuration); - changedKeys = [...added, ...updated, ...removed]; + let changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); @@ -247,29 +242,62 @@ export class Configuration extends BaseConfiguration { this.mergeFolder(resource); changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, { resource }), this.getValue(key, { resource }))); - return changedKeys; } - return []; + return new ConfigurationChangeEvent().change(changedKeys, resource); } this.folders.set(resource, configuration); this.mergeFolder(resource); - return configuration.keys; + return new ConfigurationChangeEvent().change(configuration.keys, resource); } - deleteFolderConfiguration(folder: URI): string[] { + deleteFolderConfiguration(folder: URI): ConfigurationChangeEvent { if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) { // Do not remove workspace configuration - return []; + return new ConfigurationChangeEvent(); } const keys = this.folders.get(folder).keys; this.folders.delete(folder); this._foldersConsolidatedConfigurations.delete(folder); - return keys; + return new ConfigurationChangeEvent().change(keys, folder); } getFolderConfigurationModel(folder: URI): FolderConfigurationModel { return this.folders.get(folder); } +} + +export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { + + constructor(private configurationChangeEvent: ConfigurationChangeEvent, private workspace: Workspace) { + } + + get affectedKeys(): string[] { + return this.configurationChangeEvent.affectedKeys; + } + + get source(): ConfigurationTarget { + return this.configurationChangeEvent.source; + } + + get sourceConfig(): any { + return this.configurationChangeEvent.sourceConfig; + } + + affectsConfiugration(config: string, arg1?: any, arg2?: any): boolean { + if (this.configurationChangeEvent.affectsConfiugration(config, arg1, arg2)) { + return true; + } + + let resource = arg1 instanceof URI ? arg1 : arg2 instanceof URI ? arg2 : void 0; + if (resource) { + let workspaceFolder = this.workspace.getFolder(resource); + if (workspaceFolder) { + return this.configurationChangeEvent.affectsConfiugration(config, resource && arg1 !== resource ? arg1 : void 0, resource); + } + } + + return false; + } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 6edf38685bb..a57b41a33f6 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -23,9 +23,9 @@ import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { CustomConfigurationModel, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; -import { IConfigurationChangeEvent, ConfigurationTarget, toConfigurationUpdateEvent, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; -import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration } from 'vs/workbench/services/configuration/common/configurationModels'; +import { CustomConfigurationModel, ConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; +import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { ConfigurationService as GlobalConfigurationService, isConfigurationOverrides } from 'vs/platform/configuration/node/configurationService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -37,7 +37,6 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; -import { distinct, flatten } from 'vs/base/common/arrays'; import { IConfigurationEditingService, ConfigurationTarget as EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; @@ -327,7 +326,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // TODO: compare with old values?? const keys = this._configuration.keys(); - this.triggerConfigurationChange([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder]), ConfigurationTarget.WORKSPACE); }); } @@ -363,7 +362,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat if (e.source === ConfigurationTarget.DEFAULT) { this.workspace.folders.forEach(folder => this._configuration.getFolderConfigurationModel(folder.uri).update()); this._configuration.updateDefaultConfiguration(this.baseConfigurationService.configuration.defaults); - this._onDidUpdateConfiguration.fire(e); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change(e.affectedKeys), e.source); } else { let keys = this._configuration.updateUserConfiguration(this.baseConfigurationService.configuration.user); this.triggerConfigurationChange(keys, e.source); @@ -373,18 +372,18 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private onWorkspaceConfigurationChanged(): TPromise { if (this.workspace && this.workspace.configuration && this._configuration) { - const changedWorkspaceKeys = this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration); + const workspaceConfigurationChangeEvent = this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration); let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.workspaceConfigurationModel.folders, URI.file(paths.dirname(this.workspace.configuration.fsPath))); const changes = this.compareFolders(this.workspace.folders, configuredFolders); if (changes.added.length || changes.removed.length || changes.changed.length) { this.workspace.folders = configuredFolders; return this.onFoldersChanged() - .then(changedFolderKeys => { - this.triggerConfigurationChange([...changedFolderKeys, ...changedWorkspaceKeys], ConfigurationTarget.WORKSPACE_FOLDER); + .then(foldersConfigurationChangeEvent => { + this.triggerConfigurationChange(foldersConfigurationChangeEvent.change(workspaceConfigurationChangeEvent), ConfigurationTarget.WORKSPACE_FOLDER); this._onDidChangeWorkspaceFolders.fire(changes); }); } else { - this.triggerConfigurationChange(changedWorkspaceKeys, ConfigurationTarget.WORKSPACE); + this.triggerConfigurationChange(workspaceConfigurationChangeEvent, ConfigurationTarget.WORKSPACE); } } return TPromise.as(null); @@ -395,8 +394,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // handle file event for each folder this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event) // Update folder configuration if handled - .then(folderConfiguration => folderConfiguration ? this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration) : [])) - ).then(changedKeys => this.triggerConfigurationChange(flatten(changedKeys), ConfigurationTarget.WORKSPACE_FOLDER)); + .then(folderConfiguration => folderConfiguration ? this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration) : new ConfigurationChangeEvent())) + ).then(changeEvents => { + const consolidateChangeEvent = changeEvents.reduce((consolidated, e) => consolidated.change(e), new ConfigurationChangeEvent()); + this.triggerConfigurationChange(consolidateChangeEvent, ConfigurationTarget.WORKSPACE_FOLDER); + }); } private onSingleFolderFileChanges(event: FileChangesEvent): TPromise { @@ -426,14 +428,14 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat }); } - private onFoldersChanged(): TPromise { - let changedKeys = []; + private onFoldersChanged(): TPromise { + let changeEvent = new ConfigurationChangeEvent(); // Remove the configurations of deleted folders for (const key of this.cachedFolderConfigs.keys()) { if (!this.workspace.folders.filter(folder => folder.uri.toString() === key.toString())[0]) { this.cachedFolderConfigs.delete(key); - changedKeys.push(...this._configuration.deleteFolderConfiguration(key)); + changeEvent = changeEvent.change(this._configuration.deleteFolderConfiguration(key)); } } @@ -442,12 +444,12 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return this.loadFolderConfigurations(toInitialize) .then(folderConfigurations => { folderConfigurations.forEach((folderConfiguration, index) => { - changedKeys.push(...this._configuration.updateFolderConfiguration(toInitialize[index].uri, folderConfiguration)); + changeEvent = changeEvent.change(this._configuration.updateFolderConfiguration(toInitialize[index].uri, folderConfiguration)); }); - return changedKeys; + return changeEvent; }); } - return TPromise.as(changedKeys); + return TPromise.as(changeEvent); } private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise { @@ -470,7 +472,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat if (target === ConfigurationTarget.MEMORY) { this._configuration.updateValue(key, value, overrides); - this.triggerConfigurationChange([key], target); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change(overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier)] : [key], overrides.resource), target); return TPromise.as(null); } @@ -531,9 +533,10 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } } - private triggerConfigurationChange(keys: string[], target: ConfigurationTarget): void { - if (keys.length) { - this._onDidUpdateConfiguration.fire(toConfigurationUpdateEvent(distinct(keys), target, this.getTargetConfiguration(target))); + private triggerConfigurationChange(configurationEvent: ConfigurationChangeEvent, target: ConfigurationTarget): void { + if (configurationEvent.affectedKeys.length) { + configurationEvent.telemetryData(target, this.getTargetConfiguration(target)); + this._onDidUpdateConfiguration.fire(new WorkspaceConfigurationChangeEvent(configurationEvent, this.workspace)); } } From 468389242f8226d03551bf9a2234a34be73949f6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2017 17:43:33 +0200 Subject: [PATCH 162/303] some :lipstick: to reduce editor opening flickering --- .../browser/parts/editor/editorGroupsControl.ts | 15 +++++++++++++++ .../workbench/browser/parts/editor/editorPart.ts | 2 +- .../browser/parts/editor/titleControl.ts | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index f7653de9370..ff6acd7892e 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -321,6 +321,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro public show(editor: BaseEditor, position: Position, preserveActive: boolean, ratio?: number[]): void { const visibleEditorCount = this.getVisibleEditorCount(); + const currentActivePosition = this.getActivePosition(); // Store into editor bucket this.visibleEditors[position] = editor; @@ -391,6 +392,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro this.sashOne.layout(); this.layoutContainers(); + this.updateInactiveEditorGroupActions(currentActivePosition); // prevent some ugly flickering when opening a group } // Adjust layout: []|[] -> []|[]|[!] @@ -404,6 +406,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro this.sashTwo.layout(); this.layoutContainers(); + this.updateInactiveEditorGroupActions(currentActivePosition); // prevent some ugly flickering when opening a group } // Show editor container @@ -2062,6 +2065,18 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro } } + private updateInactiveEditorGroupActions(position: Position): void { + const activePosition = this.getActivePosition(); + if (activePosition === position) { + return; // this position is actually active + } + + const titleArea = this.getTitleAreaControl(position); + if (titleArea) { + titleArea.updateEditorActionsToolbar(); + } + } + public getInstantiationService(position: Position): IInstantiationService { return this.getFromContainer(position, EditorGroupsControl.INSTANTIATION_SERVICE_KEY); } diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index d97142a5807..f64bf88b532 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -1164,7 +1164,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService const input = editor.input; // Resolve editor options - const preserveFocus = (activePosition !== position); + const preserveFocus = (activePosition !== position && ratio && ratio.length > 0); // during restore, preserve focus to reduce flicker let options: EditorOptions; if (editor.options) { options = editor.options; diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 8f78fd0e943..422ab06260c 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -60,6 +60,7 @@ export interface ITitleAreaControl { getContainer(): HTMLElement; refresh(instant?: boolean): void; update(instant?: boolean): void; + updateEditorActionsToolbar(): void; layout(): void; dispose(): void; } @@ -340,7 +341,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl return { primary, secondary }; } - protected updateEditorActionsToolbar(): void { + public updateEditorActionsToolbar(): void { const group = this.context; if (!group) { return; From ca6a055ba202bf2e57e55c6aa05f22317ce6de4f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2017 17:52:55 +0200 Subject: [PATCH 163/303] git - once again fix broken selection syncing --- extensions/git/src/commands.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 64dd80ceaa3..2988ad609a7 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -177,7 +177,9 @@ export class CommandCenter { const activeTextEditor = window.activeTextEditor; - if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.toString() === right.toString()) { + // Check if active text editor has same path as other editor. we cannot compare via + // URI.toString() here because the schemas can be different. Instead we just go by path. + if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.path === right.path) { opts.selection = activeTextEditor.selection; } @@ -414,11 +416,13 @@ export class CommandCenter { for (const uri of uris) { const opts: TextDocumentShowOptions = { preserveFocus, - preview: preview, + preview, viewColumn: ViewColumn.Active }; - if (activeTextEditor && activeTextEditor.document.uri.toString() === uri.toString()) { + // Check if active text editor has same path as other editor. we cannot compare via + // URI.toString() here because the schemas can be different. Instead we just go by path. + if (activeTextEditor && activeTextEditor.document.uri.path === uri.path) { opts.selection = activeTextEditor.selection; } From 3d503cb9a729581b33d225204c61e2632e9619f1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 18:19:52 +0200 Subject: [PATCH 164/303] deco - properly update on theme change --- .../decorations/browser/decorationsService.ts | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 3a8c06338c3..f489c5004d4 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -9,10 +9,10 @@ import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; -import { createStyleSheet, createCSSRule } from 'vs/base/browser/dom'; +import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; import { listActiveSelectionForeground, ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; @@ -126,19 +126,21 @@ class DecorationProviderWrapper { class DecorationColors { + private readonly _disposables: IDisposable[]; private readonly _styleElement = createStyleSheet(); - private readonly _themeListener: IDisposable; private readonly _classNames = new IdGenerator('monaco-decoration-styles-'); private readonly _classNames2ColorIds = new Map(); constructor( - @IThemeService private _themeService: IThemeService, + private _themeService: IThemeService, ) { - this._themeListener = this._themeService.onThemeChange(this._onThemeChange, this); + this._disposables = [ + this._themeService.onThemeChange(this._onThemeChange, this), + ]; } dispose(): void { - this._themeListener.dispose(); + dispose(this._disposables); this._styleElement.innerHTML = ''; } @@ -166,9 +168,10 @@ class DecorationColors { } private _onThemeChange(): void { - this._styleElement.innerHTML = ''; this._classNames2ColorIds.forEach((tuple, color) => { const [labelClassName, badgeClassName] = tuple; + removeCSSRulesContainingSelector(labelClassName, this._styleElement); + removeCSSRulesContainingSelector(badgeClassName, this._styleElement); this._createCssRules(labelClassName, badgeClassName, color); }); } @@ -201,7 +204,9 @@ export class FileDecorationsService implements IResourceDecorationsService { ) ); - constructor( @IThemeService themeService: IThemeService) { + constructor( + @IThemeService themeService: IThemeService, + ) { this._decorationStyles = new DecorationColors(themeService); } From 29cccbb9cbb6ce95bef97e3871d6060f005f48a6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 18:28:21 +0200 Subject: [PATCH 165/303] deco - never ending settings tweaks --- src/vs/workbench/browser/labels.ts | 10 ++++++---- .../parts/files/browser/files.contribution.ts | 13 ++++--------- .../parts/files/browser/views/explorerViewer.ts | 2 +- src/vs/workbench/parts/files/common/files.ts | 7 +++---- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 44862848b46..255348a5218 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -34,7 +34,7 @@ export interface IResourceLabel { export interface IResourceLabelOptions extends IIconLabelOptions { fileKind?: FileKind; - fileDecorations?: { useColors: boolean, useBadges: boolean }; + fileDecorations?: { colors: boolean, badges: boolean }; } export class ResourceLabel extends IconLabel { @@ -187,13 +187,15 @@ export class ResourceLabel extends IconLabel { resource, this.options.fileKind !== FileKind.FILE ); - if (deco) { + if (deco && this.options.fileDecorations.colors) { iconLabelOptions.extraClasses.push(deco.labelClasses); - iconLabelOptions.badge = deco.letter ? { + } + if (deco && deco.letter && this.options.fileDecorations.badges) { + iconLabelOptions.badge = { letter: deco.letter, title: deco.tooltip, className: deco.badgeClassName, - } : undefined; + }; } } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index c9afa393d06..878dea1810b 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -351,19 +351,14 @@ configurationRegistry.registerConfiguration({ ], 'description': nls.localize({ key: 'sortOrder', comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'] }, "Controls sorting order of files and folders in the explorer. In addition to the default sorting, you can set the order to 'mixed' (files and folders sorted combined), 'type' (by file type), 'modified' (by last modified date) or 'filesFirst' (sort files before folders).") }, - 'explorer.fileDecorations.enabled': { + 'explorer.decorations.colors': { type: 'boolean', - description: nls.localize('explorer.fileDecorations.enabled', "Controls if the explorer should show file decorations, like SCM status or problems."), + description: nls.localize('explorer.decorations.colors', "Controls if file decorations should use colors."), default: true }, - 'explorer.fileDecorations.useColors': { + 'explorer.decorations.badges': { type: 'boolean', - description: nls.localize('explorer.fileDecorations.useColors', "Controls if file decorations should use colors."), - default: true - }, - 'explorer.fileDecorations.useBadges': { - type: 'boolean', - description: nls.localize('explorer.fileDecorations.useBadges', "Controls if file decorations should use badges."), + description: nls.localize('explorer.decorations.badges', "Controls if file decorations should use badges."), default: true }, } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index d1bfd069259..b82590980a9 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -323,7 +323,7 @@ export class FileRenderer implements IRenderer { title: stat.nonexistentRoot ? nls.localize('canNotResolve', "Can not resolve folder {0}", stat.resource.toString()) : undefined, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses, - fileDecorations: this.configurationService.getConfiguration().explorer.fileDecorations.enabled ? this.configurationService.getConfiguration().explorer.fileDecorations : undefined + fileDecorations: this.configurationService.getConfiguration().explorer.decorations }); } diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index c77f34767ba..e63b3e56b59 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -71,10 +71,9 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit enableDragAndDrop: boolean; confirmDelete: boolean; sortOrder: SortOrder; - fileDecorations: { - enabled: boolean; - useColors: boolean; - useBadges: boolean; + decorations: { + colors: boolean; + badges: boolean; }; }; editor: IEditorOptions; From fcf92f6bc3469bc7cdb79b4eb88683f009f5a604 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2017 18:51:28 +0200 Subject: [PATCH 166/303] deco - split between decorations (reading) and decorations data (providing) --- src/vs/workbench/browser/labels.ts | 2 +- .../markers/browser/markersFileDecorations.ts | 4 +- .../electron-browser/scmFileDecorations.ts | 9 +- .../decorations/browser/decorations.ts | 16 +- .../decorations/browser/decorationsService.ts | 169 ++++++++++-------- .../test/browser/decorationsService.test.ts | 17 +- 6 files changed, 119 insertions(+), 98 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 255348a5218..963815fa275 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -188,7 +188,7 @@ export class ResourceLabel extends IconLabel { this.options.fileKind !== FileKind.FILE ); if (deco && this.options.fileDecorations.colors) { - iconLabelOptions.extraClasses.push(deco.labelClasses); + iconLabelOptions.extraClasses.push(deco.labelClassName); } if (deco && deco.letter && this.options.fileDecorations.badges) { iconLabelOptions.badge = { diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 9559c096924..d2e31659374 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; +import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; @@ -30,7 +30,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { this.onDidChange = _markerService.onMarkerChanged; } - provideDecorations(resource: URI): IResourceDecoration { + provideDecorations(resource: URI): IResourceDecorationData { const markers = this._markerService.read({ resource }) .sort((a, b) => Severity.compare(a.severity, b.severity)); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index cfef09270ad..dec7a16bb77 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -6,7 +6,7 @@ 'use strict'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IResourceDecorationsService, IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; +import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; @@ -61,17 +61,16 @@ class SCMDecorationsProvider implements IDecorationsProvider { this._onDidChange.fire(uris); } - provideDecorations(uri: URI): IResourceDecoration { + provideDecorations(uri: URI): IResourceDecorationData { const resource = this._data.get(uri.toString()); if (!resource) { return undefined; } return { severity: Severity.Info, - tooltip: localize('tooltip', "{0} - {1}", resource.decorations.tooltip, this._provider.label), + tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), color: resource.decorations.color, - letter: resource.decorations.tooltip.charAt(0), - icon: { light: resource.decorations.icon, dark: resource.decorations.iconDark }, + letter: resource.decorations.tooltip.charAt(0) }; } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 0e229c103d6..72f06102f77 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -13,22 +13,26 @@ import { IDisposable } from 'vs/base/common/lifecycle'; export const IResourceDecorationsService = createDecorator('IFileDecorationsService'); -export interface IResourceDecoration { +export interface IResourceDecorationData { readonly severity: Severity; readonly color?: ColorIdentifier; readonly letter?: string; readonly tooltip?: string; - readonly icon?: { light: URI, dark: URI }; - readonly leafOnly?: boolean; +} - labelClasses?: string; - badgeClassName?: string; +export interface IResourceDecoration { + readonly _decoBrand: undefined; + readonly severity: Severity; + readonly letter?: string; + readonly tooltip?: string; + readonly labelClassName?: string; + readonly badgeClassName?: string; } export interface IDecorationsProvider { readonly label: string; readonly onDidChange: Event; - provideDecorations(uri: URI): IResourceDecoration | Thenable; + provideDecorations(uri: URI): IResourceDecorationData | Thenable; } export interface IResourceDecorationChangeEvent { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index f489c5004d4..501c6ae6735 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; -import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider } from './decorations'; +import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IResourceDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; @@ -17,6 +17,79 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; import { listActiveSelectionForeground, ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; + +class DecorationColors { + + private readonly _disposables: IDisposable[]; + private readonly _styleElement = createStyleSheet(); + private readonly _classNames = new IdGenerator('monaco-decoration-styles-'); + private readonly _classNames2ColorIds = new Map(); + + constructor( + private _themeService: IThemeService, + ) { + this._disposables = [ + this._themeService.onThemeChange(this._onThemeChange, this), + ]; + } + + dispose(): void { + dispose(this._disposables); + this._styleElement.innerHTML = ''; + } + + makeResourceDecoration(decoration: IResourceDecorationData): IResourceDecoration { + if (!decoration) { + return undefined; + } + + let { severity, letter, tooltip } = decoration; + let labelClassName, badgeClassName; + + let tuple = this._classNames2ColorIds.get(decoration.color); + + if (tuple) { + // from cache + labelClassName = tuple[0]; + badgeClassName = tuple[1]; + } else { + // new css rules + labelClassName = this._classNames.nextId(); + badgeClassName = this._classNames.nextId(); + this._classNames2ColorIds.set(decoration.color, [labelClassName, badgeClassName]); + this._createCssRules(labelClassName, badgeClassName, decoration.color); + } + + return { + _decoBrand: undefined, + severity, + letter, + tooltip, + labelClassName, + badgeClassName + }; + } + + private _onThemeChange(): void { + this._classNames2ColorIds.forEach((tuple, color) => { + const [labelClassName, badgeClassName] = tuple; + removeCSSRulesContainingSelector(labelClassName, this._styleElement); + removeCSSRulesContainingSelector(badgeClassName, this._styleElement); + this._createCssRules(labelClassName, badgeClassName, color); + }); + } + + private _createCssRules(labelClassName: string, badgeClassName: string, color: ColorIdentifier): void { + const theme = this._themeService.getTheme(); + // label + createCSSRule(`.${labelClassName}`, `color: ${theme.getColor(color)}`, this._styleElement); + createCSSRule(`.selected .${labelClassName}`, `color: ${theme.getColor(listActiveSelectionForeground)}`, this._styleElement); + + // badge + createCSSRule(`.${badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, this._styleElement); + } +} + class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { private readonly _data = TernarySearchTree.forPaths(); @@ -49,6 +122,7 @@ class DecorationProviderWrapper { private readonly _dispoable: IDisposable; constructor( + private readonly _decorationStyles: DecorationColors, private readonly _provider: IDecorationsProvider, private readonly _emitter: Emitter ) { @@ -92,7 +166,7 @@ class DecorationProviderWrapper { const childTree = this._data.findSuperstr(key); if (childTree) { childTree.forEach(([, value]) => { - if (value && !isThenable(value) && !value.leafOnly) { + if (value && !isThenable(value)) { callback(value, true); } }); @@ -102,88 +176,27 @@ class DecorationProviderWrapper { private _fetchData(uri: URI): IResourceDecoration { - const decoOrThenable = this._provider.provideDecorations(uri); - if (!isThenable(decoOrThenable)) { + const dataOrThenable = this._provider.provideDecorations(uri); + if (!isThenable(dataOrThenable)) { // sync -> we have a result now - this._data.set(uri.toString(), decoOrThenable || null); - this._emitter.fire(uri); - return decoOrThenable; + return this._keepItem(uri, dataOrThenable); } else { // async -> we have a result soon - const request = Promise.resolve(decoOrThenable) - .then(data => { - this._data.set(uri.toString(), data || null); - this._emitter.fire(uri); - }) + const request = Promise.resolve(dataOrThenable) + .then(data => this._keepItem(uri, data)) .catch(_ => this._data.delete(uri.toString())); this._data.set(uri.toString(), request); return undefined; } } -} -class DecorationColors { - - private readonly _disposables: IDisposable[]; - private readonly _styleElement = createStyleSheet(); - private readonly _classNames = new IdGenerator('monaco-decoration-styles-'); - private readonly _classNames2ColorIds = new Map(); - - constructor( - private _themeService: IThemeService, - ) { - this._disposables = [ - this._themeService.onThemeChange(this._onThemeChange, this), - ]; - } - - dispose(): void { - dispose(this._disposables); - this._styleElement.innerHTML = ''; - } - - ensureCssStyles(decoration: IResourceDecoration): void { - if (!decoration || !decoration.color) { - return; - } - - const tuple = this._classNames2ColorIds.get(decoration.color); - if (tuple) { - // from cache - decoration.labelClasses = tuple[0]; - decoration.badgeClassName = tuple[1]; - return; - } - - let labelClassName = this._classNames.nextId(); - let badgeClassName = this._classNames.nextId(); - - this._classNames2ColorIds.set(decoration.color, [labelClassName, badgeClassName]); - decoration.labelClasses = labelClassName; - decoration.badgeClassName = badgeClassName; - - this._createCssRules(labelClassName, badgeClassName, decoration.color); - } - - private _onThemeChange(): void { - this._classNames2ColorIds.forEach((tuple, color) => { - const [labelClassName, badgeClassName] = tuple; - removeCSSRulesContainingSelector(labelClassName, this._styleElement); - removeCSSRulesContainingSelector(badgeClassName, this._styleElement); - this._createCssRules(labelClassName, badgeClassName, color); - }); - } - - private _createCssRules(labelClassName: string, badgeClassName: string, color: ColorIdentifier): void { - const theme = this._themeService.getTheme(); - // label - createCSSRule(`.${labelClassName}`, `color: ${theme.getColor(color)}`, this._styleElement); - createCSSRule(`.selected .${labelClassName}`, `color: ${theme.getColor(listActiveSelectionForeground)}`, this._styleElement); - - // badge - createCSSRule(`.${badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, this._styleElement); + private _keepItem(uri: URI, data: IResourceDecorationData): IResourceDecoration { + let deco = data ? this._decorationStyles.makeResourceDecoration(data) : null; + this._data.set(uri.toString(), deco); + this._emitter.fire(uri); + return deco; } } @@ -216,7 +229,11 @@ export class FileDecorationsService implements IResourceDecorationsService { registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { - const wrapper = new DecorationProviderWrapper(provider, this._onDidChangeDecorationsDelayed); + const wrapper = new DecorationProviderWrapper( + this._decorationStyles, + provider, + this._onDidChangeDecorationsDelayed + ); const remove = this._data.push(wrapper); return { dispose: () => { @@ -237,13 +254,13 @@ export class FileDecorationsService implements IResourceDecorationsService { if (isChild && top === candidate) { // only bubble up color top = { + _decoBrand: undefined, severity: top.severity, - color: top.color + labelClassName: top.labelClassName }; } }); } - this._decorationStyles.ensureCssStyles(top); return top; } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 3f5e430ac97..f6a004f6fb0 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; -import { IDecorationsProvider, IResourceDecoration } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import URI from 'vs/base/common/uri'; import Event, { toPromise } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; @@ -34,10 +34,11 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => resolve({ severity: Severity.Info, - color: 'someBlue' + color: 'someBlue', + letter: 'T' })); }); } @@ -52,7 +53,7 @@ suite('DecorationsService', function () { assert.equal(e.affectsResource(uri), true); // sync result - assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.deepEqual(service.getTopDecoration(uri, false).letter, 'T'); assert.equal(callCounter, 1); }); }); @@ -67,12 +68,12 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue' }; + return { severity: Severity.Info, color: 'someBlue', letter: 'Z' }; } }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.deepEqual(service.getTopDecoration(uri, false).letter, 'Z'); assert.equal(callCounter, 1); }); @@ -85,12 +86,12 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue' }; + return { severity: Severity.Info, color: 'someBlue', letter: 'J' }; } }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false), { severity: Severity.Info, color: 'someBlue' }); + assert.deepEqual(service.getTopDecoration(uri, false).letter, 'J'); assert.equal(callCounter, 1); // un-register -> ensure good event From 49e570e136d8416cc794f46794ce75d09de5ad5a Mon Sep 17 00:00:00 2001 From: jmdowns2 Date: Thu, 12 Oct 2017 13:26:55 -0400 Subject: [PATCH 167/303] Fix for #32342 (#35463) * When expanding abbreviations, do so from bottom to top. This way a change higher up will not interfere with text below. * When expanding abbreviations, do so from bottom to top. This way a change higher up will not interfere with text below. --- extensions/emmet/src/abbreviationActions.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index c0d3758abdb..2cf7e0501de 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -139,7 +139,14 @@ export function expandEmmetAbbreviation(args): Thenable { return [new vscode.Range(abbreviationRange.start.line, abbreviationRange.start.character, abbreviationRange.end.line, abbreviationRange.end.character), abbreviation, filter]; }; - editor.selections.forEach(selection => { + let selectionsInReverseOrder = editor.selections.slice(0); + selectionsInReverseOrder.sort((a, b) => { + var posA = a.isReversed ? a.anchor : a.active; + var posB = b.isReversed ? b.anchor : b.active; + return posA.compareTo(posB) * -1; + }); + + selectionsInReverseOrder.forEach(selection => { let position = selection.isReversed ? selection.anchor : selection.active; let [rangeToReplace, abbreviation, filter] = getAbbreviation(editor.document, selection, position, syntax); if (!rangeToReplace) { From b5f41b98022df299ec8c99143be38bb8f7dae063 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 12 Oct 2017 15:59:00 -0700 Subject: [PATCH 168/303] Let workspaceContains trigger use rg --quiet (fixes #35236) --- src/vs/platform/search/common/search.ts | 6 ++ src/vs/workbench/node/extensionHostMain.ts | 4 +- .../services/search/node/fileSearch.ts | 10 ++- .../services/search/node/ripgrepFileSearch.ts | 4 + .../workbench/services/search/node/search.ts | 1 + .../services/search/node/searchService.ts | 1 + .../services/search/test/node/search.test.ts | 82 +++++++++++++++++++ 7 files changed, 104 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index bb2a8df08e4..bdd1918a876 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -44,6 +44,12 @@ export interface ICommonQueryOptions { filePattern?: string; // file search only fileEncoding?: string; maxResults?: number; + /** + * If true no results will be returned. Instead `limitHit` will indicate if at least one result exists or not. + * + * Currently does not work with queries including a 'siblings clause'. + */ + exists?: boolean; sortByScore?: boolean; cacheKey?: string; useRipgrep?: boolean; diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index cda0a718027..a28fb2b6a9b 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -232,13 +232,13 @@ export class ExtensionHostMain { const query: ISearchQuery = { folderQueries, type: QueryType.File, - maxResults: 1, + exists: true, includePattern: includes, useRipgrep }; let result = await this._diskSearch.search(query); - if (result.results.length > 0) { + if (result.limitHit) { // a file was found matching one of the glob patterns return ( this._extensionService.activateById(extensionId, true) diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index ff457516718..02e7c5e570c 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -53,6 +53,7 @@ export class FileWalker { private normalizedFilePatternLowercase: string; private includePattern: glob.ParsedExpression; private maxResults: number; + private exists: boolean; private maxFilesize: number; private isLimitHit: boolean; private resultCount: number; @@ -77,6 +78,7 @@ export class FileWalker { this.filePattern = config.filePattern; this.includePattern = config.includePattern && glob.parse(config.includePattern); this.maxResults = config.maxResults || null; + this.exists = config.exists; this.maxFilesize = config.maxFilesize || null; this.walkedPaths = Object.create(null); this.resultCount = 0; @@ -234,6 +236,7 @@ export class FileWalker { return; } if (this.isLimitHit) { + done(); return; } @@ -392,9 +395,12 @@ export class FileWalker { cmd.on('close', (code: number) => { // ripgrep returns code=1 when no results are found - if (code !== 0 && ((isRipgrep && stderr.length) || !isRipgrep)) { + if (code !== 0 && (!isRipgrep || code !== 1)) { done(new Error(`command failed with error code ${code}: ${this.decodeData(stderr, encoding)}`)); } else { + if (isRipgrep && this.exists && code === 0) { + this.isLimitHit = true; + } done(null, '', true); } }); @@ -657,7 +663,7 @@ export class FileWalker { if (this.isFilePatternMatch(candidate.relativePath) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) { this.resultCount++; - if (this.maxResults && this.resultCount > this.maxResults) { + if (this.exists || (this.maxResults && this.resultCount > this.maxResults)) { this.isLimitHit = true; } diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts index 7b4b508b4e4..caba0ebd233 100644 --- a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -44,6 +44,10 @@ function getRgArgs(config: IRawSearch, folderQuery: IFolderSearch, includePatter // Follow symlinks args.push('--follow'); + if (config.exists) { + args.push('--quiet'); + } + // Folder to search args.push('--'); diff --git a/src/vs/workbench/services/search/node/search.ts b/src/vs/workbench/services/search/node/search.ts index 424b3b4f0f7..38c3be3415c 100644 --- a/src/vs/workbench/services/search/node/search.ts +++ b/src/vs/workbench/services/search/node/search.ts @@ -25,6 +25,7 @@ export interface IRawSearch { includePattern?: IExpression; contentPattern?: IPatternInfo; maxResults?: number; + exists?: boolean; sortByScore?: boolean; cacheKey?: string; maxFilesize?: number; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index b7adc8e63a9..85c20bd1f10 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -266,6 +266,7 @@ export class DiskSearch implements ISearchResultProvider { excludePattern: query.excludePattern, includePattern: query.includePattern, maxResults: query.maxResults, + exists: query.exists, sortByScore: query.sortByScore, cacheKey: query.cacheKey, useRipgrep: query.useRipgrep, diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index abecd589774..f7fbebd6835 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -84,6 +84,88 @@ suite('FileSearchEngine', () => { }); }); + test('Files: exists', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/file.txt': true }, + exists: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + + test('Files: not exists', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/nofile.txt': true }, + exists: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(!complete.limitHit); + done(); + }); + }); + + test('Files: exists without Ripgrep', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/file.txt': true }, + exists: true, + useRipgrep: false + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + + test('Files: not exists without Ripgrep', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/nofile.txt': true }, + exists: true, + useRipgrep: false + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(!complete.limitHit); + done(); + }); + }); + test('Files: examples/com*', function (done: () => void) { let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, From 9ca019f9e8c7a6a35dcff32fa9bfb6439c5c1699 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 12 Oct 2017 15:38:21 -0700 Subject: [PATCH 169/303] Update js/ts grammars --- .../syntaxes/JavaScript.tmLanguage.json | 22 +++++++++---------- .../syntaxes/JavaScriptReact.tmLanguage.json | 22 +++++++++---------- .../syntaxes/TypeScript.tmLanguage.json | 22 +++++++++---------- .../syntaxes/TypeScriptReact.tmLanguage.json | 22 +++++++++---------- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 466cb34a314..2c53d302110 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -278,7 +278,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -512,7 +512,7 @@ } }, { - "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -739,7 +739,7 @@ }, { "name": "meta.definition.property.js entity.name.function.js", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" }, { "name": "meta.definition.property.js variable.object.property.js", @@ -1002,7 +1002,7 @@ }, { "name": "meta.arrow.js", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -1950,7 +1950,7 @@ }, { "name": "meta.object.member.js", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js" @@ -2043,13 +2043,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2496,7 +2496,7 @@ } }, { - "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.js" @@ -2576,7 +2576,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js" diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 29aa8b6a2a2..c516b79e5c9 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "fileTypes": [ @@ -278,7 +278,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js.jsx", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" @@ -512,7 +512,7 @@ } }, { - "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -739,7 +739,7 @@ }, { "name": "meta.definition.property.js.jsx entity.name.function.js.jsx", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" }, { "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", @@ -1002,7 +1002,7 @@ }, { "name": "meta.arrow.js.jsx", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -1950,7 +1950,7 @@ }, { "name": "meta.object.member.js.jsx", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js.jsx" @@ -2043,13 +2043,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js.jsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2496,7 +2496,7 @@ } }, { - "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.js.jsx" @@ -2576,7 +2576,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js.jsx" diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index ba5c664ccf4..fc4a8971471 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -272,7 +272,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.ts", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -506,7 +506,7 @@ } }, { - "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -733,7 +733,7 @@ }, { "name": "meta.definition.property.ts entity.name.function.ts", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" }, { "name": "meta.definition.property.ts variable.object.property.ts", @@ -996,7 +996,7 @@ }, { "name": "meta.arrow.ts", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -1944,7 +1944,7 @@ }, { "name": "meta.object.member.ts", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.ts" @@ -2037,13 +2037,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.ts", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2527,7 +2527,7 @@ } }, { - "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -2607,7 +2607,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.ts" diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json index 8266fec39bb..aab4d2f34e3 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/5955a5aed3d8d2862c614f2137d22f2334d490e9", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", "name": "TypeScriptReact", "scopeName": "source.tsx", "fileTypes": [ @@ -275,7 +275,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.tsx", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -509,7 +509,7 @@ } }, { - "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -736,7 +736,7 @@ }, { "name": "meta.definition.property.tsx entity.name.function.tsx", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" }, { "name": "meta.definition.property.tsx variable.object.property.tsx", @@ -999,7 +999,7 @@ }, { "name": "meta.arrow.tsx", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -1947,7 +1947,7 @@ }, { "name": "meta.object.member.tsx", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.tsx" @@ -2040,13 +2040,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.tsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2493,7 +2493,7 @@ } }, { - "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -2573,7 +2573,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.tsx" From ae20b2073a90a80422f3fc873ff212ce3a64da4b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 12 Oct 2017 15:47:26 -0700 Subject: [PATCH 170/303] Make sure we rewrite contentName for jsx grammar --- .../syntaxes/JavaScript.tmLanguage.json | 8 +- .../syntaxes/JavaScriptReact.tmLanguage.json | 8 +- .../test/colorize-results/test_jsx.json | 78 +++++++++---------- .../typescript/build/update-grammars.js | 3 + 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 2c53d302110..85546d41404 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -3225,7 +3225,7 @@ "include": "#expression" } ], - "contentName": "meta.embedded.line.tsx" + "contentName": "meta.embedded.line.js" }, "regex": { "patterns": [ @@ -3482,7 +3482,7 @@ } }, "end": "(?=^)", - "contentName": "comment.line.double-slash.tsx" + "contentName": "comment.line.double-slash.js" } ] }, @@ -4020,7 +4020,7 @@ "name": "punctuation.definition.tag.end.js" } }, - "contentName": "meta.jsx.children.tsx", + "contentName": "meta.jsx.children.js", "patterns": [ { "include": "#jsx-children" @@ -4124,7 +4124,7 @@ } }, "end": "(?=", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1651,7 +1651,7 @@ }, { "c": "Hello ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1662,7 +1662,7 @@ }, { "c": "{", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1673,7 +1673,7 @@ }, { "c": "message", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx variable.other.readwrite.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1684,7 +1684,7 @@ }, { "c": "}", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1695,7 +1695,7 @@ }, { "c": "!", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1706,7 +1706,7 @@ }, { "c": "", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1739,7 +1739,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1750,7 +1750,7 @@ }, { "c": "<", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1761,7 +1761,7 @@ }, { "c": "a", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.name.tag.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1772,7 +1772,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1783,7 @@ }, { "c": "href", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1794,7 +1794,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1805,7 +1805,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1816,7 +1816,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1827,7 +1827,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1838,7 +1838,7 @@ }, { "c": "onClick", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1849,7 +1849,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1860,7 +1860,7 @@ }, { "c": "{", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1871,7 +1871,7 @@ }, { "c": "this", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1882,7 +1882,7 @@ }, { "c": ".", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "meta.embedded: #D4D4D4", "light_plus": "meta.embedded: #000000", @@ -1893,7 +1893,7 @@ }, { "c": "toggle", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1904,7 +1904,7 @@ }, { "c": "}", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1915,7 +1915,7 @@ }, { "c": ">", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1926,7 +1926,7 @@ }, { "c": "Toggle", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1937,7 +1937,7 @@ }, { "c": "", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1970,7 +1970,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/typescript/build/update-grammars.js b/extensions/typescript/build/update-grammars.js index e82549b4eef..bae3329d9b1 100644 --- a/extensions/typescript/build/update-grammars.js +++ b/extensions/typescript/build/update-grammars.js @@ -15,6 +15,9 @@ function adaptToJavaScript(grammar, replacementScope) { if (typeof rule.name === 'string') { rule.name = rule.name.replace(/\.tsx/g, replacementScope); } + if (typeof rule.contentName === 'string') { + rule.contentName = rule.contentName.replace(/\.tsx/g, replacementScope); + } for (var property in rule) { var value = rule[property]; if (typeof value === 'object') { From d1047a65ed5db2ffc26c01ebc6f4ed91a0b5eb26 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 12 Oct 2017 19:24:57 -0700 Subject: [PATCH 171/303] Pick up first TS 2.6 insiders --- extensions/npm-shrinkwrap.json | 6 +++--- extensions/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/npm-shrinkwrap.json b/extensions/npm-shrinkwrap.json index 4a636d0dcfe..3a586ecad98 100644 --- a/extensions/npm-shrinkwrap.json +++ b/extensions/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "0.0.1", "dependencies": { "typescript": { - "version": "2.5.3", - "from": "typescript@2.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz" + "version": "2.6.0-insiders.20171013", + "from": "typescript@2.6.0-insiders.20171013", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.0-insiders.20171013.tgz" } } } diff --git a/extensions/package.json b/extensions/package.json index 798babbda78..ce960b5b23b 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "2.5.3" + "typescript": "2.6.0-insiders.20171013" }, "scripts": { "postinstall": "node ./postinstall" From c697689589e7f3b81551ba78b17d28f5ba88c6a0 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 09:30:33 +0200 Subject: [PATCH 172/303] [folding] add java folding regions --- extensions/java/language-configuration.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/java/language-configuration.json b/extensions/java/language-configuration.json index 5ae0cec3192..cc45a8a0139 100644 --- a/extensions/java/language-configuration.json +++ b/extensions/java/language-configuration.json @@ -23,5 +23,11 @@ ["\"", "\""], ["'", "'"], ["<", ">"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*(#?region\\b)|()" + } + } } From 1621e289c4a2466c6f98e56edeaf7978ab229637 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2017 09:55:05 +0200 Subject: [PATCH 173/303] fix broken terminal --- .../electron-browser/terminalInstance.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index da798434930..113ed5e0e48 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -511,14 +511,16 @@ export class TerminalInstance implements ITerminalInstance { // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. this._xterm.emit('scroll', this._xterm.buffer.ydisp); - // Force a layout when the instance becomes invisible. This is particularly important - // for ensuring that terminals that are created in the background by an extension will - // correctly get correct character measurements in order to render to the screen (see - // #34554). - const computedStyle = window.getComputedStyle(this._container); - const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); - const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); - this.layout(new Dimension(width, height)); + if (this._container) { + // Force a layout when the instance becomes invisible. This is particularly important + // for ensuring that terminals that are created in the background by an extension will + // correctly get correct character measurements in order to render to the screen (see + // #34554). + const computedStyle = window.getComputedStyle(this._container); + const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); + const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); + this.layout(new Dimension(width, height)); + } } } From f1ee80be081b0d47f4423b9dc5f41a65c36146da Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 10:01:15 +0200 Subject: [PATCH 174/303] support opacity --- .../decorations/browser/decorations.ts | 1 + .../decorations/browser/decorationsService.ts | 123 +++++++++++------- 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 72f06102f77..337311d6709 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -16,6 +16,7 @@ export const IResourceDecorationsService = createDecorator(); + private readonly _classNames2ColorIds = new Map(); constructor( private _themeService: IThemeService, @@ -35,59 +83,36 @@ class DecorationColors { dispose(): void { dispose(this._disposables); - this._styleElement.innerHTML = ''; + this._styleElement.parentElement.removeChild(this._styleElement); } - makeResourceDecoration(decoration: IResourceDecorationData): IResourceDecoration { - if (!decoration) { + asDecoration(data: IResourceDecorationData): IResourceDecoration { + if (!data) { return undefined; } - let { severity, letter, tooltip } = decoration; - let labelClassName, badgeClassName; + let key = DecorationRule.keyOf(data); + let rule = this._classNames2ColorIds.get(data.color); + let result = new ResourceDecoration(data); - let tuple = this._classNames2ColorIds.get(decoration.color); - - if (tuple) { - // from cache - labelClassName = tuple[0]; - badgeClassName = tuple[1]; - } else { - // new css rules - labelClassName = this._classNames.nextId(); - badgeClassName = this._classNames.nextId(); - this._classNames2ColorIds.set(decoration.color, [labelClassName, badgeClassName]); - this._createCssRules(labelClassName, badgeClassName, decoration.color); + if (!rule) { + // new css rule + rule = new DecorationRule(data); + this._classNames2ColorIds.set(key, rule); + rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); } - return { - _decoBrand: undefined, - severity, - letter, - tooltip, - labelClassName, - badgeClassName - }; + result.labelClassName = rule.labelClassName; + result.badgeClassName = rule.badgeClassName; + return result; } private _onThemeChange(): void { - this._classNames2ColorIds.forEach((tuple, color) => { - const [labelClassName, badgeClassName] = tuple; - removeCSSRulesContainingSelector(labelClassName, this._styleElement); - removeCSSRulesContainingSelector(badgeClassName, this._styleElement); - this._createCssRules(labelClassName, badgeClassName, color); + this._classNames2ColorIds.forEach((rule, color) => { + rule.removeCSSRules(this._styleElement); + rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); }); } - - private _createCssRules(labelClassName: string, badgeClassName: string, color: ColorIdentifier): void { - const theme = this._themeService.getTheme(); - // label - createCSSRule(`.${labelClassName}`, `color: ${theme.getColor(color)}`, this._styleElement); - createCSSRule(`.selected .${labelClassName}`, `color: ${theme.getColor(listActiveSelectionForeground)}`, this._styleElement); - - // badge - createCSSRule(`.${badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, this._styleElement); - } } class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -122,7 +147,7 @@ class DecorationProviderWrapper { private readonly _dispoable: IDisposable; constructor( - private readonly _decorationStyles: DecorationColors, + private readonly _decorationStyles: DecorationStyles, private readonly _provider: IDecorationsProvider, private readonly _emitter: Emitter ) { @@ -193,7 +218,7 @@ class DecorationProviderWrapper { } private _keepItem(uri: URI, data: IResourceDecorationData): IResourceDecoration { - let deco = data ? this._decorationStyles.makeResourceDecoration(data) : null; + let deco = data ? this._decorationStyles.asDecoration(data) : null; this._data.set(uri.toString(), deco); this._emitter.fire(uri); return deco; @@ -207,7 +232,7 @@ export class FileDecorationsService implements IResourceDecorationsService { private readonly _data = new LinkedList(); private readonly _onDidChangeDecorationsDelayed = new Emitter(); private readonly _onDidChangeDecorations = new Emitter(); - private readonly _decorationStyles: DecorationColors; + private readonly _decorationStyles: DecorationStyles; readonly onDidChangeDecorations: Event = any( this._onDidChangeDecorations.event, @@ -220,7 +245,7 @@ export class FileDecorationsService implements IResourceDecorationsService { constructor( @IThemeService themeService: IThemeService, ) { - this._decorationStyles = new DecorationColors(themeService); + this._decorationStyles = new DecorationStyles(themeService); } dispose(): void { From 0cd0f70b35e6c04141aa6bbde7b55e5172064a8c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 10:34:40 +0200 Subject: [PATCH 175/303] deco - move badge letter into css rule --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 5 +---- src/vs/workbench/browser/labels.ts | 3 +-- .../services/decorations/browser/decorations.ts | 1 - .../decorations/browser/decorationsService.ts | 9 ++++----- .../test/browser/decorationsService.test.ts | 12 ++++++------ 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 34f285e8c56..f522468ee32 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -19,7 +19,6 @@ export interface IIconLabelCreationOptions { } export interface ILabelBadgeOptions { - letter: string; title: string; className: string; } @@ -157,9 +156,7 @@ export class IconLabel { this.element.style.display = 'flex'; this.element.appendChild(this.badgeNode); } - const { letter, title } = options.badge; - this.badgeNode.innerHTML = letter; - this.badgeNode.title = title; + this.badgeNode.title = options.badge.title; dom.addClass(this.badgeNode, options.badge.className); dom.show(this.badgeNode); diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 963815fa275..8a312fa3457 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -190,9 +190,8 @@ export class ResourceLabel extends IconLabel { if (deco && this.options.fileDecorations.colors) { iconLabelOptions.extraClasses.push(deco.labelClassName); } - if (deco && deco.letter && this.options.fileDecorations.badges) { + if (deco && deco.badgeClassName && this.options.fileDecorations.badges) { iconLabelOptions.badge = { - letter: deco.letter, title: deco.tooltip, className: deco.badgeClassName, }; diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 337311d6709..9c3ae31c0d8 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -24,7 +24,6 @@ export interface IResourceDecorationData { export interface IResourceDecoration { readonly _decoBrand: undefined; readonly severity: Severity; - readonly letter?: string; readonly tooltip?: string; readonly labelClassName?: string; readonly badgeClassName?: string; diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 27ad1ddf8e4..a7ce6666458 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -20,8 +20,8 @@ import { listActiveSelectionForeground } from 'vs/platform/theme/common/colorReg class DecorationRule { static keyOf(data: IResourceDecorationData): string { - const { color, opacity } = data; - return `${color}/${opacity}`; + const { color, opacity, letter } = data; + return `${color}/${opacity}/${letter}`; } private static readonly _classNames = new IdGenerator('monaco-decorations-style-'); @@ -37,12 +37,13 @@ class DecorationRule { } appendCSSRules(element: HTMLStyleElement, theme: ITheme): void { - const { color, opacity } = this.data; + const { color, opacity, letter } = this.data; // label createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge createCSSRule(`.${this.badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, element); + createCSSRule(`.${this.badgeClassName}::before`, `content: "${letter}"`, element); } removeCSSRules(element: HTMLStyleElement): void { @@ -55,14 +56,12 @@ class ResourceDecoration implements IResourceDecoration { _decoBrand: undefined; severity: Severity; - letter?: string; tooltip?: string; labelClassName?: string; badgeClassName?: string; constructor(data: IResourceDecorationData) { this.severity = data.severity; - this.letter = data.letter; this.tooltip = data.tooltip; } } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index f6a004f6fb0..f9005929c61 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -38,7 +38,7 @@ suite('DecorationsService', function () { setTimeout(() => resolve({ severity: Severity.Info, color: 'someBlue', - letter: 'T' + tooltip: 'T' })); }); } @@ -53,7 +53,7 @@ suite('DecorationsService', function () { assert.equal(e.affectsResource(uri), true); // sync result - assert.deepEqual(service.getTopDecoration(uri, false).letter, 'T'); + assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'T'); assert.equal(callCounter, 1); }); }); @@ -68,12 +68,12 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue', letter: 'Z' }; + return { severity: Severity.Info, color: 'someBlue', tooltip: 'Z' }; } }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false).letter, 'Z'); + assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'Z'); assert.equal(callCounter, 1); }); @@ -86,12 +86,12 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue', letter: 'J' }; + return { severity: Severity.Info, color: 'someBlue', tooltip: 'J' }; } }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false).letter, 'J'); + assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'J'); assert.equal(callCounter, 1); // un-register -> ensure good event From 55643dd7e3f3e1577dd41b750a0a7f6ecbfb3749 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2017 11:06:51 +0200 Subject: [PATCH 176/303] debug: make createProcess private and remove startDebugSession from exHostDebugService fixes #36132 --- .../electron-browser/mainThreadDebugService.ts | 16 ---------------- src/vs/workbench/api/node/extHost.protocol.ts | 1 - src/vs/workbench/api/node/extHostDebugService.ts | 8 -------- src/vs/workbench/parts/debug/common/debug.ts | 5 ----- .../parts/debug/electron-browser/debugService.ts | 9 ++------- .../parts/debug/test/common/mockDebug.ts | 4 ---- 6 files changed, 2 insertions(+), 41 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 3776bf439c0..af2d72759b5 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -80,22 +80,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { }); } - public $startDebugSession(folderUri: uri | undefined, configuration: IConfig): TPromise { - if (configuration.request !== 'launch' && configuration.request !== 'attach') { - return TPromise.wrapError(new Error(`only 'launch' or 'attach' allowed for 'request' attribute`)); - } - - const folder = folderUri ? this.contextService.getWorkspace().folders.filter(wf => wf.uri.toString() === folderUri.toString()).pop() : undefined; - return this.debugService.createProcess(folder, configuration).then(process => { - if (process) { - return process.getId(); - } - return TPromise.wrapError(new Error('cannot create debug session')); - }, err => { - return TPromise.wrapError(err && err.message ? err.message : 'cannot start debug session'); - }); - } - public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): TPromise { const process = this.debugService.findProcessByUUID(sessionId); if (process) { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index a3d65955516..1156af8806e 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -393,7 +393,6 @@ export interface MainThreadDebugServiceShape extends IDisposable { $registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, handle: number): TPromise; $unregisterDebugConfigurationProvider(handle: number): TPromise; $startDebugging(folder: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise; - $startDebugSession(folder: URI | undefined, config: vscode.DebugConfiguration): TPromise; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise; } diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 0e27ea89109..71727e711d5 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -98,14 +98,6 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig); } - public startDebugSession(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): TPromise { - return this._debugServiceProxy.$startDebugSession(folder ? folder.uri : undefined, config).then((id: DebugSessionUUID) => { - const debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, config.type, config.name); - this._debugSessions.set(id, debugSession); - return debugSession; - }); - } - public $acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void { let debugSession = this._debugSessions.get(id); diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index f226ca69b2b..24ee1c34060 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -591,11 +591,6 @@ export interface IDebugService { */ startDebugging(root: IWorkspaceFolder, configOrName?: IConfig | string, noDebug?: boolean): TPromise; - /** - * Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'. - */ - createProcess(root: IWorkspaceFolder, config: IConfig): TPromise; - /** * Find process by ID. */ diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index b5f6a854f91..844f50b20e6 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -727,7 +727,7 @@ export class DebugService implements debug.IDebugService { return null; } - public createProcess(root: IWorkspaceFolder, config: debug.IConfig, sessionId?: string): TPromise { + private createProcess(root: IWorkspaceFolder, config: debug.IConfig, sessionId: string): TPromise { return this.textFileService.saveAll().then(() => (this.configurationManager.selectedLaunch ? this.configurationManager.selectedLaunch.resolveConfiguration(config) : TPromise.as(config)).then(resolvedConfig => { if (!resolvedConfig) { @@ -749,11 +749,6 @@ export class DebugService implements debug.IDebugService { return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] })); } - if (!sessionId) { - sessionId = generateUuid(); - this.updateStateAndEmit(sessionId, debug.State.Initializing); - } - return this.runPreLaunchTask(root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; @@ -1003,7 +998,7 @@ export class DebugService implements debug.IDebugService { config.noDebug = process.configuration.noDebug; } config.__restart = restartData; - this.createProcess(process.session.root, config).then(() => c(null), err => e(err)); + this.createProcess(process.session.root, config, process.getId()).then(() => c(null), err => e(err)); }, 300); }); }).then(() => { diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 975950318de..c36e51331c9 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -92,10 +92,6 @@ export class MockDebugService implements debug.IDebugService { return TPromise.as(null); } - public createProcess(root: IWorkspaceFolder, config: debug.IConfig): TPromise { - return TPromise.as(null); - } - public findProcessByUUID(uuid: string): debug.IProcess | null { return null; } From 103b9ba1a2f9eecc4d4019552c66ca7f25eac989 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 11:10:55 +0200 Subject: [PATCH 177/303] deco - check for unused css rules every N change --- src/vs/base/common/map.ts | 6 +- src/vs/base/test/common/map.test.ts | 3 +- .../decorations/browser/decorationsService.ts | 80 ++++++++++++++----- 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 894f82082b6..bb7f231500b 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -452,11 +452,11 @@ export class TernarySearchTree { } } - forEach(callback: (entry: [string, E]) => any) { + forEach(callback: (value: E, index: string) => any) { this._forEach(this._root, [], callback); } - private _forEach(node: TernarySearchTreeNode, parts: string[], callback: (entry: [string, E]) => any) { + private _forEach(node: TernarySearchTreeNode, parts: string[], callback: (value: E, index: string) => any) { if (!node) { return; } @@ -465,7 +465,7 @@ export class TernarySearchTree { let newParts = parts.slice(); newParts.push(node.str); if (node.element) { - callback([this._segments.join(newParts), node.element]); + callback(node.element, this._segments.join(newParts)); } this._forEach(node.mid, newParts, callback); } diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index e53c60a028b..9eff83860da 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -319,8 +319,7 @@ suite('Map', () => { map.forEach((value, key) => { assert.equal(trie.get(key), value); }); - trie.forEach(entry => { - const [key, element] = entry; + trie.forEach((element, key) => { assert.equal(element, map.get(key)); map.delete(key); }); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index a7ce6666458..9c1917265c5 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -16,6 +16,7 @@ import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } fro import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; import { listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IIterator } from 'vs/base/common/iterator'; class DecorationRule { @@ -54,13 +55,15 @@ class DecorationRule { class ResourceDecoration implements IResourceDecoration { _decoBrand: undefined; + _key: string; severity: Severity; tooltip?: string; labelClassName?: string; badgeClassName?: string; - constructor(data: IResourceDecorationData) { + constructor(key: string, data: IResourceDecorationData) { + this._key = key; this.severity = data.severity; this.tooltip = data.tooltip; } @@ -70,7 +73,7 @@ class DecorationStyles { private readonly _disposables: IDisposable[]; private readonly _styleElement = createStyleSheet(); - private readonly _classNames2ColorIds = new Map(); + private readonly _decorationRules = new Map(); constructor( private _themeService: IThemeService, @@ -85,19 +88,19 @@ class DecorationStyles { this._styleElement.parentElement.removeChild(this._styleElement); } - asDecoration(data: IResourceDecorationData): IResourceDecoration { + asDecoration(data: IResourceDecorationData): ResourceDecoration { if (!data) { return undefined; } let key = DecorationRule.keyOf(data); - let rule = this._classNames2ColorIds.get(data.color); - let result = new ResourceDecoration(data); + let rule = this._decorationRules.get(key); + let result = new ResourceDecoration(key, data); if (!rule) { // new css rule rule = new DecorationRule(data); - this._classNames2ColorIds.set(key, rule); + this._decorationRules.set(key, rule); rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); } @@ -107,11 +110,30 @@ class DecorationStyles { } private _onThemeChange(): void { - this._classNames2ColorIds.forEach((rule, color) => { + this._decorationRules.forEach(rule => { rule.removeCSSRules(this._styleElement); rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); }); } + + cleanUp(iter: IIterator): void { + // remove every rule for which no more + // decoration (data) is kept. this isn't cheap + let usedDecorations = new Set(); + for (let e = iter.next(); !e.done; e = iter.next()) { + e.value.data.forEach(value => { + if (value instanceof ResourceDecoration) { + usedDecorations.add(value._key); + } + }); + } + this._decorationRules.forEach((value, index) => { + if (!usedDecorations.has(index)) { + value.removeCSSRules(this._styleElement); + this._decorationRules.delete(index); + } + }); + } } class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -142,7 +164,7 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { class DecorationProviderWrapper { - private readonly _data = TernarySearchTree.forPaths | IResourceDecoration>(); + readonly data = TernarySearchTree.forPaths | ResourceDecoration>(); private readonly _dispoable: IDisposable; constructor( @@ -152,7 +174,7 @@ class DecorationProviderWrapper { ) { this._dispoable = this._provider.onDidChange(uris => { for (const uri of uris) { - this._data.delete(uri.toString()); + this.data.delete(uri.toString()); this._fetchData(uri); } }); @@ -160,16 +182,16 @@ class DecorationProviderWrapper { dispose(): void { this._dispoable.dispose(); - this._data.clear(); + this.data.clear(); } knowsAbout(uri: URI): boolean { - return Boolean(this._data.get(uri.toString())) || Boolean(this._data.findSuperstr(uri.toString())); + return Boolean(this.data.get(uri.toString())) || Boolean(this.data.findSuperstr(uri.toString())); } - getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecoration, isChild: boolean) => void): void { + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: ResourceDecoration, isChild: boolean) => void): void { const key = uri.toString(); - let item = this._data.get(key); + let item = this.data.get(key); if (isThenable(item)) { // pending -> still waiting @@ -187,9 +209,9 @@ class DecorationProviderWrapper { } if (includeChildren) { // (resolved) children - const childTree = this._data.findSuperstr(key); + const childTree = this.data.findSuperstr(key); if (childTree) { - childTree.forEach(([, value]) => { + childTree.forEach(value => { if (value && !isThenable(value)) { callback(value, true); } @@ -198,7 +220,7 @@ class DecorationProviderWrapper { } } - private _fetchData(uri: URI): IResourceDecoration { + private _fetchData(uri: URI): ResourceDecoration { const dataOrThenable = this._provider.provideDecorations(uri); if (!isThenable(dataOrThenable)) { @@ -209,16 +231,16 @@ class DecorationProviderWrapper { // async -> we have a result soon const request = Promise.resolve(dataOrThenable) .then(data => this._keepItem(uri, data)) - .catch(_ => this._data.delete(uri.toString())); + .catch(_ => this.data.delete(uri.toString())); - this._data.set(uri.toString(), request); + this.data.set(uri.toString(), request); return undefined; } } - private _keepItem(uri: URI, data: IResourceDecorationData): IResourceDecoration { + private _keepItem(uri: URI, data: IResourceDecorationData): ResourceDecoration { let deco = data ? this._decorationStyles.asDecoration(data) : null; - this._data.set(uri.toString(), deco); + this.data.set(uri.toString(), deco); this._emitter.fire(uri); return deco; } @@ -232,6 +254,7 @@ export class FileDecorationsService implements IResourceDecorationsService { private readonly _onDidChangeDecorationsDelayed = new Emitter(); private readonly _onDidChangeDecorations = new Emitter(); private readonly _decorationStyles: DecorationStyles; + private readonly _disposables: IDisposable[]; readonly onDidChangeDecorations: Event = any( this._onDidChangeDecorations.event, @@ -243,12 +266,27 @@ export class FileDecorationsService implements IResourceDecorationsService { constructor( @IThemeService themeService: IThemeService, + cleanUpCount: number = 17 ) { this._decorationStyles = new DecorationStyles(themeService); + + // every so many events we check if there are + // css styles that we don't need anymore + let count = 0; + let reg = this.onDidChangeDecorations(() => { + if (++count % cleanUpCount === 0) { + this._decorationStyles.cleanUp(this._data.iterator()); + } + }); + + this._disposables = [ + reg, + this._decorationStyles + ]; } dispose(): void { - this._decorationStyles.dispose(); + dispose(this._disposables); } registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { From 1d2243a1b243713df09c210d920771e5a8429515 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 13 Oct 2017 08:43:17 +0200 Subject: [PATCH 178/303] Execute msbuild as a shell task (see 35752) --- src/vs/workbench/parts/tasks/common/taskTemplates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/tasks/common/taskTemplates.ts b/src/vs/workbench/parts/tasks/common/taskTemplates.ts index 6165c13bc0a..35a33f94ca9 100644 --- a/src/vs/workbench/parts/tasks/common/taskTemplates.ts +++ b/src/vs/workbench/parts/tasks/common/taskTemplates.ts @@ -54,7 +54,7 @@ const msbuild: TaskEntry = { '\t"tasks": [', '\t\t{', '\t\t\t"taskName": "build",', - '\t\t\t"type": "process",', + '\t\t\t"type": "shell",', '\t\t\t"command": "msbuild",', '\t\t\t"args": [', '\t\t\t\t// Ask msbuild to generate full paths for file names.', From 033e6f1c3d98aae6c25ac996e052a572a4eb8fec Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2017 11:27:55 +0200 Subject: [PATCH 179/303] debug: better state wrap up, make sure to not end up in INITIAZLING forever --- .../parts/debug/electron-browser/debugService.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 844f50b20e6..b3cda1acdc0 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -703,6 +703,12 @@ export class DebugService implements debug.IDebugService { const sessionId = generateUuid(); this.updateStateAndEmit(sessionId, debug.State.Initializing); + const wrapUpState = () => { + if (this.sessionStates.get(sessionId) === debug.State.Initializing) { + this.updateStateAndEmit(sessionId, debug.State.Inactive); + } + }; + return (type ? TPromise.as(null) : this.configurationManager.guessAdapter().then(a => type = a && a.type)).then(() => this.configurationManager.resolveConfigurationByProviders(launch ? launch.workspace.uri : undefined, type, config).then(config => { // a falsy config indicates an aborted launch @@ -710,10 +716,12 @@ export class DebugService implements debug.IDebugService { return this.createProcess(root, config, sessionId); } - this.updateStateAndEmit(sessionId, debug.State.Inactive); return launch.openConfigFile(false, type); // cast to ignore weird compile error }) - ); + ).then(() => wrapUpState(), (err) => { + wrapUpState(); + return err; + }); }) ))); } @@ -772,7 +780,6 @@ export class DebugService implements debug.IDebugService { }); return undefined; }, (err: TaskError) => { - this.updateStateAndEmit(sessionId, debug.State.Inactive); this.messageService.show(err.severity, { message: err.message, actions: [ @@ -783,7 +790,6 @@ export class DebugService implements debug.IDebugService { }); }); }, err => { - this.updateStateAndEmit(sessionId, debug.State.Inactive); if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(severity.Error, nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type.")); return undefined; From 17bdd27d0a34ecf55b031c6ab2e236b49cac814e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 11:24:02 +0200 Subject: [PATCH 180/303] deco - use relative line height for badge --- src/vs/base/browser/ui/iconLabel/iconlabel.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index a1dda94d93e..77a60e33789 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -48,7 +48,7 @@ align-self: center; height: 12px; min-width: 10px; - line-height: 12px; + line-height: 125%; font-size: 80%; margin: 1px 15px 1px auto; padding: 2px 4px; From 8ee7a4991ea4dda9f74518f8aedbdc6422cfbbfe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 11:29:35 +0200 Subject: [PATCH 181/303] deco - more boxy badges --- src/vs/base/browser/ui/iconLabel/iconlabel.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 77a60e33789..259040da2c2 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -51,8 +51,8 @@ line-height: 125%; font-size: 80%; margin: 1px 15px 1px auto; - padding: 2px 4px; - border-radius: 14px; + padding: 2px 3px; + border-radius: 5px; font-weight: normal; text-align: center; } From 683b531ca9b4a90c7615275e2fc8bf9be934ecf2 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 13 Oct 2017 11:38:10 +0200 Subject: [PATCH 182/303] Addresses 35734 --- .../tasks/electron-browser/task.contribution.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 1737491b685..d1dc34a51f8 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -1421,6 +1421,8 @@ class TaskService extends EventEmitter implements ITaskService { let legacyTaskConfigurations = folderTasks.set ? this.getLegacyTaskConfigurations(folderTasks.set) : undefined; let customTasksToDelete: Task[] = []; if (configurations || legacyTaskConfigurations) { + let unUsedConfigurations: Set = new Set(); + Object.keys(configurations.byIdentifier).forEach(key => unUsedConfigurations.add(key)); for (let task of contributed) { if (!ContributedTask.is(task)) { continue; @@ -1428,6 +1430,7 @@ class TaskService extends EventEmitter implements ITaskService { if (configurations) { let configuringTask = configurations.byIdentifier[task.defines._key]; if (configuringTask) { + unUsedConfigurations.delete(task.defines._key); result.add(key, TaskConfig.createCustomTask(task, configuringTask)); } else { result.add(key, task); @@ -1458,6 +1461,15 @@ class TaskService extends EventEmitter implements ITaskService { } else { result.add(key, ...folderTasks.set.tasks); } + unUsedConfigurations.forEach((value) => { + let configuringTask = configurations.byIdentifier[value]; + this._outputChannel.append(nls.localize( + 'TaskService.noConfiguration', + 'Error: No task has been contributed for the following task configuration:\n{0}\nThe task configuration will be ignored.\n', + JSON.stringify(configuringTask._source.config.element, undefined, 4) + )); + this.showOutput(); + }); } else { result.add(key, ...folderTasks.set.tasks); result.add(key, ...contributed); From f61f960249f40ca4d9aaca11697340300e9eb0ed Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 11:46:13 +0200 Subject: [PATCH 183/303] deco - use weight instead of severity --- .../parts/markers/browser/markersFileDecorations.ts | 2 +- .../parts/scm/electron-browser/scmFileDecorations.ts | 3 +-- .../services/decorations/browser/decorations.ts | 5 ++--- .../services/decorations/browser/decorationsService.ts | 9 ++++----- .../decorations/test/browser/decorationsService.test.ts | 6 ++---- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index d2e31659374..045838d7db9 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -41,7 +41,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { const [first] = markers; return { - severity: first.severity, + weight: 100 * first.severity, tooltip: localize('tooltip', "{0} problems in this file", markers.length), letter: markers.length.toString(), color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index dec7a16bb77..3e15ece693a 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -10,7 +10,6 @@ import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationD import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; -import Severity from 'vs/base/common/severity'; import Event, { Emitter } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; @@ -67,7 +66,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { return undefined; } return { - severity: Severity.Info, + weight: 10, tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), color: resource.decorations.color, letter: resource.decorations.tooltip.charAt(0) diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 9c3ae31c0d8..110b0e39b2a 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -7,14 +7,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; -import Severity from 'vs/base/common/severity'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; export const IResourceDecorationsService = createDecorator('IFileDecorationsService'); export interface IResourceDecorationData { - readonly severity: Severity; + readonly weight?: number; readonly color?: ColorIdentifier; readonly opacity?: number; readonly letter?: string; @@ -23,7 +22,7 @@ export interface IResourceDecorationData { export interface IResourceDecoration { readonly _decoBrand: undefined; - readonly severity: Severity; + readonly weight?: number; readonly tooltip?: string; readonly labelClassName?: string; readonly badgeClassName?: string; diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 9c1917265c5..7d3172294cd 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -5,7 +5,6 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import Severity from 'vs/base/common/severity'; import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IResourceDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; @@ -57,14 +56,14 @@ class ResourceDecoration implements IResourceDecoration { _decoBrand: undefined; _key: string; - severity: Severity; + weight?: number; tooltip?: string; labelClassName?: string; badgeClassName?: string; constructor(key: string, data: IResourceDecorationData) { this._key = key; - this.severity = data.severity; + this.weight = data.weight; this.tooltip = data.tooltip; } } @@ -317,7 +316,7 @@ export class FileDecorationsService implements IResourceDecorationsService { // only bubble up color top = { _decoBrand: undefined, - severity: top.severity, + weight: top.weight, labelClassName: top.labelClassName }; } @@ -331,7 +330,7 @@ export class FileDecorationsService implements IResourceDecorationsService { return b; } else if (!b) { return a; - } else if (Severity.compare(a.severity, b.severity) < 0) { + } else if (a.weight > b.weight) { return a; } else { return b; diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index f9005929c61..d1611916273 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -10,7 +10,6 @@ import { FileDecorationsService } from 'vs/workbench/services/decorations/browse import { IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import URI from 'vs/base/common/uri'; import Event, { toPromise } from 'vs/base/common/event'; -import Severity from 'vs/base/common/severity'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; suite('DecorationsService', function () { @@ -36,7 +35,6 @@ suite('DecorationsService', function () { callCounter += 1; return new Promise(resolve => { setTimeout(() => resolve({ - severity: Severity.Info, color: 'someBlue', tooltip: 'T' })); @@ -68,7 +66,7 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue', tooltip: 'Z' }; + return { color: 'someBlue', tooltip: 'Z' }; } }); @@ -86,7 +84,7 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { severity: Severity.Info, color: 'someBlue', tooltip: 'J' }; + return { color: 'someBlue', tooltip: 'J' }; } }); From 0d3c0dcb4a19ceda197ca4a7c58118aa585c0126 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 13 Oct 2017 11:53:25 +0200 Subject: [PATCH 184/303] Use all keys configuration change event when configuration is initialized --- .../platform/configuration/common/configurationModels.ts | 8 ++++++++ .../services/configuration/node/configurationService.ts | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index f86a10ee7d1..68a3f544f61 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -415,6 +415,14 @@ export class Configuration { } } +export class AllKeysConfigurationChangeEvent implements IConfigurationChangeEvent { + + constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { } + + affectsConfiugration: () => true; + +} + export class ConfigurationChangeEvent implements IConfigurationChangeEvent { private changedConfiguration: ConfigurationModel = new ConfigurationModel(); diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index a57b41a33f6..3cccaa1e6b2 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -23,7 +23,7 @@ import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { CustomConfigurationModel, ConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { CustomConfigurationModel, ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; @@ -326,7 +326,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // TODO: compare with old values?? const keys = this._configuration.keys(); - this.triggerConfigurationChange(new ConfigurationChangeEvent().change([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder]), ConfigurationTarget.WORKSPACE); + this._onDidUpdateConfiguration.fire(new AllKeysConfigurationChangeEvent([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); }); } From 74423a68d62fc66f9c2678208a5a15c58f2e4476 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 11:58:32 +0200 Subject: [PATCH 185/303] deco - create css rules for decoration as late as possible --- .../decorations/browser/decorationsService.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 7d3172294cd..10d7d30cd87 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -42,8 +42,10 @@ class DecorationRule { createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge - createCSSRule(`.${this.badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, element); - createCSSRule(`.${this.badgeClassName}::before`, `content: "${letter}"`, element); + if (letter) { + createCSSRule(`.${this.badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, element); + createCSSRule(`.${this.badgeClassName}::before`, `content: "${letter}"`, element); + } } removeCSSRules(element: HTMLStyleElement): void { @@ -88,10 +90,6 @@ class DecorationStyles { } asDecoration(data: IResourceDecorationData): ResourceDecoration { - if (!data) { - return undefined; - } - let key = DecorationRule.keyOf(data); let rule = this._decorationRules.get(key); let result = new ResourceDecoration(key, data); @@ -163,11 +161,10 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { class DecorationProviderWrapper { - readonly data = TernarySearchTree.forPaths | ResourceDecoration>(); + readonly data = TernarySearchTree.forPaths | IResourceDecorationData>(); private readonly _dispoable: IDisposable; constructor( - private readonly _decorationStyles: DecorationStyles, private readonly _provider: IDecorationsProvider, private readonly _emitter: Emitter ) { @@ -188,7 +185,7 @@ class DecorationProviderWrapper { return Boolean(this.data.get(uri.toString())) || Boolean(this.data.findSuperstr(uri.toString())); } - getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: ResourceDecoration, isChild: boolean) => void): void { + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecorationData, isChild: boolean) => void): void { const key = uri.toString(); let item = this.data.get(key); @@ -219,7 +216,7 @@ class DecorationProviderWrapper { } } - private _fetchData(uri: URI): ResourceDecoration { + private _fetchData(uri: URI): IResourceDecorationData { const dataOrThenable = this._provider.provideDecorations(uri); if (!isThenable(dataOrThenable)) { @@ -237,8 +234,8 @@ class DecorationProviderWrapper { } } - private _keepItem(uri: URI, data: IResourceDecorationData): ResourceDecoration { - let deco = data ? this._decorationStyles.asDecoration(data) : null; + private _keepItem(uri: URI, data: IResourceDecorationData): IResourceDecorationData { + let deco = data ? data : null; this.data.set(uri.toString(), deco); this._emitter.fire(uri); return deco; @@ -291,7 +288,6 @@ export class FileDecorationsService implements IResourceDecorationsService { registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { const wrapper = new DecorationProviderWrapper( - this._decorationStyles, provider, this._onDidChangeDecorationsDelayed ); @@ -308,24 +304,28 @@ export class FileDecorationsService implements IResourceDecorationsService { } getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { - let top: IResourceDecoration; + let top: IResourceDecorationData; + let topIsChild: boolean; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { next.value.getOrRetrieve(uri, includeChildren, (candidate, isChild) => { top = FileDecorationsService._pickBest(top, candidate); - if (isChild && top === candidate) { - // only bubble up color - top = { - _decoBrand: undefined, - weight: top.weight, - labelClassName: top.labelClassName - }; - } + topIsChild = top === candidate && isChild; }); } - return top; + + if (!top) { + return undefined; + } + + let deco = this._decorationStyles.asDecoration(top); + if (topIsChild) { + // don't show badges for child status + deco.badgeClassName = ''; + } + return deco; } - private static _pickBest(a: IResourceDecoration, b: IResourceDecoration): IResourceDecoration { + private static _pickBest(a: IResourceDecorationData, b: IResourceDecorationData): IResourceDecorationData { if (!a) { return b; } else if (!b) { From 395112db9ecd3418a43b6c2504b4fb00fa9a87a7 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 11:14:20 +0200 Subject: [PATCH 186/303] [themes] use 'color-hex' in JSON schemas --- src/vs/platform/theme/common/colorExtensionPoint.ts | 6 +++--- src/vs/platform/theme/common/colorRegistry.ts | 5 ++--- src/vs/workbench/services/themes/common/colorThemeSchema.ts | 2 +- .../workbench/services/themes/common/fileIconThemeSchema.ts | 2 +- .../themes/electron-browser/workbenchThemeService.ts | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/theme/common/colorExtensionPoint.ts b/src/vs/platform/theme/common/colorExtensionPoint.ts index 51a47fdb4bb..d9e077db578 100644 --- a/src/vs/platform/theme/common/colorExtensionPoint.ts +++ b/src/vs/platform/theme/common/colorExtensionPoint.ts @@ -42,7 +42,7 @@ const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint Date: Fri, 13 Oct 2017 11:15:03 +0200 Subject: [PATCH 187/303] [json] update service --- extensions/json/server/npm-shrinkwrap.json | 19 +++++++++++++------ extensions/json/server/package.json | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/extensions/json/server/npm-shrinkwrap.json b/extensions/json/server/npm-shrinkwrap.json index 13925889795..4f69e09581f 100644 --- a/extensions/json/server/npm-shrinkwrap.json +++ b/extensions/json/server/npm-shrinkwrap.json @@ -43,9 +43,9 @@ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz" }, "vscode-json-languageservice": { - "version": "2.0.21", + "version": "2.0.22", "from": "vscode-json-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.21.tgz" + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.22.tgz" }, "vscode-jsonrpc": { "version": "3.5.0-next.1", @@ -60,12 +60,19 @@ "vscode-languageserver-protocol": { "version": "3.5.0-next.3", "from": "vscode-languageserver-protocol@>=3.5.0-next.2 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.3.tgz", + "dependencies": { + "vscode-languageserver-types": { + "version": "3.5.0-next.1", + "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" + } + } }, "vscode-languageserver-types": { - "version": "3.5.0-next.1", - "from": "vscode-languageserver-types@>=3.5.0-next.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.1.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 3e4dfd6508f..e570819c565 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -10,7 +10,7 @@ "dependencies": { "jsonc-parser": "^1.0.0", "request-light": "^0.2.1", - "vscode-json-languageservice": "^2.0.21", + "vscode-json-languageservice": "^2.0.22", "vscode-languageserver": "^3.5.0-next.2", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" From fed4b741150cc5a2d6f8ebe12e05fc9d85db50d3 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 11:50:37 +0200 Subject: [PATCH 188/303] Update IJSONSchema: v6 and custom properties --- src/vs/base/common/jsonSchema.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/jsonSchema.ts b/src/vs/base/common/jsonSchema.ts index 2aa8c50c9f7..538858e0c0d 100644 --- a/src/vs/base/common/jsonSchema.ts +++ b/src/vs/base/common/jsonSchema.ts @@ -6,6 +6,7 @@ export interface IJSONSchema { id?: string; + $id?: string; $schema?: string; type?: string | string[]; title?: string; @@ -17,7 +18,7 @@ export interface IJSONSchema { additionalProperties?: boolean | IJSONSchema; minProperties?: number; maxProperties?: number; - dependencies?: IJSONSchemaMap | { [name: string]: string[] }; + dependencies?: IJSONSchemaMap | { [prop: string]: string[] }; items?: IJSONSchema | IJSONSchema[]; minItems?: number; maxItems?: number; @@ -28,8 +29,8 @@ export interface IJSONSchema { maxLength?: number; minimum?: number; maximum?: number; - exclusiveMinimum?: boolean; - exclusiveMaximum?: boolean; + exclusiveMinimum?: boolean | number; + exclusiveMaximum?: boolean | number; multipleOf?: number; required?: string[]; $ref?: string; @@ -40,11 +41,19 @@ export interface IJSONSchema { enum?: any[]; format?: string; + // schema draft 06 + const?: any; + contains?: IJSONSchema; + propertyNames?: IJSONSchema; + + // VSCode extensions defaultSnippets?: IJSONSchemaSnippet[]; // VSCode extension errorMessage?: string; // VSCode extension patternErrorMessage?: string; // VSCode extension deprecationMessage?: string; // VSCode extension enumDescriptions?: string[]; // VSCode extension + markdownEnumDescriptions?: string[]; // VSCode extension + markdownDescription?: string; // VSCode extension doNotSuggest?: boolean; // VSCode extension } From 366d85a42c23370af4139dcbc92d313c68a9d27c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 11:54:05 +0200 Subject: [PATCH 189/303] Fix use of notifyConfigurationSchemaUpdated --- .../electron-browser/workbenchThemeService.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 8b5f5ce8412..59d95aacbcf 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -13,11 +13,10 @@ import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIc import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import errors = require('vs/base/common/errors'); import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IMessageService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -151,12 +150,12 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.colorThemeStore.onDidChange(themes => { colorThemeSettingSchema.enum = themes.map(t => t.settingsId); colorThemeSettingSchema.enumDescriptions = themes.map(t => themeData.description || ''); - configurationRegistry.notifyConfigurationSchemaUpdated(colorThemeSettingSchema); + configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration); }); this.iconThemeStore.onDidChange(themes => { iconThemeSettingSchema.enum = [null, ...themes.map(t => t.settingsId)]; iconThemeSettingSchema.enumDescriptions = [iconThemeSettingSchema.enumDescriptions[0], ...themes.map(t => themeData.description || '')]; - configurationRegistry.notifyConfigurationSchemaUpdated(iconThemeSettingSchema); + configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration); }); } @@ -534,7 +533,7 @@ class ConfigurationWriter { // Configuration: Themes const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); -const colorThemeSettingSchema: IJSONSchema = { +const colorThemeSettingSchema: IConfigurationPropertySchema = { type: 'string', description: nls.localize('colorTheme', "Specifies the color theme used in the workbench."), default: DEFAULT_THEME_SETTING_VALUE, @@ -543,7 +542,7 @@ const colorThemeSettingSchema: IJSONSchema = { errorMessage: nls.localize('colorThemeError', "Theme is unknown or not installed."), }; -const iconThemeSettingSchema: IJSONSchema = { +const iconThemeSettingSchema: IConfigurationPropertySchema = { type: ['string', 'null'], default: DEFAULT_ICON_THEME_SETTING_VALUE, description: nls.localize('iconTheme', "Specifies the icon theme used in the workbench or 'null' to not show any file icons."), @@ -551,7 +550,7 @@ const iconThemeSettingSchema: IJSONSchema = { enumDescriptions: [nls.localize('noIconThemeDesc', 'No file icons')], errorMessage: nls.localize('iconThemeError', "File icon theme is unknown or not installed.") }; -const colorCustomizationsSchema: IJSONSchema = { +const colorCustomizationsSchema: IConfigurationPropertySchema = { type: ['object'], description: nls.localize('workbenchColors', "Overrides colors from the currently selected color theme."), properties: colorThemeSchema.colorsSchema.properties, @@ -566,7 +565,7 @@ const colorCustomizationsSchema: IJSONSchema = { }] }; -configurationRegistry.registerConfiguration({ +const themeSettingsConfiguration: IConfigurationNode = { id: 'workbench', order: 7.1, type: 'object', @@ -575,7 +574,8 @@ configurationRegistry.registerConfiguration({ [ICON_THEME_SETTING]: iconThemeSettingSchema, [CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema } -}); +}; +configurationRegistry.registerConfiguration(themeSettingsConfiguration); function tokenGroupSettings(description: string) { return { From dd054ab5cee88e18e855a0a428ba1137800676d6 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 12:03:42 +0200 Subject: [PATCH 190/303] Warn about usage of token background colors --- src/vs/workbench/services/themes/common/colorThemeSchema.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/services/themes/common/colorThemeSchema.ts b/src/vs/workbench/services/themes/common/colorThemeSchema.ts index c2403012f98..af8bb743f48 100644 --- a/src/vs/workbench/services/themes/common/colorThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/colorThemeSchema.ts @@ -124,6 +124,10 @@ export const tokenColorizationSettingSchema: IJSONSchema = { format: 'color-hex', defaultSnippets: [{ body: '${1:#FF0000}' }] }, + background: { + type: 'string', + deprecationMessage: nls.localize('schema.token.background.warning', 'Token background colors are currently not supported.') + }, fontStyle: { type: 'string', description: nls.localize('schema.token.fontStyle', 'Font style of the rule: One or a combination of \'italic\', \'bold\' and \'underline\''), From 9c78e13b29238d35aff12d8ae1788599d2c48115 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2017 12:15:52 +0200 Subject: [PATCH 191/303] Gulp watch fails to trigger recompilation while TypeScript compiles (fixes #36214) --- build/lib/watch/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/build/lib/watch/index.js b/build/lib/watch/index.js index bed579ec075..93d9babc2de 100644 --- a/build/lib/watch/index.js +++ b/build/lib/watch/index.js @@ -19,14 +19,15 @@ function handleDeletions() { let watch = void 0; -if (!process.env['VSCODE_USE_LEGACY_WATCH']) { - try { - watch = require('./watch-nsfw'); - } catch (err) { - console.warn('Could not load our cross platform file watcher: ' + err.toString()); - console.warn('Falling back to our platform specific watcher...'); - } -} +// Disabled due to https://github.com/Microsoft/vscode/issues/36214 +// if (!process.env['VSCODE_USE_LEGACY_WATCH']) { +// try { +// watch = require('./watch-nsfw'); +// } catch (err) { +// console.warn('Could not load our cross platform file watcher: ' + err.toString()); +// console.warn('Falling back to our platform specific watcher...'); +// } +// } if (!watch) { watch = process.platform === 'win32' ? require('./watch-win32') : require('gulp-watch'); From 016cef69120bded64ed0e90cfd0bfa1596688ab2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 13 Oct 2017 12:23:41 +0200 Subject: [PATCH 192/303] Smart merge of override contents --- .../common/configurationModels.ts | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 68a3f544f61..7e5751fcdd4 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -60,17 +60,33 @@ export class ConfigurationModel implements IConfiguraionModel { } public override(identifier: string): ConfigurationModel { - const result = new ConfigurationModel(); - const contents = objects.clone(this.contents); - if (this._overrides) { - for (const override of this._overrides) { - if (override.identifiers.indexOf(identifier) !== -1) { - merge(contents, override.contents, true); + const overrideContents = this.getContentsForOverrideIdentifer(identifier); + + if (!overrideContents) { + // If there are no overrides, use base contents + return new ConfigurationModel(this._contents); + } + + let contents = {}; + for (const key of Object.keys(this._contents)) { + + let contentsForKey = this._contents[key]; + let overrideContentsForKey = overrideContents[key]; + + // If there are override contents for the key clone and merge otherwise use base contents + if (overrideContentsForKey) { + // Clone and merge only if base contents is of type object otherwise just override + if (typeof contentsForKey === 'object') { + contentsForKey = objects.clone(contents[key]); + merge(contentsForKey, overrideContentsForKey, true); + } else { + contentsForKey = overrideContentsForKey; } } + + contents[key] = contentsForKey; } - result._contents = contents; - return result; + return new ConfigurationModel(contents); } public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { @@ -93,6 +109,15 @@ export class ConfigurationModel implements IConfiguraionModel { } source._overrides = overrides; } + + private getContentsForOverrideIdentifer(identifier: string): any { + for (const override of this._overrides) { + if (override.identifiers.indexOf(identifier) !== -1) { + return override.contents; + } + } + return null; + } } export class DefaultConfigurationModel extends ConfigurationModel { From 07da4309a3635c0831537aaea067d9c30c737bc1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 13 Oct 2017 12:14:11 +0200 Subject: [PATCH 193/303] theme-schemas: set color defaults (for better code completion) --- src/vs/workbench/services/themes/common/colorThemeSchema.ts | 2 +- .../services/themes/electron-browser/workbenchThemeService.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/themes/common/colorThemeSchema.ts b/src/vs/workbench/services/themes/common/colorThemeSchema.ts index af8bb743f48..4e7c779283c 100644 --- a/src/vs/workbench/services/themes/common/colorThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/colorThemeSchema.ts @@ -122,7 +122,7 @@ export const tokenColorizationSettingSchema: IJSONSchema = { type: 'string', description: nls.localize('schema.token.foreground', 'Foreground color for the token.'), format: 'color-hex', - defaultSnippets: [{ body: '${1:#FF0000}' }] + default: '#ff0000' }, background: { type: 'string', diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 59d95aacbcf..e09d12ba057 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -584,8 +584,7 @@ function tokenGroupSettings(description: string) { anyOf: [ { type: 'string', - format: 'color-hex', - defaultSnippets: [{ body: '#FF0000' }] + format: 'color-hex' }, colorThemeSchema.tokenColorizationSettingSchema ] From 694dff3057f87f3f713a52ec73186de90ebf122b Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 13 Oct 2017 12:24:23 +0200 Subject: [PATCH 194/303] Return error when terminal creation failed --- .../parts/tasks/electron-browser/terminalTaskSystem.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index 446001d7d91..b3e4d73c599 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -397,6 +397,9 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { }); }); } + if (!terminal) { + return TPromise.wrapError(new Error(`Failed to create terminal for task ${task._label}`)); + } this.terminalService.setActiveInstance(terminal); if (task.command.presentation.reveal === RevealKind.Always || (task.command.presentation.reveal === RevealKind.Silent && task.problemMatchers.length === 0)) { this.terminalService.showPanel(task.command.presentation.focus); From 62dab62fc0191d12c85fefb5ed839c6b910abfcc Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 13 Oct 2017 12:56:41 +0200 Subject: [PATCH 195/303] Improved error message for task not found --- .../parts/tasks/electron-browser/task.contribution.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index d1dc34a51f8..69ae1d21ee8 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -1465,7 +1465,8 @@ class TaskService extends EventEmitter implements ITaskService { let configuringTask = configurations.byIdentifier[value]; this._outputChannel.append(nls.localize( 'TaskService.noConfiguration', - 'Error: No task has been contributed for the following task configuration:\n{0}\nThe task configuration will be ignored.\n', + 'Error: The {0} task detection didn\'t contribute a task for the following configuration:\n{1}\nThe task will be ignored.\n', + configuringTask.configures.type, JSON.stringify(configuringTask._source.config.element, undefined, 4) )); this.showOutput(); From 36c55adcf5918a74d990cf6e4fc5bfc4cbe6e4f2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 13:03:54 +0200 Subject: [PATCH 196/303] deco - enable marker decorations but disable them by default --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 3 +- .../markers/browser/markersFileDecorations.ts | 33 +++++++++++-------- .../parts/markers/markers.contribution.ts | 2 +- .../decorations/browser/decorationsService.ts | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index f522468ee32..89dac41da35 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -152,12 +152,11 @@ export class IconLabel { if (options && options.badge) { if (!this.badgeNode) { this.badgeNode = document.createElement('span'); - this.badgeNode.className = 'label-badge'; this.element.style.display = 'flex'; this.element.appendChild(this.badgeNode); } this.badgeNode.title = options.badge.title; - dom.addClass(this.badgeNode, options.badge.className); + this.badgeNode.className = `label-badge ${options.badge.className}`; dom.show(this.badgeNode); } else if (this.badgeNode) { diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 045838d7db9..46f91a0b701 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -6,13 +6,12 @@ 'use strict'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import { localize } from 'vs/nls'; -import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { Registry } from 'vs/platform/registry/common/platform'; import Severity from 'vs/base/common/severity'; import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; @@ -31,18 +30,21 @@ class MarkersDecorationsProvider implements IDecorationsProvider { } provideDecorations(resource: URI): IResourceDecorationData { + let markers = this._markerService.read({ resource }); + let first: IMarker; + for (const marker of markers) { + if (!first || marker.severity > first.severity) { + first = marker; + } + } - const markers = this._markerService.read({ resource }) - .sort((a, b) => Severity.compare(a.severity, b.severity)); - - if (isFalsyOrEmpty(markers)) { + if (!first) { return undefined; } - const [first] = markers; return { weight: 100 * first.severity, - tooltip: localize('tooltip', "{0} problems in this file", markers.length), + tooltip: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), letter: markers.length.toString(), color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, }; @@ -53,6 +55,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { private readonly _disposables: IDisposable[]; private _provider: IDisposable; + private _enabled: boolean; constructor( @IMarkerService private _markerService: IMarkerService, @@ -63,7 +66,6 @@ class MarkersFileDecorations implements IWorkbenchContribution { this._disposables = [ this._configurationService.onDidUpdateConfiguration(this._updateEnablement, this), ]; - this._updateEnablement(); } @@ -77,11 +79,16 @@ class MarkersFileDecorations implements IWorkbenchContribution { } private _updateEnablement(): void { - let value = this._configurationService.getConfiguration<{ fileDecorations: { enabled: boolean } }>('problems'); - if (value.fileDecorations.enabled) { + let value = this._configurationService.getConfiguration<{ decorations: { enabled: boolean } }>('problems'); + if (value.decorations.enabled === this._enabled) { + return; + } + this._enabled = value.decorations.enabled; + if (this._enabled) { const provider = new MarkersDecorationsProvider(this._markerService); this._provider = this._decorationsService.registerDecortionsProvider(provider); } else if (this._provider) { + this._enabled = value.decorations.enabled; this._provider.dispose(); } } @@ -94,10 +101,10 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'order': 101, 'type': 'object', 'properties': { - 'problems.fileDecorations.enabled': { + 'problems.decorations.enabled': { 'description': localize('markers.showOnFile', "Show Errors & Warnings on files and folder."), 'type': 'boolean', - 'default': true + 'default': false } } }); diff --git a/src/vs/workbench/parts/markers/markers.contribution.ts b/src/vs/workbench/parts/markers/markers.contribution.ts index 4ab845211d8..b7b91dbc852 100644 --- a/src/vs/workbench/parts/markers/markers.contribution.ts +++ b/src/vs/workbench/parts/markers/markers.contribution.ts @@ -5,7 +5,7 @@ import { registerContributions } from 'vs/workbench/parts/markers/browser/markersWorkbenchContributions'; import { registerContributions as registerElectronContributions } from 'vs/workbench/parts/markers/electron-browser/markersElectronContributions'; -// import './browser/markersFileDecorations'; +import './browser/markersFileDecorations'; registerContributions(); registerElectronContributions(); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 10d7d30cd87..2b275e9dd54 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -309,7 +309,7 @@ export class FileDecorationsService implements IResourceDecorationsService { for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { next.value.getOrRetrieve(uri, includeChildren, (candidate, isChild) => { top = FileDecorationsService._pickBest(top, candidate); - topIsChild = top === candidate && isChild; + topIsChild = top === candidate && isChild || topIsChild; }); } From 937fb72255c43c70c36440dcab1ad060e2ea5cfc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 15:03:12 +0200 Subject: [PATCH 197/303] support to merge decorations --- .../decorations/browser/decorationsService.ts | 125 ++++++++++++------ 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 2b275e9dd54..0203f93a682 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -19,25 +19,37 @@ import { IIterator } from 'vs/base/common/iterator'; class DecorationRule { - static keyOf(data: IResourceDecorationData): string { - const { color, opacity, letter } = data; - return `${color}/${opacity}/${letter}`; + static keyOf(data: IResourceDecorationData | IResourceDecorationData[]): string { + if (Array.isArray(data)) { + return data.map(DecorationRule.keyOf).join(','); + } else { + const { color, opacity, letter } = data; + return `${color}/${opacity}/${letter}`; + } } private static readonly _classNames = new IdGenerator('monaco-decorations-style-'); - readonly data: IResourceDecorationData; + readonly data: IResourceDecorationData | IResourceDecorationData[]; readonly labelClassName: string; readonly badgeClassName: string; - constructor(data: IResourceDecorationData) { + constructor(data: IResourceDecorationData | IResourceDecorationData[]) { this.data = data; this.labelClassName = DecorationRule._classNames.nextId(); this.badgeClassName = DecorationRule._classNames.nextId(); } appendCSSRules(element: HTMLStyleElement, theme: ITheme): void { - const { color, opacity, letter } = this.data; + if (!Array.isArray(this.data)) { + this._appendForOne(this.data, element, theme); + } else { + this._appendForMany(this.data, element, theme); + } + } + + private _appendForOne(data: IResourceDecorationData, element: HTMLStyleElement, theme: ITheme): void { + const { color, opacity, letter } = data; // label createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); @@ -48,6 +60,27 @@ class DecorationRule { } } + private _appendForMany(data: IResourceDecorationData[], element: HTMLStyleElement, theme: ITheme): void { + // label + const { color, opacity } = data[0]; + createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); + createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); + + // badge + let letters: string[] = []; + let colors: string[] = []; + for (const deco of data) { + letters.push(deco.letter); + colors.push(`${theme.getColor(deco.color).toString()} ${100 / data.length}%`); + } + createCSSRule(`.${this.badgeClassName}::before`, `content: "${letters.join('\u2002')}"`, element); + createCSSRule( + `.${this.badgeClassName}`, + `background: linear-gradient(90deg, ${colors.join()}); color: ${theme.getColor(listActiveSelectionForeground)};`, + element + ); + } + removeCSSRules(element: HTMLStyleElement): void { removeCSSRulesContainingSelector(this.labelClassName, element); removeCSSRulesContainingSelector(this.badgeClassName, element); @@ -55,18 +88,29 @@ class DecorationRule { } class ResourceDecoration implements IResourceDecoration { + + static from(data: IResourceDecorationData | IResourceDecorationData[]): ResourceDecoration { + let result = new ResourceDecoration(data); + if (Array.isArray(data)) { + result.weight = data[0].weight; + result.tooltip = data.map(d => d.tooltip).join(', '); + } else { + result.weight = data.weight; + result.tooltip = data.tooltip; + } + return result; + } + _decoBrand: undefined; - _key: string; + _data: IResourceDecorationData | IResourceDecorationData[]; weight?: number; tooltip?: string; labelClassName?: string; badgeClassName?: string; - constructor(key: string, data: IResourceDecorationData) { - this._key = key; - this.weight = data.weight; - this.tooltip = data.tooltip; + private constructor(data: IResourceDecorationData | IResourceDecorationData[]) { + this._data = data; } } @@ -89,10 +133,10 @@ class DecorationStyles { this._styleElement.parentElement.removeChild(this._styleElement); } - asDecoration(data: IResourceDecorationData): ResourceDecoration { + asDecoration(data: IResourceDecorationData | IResourceDecorationData[]): ResourceDecoration { let key = DecorationRule.keyOf(data); let rule = this._decorationRules.get(key); - let result = new ResourceDecoration(key, data); + let result = ResourceDecoration.from(data); if (!rule) { // new css rule @@ -116,16 +160,27 @@ class DecorationStyles { cleanUp(iter: IIterator): void { // remove every rule for which no more // decoration (data) is kept. this isn't cheap - let usedDecorations = new Set(); + let usedDecorations = new Set(); for (let e = iter.next(); !e.done; e = iter.next()) { e.value.data.forEach(value => { if (value instanceof ResourceDecoration) { - usedDecorations.add(value._key); + if (Array.isArray(value._data)) { + value._data.forEach(data => usedDecorations.add(data)); + } else { + usedDecorations.add(value._data); + } } }); } this._decorationRules.forEach((value, index) => { - if (!usedDecorations.has(index)) { + const { data } = value; + let remove: boolean; + if (Array.isArray(data)) { + remove = data.every(data => !usedDecorations.has(data)); + } else if (!usedDecorations.has(data)) { + remove = true; + } + if (remove) { value.removeCSSRules(this._styleElement); this._decorationRules.delete(index); } @@ -304,36 +359,26 @@ export class FileDecorationsService implements IResourceDecorationsService { } getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { - let top: IResourceDecorationData; - let topIsChild: boolean; + let data: IResourceDecorationData[] = []; + let onlyChildren = true; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { - next.value.getOrRetrieve(uri, includeChildren, (candidate, isChild) => { - top = FileDecorationsService._pickBest(top, candidate); - topIsChild = top === candidate && isChild || topIsChild; + next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { + // top = FileDecorationsService._pickBest(top, candidate); + data.push(deco); + onlyChildren = onlyChildren && isChild; }); } - if (!top) { + if (data.length === 0) { return undefined; - } - - let deco = this._decorationStyles.asDecoration(top); - if (topIsChild) { - // don't show badges for child status - deco.badgeClassName = ''; - } - return deco; - } - - private static _pickBest(a: IResourceDecorationData, b: IResourceDecorationData): IResourceDecorationData { - if (!a) { - return b; - } else if (!b) { - return a; - } else if (a.weight > b.weight) { - return a; + } else if (onlyChildren) { + let result = this._decorationStyles.asDecoration(data.sort((a, b) => b.weight - a.weight)[0]); + result.badgeClassName = ''; + return result; + } else if (data.length === 1) { + return this._decorationStyles.asDecoration(data[0]); } else { - return b; + return this._decorationStyles.asDecoration(data.sort((a, b) => b.weight - a.weight)); } } } From 894c6c6193e46ea2db38f59135238a6e5b274283 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 15:13:11 +0200 Subject: [PATCH 198/303] deco - scm decorator hacks to make things look nice. time for extension api... --- .../parts/scm/electron-browser/scmFileDecorations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 3e15ece693a..dea57c82381 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -62,11 +62,11 @@ class SCMDecorationsProvider implements IDecorationsProvider { provideDecorations(uri: URI): IResourceDecorationData { const resource = this._data.get(uri.toString()); - if (!resource) { + if (!resource || !resource.decorations.color) { return undefined; } return { - weight: 10, + weight: 100 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0), tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), color: resource.decorations.color, letter: resource.decorations.tooltip.charAt(0) From 3a4ee7e2b66b47c129da1f93cc42f7735730339a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2017 15:24:37 +0200 Subject: [PATCH 199/303] add failing, inactive test, #36089 --- .../contrib/snippet/test/browser/snippetVariables.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts index e5de27daa03..aad0d69ba7a 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts @@ -164,4 +164,12 @@ suite('Snippet Variables Resolver', function () { assertVariableResolve2('${foobarfoobar/(foo)/${2:+FAR}/g}', 'barbar'); // bad group reference }); + + // test('Snippet transforms do not handle regex with alternatives or optional matches, #36089', function () { + // assertVariableResolve2( + // '${TM_FILENAME/^(.)|(?:-(.))|(\\.js)/${1:+/upcase}${2:+/upcase}/g}', + // 'MyClass', + // 'my-class.js' + // ); + // }); }); From a38df198437f5b7fa2f57de10a663daee01054e4 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2017 16:01:23 +0200 Subject: [PATCH 200/303] take out composite handling from activityBarPart into compositeBar --- src/vs/workbench/browser/compositeBar.ts | 377 ++++++++++++++++++ .../workbench/browser/compositeBarActions.ts | 335 ++++++++++++++++ .../parts/activitybar/activitybarActions.ts | 366 +---------------- .../parts/activitybar/activitybarPart.ts | 370 ++--------------- 4 files changed, 769 insertions(+), 679 deletions(-) create mode 100644 src/vs/workbench/browser/compositeBar.ts create mode 100644 src/vs/workbench/browser/compositeBarActions.ts diff --git a/src/vs/workbench/browser/compositeBar.ts b/src/vs/workbench/browser/compositeBar.ts new file mode 100644 index 00000000000..0fc8b7b53ee --- /dev/null +++ b/src/vs/workbench/browser/compositeBar.ts @@ -0,0 +1,377 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); +import { Action } from 'vs/base/common/actions'; +import { illegalArgument } from 'vs/base/common/errors'; +import * as dom from 'vs/base/browser/dom'; +import * as arrays from 'vs/base/common/arrays'; +import { Dimension } from 'vs/base/browser/builder'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import Event, { Emitter } from 'vs/base/common/event'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem } from 'vs/workbench/browser/compositeBarActions'; + +// first goal make the activity bar depend on the composite bar and everything works as before +// after that think about how to plug this into the panel part and the overflow nicely wokring (composite bar in panel will need overflow: hidden) +// on the action bar offsetWidth = gets the width of every child (on the first layout need to check if it is still in the constraints) + +export interface ICompositeBarOptions { + label: 'icon' | 'name'; + storageId: string; + orientation: ActionsOrientation; + composites: { id: string, name: string }[]; + getActivityAction: (compositeId: string) => ActivityAction; + getCompositePinnedAction: (compositeId: string) => Action; + getOpenCompositeAction: (compositeId: string) => Action; +} + +export class CompositeBar { + + private _onDidContextMenu: Emitter; + private _onDidDropComposite: Emitter<{ compositeId: string, toCompositeId: string }>; + + private dimension: Dimension; + private toDispose: IDisposable[]; + + private compositeSwitcherBar: ActionBar; + private compositeOverflowAction: CompositeOverflowActivityAction; + private compositeOverflowActionItem: CompositeOverflowActivityActionItem; + + private compositeIdToActions: { [compositeId: string]: ActivityAction; }; + private compositeIdToActionItems: { [compositeId: string]: IActionItem; }; + private compositeIdToActivityStack: { [compositeId: string]: ICompositeActivity[]; }; + + private pinnedComposites: string[]; + private activeCompositeId: string; + private activeUnpinnedCompositeId: string; + + constructor( + private options: ICompositeBarOptions, + @IContextMenuService private contextMenuService: IContextMenuService, + @IInstantiationService private instantiationService: IInstantiationService, + @IStorageService private storageService: IStorageService, + @IPartService private partService: IPartService, + @IThemeService themeService: IThemeService, + ) { + this.toDispose = []; + this.compositeIdToActionItems = Object.create(null); + this.compositeIdToActions = Object.create(null); + this.compositeIdToActivityStack = Object.create(null); + + this._onDidContextMenu = new Emitter(); + this._onDidDropComposite = new Emitter<{ compositeId: string, toCompositeId: string }>(); + + const pinnedComposites = JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, null)) as string[]; + if (pinnedComposites) { + this.pinnedComposites = pinnedComposites; + } else { + this.pinnedComposites = this.options.composites.map(c => c.id); + } + } + + public get onDidContextMenu(): Event { + return this._onDidContextMenu.event; + } + + public get onDidDropComposite(): Event<{ compositeId: string, toCompositeId: string }> { + return this._onDidDropComposite.event; + } + + public activateComposite(id: string): void { + if (this.compositeIdToActions[id]) { + this.compositeIdToActions[id].activate(); + } + this.activeCompositeId = id; + + const activeUnpinnedCompositeShouldClose = this.activeUnpinnedCompositeId && this.activeUnpinnedCompositeId !== id; + const activeUnpinnedCompositeShouldShow = !this.pinnedComposites.some(pid => pid === id); + if (activeUnpinnedCompositeShouldShow || activeUnpinnedCompositeShouldClose) { + this.updateCompositeSwitcher(); + } + } + + public deactivateComposite(id: string): void { + if (this.compositeIdToActions[id]) { + this.compositeIdToActions[id].deactivate(); + } + } + + public showActivity(compositeId: string, badge: IBadge, clazz?: string): IDisposable { + if (!badge) { + throw illegalArgument('badge'); + } + + const activity = { badge, clazz }; + const stack = this.compositeIdToActivityStack[compositeId] || (this.compositeIdToActivityStack[compositeId] = []); + stack.unshift(activity); + + this.updateActivity(compositeId); + + return { + dispose: () => { + const stack = this.compositeIdToActivityStack[compositeId]; + if (!stack) { + return; + } + + const idx = stack.indexOf(activity); + if (idx < 0) { + return; + } + + stack.splice(idx, 1); + if (stack.length === 0) { + delete this.compositeIdToActivityStack[compositeId]; + } + + this.updateActivity(compositeId); + } + }; + } + + private updateActivity(compositeId: string) { + const action = this.compositeIdToActions[compositeId]; + if (!action) { + return; + } + + const stack = this.compositeIdToActivityStack[compositeId]; + + // reset + if (!stack || !stack.length) { + action.setBadge(undefined); + } + + // update + else { + const [{ badge, clazz }] = stack; + action.setBadge(badge); + if (clazz) { + action.class = clazz; + } + } + } + + public create(container: HTMLElement): void { + this.compositeSwitcherBar = new ActionBar(container, { + actionItemProvider: (action: Action) => action instanceof CompositeOverflowActivityAction ? this.compositeOverflowActionItem : this.compositeIdToActionItems[action.id], + orientation: this.options.orientation, + ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), + animated: false + }); + this.updateCompositeSwitcher(); + + // Contextmenu for composites + this.toDispose.push(dom.addDisposableListener(container, dom.EventType.CONTEXT_MENU, (e: MouseEvent) => { + dom.EventHelper.stop(e, true); + this._onDidContextMenu.fire(e); + })); + + // Allow to drop at the end to move composites to the end + this.toDispose.push(dom.addDisposableListener(container, dom.EventType.DROP, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + dom.EventHelper.stop(e, true); + CompositeActionItem.clearDraggedComposite(); + + const targetId = this.pinnedComposites[this.pinnedComposites.length - 1]; + if (targetId !== draggedCompositeId) { + this._onDidDropComposite.fire({ compositeId: draggedCompositeId, toCompositeId: this.pinnedComposites[this.pinnedComposites.length - 1] }); + } + } + })); + } + + private updateCompositeSwitcher(): void { + if (!this.compositeSwitcherBar) { + return; // We have not been rendered yet so there is nothing to update. + } + + let compositesToShow = this.pinnedComposites; + + // Always show the active composite even if it is marked to be hidden + if (this.activeCompositeId && !compositesToShow.some(id => id === this.activeCompositeId)) { + this.activeUnpinnedCompositeId = this.activeCompositeId; + compositesToShow.push(this.activeUnpinnedCompositeId); + } else { + this.activeUnpinnedCompositeId = void 0; + } + + // Ensure we are not showing more composites than we have height for + let overflows = false; + if (this.dimension) { + // TODO@Isidor change this maxVisible computation to be dynamic + const maxVisible = Math.floor(this.dimension.height / 50); + overflows = compositesToShow.length > maxVisible; + + if (overflows) { + compositesToShow = compositesToShow.slice(0, maxVisible - 1 /* make room for overflow action */); + } + } + + const visibleComposites = Object.keys(this.compositeIdToActions); + const visibleCompositesChange = !arrays.equals(compositesToShow, visibleComposites); + + // Pull out overflow action if there is a composite change so that we can add it to the end later + if (this.compositeOverflowAction && visibleCompositesChange) { + this.compositeSwitcherBar.pull(this.compositeSwitcherBar.length() - 1); + + this.compositeOverflowAction.dispose(); + this.compositeOverflowAction = null; + + this.compositeOverflowActionItem.dispose(); + this.compositeOverflowActionItem = null; + } + + // Pull out composites that overflow or got hidden + visibleComposites.forEach(compositeId => { + if (compositesToShow.indexOf(compositeId) === -1) { + this.pullComposite(compositeId); + } + }); + + // Built actions for composites to show + const newCompositesToShow = compositesToShow + .filter(compositeId => !this.compositeIdToActions[compositeId]) + .map(compositeId => this.toAction(compositeId)); + + // Update when we have new composites to show + if (newCompositesToShow.length) { + + // Add to composite switcher + this.compositeSwitcherBar.push(newCompositesToShow, { label: true, icon: true }); + + // Make sure to activate the active one + if (this.activeCompositeId) { + const activeCompositeEntry = this.compositeIdToActions[this.activeCompositeId]; + if (activeCompositeEntry) { + activeCompositeEntry.activate(); + } + } + + // Make sure to restore activity + Object.keys(this.compositeIdToActions).forEach(compositeId => { + this.updateActivity(compositeId); + }); + } + + // Add overflow action as needed + if (visibleCompositesChange && overflows) { + this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => this.compositeOverflowActionItem.showMenu()); + this.compositeOverflowActionItem = this.instantiationService.createInstance( + CompositeOverflowActivityActionItem, + this.compositeOverflowAction, + () => this.getOverflowingComposites(), + () => this.activeCompositeId, + (compositeId: string) => this.compositeIdToActivityStack[compositeId] && this.compositeIdToActivityStack[compositeId][0].badge, + this.options.getOpenCompositeAction + ); + + this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: true, icon: true }); + } + } + + private getOverflowingComposites(): { id: string, name: string }[] { + let overflowingIds = this.pinnedComposites; + if (this.activeUnpinnedCompositeId) { + overflowingIds = overflowingIds.concat(this.activeUnpinnedCompositeId); + } + const visibleComposites = Object.keys(this.compositeIdToActions); + + overflowingIds = overflowingIds.filter(compositeId => visibleComposites.indexOf(compositeId) === -1); + return this.options.composites.filter(c => overflowingIds.indexOf(c.id) !== -1); + } + + public getVisibleComposites(): string[] { + return Object.keys(this.compositeIdToActions); + } + + private pullComposite(compositeId: string): void { + const index = Object.keys(this.compositeIdToActions).indexOf(compositeId); + if (index >= 0) { + this.compositeSwitcherBar.pull(index); + + const action = this.compositeIdToActions[compositeId]; + action.dispose(); + delete this.compositeIdToActions[compositeId]; + + const actionItem = this.compositeIdToActionItems[action.id]; + actionItem.dispose(); + delete this.compositeIdToActionItems[action.id]; + } + } + + private toAction(compositeId: string): ActivityAction { + const compositeActivityAction = this.options.getActivityAction(compositeId); + const pinnedAction = this.options.getCompositePinnedAction(compositeId); + this.compositeIdToActionItems[compositeId] = this.instantiationService.createInstance(CompositeActionItem, compositeActivityAction, pinnedAction); + this.compositeIdToActions[compositeId] = compositeActivityAction; + + return compositeActivityAction; + } + + public unpin(compositeId: string): void { + const index = this.pinnedComposites.indexOf(compositeId); + this.pinnedComposites.splice(index, 1); + + this.updateCompositeSwitcher(); + } + + public isPinned(compositeId: string): boolean { + return this.pinnedComposites.indexOf(compositeId) >= 0; + } + + public pin(compositeId: string, update = true): void { + this.pinnedComposites.push(compositeId); + this.pinnedComposites = arrays.distinct(this.pinnedComposites); + + if (update) { + this.updateCompositeSwitcher(); + } + } + + public move(compositeId: string, toCompositeId: string): void { + + const fromIndex = this.pinnedComposites.indexOf(compositeId); + const toIndex = this.pinnedComposites.indexOf(toCompositeId); + + this.pinnedComposites.splice(fromIndex, 1); + this.pinnedComposites.splice(toIndex, 0, compositeId); + + // Clear composites that are impacted by the move + const visibleComposites = Object.keys(this.compositeIdToActions); + for (let i = Math.min(fromIndex, toIndex); i < visibleComposites.length; i++) { + this.pullComposite(visibleComposites[i]); + } + + // timeout helps to prevent artifacts from showing up + setTimeout(() => { + this.updateCompositeSwitcher(); + }, 0); + } + + public layout(dimension: Dimension): void { + this.dimension = dimension; + this.updateCompositeSwitcher(); + } + + public store(): void { + this.storageService.store(this.options.storageId, JSON.stringify(this.pinnedComposites), StorageScope.GLOBAL); + } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } +} diff --git a/src/vs/workbench/browser/compositeBarActions.ts b/src/vs/workbench/browser/compositeBarActions.ts new file mode 100644 index 00000000000..6b0986b6b0f --- /dev/null +++ b/src/vs/workbench/browser/compositeBarActions.ts @@ -0,0 +1,335 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); +import { Action } from 'vs/base/common/actions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import * as dom from 'vs/base/browser/dom'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { dispose } from 'vs/base/common/lifecycle'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IActivityBarService, TextBadge, NumberBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; +import { DelayedDragHandler } from 'vs/base/browser/dnd'; +import { IActivity } from 'vs/workbench/common/activity'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; + +export interface ICompositeActivity { + badge: IBadge; + clazz: string; +} + +export class CompositeOverflowActivityAction extends ActivityAction { + + constructor( + private showMenu: () => void + ) { + super({ + id: 'activitybar.additionalComposites.action', + name: nls.localize('additionalViews', "Additional Views"), + cssClass: 'toggle-more' + }); + } + + public run(event: any): TPromise { + this.showMenu(); + + return TPromise.as(true); + } +} + +export class CompositeOverflowActivityActionItem extends ActivityActionItem { + private name: string; + private cssClass: string; + private actions: Action[]; + + constructor( + action: ActivityAction, + private getOverflowingComposites: () => { id: string, name: string }[], + private getActiveCompositeId: () => string, + private getBadge: (compositeId: string) => IBadge, + private getCompositeOpenAction: (compositeId: string) => Action, + @IInstantiationService private instantiationService: IInstantiationService, + @IContextMenuService private contextMenuService: IContextMenuService, + @IThemeService themeService: IThemeService + ) { + super(action, null, themeService); + + this.cssClass = action.class; + this.name = action.label; + } + + public showMenu(): void { + if (this.actions) { + dispose(this.actions); + } + + this.actions = this.getActions(); + + this.contextMenuService.showContextMenu({ + getAnchor: () => this.builder.getHTMLElement(), + getActions: () => TPromise.as(this.actions), + onHide: () => dispose(this.actions) + }); + } + + private getActions(): Action[] { + return this.getOverflowingComposites().map(composite => { + const action = this.getCompositeOpenAction(composite.id); + action.radio = this.getActiveCompositeId() === action.id; + + const badge = this.getBadge(composite.id); + let suffix: string | number; + if (badge instanceof NumberBadge) { + suffix = badge.number; + } else if (badge instanceof TextBadge) { + suffix = badge.text; + } + + if (suffix) { + action.label = nls.localize('numberBadge', "{0} ({1})", composite.name, suffix); + } else { + action.label = composite.name; + } + + return action; + }); + } + + public dispose(): void { + super.dispose(); + + this.actions = dispose(this.actions); + } +} + +class ManageExtensionAction extends Action { + + constructor( + @ICommandService private commandService: ICommandService + ) { + super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); + } + + public run(id: string): TPromise { + return this.commandService.executeCommand('_extensions.manage', id); + } +} + +export class CompositeActionItem extends ActivityActionItem { + + private static manageExtensionAction: ManageExtensionAction; + private static draggedCompositeId: string; + + private compositeActivity: IActivity; + private cssClass: string; + + constructor( + private compositeActivityAction: ActivityAction, + private toggleCompositePinnedAction: Action, + @IContextMenuService private contextMenuService: IContextMenuService, + @IActivityBarService private activityBarService: IActivityBarService, + @IKeybindingService private keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService + ) { + super(compositeActivityAction, { draggable: true }, themeService); + + this.cssClass = compositeActivityAction.class; + + if (!CompositeActionItem.manageExtensionAction) { + CompositeActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); + } + } + + protected get activity(): IActivity { + if (!this.compositeActivity) { + let activityName: string; + + const keybinding = this.getKeybindingLabel(this.compositeActivityAction.activity.id); + if (keybinding) { + activityName = nls.localize('titleKeybinding', "{0} ({1})", this.compositeActivityAction.activity.name, keybinding); + } else { + activityName = this.compositeActivityAction.activity.name; + } + + this.compositeActivity = { + id: this.compositeActivityAction.activity.id, + cssClass: this.cssClass, + name: activityName + }; + } + + return this.compositeActivity; + } + + private getKeybindingLabel(id: string): string { + const kb = this.keybindingService.lookupKeybinding(id); + if (kb) { + return kb.getLabel(); + } + + return null; + } + + public render(container: HTMLElement): void { + super.render(container); + + this.$container.on('contextmenu', e => { + dom.EventHelper.stop(e, true); + + this.showContextMenu(container); + }); + + // Allow to drag + this.$container.on(dom.EventType.DRAG_START, (e: DragEvent) => { + e.dataTransfer.effectAllowed = 'move'; + this.setDraggedComposite(this.activity.id); + + // Trigger the action even on drag start to prevent clicks from failing that started a drag + if (!this.getAction().checked) { + this.getAction().run(); + } + }); + + // Drag enter + let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 + this.$container.on(dom.EventType.DRAG_ENTER, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId && draggedCompositeId !== this.activity.id) { + counter++; + this.updateFromDragging(container, true); + } + }); + + // Drag leave + this.$container.on(dom.EventType.DRAG_LEAVE, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + counter--; + if (counter === 0) { + this.updateFromDragging(container, false); + } + } + }); + + // Drag end + this.$container.on(dom.EventType.DRAG_END, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + counter = 0; + this.updateFromDragging(container, false); + + CompositeActionItem.clearDraggedComposite(); + } + }); + + // Drop + this.$container.on(dom.EventType.DROP, (e: DragEvent) => { + dom.EventHelper.stop(e, true); + + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId && draggedCompositeId !== this.activity.id) { + this.updateFromDragging(container, false); + CompositeActionItem.clearDraggedComposite(); + + this.activityBarService.move(draggedCompositeId, this.activity.id); + } + }); + + // Activate on drag over to reveal targets + [this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { + if (!CompositeActionItem.getDraggedCompositeId() && !this.getAction().checked) { + this.getAction().run(); + } + })); + + this.updateStyles(); + } + + private updateFromDragging(element: HTMLElement, isDragging: boolean): void { + const theme = this.themeService.getTheme(); + const dragBackground = theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND); + + element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : null; + } + + public static getDraggedCompositeId(): string { + return CompositeActionItem.draggedCompositeId; + } + + private setDraggedComposite(compositeId: string): void { + CompositeActionItem.draggedCompositeId = compositeId; + } + + public static clearDraggedComposite(): void { + CompositeActionItem.draggedCompositeId = void 0; + } + + private showContextMenu(container: HTMLElement): void { + const actions: Action[] = [this.toggleCompositePinnedAction]; + if ((this.compositeActivityAction.activity).extensionId) { + actions.push(new Separator()); + actions.push(CompositeActionItem.manageExtensionAction); + } + + const isPinned = this.activityBarService.isPinned(this.activity.id); + if (isPinned) { + this.toggleCompositePinnedAction.label = nls.localize('removeFromActivityBar', "Hide from Activity Bar"); + this.toggleCompositePinnedAction.checked = false; + } else { + this.toggleCompositePinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar"); + } + + this.contextMenuService.showContextMenu({ + getAnchor: () => container, + getActionsContext: () => this.activity.id, + getActions: () => TPromise.as(actions) + }); + } + + public focus(): void { + this.$container.domFocus(); + } + + protected _updateClass(): void { + if (this.cssClass) { + this.$badge.removeClass(this.cssClass); + } + + this.cssClass = this.getAction().class; + this.$badge.addClass(this.cssClass); + } + + protected _updateChecked(): void { + if (this.getAction().checked) { + this.$container.addClass('checked'); + } else { + this.$container.removeClass('checked'); + } + } + + protected _updateEnabled(): void { + if (this.getAction().enabled) { + this.builder.removeClass('disabled'); + } else { + this.builder.addClass('disabled'); + } + } + + public dispose(): void { + super.dispose(); + + CompositeActionItem.clearDraggedComposite(); + + this.$label.destroy(); + } +} diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 8add806cda5..69b532ccb46 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -10,32 +10,23 @@ import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, $ } from 'vs/base/browser/builder'; -import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { Action } from 'vs/base/common/actions'; -import { BaseActionItem, Separator, IBaseActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem, IBaseActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { IActivityBarService, ProgressBadge, TextBadge, NumberBadge, IconBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; import Event, { Emitter } from 'vs/base/common/event'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; import { dispose } from 'vs/base/common/lifecycle'; import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; import { contrastBorder, activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -export interface IViewletActivity { - badge: IBadge; - clazz: string; -} - export class ActivityAction extends Action { private badge: IBadge; private _onDidChangeBadge = new Emitter(); @@ -83,15 +74,11 @@ export class ViewletActivityAction extends ActivityAction { private lastRun: number = 0; constructor( - private viewlet: ViewletDescriptor, + activity: IActivity, @IViewletService private viewletService: IViewletService, @IPartService private partService: IPartService ) { - super(viewlet); - } - - public get descriptor(): ViewletDescriptor { - return this.viewlet; + super(activity); } public run(event: any): TPromise { @@ -110,11 +97,11 @@ export class ViewletActivityAction extends ActivityAction { const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.viewlet.id) { + if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.activity.id) { return this.partService.setSideBarHidden(true); } - return this.viewletService.openViewlet(this.viewlet.id, true).then(() => this.activate()); + return this.viewletService.openViewlet(this.activity.id, true).then(() => this.activate()); } } @@ -283,322 +270,7 @@ export class ActivityActionItem extends BaseActionItem { } } -export class ViewletActionItem extends ActivityActionItem { - - private static manageExtensionAction: ManageExtensionAction; - private static toggleViewletPinnedAction: ToggleViewletPinnedAction; - private static draggedViewlet: ViewletDescriptor; - - private viewletActivity: IActivity; - private cssClass: string; - - constructor( - private action: ViewletActivityAction, - @IContextMenuService private contextMenuService: IContextMenuService, - @IActivityBarService private activityBarService: IActivityBarService, - @IKeybindingService private keybindingService: IKeybindingService, - @IInstantiationService instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService - ) { - super(action, { draggable: true }, themeService); - - this.cssClass = action.class; - - if (!ViewletActionItem.manageExtensionAction) { - ViewletActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); - } - - if (!ViewletActionItem.toggleViewletPinnedAction) { - ViewletActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0); - } - } - - protected get activity(): IActivity { - if (!this.viewletActivity) { - let activityName: string; - - const keybinding = this.getKeybindingLabel(this.viewlet.id); - if (keybinding) { - activityName = nls.localize('titleKeybinding', "{0} ({1})", this.viewlet.name, keybinding); - } else { - activityName = this.viewlet.name; - } - - this.viewletActivity = { - id: this.viewlet.id, - cssClass: this.cssClass, - name: activityName - }; - } - - return this.viewletActivity; - } - - private get viewlet(): ViewletDescriptor { - return this.action.descriptor; - } - - private getKeybindingLabel(id: string): string { - const kb = this.keybindingService.lookupKeybinding(id); - if (kb) { - return kb.getLabel(); - } - - return null; - } - - public render(container: HTMLElement): void { - super.render(container); - - this.$container.on('contextmenu', e => { - DOM.EventHelper.stop(e, true); - - this.showContextMenu(container); - }); - - // Allow to drag - this.$container.on(DOM.EventType.DRAG_START, (e: DragEvent) => { - e.dataTransfer.effectAllowed = 'move'; - this.setDraggedViewlet(this.viewlet); - - // Trigger the action even on drag start to prevent clicks from failing that started a drag - if (!this.getAction().checked) { - this.getAction().run(); - } - }); - - // Drag enter - let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 - this.$container.on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) { - counter++; - this.updateFromDragging(container, true); - } - }); - - // Drag leave - this.$container.on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - counter--; - if (counter === 0) { - this.updateFromDragging(container, false); - } - } - }); - - // Drag end - this.$container.on(DOM.EventType.DRAG_END, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - counter = 0; - this.updateFromDragging(container, false); - - ViewletActionItem.clearDraggedViewlet(); - } - }); - - // Drop - this.$container.on(DOM.EventType.DROP, (e: DragEvent) => { - DOM.EventHelper.stop(e, true); - - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) { - this.updateFromDragging(container, false); - ViewletActionItem.clearDraggedViewlet(); - - this.activityBarService.move(draggedViewlet.id, this.viewlet.id); - } - }); - - // Activate on drag over to reveal targets - [this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { - if (!ViewletActionItem.getDraggedViewlet() && !this.getAction().checked) { - this.getAction().run(); - } - })); - - this.updateStyles(); - } - - private updateFromDragging(element: HTMLElement, isDragging: boolean): void { - const theme = this.themeService.getTheme(); - const dragBackground = theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND); - - element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : null; - } - - public static getDraggedViewlet(): ViewletDescriptor { - return ViewletActionItem.draggedViewlet; - } - - private setDraggedViewlet(viewlet: ViewletDescriptor): void { - ViewletActionItem.draggedViewlet = viewlet; - } - - public static clearDraggedViewlet(): void { - ViewletActionItem.draggedViewlet = void 0; - } - - private showContextMenu(container: HTMLElement): void { - const actions: Action[] = [ViewletActionItem.toggleViewletPinnedAction]; - if (this.viewlet.extensionId) { - actions.push(new Separator()); - actions.push(ViewletActionItem.manageExtensionAction); - } - - const isPinned = this.activityBarService.isPinned(this.viewlet.id); - if (isPinned) { - ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Hide from Activity Bar"); - } else { - ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar"); - } - - this.contextMenuService.showContextMenu({ - getAnchor: () => container, - getActionsContext: () => this.viewlet, - getActions: () => TPromise.as(actions) - }); - } - - public focus(): void { - this.$container.domFocus(); - } - - protected _updateClass(): void { - if (this.cssClass) { - this.$badge.removeClass(this.cssClass); - } - - this.cssClass = this.getAction().class; - this.$badge.addClass(this.cssClass); - } - - protected _updateChecked(): void { - if (this.getAction().checked) { - this.$container.addClass('checked'); - } else { - this.$container.removeClass('checked'); - } - } - - protected _updateEnabled(): void { - if (this.getAction().enabled) { - this.builder.removeClass('disabled'); - } else { - this.builder.addClass('disabled'); - } - } - - public dispose(): void { - super.dispose(); - - ViewletActionItem.clearDraggedViewlet(); - - this.$label.destroy(); - } -} - -export class ViewletOverflowActivityAction extends ActivityAction { - - constructor( - private showMenu: () => void - ) { - super({ - id: 'activitybar.additionalViewlets.action', - name: nls.localize('additionalViews', "Additional Views"), - cssClass: 'toggle-more' - }); - } - - public run(event: any): TPromise { - this.showMenu(); - - return TPromise.as(true); - } -} - -export class ViewletOverflowActivityActionItem extends ActivityActionItem { - private name: string; - private cssClass: string; - private actions: OpenViewletAction[]; - - constructor( - action: ActivityAction, - private getOverflowingViewlets: () => ViewletDescriptor[], - private getBadge: (viewlet: ViewletDescriptor) => IBadge, - @IInstantiationService private instantiationService: IInstantiationService, - @IViewletService private viewletService: IViewletService, - @IContextMenuService private contextMenuService: IContextMenuService, - @IThemeService themeService: IThemeService - ) { - super(action, null, themeService); - - this.cssClass = action.class; - this.name = action.label; - } - - public showMenu(): void { - if (this.actions) { - dispose(this.actions); - } - - this.actions = this.getActions(); - - this.contextMenuService.showContextMenu({ - getAnchor: () => this.builder.getHTMLElement(), - getActions: () => TPromise.as(this.actions), - onHide: () => dispose(this.actions) - }); - } - - private getActions(): OpenViewletAction[] { - const activeViewlet = this.viewletService.getActiveViewlet(); - - return this.getOverflowingViewlets().map(viewlet => { - const action = this.instantiationService.createInstance(OpenViewletAction, viewlet); - action.radio = activeViewlet && activeViewlet.getId() === action.id; - - const badge = this.getBadge(action.viewlet); - let suffix: string | number; - if (badge instanceof NumberBadge) { - suffix = badge.number; - } else if (badge instanceof TextBadge) { - suffix = badge.text; - } - - if (suffix) { - action.label = nls.localize('numberBadge', "{0} ({1})", action.viewlet.name, suffix); - } else { - action.label = action.viewlet.name; - } - - return action; - }); - } - - public dispose(): void { - super.dispose(); - - this.actions = dispose(this.actions); - } -} - -class ManageExtensionAction extends Action { - - constructor( - @ICommandService private commandService: ICommandService - ) { - super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); - } - - public run(viewlet: ViewletDescriptor): TPromise { - return this.commandService.executeCommand('_extensions.manage', viewlet.extensionId); - } -} - -class OpenViewletAction extends Action { +export class OpenViewletAction extends Action { constructor( private _viewlet: ViewletDescriptor, @@ -608,41 +280,37 @@ class OpenViewletAction extends Action { super(_viewlet.id, _viewlet.name); } - public get viewlet(): ViewletDescriptor { - return this._viewlet; - } - public run(): TPromise { const sideBarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.viewlet.id) { + if (sideBarVisible && activeViewlet && activeViewlet.getId() === this._viewlet.id) { return this.partService.setSideBarHidden(true); } - return this.viewletService.openViewlet(this.viewlet.id, true); + return this.viewletService.openViewlet(this._viewlet.id, true); } } export class ToggleViewletPinnedAction extends Action { constructor( - private viewlet: ViewletDescriptor, + private activity: IActivity, @IActivityBarService private activityBarService: IActivityBarService ) { - super('activitybar.show.toggleViewletPinned', viewlet ? viewlet.name : nls.localize('toggle', "Toggle View Pinned")); + super('activitybar.show.toggleViewletPinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned")); - this.checked = this.viewlet && this.activityBarService.isPinned(this.viewlet.id); + this.checked = this.activity && this.activityBarService.isPinned(this.activity.id); } - public run(context?: ViewletDescriptor): TPromise { - const viewlet = this.viewlet || context; + public run(context: string): TPromise { + const id = this.activity ? this.activity.id : context; - if (this.activityBarService.isPinned(viewlet.id)) { - this.activityBarService.unpin(viewlet.id); + if (this.activityBarService.isPinned(id)) { + this.activityBarService.unpin(id); } else { - this.activityBarService.pin(viewlet.id); + this.activityBarService.pin(id); } return TPromise.as(true); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 5afcced6e5c..035d1ad57b9 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,25 +8,20 @@ import 'vs/css!./media/activitybarpart'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import DOM = require('vs/base/browser/dom'); -import * as arrays from 'vs/base/common/arrays'; import { illegalArgument } from 'vs/base/common/errors'; import { Builder, $, Dimension } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; -import { ActionsOrientation, ActionBar, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; import { Part } from 'vs/workbench/browser/part'; -import { IViewlet } from 'vs/workbench/common/viewlet'; -import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, GlobalActivityActionItem, ViewletActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem, GlobalActivityAction, IViewletActivity } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { ToggleViewletPinnedAction, GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, OpenViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { Scope as MementoScope } from 'vs/workbench/common/memento'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -34,6 +29,7 @@ import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { CompositeBar } from 'vs/workbench/browser/compositeBar'; export class ActivitybarPart extends Part implements IActivityBarService { @@ -47,17 +43,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private globalActionBar: ActionBar; private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; }; - private viewletSwitcherBar: ActionBar; - private viewletOverflowAction: ViewletOverflowActivityAction; - private viewletOverflowActionItem: ViewletOverflowActivityActionItem; - - private viewletIdToActions: { [viewletId: string]: ActivityAction; }; - private viewletIdToActionItems: { [viewletId: string]: IActionItem; }; - private viewletIdToActivityStack: { [viewletId: string]: IViewletActivity[]; }; - - private memento: object; - private pinnedViewlets: string[]; - private activeUnpinnedViewlet: ViewletDescriptor; + private compositeBar: CompositeBar; constructor( id: string, @@ -72,58 +58,32 @@ export class ActivitybarPart extends Part implements IActivityBarService { super(id, { hasTitle: false }, themeService); this.globalActivityIdToActions = Object.create(null); - - this.viewletIdToActionItems = Object.create(null); - this.viewletIdToActions = Object.create(null); - this.viewletIdToActivityStack = Object.create(null); - - this.memento = this.getMemento(this.storageService, MementoScope.GLOBAL); - - const pinnedViewlets = this.memento[ActivitybarPart.PINNED_VIEWLETS] as string[]; - - if (pinnedViewlets) { - this.pinnedViewlets = pinnedViewlets; - } else { - this.pinnedViewlets = this.viewletService.getViewlets().map(v => v.id); - } - + this.compositeBar = this.instantiationService.createInstance(CompositeBar, { + label: 'icon', + storageId: ActivitybarPart.PINNED_VIEWLETS, + orientation: ActionsOrientation.VERTICAL, + composites: this.viewletService.getViewlets(), + getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)), + getCompositePinnedAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletPinnedAction, this.viewletService.getViewlet(compositeId)), + getOpenCompositeAction: (compositeId: string) => this.instantiationService.createInstance(OpenViewletAction, this.viewletService.getViewlet(compositeId)) + }); this.registerListeners(); } private registerListeners(): void { // Activate viewlet action on opening of a viewlet - this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.onDidViewletOpen(viewlet))); + this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.compositeBar.activateComposite(viewlet.getId()))); // Deactivate viewlet action on close - this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onDidViewletClose(viewlet))); - } - - private onDidViewletOpen(viewlet: IViewlet): void { - const id = viewlet.getId(); - - if (this.viewletIdToActions[id]) { - this.viewletIdToActions[id].activate(); - } - - const activeUnpinnedViewletShouldClose = this.activeUnpinnedViewlet && this.activeUnpinnedViewlet.id !== viewlet.getId(); - const activeUnpinnedViewletShouldShow = !this.getPinnedViewlets().some(v => v.id === viewlet.getId()); - if (activeUnpinnedViewletShouldShow || activeUnpinnedViewletShouldClose) { - this.updateViewletSwitcher(); - } - } - - private onDidViewletClose(viewlet: IViewlet): void { - const id = viewlet.getId(); - - if (this.viewletIdToActions[id]) { - this.viewletIdToActions[id].deactivate(); - } + this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId()))); + this.toUnbind.push(this.compositeBar.onDidDropComposite(data => this.move(data.compositeId, data.toCompositeId))); + this.toUnbind.push(this.compositeBar.onDidContextMenu(e => this.showContextMenu(e))); } public showActivity(viewletOrActionId: string, badge: IBadge, clazz?: string): IDisposable { if (this.viewletService.getViewlet(viewletOrActionId)) { - return this.showViewletActivity(viewletOrActionId, badge, clazz); + return this.compositeBar.showActivity(viewletOrActionId, badge, clazz); } return this.showGlobalActivity(viewletOrActionId, badge); @@ -144,94 +104,16 @@ export class ActivitybarPart extends Part implements IActivityBarService { return toDisposable(() => action.setBadge(undefined)); } - private showViewletActivity(viewletId: string, badge: IBadge, clazz?: string): IDisposable { - if (!badge) { - throw illegalArgument('badge'); - } - - const activity = { badge, clazz }; - const stack = this.viewletIdToActivityStack[viewletId] || (this.viewletIdToActivityStack[viewletId] = []); - stack.unshift(activity); - - this.updateViewletActivity(viewletId); - - return { - dispose: () => { - const stack = this.viewletIdToActivityStack[viewletId]; - if (!stack) { - return; - } - - const idx = stack.indexOf(activity); - if (idx < 0) { - return; - } - - stack.splice(idx, 1); - if (stack.length === 0) { - delete this.viewletIdToActivityStack[viewletId]; - } - - this.updateViewletActivity(viewletId); - } - }; - } - - private updateViewletActivity(viewletId: string) { - const action = this.viewletIdToActions[viewletId]; - if (!action) { - return; - } - - const stack = this.viewletIdToActivityStack[viewletId]; - - // reset - if (!stack || !stack.length) { - action.setBadge(undefined); - } - - // update - else { - const [{ badge, clazz }] = stack; - action.setBadge(badge); - if (clazz) { - action.class = clazz; - } - } - } - public createContentArea(parent: Builder): Builder { const $el = $(parent); const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.createViewletSwitcher($result.clone()); + this.compositeBar.create($result.clone().getHTMLElement()); // Top Actionbar with action items for each viewlet action this.createGlobalActivityActionBar($result.getHTMLElement()); - // Contextmenu for viewlets - $(parent).on('contextmenu', (e: MouseEvent) => { - DOM.EventHelper.stop(e, true); - - this.showContextMenu(e); - }, this.toUnbind); - - // Allow to drop at the end to move viewlet to the end - $(parent).on(DOM.EventType.DROP, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - DOM.EventHelper.stop(e, true); - - ViewletActionItem.clearDraggedViewlet(); - - const targetId = this.pinnedViewlets[this.pinnedViewlets.length - 1]; - if (targetId !== draggedViewlet.id) { - this.move(draggedViewlet.id, this.pinnedViewlets[this.pinnedViewlets.length - 1]); - } - } - }); - return $result; } @@ -268,20 +150,6 @@ export class ActivitybarPart extends Part implements IActivityBarService { }); } - private createViewletSwitcher(div: Builder): void { - this.viewletSwitcherBar = new ActionBar(div, { - actionItemProvider: (action: Action) => action instanceof ViewletOverflowActivityAction ? this.viewletOverflowActionItem : this.viewletIdToActionItems[action.id], - orientation: ActionsOrientation.VERTICAL, - ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), - animated: false - }); - - this.updateViewletSwitcher(); - - // Update viewlet switcher when external viewlets become ready - this.extensionService.onReady().then(() => this.updateViewletSwitcher()); - } - private createGlobalActivityActionBar(container: HTMLElement): void { const activityRegistry = Registry.as(GlobalActivityExtensions); const descriptors = activityRegistry.getActivities(); @@ -302,152 +170,18 @@ export class ActivitybarPart extends Part implements IActivityBarService { }); } - private updateViewletSwitcher() { - if (!this.viewletSwitcherBar) { - return; // We have not been rendered yet so there is nothing to update. - } - - let viewletsToShow = this.getPinnedViewlets(); - - // Always show the active viewlet even if it is marked to be hidden - const activeViewlet = this.viewletService.getActiveViewlet(); - if (activeViewlet && !viewletsToShow.some(viewlet => viewlet.id === activeViewlet.getId())) { - this.activeUnpinnedViewlet = this.viewletService.getViewlet(activeViewlet.getId()); - viewletsToShow.push(this.activeUnpinnedViewlet); - } else { - this.activeUnpinnedViewlet = void 0; - } - - // Ensure we are not showing more viewlets than we have height for - let overflows = false; - if (this.dimension) { - let availableHeight = this.dimension.height; - if (this.globalActionBar) { - availableHeight -= (this.globalActionBar.items.length * ActivitybarPart.ACTIVITY_ACTION_HEIGHT); // adjust for global actions showing - } - - const maxVisible = Math.floor(availableHeight / ActivitybarPart.ACTIVITY_ACTION_HEIGHT); - overflows = viewletsToShow.length > maxVisible; - - if (overflows) { - viewletsToShow = viewletsToShow.slice(0, maxVisible - 1 /* make room for overflow action */); - } - } - - const visibleViewlets = Object.keys(this.viewletIdToActions); - const visibleViewletsChange = !arrays.equals(viewletsToShow.map(viewlet => viewlet.id), visibleViewlets); - - // Pull out overflow action if there is a viewlet change so that we can add it to the end later - if (this.viewletOverflowAction && visibleViewletsChange) { - this.viewletSwitcherBar.pull(this.viewletSwitcherBar.length() - 1); - - this.viewletOverflowAction.dispose(); - this.viewletOverflowAction = null; - - this.viewletOverflowActionItem.dispose(); - this.viewletOverflowActionItem = null; - } - - // Pull out viewlets that overflow or got hidden - const viewletIdsToShow = viewletsToShow.map(v => v.id); - visibleViewlets.forEach(viewletId => { - if (viewletIdsToShow.indexOf(viewletId) === -1) { - this.pullViewlet(viewletId); - } - }); - - // Built actions for viewlets to show - const newViewletsToShow = viewletsToShow - .filter(viewlet => !this.viewletIdToActions[viewlet.id]) - .map(viewlet => this.toAction(viewlet)); - - // Update when we have new viewlets to show - if (newViewletsToShow.length) { - - // Add to viewlet switcher - this.viewletSwitcherBar.push(newViewletsToShow, { label: true, icon: true }); - - // Make sure to activate the active one - const activeViewlet = this.viewletService.getActiveViewlet(); - if (activeViewlet) { - const activeViewletEntry = this.viewletIdToActions[activeViewlet.getId()]; - if (activeViewletEntry) { - activeViewletEntry.activate(); - } - } - - // Make sure to restore activity - Object.keys(this.viewletIdToActions).forEach(viewletId => { - this.updateViewletActivity(viewletId); - }); - } - - // Add overflow action as needed - if (visibleViewletsChange && overflows) { - this.viewletOverflowAction = this.instantiationService.createInstance(ViewletOverflowActivityAction, () => this.viewletOverflowActionItem.showMenu()); - this.viewletOverflowActionItem = this.instantiationService.createInstance(ViewletOverflowActivityActionItem, this.viewletOverflowAction, () => this.getOverflowingViewlets(), (viewlet: ViewletDescriptor) => this.viewletIdToActivityStack[viewlet.id] && this.viewletIdToActivityStack[viewlet.id][0].badge); - - this.viewletSwitcherBar.push(this.viewletOverflowAction, { label: true, icon: true }); - } - } - - private getOverflowingViewlets(): ViewletDescriptor[] { - const viewlets = this.getPinnedViewlets(); - if (this.activeUnpinnedViewlet) { - viewlets.push(this.activeUnpinnedViewlet); - } - const visibleViewlets = Object.keys(this.viewletIdToActions); - - return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) === -1); - } - - private getVisibleViewlets(): ViewletDescriptor[] { - const viewlets = this.viewletService.getViewlets(); - const visibleViewlets = Object.keys(this.viewletIdToActions); - - return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) >= 0); - } - - private getPinnedViewlets(): ViewletDescriptor[] { - return this.pinnedViewlets.map(viewletId => this.viewletService.getViewlet(viewletId)).filter(v => !!v); // ensure to remove those that might no longer exist - } - - private pullViewlet(viewletId: string): void { - const index = Object.keys(this.viewletIdToActions).indexOf(viewletId); - if (index >= 0) { - this.viewletSwitcherBar.pull(index); - - const action = this.viewletIdToActions[viewletId]; - action.dispose(); - delete this.viewletIdToActions[viewletId]; - - const actionItem = this.viewletIdToActionItems[action.id]; - actionItem.dispose(); - delete this.viewletIdToActionItems[action.id]; - } - } - - private toAction(viewlet: ViewletDescriptor): ActivityAction { - const action = this.instantiationService.createInstance(ViewletActivityAction, viewlet); - - this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ViewletActionItem, action); - this.viewletIdToActions[viewlet.id] = action; - - return action; - } - public getPinned(): string[] { - return this.pinnedViewlets; + return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id));; } public unpin(viewletId: string): void { - if (!this.isPinned(viewletId)) { + if (!this.compositeBar.isPinned(viewletId)) { return; } const activeViewlet = this.viewletService.getActiveViewlet(); const defaultViewletId = this.viewletService.getDefaultViewletId(); - const visibleViewlets = this.getVisibleViewlets(); + const visibleViewlets = this.compositeBar.getVisibleComposites(); let unpinPromise: TPromise; @@ -459,7 +193,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Case: viewlet is not the default viewlet and default viewlet is still showing // Solv: we open the default viewlet - else if (defaultViewletId !== viewletId && this.isPinned(defaultViewletId)) { + else if (defaultViewletId !== viewletId && this.compositeBar.isPinned(defaultViewletId)) { unpinPromise = this.viewletService.openViewlet(defaultViewletId, true); } @@ -472,21 +206,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Case: we closed the default viewlet // Solv: we open the next visible viewlet from top else { - unpinPromise = this.viewletService.openViewlet(visibleViewlets.filter(viewlet => viewlet.id !== viewletId)[0].id, true); + unpinPromise = this.viewletService.openViewlet(visibleViewlets.filter(viewletId => viewletId !== viewletId)[0], true); } unpinPromise.then(() => { - // then remove from pinned and update switcher - const index = this.pinnedViewlets.indexOf(viewletId); - this.pinnedViewlets.splice(index, 1); - - this.updateViewletSwitcher(); + this.compositeBar.unpin(viewletId); }); } public isPinned(viewletId: string): boolean { - return this.pinnedViewlets.indexOf(viewletId) >= 0; + return this.compositeBar.isPinned(viewletId); } public pin(viewletId: string, update = true): void { @@ -495,41 +225,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { } // first open that viewlet - this.viewletService.openViewlet(viewletId, true).then(() => { - - // then update - this.pinnedViewlets.push(viewletId); - this.pinnedViewlets = arrays.distinct(this.pinnedViewlets); - - if (update) { - this.updateViewletSwitcher(); - } - }); + this.viewletService.openViewlet(viewletId, true) + .then(() => this.compositeBar.pin(viewletId, update)); } public move(viewletId: string, toViewletId: string): void { - // Make sure a moved viewlet gets pinned if (!this.isPinned(viewletId)) { this.pin(viewletId, false /* defer update, we take care of it */); } - const fromIndex = this.pinnedViewlets.indexOf(viewletId); - const toIndex = this.pinnedViewlets.indexOf(toViewletId); - - this.pinnedViewlets.splice(fromIndex, 1); - this.pinnedViewlets.splice(toIndex, 0, viewletId); - - // Clear viewlets that are impacted by the move - const visibleViewlets = Object.keys(this.viewletIdToActions); - for (let i = Math.min(fromIndex, toIndex); i < visibleViewlets.length; i++) { - this.pullViewlet(visibleViewlets[i]); - } - - // timeout helps to prevent artifacts from showing up - setTimeout(() => { - this.updateViewletSwitcher(); - }, 0); + this.compositeBar.move(viewletId, toViewletId); } /** @@ -542,16 +248,20 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.dimension = sizes[1]; - // Update switcher to handle overflow issues - this.updateViewletSwitcher(); + let availableHeight = this.dimension.height; + if (this.globalActionBar) { + // adjust height for global actions showing + availableHeight -= (this.globalActionBar.items.length * ActivitybarPart.ACTIVITY_ACTION_HEIGHT); + } + this.compositeBar.layout(new Dimension(dimension.width, availableHeight)); return sizes; } public dispose(): void { - if (this.viewletSwitcherBar) { - this.viewletSwitcherBar.dispose(); - this.viewletSwitcherBar = null; + if (this.compositeBar) { + this.compositeBar.dispose(); + this.compositeBar = null; } if (this.globalActionBar) { @@ -565,9 +275,9 @@ export class ActivitybarPart extends Part implements IActivityBarService { public shutdown(): void { // Persist Hidden State - this.memento[ActivitybarPart.PINNED_VIEWLETS] = this.pinnedViewlets; + this.compositeBar.store(); // Pass to super super.shutdown(); } -} \ No newline at end of file +} From f0f2c909d4c0e13bcceb1733d5304db84c33bb6b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2017 16:23:02 +0200 Subject: [PATCH 201/303] Open full settings editor when clicking on settings.json in explorer (fixes #35579) --- .../browser/parts/editor/editorPart.ts | 57 ++++--- src/vs/workbench/common/editor.ts | 39 ++++- .../browser/preferences.contribution.ts | 4 +- .../preferences/browser/preferencesService.ts | 36 ++--- .../parts/preferences/common/preferences.ts | 14 +- .../common/preferencesContentProvider.ts | 82 ---------- .../common/preferencesContribution.ts | 148 ++++++++++++++++++ .../services/editor/browser/editorService.ts | 17 +- .../services/group/common/groupService.ts | 7 +- .../textfile/common/textFileEditorModel.ts | 1 - .../workbench/test/workbenchTestServices.ts | 8 +- 11 files changed, 267 insertions(+), 146 deletions(-) delete mode 100644 src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts create mode 100644 src/vs/workbench/parts/preferences/common/preferencesContribution.ts diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index f64bf88b532..25fcf62c102 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -21,14 +21,14 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Scope as MementoScope } from 'vs/workbench/common/memento'; import { Part } from 'vs/workbench/browser/part'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID, EditorOpeningEvent, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import { EditorGroupsControl, Rochade, IEditorGroupsControl, ProgressState } from 'vs/workbench/browser/parts/editor/editorGroupsControl'; import { WorkbenchProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { IEditorGroupService, GroupOrientation, GroupArrangement, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEditorPart } from 'vs/workbench/services/editor/browser/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { Position, POSITIONS, Direction } from 'vs/platform/editor/common/editor'; +import { Position, POSITIONS, Direction, IEditor } from 'vs/platform/editor/common/editor'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -99,6 +99,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService private revealIfOpen: boolean; private _onEditorsChanged: Emitter; + private _onEditorOpening: Emitter; private _onEditorsMoved: Emitter; private _onEditorOpenFail: Emitter; private _onGroupOrientationChanged: Emitter; @@ -132,6 +133,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService super(id, { hasTitle: false }, themeService); this._onEditorsChanged = new Emitter(); + this._onEditorOpening = new Emitter(); this._onEditorsMoved = new Emitter(); this._onEditorOpenFail = new Emitter(); this._onGroupOrientationChanged = new Emitter(); @@ -289,6 +291,10 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this._onEditorsChanged.event; } + public get onEditorOpening(): Event { + return this._onEditorOpening.event; + } + public get onEditorsMoved(): Event { return this._onEditorsMoved.event; } @@ -309,12 +315,12 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this.tabOptions; } - public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise; - public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise { - - // Normalize some values - if (!options) { options = null; } + public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise; + public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise { + if (!options) { + options = null; + } // Determine position to open editor in (one, two, three) const position = this.findPosition(input, options, arg3, ratio); @@ -329,6 +335,20 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return TPromise.as(null); } + // Editor opening event (can be prevented and overridden) + const event = new EditorOpeningEvent(input, position); + this._onEditorOpening.fire(event); + const prevented = event.isPrevented(); + if (prevented) { + return prevented(); + } + + // Open through UI + return this.doOpenEditor(position, input, options, ratio); + } + + private doOpenEditor(position: Position, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise { + // We need an editor descriptor for the input const descriptor = Registry.as(EditorExtensions.Editors).getEditor(input); if (!descriptor) { @@ -345,12 +365,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.telemetryService.publicLog('workbenchSideEditorOpened', { position: position }); } - // Open through UI - return this.doOpenEditor(position, descriptor, input, options, ratio); - } - - private doOpenEditor(position: Position, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise { - // Update stacks: We do this early on before the UI is there because we want our stacks model to have // a consistent view of the editor world and updating it later async after the UI is there will cause // issues (e.g. when a closeEditor call is made that expects the openEditor call to have updated the @@ -1007,7 +1021,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } } - public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise { + public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise { const activeReplacements: IEditorReplacement[] = []; const hiddenReplacements: IEditorReplacement[] = []; @@ -1066,9 +1080,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return res; } - public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise { + public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise { if (!editors.length) { - return TPromise.as([]); + return TPromise.as([]); } let activePosition: Position; @@ -1085,7 +1099,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this.stacks.groups.some(g => g.count > 0); } - public restoreEditors(): TPromise { + public restoreEditors(): TPromise { const editors = this.stacks.groups.map((group, index) => { return { input: group.activeEditor, @@ -1095,7 +1109,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService }); if (!editors.length) { - return TPromise.as([]); + return TPromise.as([]); } let activePosition: Position; @@ -1108,7 +1122,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this.doOpenEditors(editors, activePosition, editorState && editorState.ratio); } - private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise { + private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise { const positionOneEditors = editors.filter(e => e.position === Position.ONE); const positionTwoEditors = editors.filter(e => e.position === Position.TWO); const positionThreeEditors = editors.filter(e => e.position === Position.THREE); @@ -1155,7 +1169,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Open each input respecting the options. Since there can only be one active editor in each // position, we have to pick the first input from each position and add the others as inactive - const promises: TPromise[] = []; + const promises: TPromise[] = []; [positionOneEditors.shift(), positionTwoEditors.shift(), positionThreeEditors.shift()].forEach((editor, position) => { if (!editor) { return; // unused position @@ -1343,6 +1357,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Emitters this._onEditorsChanged.dispose(); + this._onEditorOpening.dispose(); this._onEditorsMoved.dispose(); this._onEditorOpenFail.dispose(); diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 440ef0a6265..0e2582432d6 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -11,7 +11,7 @@ import types = require('vs/base/common/types'); import URI from 'vs/base/common/uri'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IEditor, IEditorViewState, IModel, ScrollType } from 'vs/editor/common/editorCommon'; -import { IEditorInput, IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, Position, Verbosity } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, Position, Verbosity, IEditor as IBaseEditor } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -260,6 +260,43 @@ export abstract class EditorInput implements IEditorInput { } } +export interface IEditorOpeningEvent { + input: IEditorInput; + position: Position; + + /** + * Allows to prevent the opening of an editor by providing a callback + * that will be executed instead. By returning another editor promise + * it is possible to override the opening with another editor. It is ok + * to return a promise that resolves to NULL to prevent the opening + * altogether. + */ + prevent(callback: () => TPromise): void; +} + +export class EditorOpeningEvent { + private override: () => TPromise; + + constructor(private _editorInput: IEditorInput, private _position: Position) { + } + + public get input(): IEditorInput { + return this._editorInput; + } + + public get position(): Position { + return this._position; + } + + public prevent(callback: () => TPromise): void { + this.override = callback; + } + + public isPrevented(): () => TPromise { + return this.override; + } +} + export enum EncodingMode { /** diff --git a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts index a2007eb7622..d24ed6250c3 100644 --- a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts @@ -24,7 +24,7 @@ import { import { PreferencesService } from 'vs/workbench/parts/preferences/browser/preferencesService'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { PreferencesContentProvider } from 'vs/workbench/parts/preferences/common/preferencesContentProvider'; +import { PreferencesContribution } from 'vs/workbench/parts/preferences/common/preferencesContribution'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -257,7 +257,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContentProvider); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContribution); CommandsRegistry.registerCommand(OPEN_FOLDER_SETTINGS_COMMAND, function (accessor: ServicesAccessor, args?: IWorkspaceFolder) { const preferencesService = accessor.get(IPreferencesService); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 5e5597721c6..eea8fda7f35 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -8,7 +8,6 @@ import * as network from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; import { ResourceMap } from 'vs/base/common/map'; import * as labels from 'vs/base/common/labels'; import * as strings from 'vs/base/common/strings'; @@ -28,7 +27,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences'; +import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; @@ -42,15 +41,6 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; - -interface IWorkbenchSettingsConfiguration { - workbench: { - settings: { - openDefaultSettings: boolean; - } - }; -} - const emptyEditableSettingsContent = '{\n}'; export class PreferencesService extends Disposable implements IPreferencesService { @@ -186,20 +176,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic return TPromise.wrap>(null); } - openGlobalSettings(): TPromise { - return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource); + openGlobalSettings(position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource, position); } - openWorkspaceSettings(): TPromise { + openWorkspaceSettings(position?: EditorPosition): TPromise { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings")); return TPromise.as(null); } - return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource); + return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, position); } - openFolderSettings(folder: URI): TPromise { - return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder)); + openFolderSettings(folder: URI, position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder), position); } switchSettings(target: ConfigurationTarget, resource: URI): TPromise { @@ -259,17 +249,17 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI): TPromise { - const openDefaultSettings = !!this.configurationService.getConfiguration().workbench.settings.openDefaultSettings; + private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, position?: EditorPosition): TPromise { + const openDefaultSettings = !!this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value; return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource) .then(editableSettingsEditorInput => { if (openDefaultSettings) { const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget)); const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, editableSettingsEditorInput); this.lastOpenedSettingsInput = preferencesEditorInput; - return this.editorService.openEditor(preferencesEditorInput, { pinned: true }); + return this.editorService.openEditor(preferencesEditorInput, { pinned: true }, position); } - return this.editorService.openEditor(editableSettingsEditorInput, { pinned: true }); + return this.editorService.openEditor(editableSettingsEditorInput, { pinned: true }, position); }); } @@ -325,10 +315,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic return null; } const workspace = this.contextService.getWorkspace(); - return workspace.configuration || workspace.folders[0].toResource(paths.join('.vscode', 'settings.json')); + return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); case ConfigurationTarget.FOLDER: const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? folder.toResource(paths.join('.vscode', 'settings.json')) : null; + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } return null; } diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 1b7200927c9..ac93b8ec775 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -8,11 +8,12 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IEditor } from 'vs/platform/editor/common/editor'; +import { IEditor, Position } from 'vs/platform/editor/common/editor'; import { IKeybindingItemEntry } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel'; import { IRange } from 'vs/editor/common/core/range'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { join } from 'vs/base/common/paths'; export interface ISettingsGroup { id: string; @@ -76,9 +77,9 @@ export interface IPreferencesService { resolveContent(uri: URI): TPromise; createPreferencesEditorModel(uri: URI): TPromise>; - openGlobalSettings(): TPromise; - openWorkspaceSettings(): TPromise; - openFolderSettings(folder: URI): TPromise; + openGlobalSettings(position?: Position): TPromise; + openWorkspaceSettings(position?: Position): TPromise; + openFolderSettings(folder: URI, position?: Position): TPromise; switchSettings(target: ConfigurationTarget, resource: URI): TPromise; openGlobalKeybindingSettings(textual: boolean): TPromise; @@ -130,4 +131,7 @@ export const KEYBINDINGS_EDITOR_COMMAND_REMOVE = 'keybindings.editor.removeKeybi export const KEYBINDINGS_EDITOR_COMMAND_RESET = 'keybindings.editor.resetKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_COPY = 'keybindings.editor.copyKeybindingEntry'; export const KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS = 'keybindings.editor.showConflicts'; -export const KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS = 'keybindings.editor.focusKeybindings'; \ No newline at end of file +export const KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS = 'keybindings.editor.focusKeybindings'; + +export const FOLDER_SETTINGS_PATH = join('.vscode', 'settings.json'); +export const DEFAULT_SETTINGS_EDITOR_SETTING = 'workbench.settings.openDefaultSettings'; \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts b/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts deleted file mode 100644 index 33141c96052..00000000000 --- a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts +++ /dev/null @@ -1,82 +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 { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import URI from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IModel } from 'vs/editor/common/editorCommon'; -import JSONContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; -import { dispose } from 'vs/base/common/lifecycle'; - -const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); - -export class PreferencesContentProvider implements IWorkbenchContribution { - - constructor( - @IModelService private modelService: IModelService, - @ITextModelService private textModelResolverService: ITextModelService, - @IPreferencesService private preferencesService: IPreferencesService, - @IModeService private modeService: IModeService - ) { - this.start(); - } - - public getId(): string { - return 'vs.contentprovider'; - } - - private start(): void { - - this.textModelResolverService.registerTextModelContentProvider('vscode', { - provideTextContent: (uri: URI): TPromise => { - if (uri.scheme !== 'vscode') { - return null; - } - if (uri.authority === 'schemas') { - const schemaModel = this.getSchemaModel(uri); - if (schemaModel) { - return TPromise.as(schemaModel); - } - } - return this.preferencesService.resolveContent(uri) - .then(content => { - if (content !== null && content !== void 0) { - let mode = this.modeService.getOrCreateMode('json'); - const model = this.modelService.createModel(content, mode, uri); - return TPromise.as(model); - } - return null; - }); - } - }); - } - - private getSchemaModel(uri: URI): IModel { - let schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; - if (schema) { - const modelContent = JSON.stringify(schema); - const mode = this.modeService.getOrCreateMode('json'); - const model = this.modelService.createModel(modelContent, mode, uri); - - let disposables = []; - disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { - if (schemaUri === uri.toString()) { - schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; - model.setValue(JSON.stringify(schema)); - } - })); - disposables.push(model.onWillDispose(() => dispose(disposables))); - - return model; - } - return null; - } -} diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts new file mode 100644 index 00000000000..ac091d532ca --- /dev/null +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -0,0 +1,148 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IModel } from 'vs/editor/common/editorCommon'; +import JSONContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IPreferencesService, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { endsWith } from 'vs/base/common/strings'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEditorOpeningEvent } from 'vs/workbench/common/editor'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); + +export class PreferencesContribution implements IWorkbenchContribution { + private editorOpeningListener: IDisposable; + private settingsListener: IDisposable; + + constructor( + @IModelService private modelService: IModelService, + @ITextModelService private textModelResolverService: ITextModelService, + @IPreferencesService private preferencesService: IPreferencesService, + @IModeService private modeService: IModeService, + @IEditorGroupService private editorGroupService: IEditorGroupService, + @IEnvironmentService private environmentService: IEnvironmentService, + @IWorkspaceContextService private workspaceService: IWorkspaceContextService, + @IConfigurationService private configurationService: IConfigurationService + ) { + this.settingsListener = this.configurationService.onDidUpdateConfiguration(() => this.handleSettingsEditorOverride()); + this.handleSettingsEditorOverride(); + + this.start(); + } + + private handleSettingsEditorOverride(): void { + + // dispose any old listener we had + this.editorOpeningListener = dispose(this.editorOpeningListener); + + // install editor opening listener unless user has disabled this + if (!!this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value) { + this.editorOpeningListener = this.editorGroupService.onEditorOpening(e => this.onEditorOpening(e)); + } + } + + private onEditorOpening(event: IEditorOpeningEvent): void { + const resource = event.input.getResource(); + if ( + !resource || resource.scheme !== 'file' || // require a file path opening + !endsWith(resource.fsPath, 'settings.json') || // file must end in settings.json + !this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value // user has not disabled default settings editor + ) { + return; + } + + // Global User Settings File + if (resource.fsPath === this.environmentService.appSettingsPath) { + return event.prevent(() => this.preferencesService.openGlobalSettings(event.position)); + } + + // Single Folder Workspace Settings File + const state = this.workspaceService.getWorkbenchState(); + if (state === WorkbenchState.FOLDER) { + const folders = this.workspaceService.getWorkspace().folders; + if (resource.fsPath === folders[0].toResource(FOLDER_SETTINGS_PATH).fsPath) { + return event.prevent(() => this.preferencesService.openWorkspaceSettings(event.position)); + } + } + + // Multi Folder Workspace Settings File + else if (state === WorkbenchState.WORKSPACE) { + const folders = this.workspaceService.getWorkspace().folders; + for (let i = 0; i < folders.length; i++) { + if (resource.fsPath === folders[i].toResource(FOLDER_SETTINGS_PATH).fsPath) { + return event.prevent(() => this.preferencesService.openFolderSettings(folders[i].uri, event.position)); + } + } + } + } + + public getId(): string { + return 'vs.contentprovider'; + } + + private start(): void { + + this.textModelResolverService.registerTextModelContentProvider('vscode', { + provideTextContent: (uri: URI): TPromise => { + if (uri.scheme !== 'vscode') { + return null; + } + if (uri.authority === 'schemas') { + const schemaModel = this.getSchemaModel(uri); + if (schemaModel) { + return TPromise.as(schemaModel); + } + } + return this.preferencesService.resolveContent(uri) + .then(content => { + if (content !== null && content !== void 0) { + let mode = this.modeService.getOrCreateMode('json'); + const model = this.modelService.createModel(content, mode, uri); + return TPromise.as(model); + } + return null; + }); + } + }); + } + + private getSchemaModel(uri: URI): IModel { + let schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + if (schema) { + const modelContent = JSON.stringify(schema); + const mode = this.modeService.getOrCreateMode('json'); + const model = this.modelService.createModel(modelContent, mode, uri); + + let disposables = []; + disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { + if (schemaUri === uri.toString()) { + schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + model.setValue(JSON.stringify(schema)); + } + })); + disposables.push(model.onWillDispose(() => dispose(disposables))); + + return model; + } + return null; + } + + public dispose(): void { + this.editorOpeningListener = dispose(this.editorOpeningListener); + this.settingsListener = dispose(this.settingsListener); + } +} diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index df0ec9e78cb..2cabe8935ca 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -9,7 +9,6 @@ import URI from 'vs/base/common/uri'; import network = require('vs/base/common/network'); import { Registry } from 'vs/platform/registry/common/platform'; import { basename, dirname } from 'vs/base/common/paths'; -import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, TextEditorOptions, Extensions as EditorExtensions, SideBySideEditorInput, IFileEditorInput, IFileInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; @@ -26,14 +25,14 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IFileService } from 'vs/platform/files/common/files'; export interface IEditorPart { - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; - openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; - replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; + openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; + replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; closeEditor(position: Position, input: IEditorInput): TPromise; closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise; closeAllEditors(except?: Position): TPromise; - getActiveEditor(): BaseEditor; + getActiveEditor(): IEditor; getVisibleEditors(): IEditor[]; getActiveEditorInput(): IEditorInput; } @@ -298,8 +297,8 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { } export interface IEditorOpenHandler { - (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; + (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; } export interface IEditorCloseHandler { @@ -349,7 +348,7 @@ export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { return handleOpen.then(editor => { if (editor) { - return TPromise.as(editor); + return TPromise.as(editor); } return super.doOpenEditor(input, options, arg3); diff --git a/src/vs/workbench/services/group/common/groupService.ts b/src/vs/workbench/services/group/common/groupService.ts index 12820ea98ea..1cdeceef1ff 100644 --- a/src/vs/workbench/services/group/common/groupService.ts +++ b/src/vs/workbench/services/group/common/groupService.ts @@ -7,7 +7,7 @@ import { createDecorator, ServiceIdentifier, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Position, IEditorInput } from 'vs/platform/editor/common/editor'; -import { IEditorStacksModel, IEditorGroup } from 'vs/workbench/common/editor'; +import { IEditorStacksModel, IEditorGroup, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import Event from 'vs/base/common/event'; export enum GroupArrangement { @@ -45,6 +45,11 @@ export interface IEditorGroupService { */ onEditorsChanged: Event; + /** + * Emitted when an editor is opening. Allows to prevent/replace the opening via the event method. + */ + onEditorOpening: Event; + /** * Emitted when opening an editor fails. */ diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 3267637c435..90b96f490d5 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -765,7 +765,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.contextService.getWorkspace().folders.some(folder => { return paths.isEqualOrParent(this.resource.fsPath, path.join(folder.uri.fsPath, '.vscode')); }); - } private doTouch(): TPromise { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 18d72e4d754..b07ab0b7f95 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -15,7 +15,7 @@ import URI from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { StorageService, InMemoryLocalStorage } from 'vs/platform/storage/common/storageService'; -import { IEditorGroup, ConfirmResult } from 'vs/workbench/common/editor'; +import { IEditorGroup, ConfirmResult, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import Event, { Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -453,6 +453,7 @@ export class TestEditorGroupService implements IEditorGroupService { private stacksModel: EditorStacksModel; private _onEditorsChanged: Emitter; + private _onEditorOpening: Emitter; private _onEditorOpenFail: Emitter; private _onEditorsMoved: Emitter; private _onGroupOrientationChanged: Emitter; @@ -461,6 +462,7 @@ export class TestEditorGroupService implements IEditorGroupService { constructor(callback?: (method: string) => void) { this._onEditorsMoved = new Emitter(); this._onEditorsChanged = new Emitter(); + this._onEditorOpening = new Emitter(); this._onGroupOrientationChanged = new Emitter(); this._onEditorOpenFail = new Emitter(); this._onTabOptionsChanged = new Emitter(); @@ -487,6 +489,10 @@ export class TestEditorGroupService implements IEditorGroupService { return this._onEditorsChanged.event; } + public get onEditorOpening(): Event { + return this._onEditorOpening.event; + } + public get onEditorOpenFail(): Event { return this._onEditorOpenFail.event; } From 90ca93fdbe6f850dcd692df9cf694e913f6764a8 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 13 Oct 2017 07:46:56 -0700 Subject: [PATCH 202/303] More tests (#35236) --- .../services/search/test/node/search.test.ts | 47 +++++++++++++++++++ .../search/test/node/searchService.test.ts | 46 +++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index f7fbebd6835..c2ce634c8d1 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -220,6 +220,53 @@ suite('FileSearchEngine', () => { }); }); + test('Files: multiroot with includePattern and maxResults', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: MULTIROOT_QUERIES, + maxResults: 1, + includePattern: { + '*.txt': true, + '*.js': true + }, + useRipgrep: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + + test('Files: multiroot with includePattern and exists', function (done: () => void) { + let engine = new FileSearchEngine({ + folderQueries: MULTIROOT_QUERIES, + exists: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + useRipgrep: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + test('Files: NPE (CamelCase)', function (done: () => void) { let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, diff --git a/src/vs/workbench/services/search/test/node/searchService.test.ts b/src/vs/workbench/services/search/test/node/searchService.test.ts index 36935227c65..7fd40591eef 100644 --- a/src/vs/workbench/services/search/test/node/searchService.test.ts +++ b/src/vs/workbench/services/search/test/node/searchService.test.ts @@ -7,9 +7,10 @@ import * as assert from 'assert'; import { normalize } from 'path'; +import path = require('path'); import { IProgress, IUncachedSearchStats } from 'vs/platform/search/common/search'; -import { ISearchEngine, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchComplete } from 'vs/workbench/services/search/node/search'; +import { ISearchEngine, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchComplete, IFolderSearch } from 'vs/workbench/services/search/node/search'; import { SearchService as RawSearchService } from 'vs/workbench/services/search/node/rawSearchService'; import { DiskSearch } from 'vs/workbench/services/search/node/searchService'; @@ -17,6 +18,12 @@ const TEST_FOLDER_QUERIES = [ { folder: normalize('/some/where') } ]; +const TEST_FIXTURES = path.normalize(require.toUrl('./fixtures')); +const MULTIROOT_QUERIES: IFolderSearch[] = [ + { folder: path.join(TEST_FIXTURES, 'examples') }, + { folder: path.join(TEST_FIXTURES, 'more') } +]; + const stats: IUncachedSearchStats = { fromCache: false, resultCount: 4, @@ -143,6 +150,43 @@ suite('SearchService', () => { }); }); + test('Multi-root with include pattern and maxResults', function () { + const service = new RawSearchService(); + + const query: IRawSearch = { + folderQueries: MULTIROOT_QUERIES, + maxResults: 1, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + return DiskSearch.collectResults(service.fileSearch(query)) + .then(result => { + assert.strictEqual(result.results.length, 1, 'Result'); + }); + }); + + test('Multi-root with include pattern and exists', function () { + const service = new RawSearchService(); + + const query: IRawSearch = { + folderQueries: MULTIROOT_QUERIES, + exists: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + return DiskSearch.collectResults(service.fileSearch(query)) + .then(result => { + assert.strictEqual(result.results.length, 0, 'Result'); + assert.ok(result.limitHit); + }); + }); + test('Sorted results', function () { const paths = ['bab', 'bbc', 'abb']; const matches: IRawFileMatch[] = paths.map(relativePath => ({ From b86c935551664d84b2b31aa1aeb885c3c689fabe Mon Sep 17 00:00:00 2001 From: Nick Snyder Date: Fri, 13 Oct 2017 07:58:08 -0700 Subject: [PATCH 203/303] guard against empty tooltip fixes JS error "Cannot read property 'charAt' of undefined" --- .../workbench/parts/scm/electron-browser/scmFileDecorations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index dea57c82381..97c1c66a212 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -62,7 +62,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { provideDecorations(uri: URI): IResourceDecorationData { const resource = this._data.get(uri.toString()); - if (!resource || !resource.decorations.color) { + if (!resource || !resource.decorations.color || !resource.decorations.tooltip) { return undefined; } return { From d17e3ddbc364e43fba80f526b0a3d140e0863bd9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 13 Oct 2017 17:20:15 +0200 Subject: [PATCH 204/303] Write tests for ConfigurationModel --- .../configuration/common/configuration.ts | 24 ++ .../common/configurationModels.ts | 51 ++- .../test/common/configuration.model.test.ts | 87 ---- .../test/common/configuration.test.ts | 89 +++- .../test/common/configurationModel.test.ts | 148 ------- .../test/common/configurationModels.test.ts | 399 ++++++++++++++++++ .../node/configurationService.ts | 4 +- 7 files changed, 546 insertions(+), 256 deletions(-) delete mode 100644 src/vs/platform/configuration/test/common/configuration.model.test.ts delete mode 100644 src/vs/platform/configuration/test/common/configurationModel.test.ts create mode 100644 src/vs/platform/configuration/test/common/configurationModels.test.ts diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index a2132efea12..8a1daa65929 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -151,6 +151,30 @@ export function addToValueTree(settingsTreeRoot: any, key: string, value: any, c } } +export function removeFromValueTree(valueTree: any, key: string): void { + const segments = key.split('.'); + doRemoveFromValueTree(valueTree, segments); +} + +function doRemoveFromValueTree(valueTree: any, segments: string[]): void { + const first = segments.shift(); + if (segments.length === 0) { + // Reached last segment + delete valueTree[first]; + return; + } + + if (Object.keys(valueTree).indexOf(first) !== -1) { + const value = valueTree[first]; + if (typeof value === 'object' && !Array.isArray(value)) { + doRemoveFromValueTree(value, segments); + if (Object.keys(value).length === 0) { + delete valueTree[first]; + } + } + } +} + /** * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting) */ diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 7e5751fcdd4..7acaca42472 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; export class ConfigurationModel implements IConfiguraionModel { @@ -36,9 +36,13 @@ export class ConfigurationModel implements IConfiguraionModel { } public setValue(key: string, value: any) { + this.addKey(key); addToValueTree(this._contents, key, value, e => { throw new Error(e); }); - if (this._keys.indexOf(key) === -1) { - this._keys.push(key); + } + + public removeValue(key: string): void { + if (this.removeKey(key)) { + removeFromValueTree(this._contents, key); } } @@ -51,33 +55,25 @@ export class ConfigurationModel implements IConfiguraionModel { addToValueTree(override.contents, key, value, e => { throw new Error(e); }); } - public removeValue(key: string) { - // Remove key from the value tree - const index = this._keys.indexOf(key); - if (index !== -1) { - this._keys.splice(index, 1); - } - } - public override(identifier: string): ConfigurationModel { const overrideContents = this.getContentsForOverrideIdentifer(identifier); - if (!overrideContents) { - // If there are no overrides, use base contents + if (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) { + // If there are no valid overrides, use base contents return new ConfigurationModel(this._contents); } let contents = {}; - for (const key of Object.keys(this._contents)) { + for (const key of arrays.distinct([...Object.keys(this._contents), ...Object.keys(overrideContents)])) { let contentsForKey = this._contents[key]; let overrideContentsForKey = overrideContents[key]; - // If there are override contents for the key clone and merge otherwise use base contents + // If there are override contents for the key, clone and merge otherwise use base contents if (overrideContentsForKey) { - // Clone and merge only if base contents is of type object otherwise just override - if (typeof contentsForKey === 'object') { - contentsForKey = objects.clone(contents[key]); + // Clone and merge only if base contents and override contents are of type object otherwise just override + if (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') { + contentsForKey = objects.clone(contentsForKey); merge(contentsForKey, overrideContentsForKey, true); } else { contentsForKey = overrideContentsForKey; @@ -118,6 +114,25 @@ export class ConfigurationModel implements IConfiguraionModel { } return null; } + + private addKey(key: string): void { + let index = this._keys.length; + for (let i = 0; i < index; i++) { + if (key.indexOf(this._keys[i]) === 0) { + index = i; + } + } + this._keys.splice(index, 1, key); + } + + private removeKey(key: string): boolean { + let index = this._keys.indexOf(key); + if (index !== -1) { + this._keys.splice(index, 1); + return true; + } + return false; + } } export class DefaultConfigurationModel extends ConfigurationModel { diff --git a/src/vs/platform/configuration/test/common/configuration.model.test.ts b/src/vs/platform/configuration/test/common/configuration.model.test.ts deleted file mode 100644 index ea0266bd500..00000000000 --- a/src/vs/platform/configuration/test/common/configuration.model.test.ts +++ /dev/null @@ -1,87 +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 { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; - -suite('Configuration', () => { - - suiteSetup(() => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': true, - 'overridable': true - } - } - }); - }); - - test('simple merge', () => { - let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); - let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); - }); - - test('recursive merge', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); - }); - - test('simple merge overrides', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': 2 } }]); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'b': 2 } }]); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); - assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': 2, 'b': 2 } }]); - }); - - test('recursive merge overrides', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'e': 2 } } }]); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); - assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': { 'd': 1, 'e': 2 } } }]); - }); - - test('merge ignore keys', () => { - let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); - let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); - let result = base.merge(add); - assert.deepEqual(result.keys, []); - }); - - test('Test contents while getting an existing property', () => { - let testObject = new ConfigurationModel({ 'a': 1 }); - assert.deepEqual(testObject.getSectionContents('a'), 1); - - testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); - assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); - }); - - test('Test contents are undefined for non existing properties', () => { - const testObject = new ConfigurationModel({ awesome: true }); - - assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); - }); - - test('Test override gives all content merged with overrides', () => { - const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); - - assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1 }); - }); -}); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/configuration.test.ts b/src/vs/platform/configuration/test/common/configuration.test.ts index 11024298132..456df853e01 100644 --- a/src/vs/platform/configuration/test/common/configuration.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { merge } from 'vs/platform/configuration/common/configuration'; +import { merge, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; suite('Configuration', () => { @@ -18,5 +18,92 @@ suite('Configuration', () => { assert.deepEqual(base, { 'a': 1, 'b': 2, 'c': 4 }); }); + test('removeFromValueTree: remove a non existing key', () => { + let target = { 'a': { 'b': 2 } }; + + removeFromValueTree(target, 'c'); + + assert.deepEqual(target, { 'a': { 'b': 2 } }); + }); + + test('removeFromValueTree: remove a multi segmented key from an object that has only sub sections of the key', () => { + let target = { 'a': { 'b': 2 } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'b': 2 } }); + }); + + test('removeFromValueTree: remove a single segemented key', () => { + let target = { 'a': 1 }; + + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a single segemented key when its value is undefined', () => { + let target = { 'a': void 0 }; + + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a multi segemented key when its value is undefined', () => { + let target = { 'a': { 'b': 1 } }; + + removeFromValueTree(target, 'a.b'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a multi segemented key when its value is array', () => { + let target = { 'a': { 'b': [1] } }; + + removeFromValueTree(target, 'a.b'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a multi segemented key first segment value is array', () => { + let target = { 'a': [1] }; + + removeFromValueTree(target, 'a.0'); + + assert.deepEqual(target, { 'a': [1] }); + }); + + test('removeFromValueTree: remove when key is the first segmenet', () => { + let target = { 'a': { 'b': 1 } }; + + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a multi segemented key when the first node has more values', () => { + let target = { 'a': { 'b': { 'c': 1 }, 'd': 1 } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'd': 1 } }); + }); + + test('removeFromValueTree: remove a multi segemented key when in between node has more values', () => { + let target = { 'a': { 'b': { 'c': { 'd': 1 }, 'd': 1 } } }; + + removeFromValueTree(target, 'a.b.c.d'); + + assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } }); + }); + + test('removeFromValueTree: remove a multi segemented key when the last but one node has more values', () => { + let target = { 'a': { 'b': { 'c': 1, 'd': 1 } } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } }); + }); }); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/configurationModel.test.ts b/src/vs/platform/configuration/test/common/configurationModel.test.ts deleted file mode 100644 index b79b8cbadcf..00000000000 --- a/src/vs/platform/configuration/test/common/configurationModel.test.ts +++ /dev/null @@ -1,148 +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 { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; - -suite('Configuration', () => { - - suiteSetup(() => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': true, - 'overridable': true - } - } - }); - }); - - test('simple merge using models', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - let add = new CustomConfigurationModel(JSON.stringify({ 'a': 3, 'c': 4 })); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); - }); - - test('simple merge with an undefined contents', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - let add = new CustomConfigurationModel(null); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); - - base = new CustomConfigurationModel(null); - add = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); - - base = new CustomConfigurationModel(null); - add = new CustomConfigurationModel(null); - result = base.merge(add); - assert.deepEqual(result.contents, {}); - }); - - test('Recursive merge using config models', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); - let add = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 2 } })); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); - }); - - test('Test contents while getting an existing property', () => { - let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 })); - assert.deepEqual(testObject.getSectionContents('a'), 1); - - testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); - assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); - }); - - test('Test contents are undefined for non existing properties', () => { - const testObject = new CustomConfigurationModel(JSON.stringify({ - awesome: true - })); - - assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); - }); - - test('Test contents are undefined for undefined config', () => { - const testObject = new CustomConfigurationModel(null); - - assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); - }); - - test('Test configWithOverrides gives all content merged with overrides', () => { - const testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } })); - - assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } }); - }); - - test('Test configWithOverrides gives empty contents', () => { - const testObject = new CustomConfigurationModel(null); - - assert.deepEqual(testObject.override('b').contents, {}); - }); - - test('Test update with empty data', () => { - const testObject = new CustomConfigurationModel(); - testObject.update(''); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - - testObject.update(null); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - - testObject.update(undefined); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - }); - - test('Test registering the same property again', () => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': false, - } - } - }); - assert.equal(true, new DefaultConfigurationModel().getSectionContents('a')); - }); - - test('Test registering the language property', () => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': '[a]', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - '[a]': { - 'description': 'a', - 'type': 'boolean', - 'default': false, - } - } - }); - assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]')); - }); - -}); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts new file mode 100644 index 00000000000..b4cc2a1d476 --- /dev/null +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -0,0 +1,399 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ConfigurationModel, CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; + +suite('ConfigurationModel', () => { + + test('setValue for a key that has no sections and not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); + + testObject.setValue('f', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f']); + }); + + test('setValue for a key that has no sections and defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('f', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'f': 3 }); + assert.deepEqual(testObject.keys, ['a.b', 'f']); + }); + + test('setValue for a key that has sections and not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('b.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'b': { 'c': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f', 'b.c']); + }); + + test('setValue for a key that has sections and defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'b': { 'c': 1 }, 'f': 1 }, ['a.b', 'b.c', 'f']); + + testObject.setValue('b.c', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'b': { 'c': 3 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'b.c', 'f']); + }); + + test('setValue for a key that has sections and sub section not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('a.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1, 'c': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f', 'a.c']); + }); + + test('setValue for a key that has sections and sub section defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1, 'c': 1 }, 'f': 1 }, ['a.b', 'a.c', 'f']); + + testObject.setValue('a.c', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1, 'c': 3 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'a.c', 'f']); + }); + + test('setValue for a key that has sections and last section is added', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': {} }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('a.b.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': { 'c': 1 } }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b.c', 'f']); + }); + + test('removeValue: remove a non existing key', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 2 } }, ['a.b']); + + testObject.removeValue('a.b.c'); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(testObject.keys, ['a.b']); + }); + + test('removeValue: remove a single segemented key', () => { + let testObject = new ConfigurationModel({ 'a': 1 }, ['a']); + + testObject.removeValue('a'); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('removeValue: remove a multi segemented key', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); + + testObject.removeValue('a.b'); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('setValueInOverrides adds to overrides if does not exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a']); + + testObject.setValueInOverrides('or', 'a', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 }); + assert.deepEqual(testObject.override('or').contents, { 'a': 2, 'b': 1 }); + }); + + test('setValueInOverrides adds to overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': 2 } }]); + + testObject.setValueInOverrides('or', 'a', 3); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 3 }); + assert.deepEqual(testObject.override('or').contents, { 'a': 3, 'b': 1 }); + }); + + test('setValueInOverrides adds a nested key to overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': { 'c': 1 } } }]); + + testObject.setValueInOverrides('or', 'a.c', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': { 'c': 2 } }); + assert.deepEqual(testObject.override('or').contents, { 'a': { 'c': 2 }, 'b': 1 }); + }); + + test('setValueInOverrides adds new overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or1'], contents: { 'a': 2 } }]); + + testObject.setValueInOverrides('or2', 'b', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 }); + assert.deepEqual(testObject.overrides[1].contents, { 'b': 2 }); + assert.deepEqual(testObject.override('or1').contents, { 'a': 2, 'b': 1 }); + assert.deepEqual(testObject.override('or2').contents, { 'a': 1, 'b': 2 }); + }); + + test('get overriding configuration model for an existing identifier', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1 }); + }); + + test('get overriding configuration model for an identifier that does not exist', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + + assert.deepEqual(testObject.override('xyz').contents, { 'a': { 'b': 1 }, 'f': 1 }); + }); + + test('get overriding configuration when one of the keys does not exist in base', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'g': 1 } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1, 'g': 1 }); + }); + + test('get overriding configuration when one of the key in base is not of object type', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'f': { 'g': 1 } } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': { 'g': 1 } }); + }); + + test('get overriding configuration when one of the key in overriding contents is not of object type', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'f': 1 } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1 }); + }); + + test('get overriding configuration if the value of overriding identifier is not object', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: 'abc' }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1 }, 'f': { 'g': 1 } }); + }); + + test('get overriding configuration if the value of overriding identifier is an empty object', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: {} }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1 }, 'f': { 'g': 1 } }); + }); + + test('simple merge', () => { + let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); + let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); + }); + + test('recursive merge', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 } }); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(result.getSectionContents('a'), { 'b': 2 }); + }); + + test('simple merge overrides', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 } }, [], [{ identifiers: ['c'], contents: { 'a': 2 } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'b': 2 } }]); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': 2, 'b': 2 } }]); + assert.deepEqual(result.override('c').contents, { 'a': 2, 'b': 2 }); + }); + + test('recursive merge overrides', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, [], [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, [], [{ identifiers: ['c'], contents: { 'a': { 'e': 2 } } }]); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 }, 'f': 1 }); + assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': { 'd': 1, 'e': 2 } } }]); + assert.deepEqual(result.override('c').contents, { 'a': { 'b': 2, 'd': 1, 'e': 2 }, 'f': 1 }); + }); + + test('merge ignore keys', () => { + let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); + let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); + let result = base.merge(add); + assert.deepEqual(result.keys, []); + }); + + test('Test contents while getting an existing property', () => { + let testObject = new ConfigurationModel({ 'a': 1 }); + assert.deepEqual(testObject.getSectionContents('a'), 1); + + testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); + }); + + test('Test contents are undefined for non existing properties', () => { + const testObject = new ConfigurationModel({ awesome: true }); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test override gives all content merged with overrides', () => { + const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); + + assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1 }); + }); +}); + +suite('CustomConfigurationModel', () => { + + suiteSetup(() => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'a', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + 'a': { + 'description': 'a', + 'type': 'boolean', + 'default': true, + 'overridable': true + } + } + }); + }); + + test('simple merge using models', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + let add = new CustomConfigurationModel(JSON.stringify({ 'a': 3, 'c': 4 })); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); + }); + + test('simple merge with an undefined contents', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + let add = new CustomConfigurationModel(null); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); + + base = new CustomConfigurationModel(null); + add = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); + + base = new CustomConfigurationModel(null); + add = new CustomConfigurationModel(null); + result = base.merge(add); + assert.deepEqual(result.contents, {}); + }); + + test('Recursive merge using config models', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); + let add = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 2 } })); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + }); + + test('Test contents while getting an existing property', () => { + let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 })); + assert.deepEqual(testObject.getSectionContents('a'), 1); + + testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); + }); + + test('Test contents are undefined for non existing properties', () => { + const testObject = new CustomConfigurationModel(JSON.stringify({ + awesome: true + })); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test contents are undefined for undefined config', () => { + const testObject = new CustomConfigurationModel(null); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test configWithOverrides gives all content merged with overrides', () => { + const testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } })); + + assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } }); + }); + + test('Test configWithOverrides gives empty contents', () => { + const testObject = new CustomConfigurationModel(null); + + assert.deepEqual(testObject.override('b').contents, {}); + }); + + test('Test update with empty data', () => { + const testObject = new CustomConfigurationModel(); + testObject.update(''); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + + testObject.update(null); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + + testObject.update(undefined); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('Test registering the same property again', () => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'a', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + 'a': { + 'description': 'a', + 'type': 'boolean', + 'default': false, + } + } + }); + assert.equal(true, new DefaultConfigurationModel().getSectionContents('a')); + }); + + test('Test registering the language property', () => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': '[a]', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + '[a]': { + 'description': 'a', + 'type': 'boolean', + 'default': false, + } + } + }); + assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]')); + }); + +}); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 3cccaa1e6b2..f2ed3e415dc 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -322,8 +322,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat const folderConfigurationModels = new StrictResourceMap(); folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration)); - this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: @Sandy Avoid passing null - // TODO: compare with old values?? + this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: Sandy Avoid passing null + // TODO Sandy: compare with old values?? const keys = this._configuration.keys(); this._onDidUpdateConfiguration.fire(new AllKeysConfigurationChangeEvent([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); From ed40c15f495215437e740b9c698b076c42563de9 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2017 17:38:21 +0200 Subject: [PATCH 205/303] getCompositeSize dynamicaly --- src/vs/workbench/browser/compositeBar.ts | 14 +++++++++++--- .../browser/parts/activitybar/activitybarPart.ts | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/compositeBar.ts b/src/vs/workbench/browser/compositeBar.ts index 0fc8b7b53ee..c8ab4d6a87a 100644 --- a/src/vs/workbench/browser/compositeBar.ts +++ b/src/vs/workbench/browser/compositeBar.ts @@ -35,6 +35,7 @@ export interface ICompositeBarOptions { getActivityAction: (compositeId: string) => ActivityAction; getCompositePinnedAction: (compositeId: string) => Action; getOpenCompositeAction: (compositeId: string) => Action; + getCompositeSize: (compositeId: string) => number; } export class CompositeBar { @@ -204,7 +205,7 @@ export class CompositeBar { // Always show the active composite even if it is marked to be hidden if (this.activeCompositeId && !compositesToShow.some(id => id === this.activeCompositeId)) { this.activeUnpinnedCompositeId = this.activeCompositeId; - compositesToShow.push(this.activeUnpinnedCompositeId); + compositesToShow = compositesToShow.concat(this.activeUnpinnedCompositeId); } else { this.activeUnpinnedCompositeId = void 0; } @@ -212,8 +213,15 @@ export class CompositeBar { // Ensure we are not showing more composites than we have height for let overflows = false; if (this.dimension) { - // TODO@Isidor change this maxVisible computation to be dynamic - const maxVisible = Math.floor(this.dimension.height / 50); + let maxVisible = compositesToShow.length; + let size = 0; + const limit = this.options.orientation === ActionsOrientation.VERTICAL ? this.dimension.height : this.dimension.width; + for (let i = 0; i < compositesToShow.length && size <= limit; i++) { + size += this.options.getCompositeSize(compositesToShow[i]); + if (size > limit) { + maxVisible = i; + } + } overflows = compositesToShow.length > maxVisible; if (overflows) { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 035d1ad57b9..2130ea88179 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -63,6 +63,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { storageId: ActivitybarPart.PINNED_VIEWLETS, orientation: ActionsOrientation.VERTICAL, composites: this.viewletService.getViewlets(), + getCompositeSize: (compositeId: string) => ActivitybarPart.ACTIVITY_ACTION_HEIGHT, getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)), getCompositePinnedAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletPinnedAction, this.viewletService.getViewlet(compositeId)), getOpenCompositeAction: (compositeId: string) => this.instantiationService.createInstance(OpenViewletAction, this.viewletService.getViewlet(compositeId)) From b5a874488f6ed87b00029c9d3e790b05d55f7a0d Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2017 17:42:14 +0200 Subject: [PATCH 206/303] remove todo comments --- src/vs/workbench/browser/compositeBar.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/workbench/browser/compositeBar.ts b/src/vs/workbench/browser/compositeBar.ts index c8ab4d6a87a..5320747811c 100644 --- a/src/vs/workbench/browser/compositeBar.ts +++ b/src/vs/workbench/browser/compositeBar.ts @@ -23,10 +23,6 @@ import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/a import Event, { Emitter } from 'vs/base/common/event'; import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem } from 'vs/workbench/browser/compositeBarActions'; -// first goal make the activity bar depend on the composite bar and everything works as before -// after that think about how to plug this into the panel part and the overflow nicely wokring (composite bar in panel will need overflow: hidden) -// on the action bar offsetWidth = gets the width of every child (on the first layout need to check if it is still in the constraints) - export interface ICompositeBarOptions { label: 'icon' | 'name'; storageId: string; From 8f1b989c36b5448e12c9f68378fc44de6e5802b1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2017 17:43:00 +0200 Subject: [PATCH 207/303] move editor service into common --- .../browser/parts/editor/editorPart.ts | 2 +- .../browser/parts/editor/tabsTitleControl.ts | 3 +- .../browser/parts/editor/textDiffEditor.ts | 3 +- .../workbench/electron-browser/workbench.ts | 3 +- .../parts/files/browser/explorerViewlet.ts | 3 +- .../services/editor/browser/editorService.ts | 365 ------------------ .../services/editor/common/editorService.ts | 359 ++++++++++++++++- .../editor/test/browser/editorService.test.ts | 2 +- 8 files changed, 363 insertions(+), 377 deletions(-) delete mode 100644 src/vs/workbench/services/editor/browser/editorService.ts diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 25fcf62c102..15ce8ce3eb0 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -26,7 +26,7 @@ import { EditorGroupsControl, Rochade, IEditorGroupsControl, ProgressState } fro import { WorkbenchProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { IEditorGroupService, GroupOrientation, GroupArrangement, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IEditorPart } from 'vs/workbench/services/editor/browser/editorService'; +import { IEditorPart } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { Position, POSITIONS, Direction, IEditor } from 'vs/platform/editor/common/editor'; import { IStorageService } from 'vs/platform/storage/common/storage'; diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 3a12c2226cf..e598d3383e3 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -20,7 +20,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ResourceLabel } from 'vs/workbench/browser/labels'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -37,7 +37,6 @@ import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElemen import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { extractResources } from 'vs/base/browser/dnd'; import { getOrSet } from 'vs/base/common/map'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER } from 'vs/workbench/common/theme'; diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 7143b5a9fa2..641e62414b7 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -22,14 +22,13 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IModeService } from 'vs/editor/common/services/modeService'; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index f6bdc8d057f..c88d5d05d54 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -39,7 +39,6 @@ import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbe import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { getServices } from 'vs/platform/instantiation/common/extensions'; -import { WorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -66,7 +65,7 @@ import { ConfigurationResolverService } from 'vs/workbench/services/configuratio import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService'; -import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; diff --git a/src/vs/workbench/parts/files/browser/explorerViewlet.ts b/src/vs/workbench/parts/files/browser/explorerViewlet.ts index 44cac3254e1..74da9b16cd4 100644 --- a/src/vs/workbench/parts/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/parts/files/browser/explorerViewlet.ts @@ -24,11 +24,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IThemeService } from 'vs/platform/theme/common/themeService'; diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts deleted file mode 100644 index 2cabe8935ca..00000000000 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ /dev/null @@ -1,365 +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 { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; -import network = require('vs/base/common/network'); -import { Registry } from 'vs/platform/registry/common/platform'; -import { basename, dirname } from 'vs/base/common/paths'; -import { EditorInput, EditorOptions, TextEditorOptions, Extensions as EditorExtensions, SideBySideEditorInput, IFileEditorInput, IFileInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IEditor, IResourceInput, IResourceDiffInput, IResourceSideBySideInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import nls = require('vs/nls'); -import { getPathLabel } from 'vs/base/common/labels'; -import { ResourceMap } from 'vs/base/common/map'; -import { once } from 'vs/base/common/event'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IFileService } from 'vs/platform/files/common/files'; - -export interface IEditorPart { - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; - openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; - replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; - closeEditor(position: Position, input: IEditorInput): TPromise; - closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise; - closeAllEditors(except?: Position): TPromise; - getActiveEditor(): IEditor; - getVisibleEditors(): IEditor[]; - getActiveEditorInput(): IEditorInput; -} - -type ICachedEditorInput = ResourceEditorInput | IFileEditorInput; - -export class WorkbenchEditorService implements IWorkbenchEditorService { - - public _serviceBrand: any; - - private static CACHE: ResourceMap = new ResourceMap(); - - private editorPart: IEditorPart | IWorkbenchEditorService; - private fileInputFactory: IFileInputFactory; - - constructor( - editorPart: IEditorPart | IWorkbenchEditorService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IInstantiationService private instantiationService: IInstantiationService, - @IEnvironmentService private environmentService: IEnvironmentService, - @IFileService private fileService: IFileService - ) { - this.editorPart = editorPart; - this.fileInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileInputFactory(); - } - - public getActiveEditor(): IEditor { - return this.editorPart.getActiveEditor(); - } - - public getActiveEditorInput(): IEditorInput { - return this.editorPart.getActiveEditorInput(); - } - - public getVisibleEditors(): IEditor[] { - return this.editorPart.getVisibleEditors(); - } - - public isVisible(input: IEditorInput, includeSideBySide: boolean): boolean { - if (!input) { - return false; - } - - return this.getVisibleEditors().some(editor => { - if (!editor.input) { - return false; - } - - if (input.matches(editor.input)) { - return true; - } - - if (includeSideBySide && editor.input instanceof SideBySideEditorInput) { - const sideBySideInput = editor.input; - return input.matches(sideBySideInput.master) || input.matches(sideBySideInput.details); - } - - return false; - }); - } - - public openEditor(input: IEditorInput, options?: IEditorOptions, sideBySide?: boolean): TPromise; - public openEditor(input: IEditorInput, options?: IEditorOptions, position?: Position): TPromise; - public openEditor(input: IResourceInputType, position?: Position): TPromise; - public openEditor(input: IResourceInputType, sideBySide?: boolean): TPromise; - public openEditor(input: any, arg2?: any, arg3?: any): TPromise { - if (!input) { - return TPromise.as(null); - } - - // Workbench Input Support - if (input instanceof EditorInput) { - return this.doOpenEditor(input, this.toOptions(arg2), arg3); - } - - // Support opening foreign resources (such as a http link that points outside of the workbench) - const resourceInput = input; - if (resourceInput.resource instanceof URI) { - const schema = resourceInput.resource.scheme; - if (schema === network.Schemas.http || schema === network.Schemas.https) { - window.open(resourceInput.resource.toString(true)); - - return TPromise.as(null); - } - } - - // Untyped Text Editor Support (required for code that uses this service below workbench level) - const textInput = input; - const typedInput = this.createInput(textInput); - if (typedInput) { - return this.doOpenEditor(typedInput, TextEditorOptions.from(textInput), arg2); - } - - return TPromise.as(null); - } - - private toOptions(options?: IEditorOptions | EditorOptions): EditorOptions { - if (!options || options instanceof EditorOptions) { - return options as EditorOptions; - } - - const textOptions: ITextEditorOptions = options; - if (!!textOptions.selection) { - return TextEditorOptions.create(options); - } - - return EditorOptions.create(options); - } - - /** - * Allow subclasses to implement their own behavior for opening editor (see below). - */ - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { - return this.editorPart.openEditor(input, options, arg3); - } - - public openEditors(editors: { input: IResourceInputType, position: Position }[]): TPromise; - public openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions }[]): TPromise; - public openEditors(editors: any[]): TPromise { - const inputs = editors.map(editor => this.createInput(editor.input)); - const typedInputs: { input: IEditorInput, position: Position, options?: EditorOptions }[] = inputs.map((input, index) => { - const options = editors[index].input instanceof EditorInput ? this.toOptions(editors[index].options) : TextEditorOptions.from(editors[index].input); - - return { - input, - options, - position: editors[index].position - }; - }); - - return this.editorPart.openEditors(typedInputs); - } - - public replaceEditors(editors: { toReplace: IResourceInputType, replaceWith: IResourceInputType }[], position?: Position): TPromise; - public replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions }[], position?: Position): TPromise; - public replaceEditors(editors: any[], position?: Position): TPromise { - const toReplaceInputs = editors.map(editor => this.createInput(editor.toReplace)); - const replaceWithInputs = editors.map(editor => this.createInput(editor.replaceWith)); - const typedReplacements: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: EditorOptions }[] = editors.map((editor, index) => { - const options = editor.toReplace instanceof EditorInput ? this.toOptions(editor.options) : TextEditorOptions.from(editor.replaceWith); - - return { - toReplace: toReplaceInputs[index], - replaceWith: replaceWithInputs[index], - options - }; - }); - - return this.editorPart.replaceEditors(typedReplacements, position); - } - - public closeEditor(position: Position, input: IEditorInput): TPromise { - return this.doCloseEditor(position, input); - } - - protected doCloseEditor(position: Position, input: IEditorInput): TPromise { - return this.editorPart.closeEditor(position, input); - } - - public closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise { - return this.editorPart.closeEditors(position, filter); - } - - public closeAllEditors(except?: Position): TPromise { - return this.editorPart.closeAllEditors(except); - } - - public createInput(input: IEditorInput): EditorInput; - public createInput(input: IResourceInputType): EditorInput; - public createInput(input: any): IEditorInput { - - // Workbench Input Support - if (input instanceof EditorInput) { - return input; - } - - // Side by Side Support - const resourceSideBySideInput = input; - if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { - const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource }); - const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource }); - - return new SideBySideEditorInput(resourceSideBySideInput.label || masterInput.getName(), typeof resourceSideBySideInput.description === 'string' ? resourceSideBySideInput.description : masterInput.getDescription(), detailInput, masterInput); - } - - // Diff Editor Support - const resourceDiffInput = input; - if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { - const leftInput = this.createInput({ resource: resourceDiffInput.leftResource }); - const rightInput = this.createInput({ resource: resourceDiffInput.rightResource }); - const label = resourceDiffInput.label || this.toDiffLabel(resourceDiffInput.leftResource, resourceDiffInput.rightResource, this.workspaceContextService, this.environmentService); - - return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); - } - - // Untitled file support - const untitledInput = input; - if (!untitledInput.resource || typeof untitledInput.filePath === 'string' || (untitledInput.resource instanceof URI && untitledInput.resource.scheme === UNTITLED_SCHEMA)) { - return this.untitledEditorService.createOrGet(untitledInput.filePath ? URI.file(untitledInput.filePath) : untitledInput.resource, untitledInput.language, untitledInput.contents, untitledInput.encoding); - } - - const resourceInput = input; - - // Files support - if (resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { - return this.createOrGet(resourceInput.resource, this.instantiationService, resourceInput.label, resourceInput.description, resourceInput.encoding); - } - - // Any other resource - else if (resourceInput.resource instanceof URI) { - const label = resourceInput.label || basename(resourceInput.resource.fsPath); - let description: string; - if (typeof resourceInput.description === 'string') { - description = resourceInput.description; - } else if (resourceInput.resource.scheme === network.Schemas.file) { - description = dirname(resourceInput.resource.fsPath); - } - - return this.createOrGet(resourceInput.resource, this.instantiationService, label, description); - } - - return null; - } - - private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string, description: string, encoding?: string): ICachedEditorInput { - if (WorkbenchEditorService.CACHE.has(resource)) { - const input = WorkbenchEditorService.CACHE.get(resource); - if (input instanceof ResourceEditorInput) { - input.setName(label); - input.setDescription(description); - } else { - input.setPreferredEncoding(encoding); - } - - return input; - } - - let input: ICachedEditorInput; - if (resource.scheme === network.Schemas.file || this.fileService.canHandleResource && this.fileService.canHandleResource(resource)) { - input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); - } else { - input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); - } - - WorkbenchEditorService.CACHE.set(resource, input); - once(input.onDispose)(() => { - WorkbenchEditorService.CACHE.delete(resource); - }); - - return input; - } - - private toDiffLabel(res1: URI, res2: URI, context: IWorkspaceContextService, environment: IEnvironmentService): string { - const leftName = getPathLabel(res1.fsPath, context, environment); - const rightName = getPathLabel(res2.fsPath, context, environment); - - return nls.localize('compareLabels', "{0} ↔ {1}", leftName, rightName); - } -} - -export interface IEditorOpenHandler { - (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; -} - -export interface IEditorCloseHandler { - (position: Position, input: IEditorInput): TPromise; -} - -/** - * Subclass of workbench editor service that delegates all calls to the provided editor service. Subclasses can choose to override the behavior - * of openEditor() and closeEditor() by providing a handler. - * - * This gives clients a chance to override the behavior of openEditor() and closeEditor(). - */ -export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { - private editorOpenHandler: IEditorOpenHandler; - private editorCloseHandler: IEditorCloseHandler; - - constructor( - @IUntitledEditorService untitledEditorService: IUntitledEditorService, - @IInstantiationService instantiationService: IInstantiationService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEnvironmentService environmentService: IEnvironmentService, - @IFileService fileService: IFileService - ) { - super( - editorService, - untitledEditorService, - workspaceContextService, - instantiationService, - environmentService, - fileService - ); - } - - public setEditorOpenHandler(handler: IEditorOpenHandler): void { - this.editorOpenHandler = handler; - } - - public setEditorCloseHandler(handler: IEditorCloseHandler): void { - this.editorCloseHandler = handler; - } - - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { - const handleOpen = this.editorOpenHandler ? this.editorOpenHandler(input, options, arg3) : TPromise.as(void 0); - - return handleOpen.then(editor => { - if (editor) { - return TPromise.as(editor); - } - - return super.doOpenEditor(input, options, arg3); - }); - } - - protected doCloseEditor(position: Position, input: IEditorInput): TPromise { - const handleClose = this.editorCloseHandler ? this.editorCloseHandler(position, input) : TPromise.as(void 0); - - return handleClose.then(() => { - return super.doCloseEditor(position, input); - }); - } -} diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 05f2ae36cc2..8100a8cd551 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -6,8 +6,23 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService, IEditor, IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IResourceInput, IResourceDiffInput, IResourceSideBySideInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; +import URI from 'vs/base/common/uri'; +import network = require('vs/base/common/network'); +import { Registry } from 'vs/platform/registry/common/platform'; +import { basename, dirname } from 'vs/base/common/paths'; +import { EditorInput, EditorOptions, TextEditorOptions, Extensions as EditorExtensions, SideBySideEditorInput, IFileEditorInput, IFileInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import nls = require('vs/nls'); +import { getPathLabel } from 'vs/base/common/labels'; +import { ResourceMap } from 'vs/base/common/map'; +import { once } from 'vs/base/common/event'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; export const IWorkbenchEditorService = createDecorator('editorService'); @@ -91,4 +106,344 @@ export interface IWorkbenchEditorService extends IEditorService { * Allows to resolve an untyped input to a workbench typed instanceof editor input */ createInput(input: IResourceInputType): IEditorInput; -} \ No newline at end of file +} + +export interface IEditorPart { + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; + openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; + replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; + closeEditor(position: Position, input: IEditorInput): TPromise; + closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise; + closeAllEditors(except?: Position): TPromise; + getActiveEditor(): IEditor; + getVisibleEditors(): IEditor[]; + getActiveEditorInput(): IEditorInput; +} + +type ICachedEditorInput = ResourceEditorInput | IFileEditorInput; + +export class WorkbenchEditorService implements IWorkbenchEditorService { + + public _serviceBrand: any; + + private static CACHE: ResourceMap = new ResourceMap(); + + private editorPart: IEditorPart | IWorkbenchEditorService; + private fileInputFactory: IFileInputFactory; + + constructor( + editorPart: IEditorPart | IWorkbenchEditorService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, + @IInstantiationService private instantiationService: IInstantiationService, + @IEnvironmentService private environmentService: IEnvironmentService, + @IFileService private fileService: IFileService + ) { + this.editorPart = editorPart; + this.fileInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileInputFactory(); + } + + public getActiveEditor(): IEditor { + return this.editorPart.getActiveEditor(); + } + + public getActiveEditorInput(): IEditorInput { + return this.editorPart.getActiveEditorInput(); + } + + public getVisibleEditors(): IEditor[] { + return this.editorPart.getVisibleEditors(); + } + + public isVisible(input: IEditorInput, includeSideBySide: boolean): boolean { + if (!input) { + return false; + } + + return this.getVisibleEditors().some(editor => { + if (!editor.input) { + return false; + } + + if (input.matches(editor.input)) { + return true; + } + + if (includeSideBySide && editor.input instanceof SideBySideEditorInput) { + const sideBySideInput = editor.input; + return input.matches(sideBySideInput.master) || input.matches(sideBySideInput.details); + } + + return false; + }); + } + + public openEditor(input: IEditorInput, options?: IEditorOptions, sideBySide?: boolean): TPromise; + public openEditor(input: IEditorInput, options?: IEditorOptions, position?: Position): TPromise; + public openEditor(input: IResourceInputType, position?: Position): TPromise; + public openEditor(input: IResourceInputType, sideBySide?: boolean): TPromise; + public openEditor(input: any, arg2?: any, arg3?: any): TPromise { + if (!input) { + return TPromise.as(null); + } + + // Workbench Input Support + if (input instanceof EditorInput) { + return this.doOpenEditor(input, this.toOptions(arg2), arg3); + } + + // Support opening foreign resources (such as a http link that points outside of the workbench) + const resourceInput = input; + if (resourceInput.resource instanceof URI) { + const schema = resourceInput.resource.scheme; + if (schema === network.Schemas.http || schema === network.Schemas.https) { + window.open(resourceInput.resource.toString(true)); + + return TPromise.as(null); + } + } + + // Untyped Text Editor Support (required for code that uses this service below workbench level) + const textInput = input; + const typedInput = this.createInput(textInput); + if (typedInput) { + return this.doOpenEditor(typedInput, TextEditorOptions.from(textInput), arg2); + } + + return TPromise.as(null); + } + + private toOptions(options?: IEditorOptions | EditorOptions): EditorOptions { + if (!options || options instanceof EditorOptions) { + return options as EditorOptions; + } + + const textOptions: ITextEditorOptions = options; + if (!!textOptions.selection) { + return TextEditorOptions.create(options); + } + + return EditorOptions.create(options); + } + + /** + * Allow subclasses to implement their own behavior for opening editor (see below). + */ + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { + return this.editorPart.openEditor(input, options, arg3); + } + + public openEditors(editors: { input: IResourceInputType, position: Position }[]): TPromise; + public openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions }[]): TPromise; + public openEditors(editors: any[]): TPromise { + const inputs = editors.map(editor => this.createInput(editor.input)); + const typedInputs: { input: IEditorInput, position: Position, options?: EditorOptions }[] = inputs.map((input, index) => { + const options = editors[index].input instanceof EditorInput ? this.toOptions(editors[index].options) : TextEditorOptions.from(editors[index].input); + + return { + input, + options, + position: editors[index].position + }; + }); + + return this.editorPart.openEditors(typedInputs); + } + + public replaceEditors(editors: { toReplace: IResourceInputType, replaceWith: IResourceInputType }[], position?: Position): TPromise; + public replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions }[], position?: Position): TPromise; + public replaceEditors(editors: any[], position?: Position): TPromise { + const toReplaceInputs = editors.map(editor => this.createInput(editor.toReplace)); + const replaceWithInputs = editors.map(editor => this.createInput(editor.replaceWith)); + const typedReplacements: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: EditorOptions }[] = editors.map((editor, index) => { + const options = editor.toReplace instanceof EditorInput ? this.toOptions(editor.options) : TextEditorOptions.from(editor.replaceWith); + + return { + toReplace: toReplaceInputs[index], + replaceWith: replaceWithInputs[index], + options + }; + }); + + return this.editorPart.replaceEditors(typedReplacements, position); + } + + public closeEditor(position: Position, input: IEditorInput): TPromise { + return this.doCloseEditor(position, input); + } + + protected doCloseEditor(position: Position, input: IEditorInput): TPromise { + return this.editorPart.closeEditor(position, input); + } + + public closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise { + return this.editorPart.closeEditors(position, filter); + } + + public closeAllEditors(except?: Position): TPromise { + return this.editorPart.closeAllEditors(except); + } + + public createInput(input: IEditorInput): EditorInput; + public createInput(input: IResourceInputType): EditorInput; + public createInput(input: any): IEditorInput { + + // Workbench Input Support + if (input instanceof EditorInput) { + return input; + } + + // Side by Side Support + const resourceSideBySideInput = input; + if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { + const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource }); + const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource }); + + return new SideBySideEditorInput(resourceSideBySideInput.label || masterInput.getName(), typeof resourceSideBySideInput.description === 'string' ? resourceSideBySideInput.description : masterInput.getDescription(), detailInput, masterInput); + } + + // Diff Editor Support + const resourceDiffInput = input; + if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { + const leftInput = this.createInput({ resource: resourceDiffInput.leftResource }); + const rightInput = this.createInput({ resource: resourceDiffInput.rightResource }); + const label = resourceDiffInput.label || this.toDiffLabel(resourceDiffInput.leftResource, resourceDiffInput.rightResource, this.workspaceContextService, this.environmentService); + + return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); + } + + // Untitled file support + const untitledInput = input; + if (!untitledInput.resource || typeof untitledInput.filePath === 'string' || (untitledInput.resource instanceof URI && untitledInput.resource.scheme === UNTITLED_SCHEMA)) { + return this.untitledEditorService.createOrGet(untitledInput.filePath ? URI.file(untitledInput.filePath) : untitledInput.resource, untitledInput.language, untitledInput.contents, untitledInput.encoding); + } + + const resourceInput = input; + + // Files support + if (resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { + return this.createOrGet(resourceInput.resource, this.instantiationService, resourceInput.label, resourceInput.description, resourceInput.encoding); + } + + // Any other resource + else if (resourceInput.resource instanceof URI) { + const label = resourceInput.label || basename(resourceInput.resource.fsPath); + let description: string; + if (typeof resourceInput.description === 'string') { + description = resourceInput.description; + } else if (resourceInput.resource.scheme === network.Schemas.file) { + description = dirname(resourceInput.resource.fsPath); + } + + return this.createOrGet(resourceInput.resource, this.instantiationService, label, description); + } + + return null; + } + + private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string, description: string, encoding?: string): ICachedEditorInput { + if (WorkbenchEditorService.CACHE.has(resource)) { + const input = WorkbenchEditorService.CACHE.get(resource); + if (input instanceof ResourceEditorInput) { + input.setName(label); + input.setDescription(description); + } else { + input.setPreferredEncoding(encoding); + } + + return input; + } + + let input: ICachedEditorInput; + if (resource.scheme === network.Schemas.file || this.fileService.canHandleResource && this.fileService.canHandleResource(resource)) { + input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); + } else { + input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); + } + + WorkbenchEditorService.CACHE.set(resource, input); + once(input.onDispose)(() => { + WorkbenchEditorService.CACHE.delete(resource); + }); + + return input; + } + + private toDiffLabel(res1: URI, res2: URI, context: IWorkspaceContextService, environment: IEnvironmentService): string { + const leftName = getPathLabel(res1.fsPath, context, environment); + const rightName = getPathLabel(res2.fsPath, context, environment); + + return nls.localize('compareLabels', "{0} ↔ {1}", leftName, rightName); + } +} + +export interface IEditorOpenHandler { + (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; +} + +export interface IEditorCloseHandler { + (position: Position, input: IEditorInput): TPromise; +} + +/** + * Subclass of workbench editor service that delegates all calls to the provided editor service. Subclasses can choose to override the behavior + * of openEditor() and closeEditor() by providing a handler. + * + * This gives clients a chance to override the behavior of openEditor() and closeEditor(). + */ +export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { + private editorOpenHandler: IEditorOpenHandler; + private editorCloseHandler: IEditorCloseHandler; + + constructor( + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @IInstantiationService instantiationService: IInstantiationService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService + ) { + super( + editorService, + untitledEditorService, + workspaceContextService, + instantiationService, + environmentService, + fileService + ); + } + + public setEditorOpenHandler(handler: IEditorOpenHandler): void { + this.editorOpenHandler = handler; + } + + public setEditorCloseHandler(handler: IEditorCloseHandler): void { + this.editorCloseHandler = handler; + } + + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { + const handleOpen = this.editorOpenHandler ? this.editorOpenHandler(input, options, arg3) : TPromise.as(void 0); + + return handleOpen.then(editor => { + if (editor) { + return TPromise.as(editor); + } + + return super.doOpenEditor(input, options, arg3); + }); + } + + protected doCloseEditor(position: Position, input: IEditorInput): TPromise { + const handleClose = this.editorCloseHandler ? this.editorCloseHandler(position, input) : TPromise.as(void 0); + + return handleClose.then(() => { + return super.doCloseEditor(position, input); + }); + } +} diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index c6ce1376dc1..dabe18285d6 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -14,7 +14,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, TextEditorOptions } from 'vs/workbench/common/editor'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; -import { DelegatingWorkbenchEditorService, WorkbenchEditorService, IEditorPart } from 'vs/workbench/services/editor/browser/editorService'; +import { DelegatingWorkbenchEditorService, WorkbenchEditorService, IEditorPart } from 'vs/workbench/services/editor/common/editorService'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; From e290a7582cd54ed538e78440005f94dffe7a9483 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2017 17:52:06 +0200 Subject: [PATCH 208/303] settings - editor options travel through --- .../browser/parts/editor/editorPart.ts | 2 +- src/vs/workbench/common/editor.ts | 9 +++++-- .../preferences/browser/preferencesService.ts | 26 ++++++++++++------- .../parts/preferences/common/preferences.ts | 8 +++--- .../common/preferencesContribution.ts | 6 ++--- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 15ce8ce3eb0..e1a28c2dd1d 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -336,7 +336,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } // Editor opening event (can be prevented and overridden) - const event = new EditorOpeningEvent(input, position); + const event = new EditorOpeningEvent(input, options, position); this._onEditorOpening.fire(event); const prevented = event.isPrevented(); if (prevented) { diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 0e2582432d6..2df8fc14a2d 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -262,6 +262,7 @@ export abstract class EditorInput implements IEditorInput { export interface IEditorOpeningEvent { input: IEditorInput; + options?: IEditorOptions; position: Position; /** @@ -277,11 +278,15 @@ export interface IEditorOpeningEvent { export class EditorOpeningEvent { private override: () => TPromise; - constructor(private _editorInput: IEditorInput, private _position: Position) { + constructor(private _input: IEditorInput, private _options: IEditorOptions, private _position: Position) { } public get input(): IEditorInput { - return this._editorInput; + return this._input; + } + + public get options(): IEditorOptions { + return this._options; } public get position(): Position { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index eea8fda7f35..fba847f728b 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -17,7 +17,7 @@ import { EditorInput } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { Position as EditorPosition, IEditor } from 'vs/platform/editor/common/editor'; +import { Position as EditorPosition, IEditor, IEditorOptions } from 'vs/platform/editor/common/editor'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -176,20 +176,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic return TPromise.wrap>(null); } - openGlobalSettings(position?: EditorPosition): TPromise { - return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource, position); + openGlobalSettings(options?: IEditorOptions, position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource, options, position); } - openWorkspaceSettings(position?: EditorPosition): TPromise { + openWorkspaceSettings(options?: IEditorOptions, position?: EditorPosition): TPromise { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings")); return TPromise.as(null); } - return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, position); + return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, options, position); } - openFolderSettings(folder: URI, position?: EditorPosition): TPromise { - return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder), position); + openFolderSettings(folder: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder), options, position); } switchSettings(target: ConfigurationTarget, resource: URI): TPromise { @@ -249,17 +249,23 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, position?: EditorPosition): TPromise { + private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { const openDefaultSettings = !!this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value; return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource) .then(editableSettingsEditorInput => { + if (!options) { + options = { pinned: true }; + } else { + options.pinned = true; + } + if (openDefaultSettings) { const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget)); const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, editableSettingsEditorInput); this.lastOpenedSettingsInput = preferencesEditorInput; - return this.editorService.openEditor(preferencesEditorInput, { pinned: true }, position); + return this.editorService.openEditor(preferencesEditorInput, options, position); } - return this.editorService.openEditor(editableSettingsEditorInput, { pinned: true }, position); + return this.editorService.openEditor(editableSettingsEditorInput, options, position); }); } diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index ac93b8ec775..d75d4737b73 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -8,7 +8,7 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IEditor, Position } from 'vs/platform/editor/common/editor'; +import { IEditor, Position, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IKeybindingItemEntry } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel'; import { IRange } from 'vs/editor/common/core/range'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; @@ -77,9 +77,9 @@ export interface IPreferencesService { resolveContent(uri: URI): TPromise; createPreferencesEditorModel(uri: URI): TPromise>; - openGlobalSettings(position?: Position): TPromise; - openWorkspaceSettings(position?: Position): TPromise; - openFolderSettings(folder: URI, position?: Position): TPromise; + openGlobalSettings(options?: IEditorOptions, position?: Position): TPromise; + openWorkspaceSettings(options?: IEditorOptions, position?: Position): TPromise; + openFolderSettings(folder: URI, options?: IEditorOptions, position?: Position): TPromise; switchSettings(target: ConfigurationTarget, resource: URI): TPromise; openGlobalKeybindingSettings(textual: boolean): TPromise; diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts index ac091d532ca..48e0ef167d2 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -67,7 +67,7 @@ export class PreferencesContribution implements IWorkbenchContribution { // Global User Settings File if (resource.fsPath === this.environmentService.appSettingsPath) { - return event.prevent(() => this.preferencesService.openGlobalSettings(event.position)); + return event.prevent(() => this.preferencesService.openGlobalSettings(event.options, event.position)); } // Single Folder Workspace Settings File @@ -75,7 +75,7 @@ export class PreferencesContribution implements IWorkbenchContribution { if (state === WorkbenchState.FOLDER) { const folders = this.workspaceService.getWorkspace().folders; if (resource.fsPath === folders[0].toResource(FOLDER_SETTINGS_PATH).fsPath) { - return event.prevent(() => this.preferencesService.openWorkspaceSettings(event.position)); + return event.prevent(() => this.preferencesService.openWorkspaceSettings(event.options, event.position)); } } @@ -84,7 +84,7 @@ export class PreferencesContribution implements IWorkbenchContribution { const folders = this.workspaceService.getWorkspace().folders; for (let i = 0; i < folders.length; i++) { if (resource.fsPath === folders[i].toResource(FOLDER_SETTINGS_PATH).fsPath) { - return event.prevent(() => this.preferencesService.openFolderSettings(folders[i].uri, event.position)); + return event.prevent(() => this.preferencesService.openFolderSettings(folders[i].uri, event.options, event.position)); } } } From fa5556c3abf12f20c78bedd7a645a90777331001 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 09:45:23 -0700 Subject: [PATCH 209/303] Add support for dim text in the terminal Fixes #36238 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index a3b4ae130d4..03a12f907f7 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#14b0137accaf350565a005d68e91f03c96a241be" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#b84b02d4b3ba962072822d923d7040fce80a4227" }, "yauzl": { "version": "2.8.0", From 3d6b6ac91c90c894018b9fbd5bf5b05fec4fbdc9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 10:00:35 -0700 Subject: [PATCH 210/303] Focus terminal when clicking a link that doesn't activate Fixes #36187 --- .../terminal/electron-browser/terminalLinkHandler.ts | 7 ++++++- .../test/electron-browser/terminalLinkHandler.test.ts | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts index 83b76d604ac..8650646c7ad 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -14,6 +14,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { TerminalWidgetManager } from 'vs/workbench/parts/terminal/browser/terminalWidgetManager'; import { TPromise } from 'vs/base/common/winjs.base'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; const pathPrefix = '(\\.\\.?|\\~)'; const pathSeparatorClause = '\\/'; @@ -67,7 +68,8 @@ export class TerminalLinkHandler { private _initialCwd: string, @IOpenerService private _openerService: IOpenerService, @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, - @IConfigurationService private _configurationService: IConfigurationService + @IConfigurationService private _configurationService: IConfigurationService, + @ITerminalService private _terminalService: ITerminalService ) { const baseLocalLinkClause = _platform === platform.Platform.Windows ? winLocalLinkClause : unixLocalLinkClause; // Append line and column number regex @@ -120,6 +122,9 @@ export class TerminalLinkHandler { event.preventDefault(); // Require correct modifier on click if (!this._isLinkActivationModifierDown(event)) { + // If the modifier is not pressed, the terminal should be + // focused if it's not already + this._terminalService.getActiveInstance().focus(true); return false; } return handler(uri); diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts index 77d9fed7145..491637a485c 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -35,7 +35,7 @@ interface LinkFormatInfo { suite('Workbench - TerminalLinkHandler', () => { suite('localLinkRegex', () => { test('Windows', () => { - const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null, null, null, null); + const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, null, null, null, null, null); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -105,7 +105,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('Linux', () => { - const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null, null, null, null); + const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null, null, null, null, null); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -169,7 +169,7 @@ suite('Workbench - TerminalLinkHandler', () => { suite('preprocessPath', () => { test('Windows', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, 'C:\\base', null, null, null); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, 'C:\\base', null, null, null, null); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '\\' + arg2; @@ -182,7 +182,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('Linux', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, '/base', null, null, null); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, '/base', null, null, null, null); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '/' + arg2; @@ -195,7 +195,7 @@ suite('Workbench - TerminalLinkHandler', () => { }); test('No Workspace', () => { - const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null, null, null, null); + const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, null, null, null, null, null); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); From 711167f7bb1db9cc7b5e5314cf8a685485657cb7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 13:23:50 -0700 Subject: [PATCH 211/303] Update xterm.js to support enableBold Part of #35666 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 03a12f907f7..dd103542200 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#b84b02d4b3ba962072822d923d7040fce80a4227" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#d57ac8df05ddf04b509505eadc0d408a0b3bfa38" }, "yauzl": { "version": "2.8.0", From d47a1babc298bf64b555c9336c9842f32920cb28 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 13:31:50 -0700 Subject: [PATCH 212/303] Pull in latest typings --- src/typings/xterm.d.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index 197f2e7ebc8..ceed656bf3f 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -41,6 +41,11 @@ interface ITerminalOptions { */ disableStdin?: boolean; + /** + * Whether to enable the rendering of bold text. + */ + enableBold?: boolean; + /** * The font size used to render text. */ @@ -397,7 +402,7 @@ declare module 'xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; + getOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -447,7 +452,7 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; + setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. From a763c7a0cb92d5ac86f7f7779943977cca820f76 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 13:34:39 -0700 Subject: [PATCH 213/303] Add support for terminal.integrated.enableBold back Fixes #35666 --- src/vs/workbench/parts/terminal/common/terminal.ts | 2 +- .../terminal/electron-browser/terminal.contribution.ts | 10 +++++----- .../terminal/electron-browser/terminalInstance.ts | 6 +++++- .../parts/terminal/electron-browser/terminalPanel.ts | 2 -- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 93ffb4af4c6..fe4841ac5ec 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -58,7 +58,7 @@ export interface ITerminalConfiguration { osx: string[]; windows: string[]; }; - // enableBold: boolean; + enableBold: boolean; rightClickCopyPaste: boolean; cursorBlinking: boolean; cursorStyle: string; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index f5d947c4492..7a048fb9732 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -140,11 +140,11 @@ configurationRegistry.registerConfiguration({ 'type': 'number', 'default': 1 }, - // 'terminal.integrated.enableBold': { - // 'type': 'boolean', - // 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal, this requires support from the terminal shell."), - // 'default': true - // }, + 'terminal.integrated.enableBold': { + 'type': 'boolean', + 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal, note that this requires support from the terminal shell."), + 'default': true + }, 'terminal.integrated.cursorBlinking': { 'description': nls.localize('terminal.integrated.cursorBlinking', "Controls whether the terminal cursor blinks."), 'type': 'boolean', diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 113ed5e0e48..7467fe7724d 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -266,7 +266,8 @@ export class TerminalInstance implements ITerminalInstance { theme: this._getXtermTheme(), fontFamily: font.fontFamily, fontSize: font.fontSize, - lineHeight: font.lineHeight + lineHeight: font.lineHeight, + enableBold: this._configHelper.config.enableBold }); if (this._shellLaunchConfig.initialText) { this._xterm.writeln(this._shellLaunchConfig.initialText); @@ -923,6 +924,9 @@ export class TerminalInstance implements ITerminalInstance { if (this._xterm.getOption('fontFamily') !== font.fontFamily) { this._xterm.setOption('fontFamily', font.fontFamily); } + if (this._xterm.getOption('enableBold') !== this._configHelper.config.enableBold) { + this._xterm.setOption('enableBold', this._configHelper.config.enableBold); + } this._xterm.resize(this._cols, this._rows); this._xterm.element.style.width = terminalWidth + 'px'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 56a3523d7e2..9acf376fef2 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -302,8 +302,6 @@ export class TerminalPanel extends Panel { this._font = this._terminalService.configHelper.getFont(); // TODO: Can we support ligatures? // dom.toggleClass(this._parentDomElement, 'enable-ligatures', this._terminalService.configHelper.config.fontLigatures); - // TODO: How to handle Disable bold? - // dom.toggleClass(this._parentDomElement, 'disable-bold', !this._terminalService.configHelper.config.enableBold); this.layout(new Dimension(this._parentDomElement.offsetWidth, this._parentDomElement.offsetHeight)); } From 3a54e322918b8845dec3fd20de84656272bb2d04 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 13 Oct 2017 14:19:46 -0700 Subject: [PATCH 214/303] Update TypeScript to use new task API Fixes #35371 --- extensions/typescript/src/features/taskProvider.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 290c07a7709..d7d042e9abb 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -168,6 +168,7 @@ class TscTaskProvider implements vscode.TaskProvider { const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; const buildTask = new vscode.Task( buildTaskidentifier, + project.workspaceFolder || vscode.TaskScope.Workspace, localize('buildTscLabel', 'build - {0}', label), 'tsc', new vscode.ShellExecution(`${command} -p "${project.path}"`), @@ -181,6 +182,7 @@ class TscTaskProvider implements vscode.TaskProvider { const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; const watchTask = new vscode.Task( watchTaskidentifier, + project.workspaceFolder || vscode.TaskScope.Workspace, localize('buildAndWatchTscLabel', 'watch - {0}', label), 'tsc', new vscode.ShellExecution(`${command} --watch -p "${project.path}"`), From 9613018ef0a7c16be99a4fdf331addafd05eb410 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 13 Oct 2017 14:46:12 -0700 Subject: [PATCH 215/303] Update ts grammar --- .../syntaxes/JavaScript.tmLanguage.json | 9 ++-- .../syntaxes/JavaScriptReact.tmLanguage.json | 9 ++-- .../test/colorize-results/test_jsx.json | 52 +++++++++---------- .../syntaxes/TypeScript.tmLanguage.json | 8 +-- .../syntaxes/TypeScriptReact.tmLanguage.json | 9 ++-- 5 files changed, 37 insertions(+), 50 deletions(-) diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 85546d41404..7b1ec3d76c5 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/824f47ea6e98590ac2e75db5bebdf6eff71421ad", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -1707,8 +1707,7 @@ "include": "#comment" }, { - "comment": "(default|*|name) as alias", - "match": "(?x) (?: \\b(default)\\b | (\\*) | ([_$[:alpha:]][_$[:alnum:]]*)) \\s+\n (as) \\s+ (?: (\\b default \\b | \\*) | ([_$[:alpha:]][_$[:alnum:]]*))", + "match": "(?)", + "contentName": "meta.tag.attributes.js", "patterns": [ { "include": "#comment" diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 0de22f4d7a9..f0ad9fc5c29 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/824f47ea6e98590ac2e75db5bebdf6eff71421ad", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "fileTypes": [ @@ -1707,8 +1707,7 @@ "include": "#comment" }, { - "comment": "(default|*|name) as alias", - "match": "(?x) (?: \\b(default)\\b | (\\*) | ([_$[:alpha:]][_$[:alnum:]]*)) \\s+\n (as) \\s+ (?: (\\b default \\b | \\*) | ([_$[:alpha:]][_$[:alnum:]]*))", + "match": "(?)", + "contentName": "meta.tag.attributes.js.jsx", "patterns": [ { "include": "#comment" diff --git a/extensions/javascript/test/colorize-results/test_jsx.json b/extensions/javascript/test/colorize-results/test_jsx.json index 9a5a14a90b7..7824e567af2 100644 --- a/extensions/javascript/test/colorize-results/test_jsx.json +++ b/extensions/javascript/test/colorize-results/test_jsx.json @@ -1772,7 +1772,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1783,7 @@ }, { "c": "href", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1794,7 +1794,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1805,7 +1805,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1816,7 +1816,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1827,7 +1827,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1838,7 +1838,7 @@ }, { "c": "onClick", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1849,7 +1849,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1860,7 +1860,7 @@ }, { "c": "{", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -1871,7 +1871,7 @@ }, { "c": "this", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1882,7 +1882,7 @@ }, { "c": ".", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "meta.embedded: #D4D4D4", "light_plus": "meta.embedded: #000000", @@ -1893,7 +1893,7 @@ }, { "c": "toggle", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1904,7 +1904,7 @@ }, { "c": "}", - "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -2168,7 +2168,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.tag.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2179,7 +2179,7 @@ }, { "c": "default", - "t": "source.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2190,7 +2190,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2201,7 +2201,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2212,7 +2212,7 @@ }, { "c": "World", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2223,7 +2223,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2234,7 +2234,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.tag.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2245,7 +2245,7 @@ }, { "c": "alt", - "t": "source.js.jsx meta.tag.js.jsx entity.other.attribute-name.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2256,7 +2256,7 @@ }, { "c": "=", - "t": "source.js.jsx meta.tag.js.jsx keyword.operator.assignment.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2267,7 +2267,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2278,7 +2278,7 @@ }, { "c": "Mars", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2289,7 +2289,7 @@ }, { "c": "\"", - "t": "source.js.jsx meta.tag.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2300,7 +2300,7 @@ }, { "c": " ", - "t": "source.js.jsx meta.tag.js.jsx", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index fc4a8971471..454dc854bdf 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4109ddc9e27186afcf7263a448c86a59e9aa7d9e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/f3a2069b99f45c34ac5cc7dc5f1dcb4e81486ab9", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -1701,8 +1701,7 @@ "include": "#comment" }, { - "comment": "(default|*|name) as alias", - "match": "(?x) (?: \\b(default)\\b | (\\*) | ([_$[:alpha:]][_$[:alnum:]]*)) \\s+\n (as) \\s+ (?: (\\b default \\b | \\*) | ([_$[:alpha:]][_$[:alnum:]]*))", + "match": "(?)", + "contentName": "meta.tag.attributes.tsx", "patterns": [ { "include": "#comment" From 989c40066d124cde846cf5ded8364251246e100e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 13 Oct 2017 14:51:04 -0700 Subject: [PATCH 216/303] Fix commenting of jsx attribute using jsx style comments Fixes #36175 --- extensions/javascript/package.json | 2 ++ extensions/typescript/package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 4d7fa6dff20..866167e1ba6 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -68,6 +68,7 @@ "embeddedLanguages": { "meta.tag.js": "jsx-tags", "meta.tag.without-attributes.js": "jsx-tags", + "meta.tag.attributes.js.jsx": "javascriptreact", "meta.embedded.expression.js": "javascriptreact" } }, @@ -78,6 +79,7 @@ "embeddedLanguages": { "meta.tag.js": "jsx-tags", "meta.tag.without-attributes.js": "jsx-tags", + "meta.tag.attributes.js": "javascript", "meta.embedded.expression.js": "javascript" } }, diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 6934e4221bd..ad4545f9355 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -78,6 +78,7 @@ "embeddedLanguages": { "meta.tag.tsx": "jsx-tags", "meta.tag.without-attributes.tsx": "jsx-tags", + "meta.tag.attributes.tsx": "typescriptreact", "meta.embedded.expression.tsx": "typescriptreact" } } From 73635a9cd341fd1b65ccd1003562387f1a76ab58 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 13 Oct 2017 15:35:54 -0700 Subject: [PATCH 217/303] Add option to disable quick suggestions for js/ts paths Fixes #35877 --- extensions/typescript/package.json | 8 ++++- extensions/typescript/package.nls.json | 3 +- .../src/features/completionItemProvider.ts | 30 ++++++++++++------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index ad4545f9355..3062949aad7 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -393,6 +393,12 @@ ], "description": "%typescript.tsc.autoDetect%", "scope": "resource" + }, + "typescript.quickSuggestionsForPaths": { + "type": "boolean", + "default": true, + "description": "%typescript.quickSuggestionsForPaths%", + "scope": "resource" } } }, @@ -571,4 +577,4 @@ } ] } -} +} \ No newline at end of file diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index f23e78bf4e1..39725205f50 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -41,5 +41,6 @@ "javascript.nameSuggestions": "Enable/disable including unique names from the file in JavaScript suggestion lists.", "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks. 'off' disables this feature. 'build' only creates single run compile tasks. 'watch' only creates compile and watch tasks. 'on' creates both build and watch tasks. Default is 'on'.", "typescript.problemMatchers.tsc.label": "TypeScript problems", - "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)" + "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)", + "typescript.quickSuggestionsForPaths": "Enable/disable quick suggestions when typing out an import path." } diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 77fe1015a32..f4e46e19cee 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -122,34 +122,36 @@ class MyCompletionItem extends CompletionItem { interface Configuration { useCodeSnippetsOnMethodSuggest: boolean; nameSuggestions: boolean; + quickSuggestionsForPaths: boolean; } namespace Configuration { export const useCodeSnippetsOnMethodSuggest = 'useCodeSnippetsOnMethodSuggest'; export const nameSuggestions = 'nameSuggestions'; + export const quickSuggestionsForPaths = 'quickSuggestionsForPaths'; } export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { - private config: Configuration; + private config: Configuration = { + useCodeSnippetsOnMethodSuggest: false, + nameSuggestions: true, + quickSuggestionsForPaths: true + }; constructor( private client: ITypescriptServiceClient, private typingsStatus: TypingsStatus - ) { - this.config = { - useCodeSnippetsOnMethodSuggest: false, - nameSuggestions: true - }; - } + ) { } public updateConfiguration(): void { // Use shared setting for js and ts const typeScriptConfig = workspace.getConfiguration('typescript'); - this.config.useCodeSnippetsOnMethodSuggest = typeScriptConfig.get(Configuration.useCodeSnippetsOnMethodSuggest, false); - const jsConfig = workspace.getConfiguration('javascript'); - this.config.nameSuggestions = jsConfig.get(Configuration.nameSuggestions, true); + this.config.useCodeSnippetsOnMethodSuggest = typeScriptConfig.get(Configuration.useCodeSnippetsOnMethodSuggest, false); + this.config.quickSuggestionsForPaths = typeScriptConfig.get(Configuration.quickSuggestionsForPaths, true); + + this.config.nameSuggestions = workspace.getConfiguration('javascript').get(Configuration.nameSuggestions, true); } public provideCompletionItems( @@ -175,6 +177,10 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { + if (!this.config.quickSuggestionsForPaths) { + return Promise.resolve([]); + } + // make sure we are in something that looks like the start of an import const line = document.lineAt(position.line).text.slice(0, position.character); if (!line.match(/\b(from|import)\s*["']$/) && !line.match(/\b(import|require)\(['"]$/)) { @@ -183,6 +189,10 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } if (context.triggerCharacter === '/') { + if (!this.config.quickSuggestionsForPaths) { + return Promise.resolve([]); + } + // make sure we are in something that looks like an import path const line = document.lineAt(position.line).text.slice(0, position.character); if (!line.match(/\bfrom\s*["'][^'"]*$/) && !line.match(/\b(import|require)\(['"][^'"]*$/)) { From 3049d48dbbcc259bdca2fb9b0cb115e455fb7266 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 16:37:49 -0700 Subject: [PATCH 218/303] Only update terminal display settings when visible Fixes #35763 --- .../electron-browser/terminalInstance.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 7467fe7724d..378e96b3648 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -913,24 +913,31 @@ export class TerminalInstance implements ITerminalInstance { if (!terminalWidth) { return; } + if (this._xterm) { const font = this._configHelper.getFont(); - if (this._xterm.getOption('lineHeight') !== font.lineHeight) { - this._xterm.setOption('lineHeight', font.lineHeight); - } - if (this._xterm.getOption('fontSize') !== font.fontSize) { - this._xterm.setOption('fontSize', font.fontSize); - } - if (this._xterm.getOption('fontFamily') !== font.fontFamily) { - this._xterm.setOption('fontFamily', font.fontFamily); - } - if (this._xterm.getOption('enableBold') !== this._configHelper.config.enableBold) { - this._xterm.setOption('enableBold', this._configHelper.config.enableBold); + + // Only apply these settings when the terminal is visible so that + // the characters are measured correctly. + if (this._isVisible) { + if (this._xterm.getOption('lineHeight') !== font.lineHeight) { + this._xterm.setOption('lineHeight', font.lineHeight); + } + if (this._xterm.getOption('fontSize') !== font.fontSize) { + this._xterm.setOption('fontSize', font.fontSize); + } + if (this._xterm.getOption('fontFamily') !== font.fontFamily) { + this._xterm.setOption('fontFamily', font.fontFamily); + } + if (this._xterm.getOption('enableBold') !== this._configHelper.config.enableBold) { + this._xterm.setOption('enableBold', this._configHelper.config.enableBold); + } } this._xterm.resize(this._cols, this._rows); this._xterm.element.style.width = terminalWidth + 'px'; } + this._processReady.then(() => { if (this._process && this._process.connected) { // The child process could aready be terminated From 2963b8ce6327b104bb8604f047bfdd20cd0988f0 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Oct 2017 16:57:50 -0700 Subject: [PATCH 219/303] Changes new terminal actions to show workspace selector All new terminal UI actions except for ctrl+shift+tilde (which remains unchanged) now show a workspace selector in a multi-root context. This includes: - The plus button on the panel - The new terminal option in the term quick open - The context menu shown by right clicking the terminal area Fixes #34163 --- .../terminal/browser/terminalQuickOpen.ts | 19 +++++++++--- .../electron-browser/terminal.contribution.ts | 4 ++- .../electron-browser/terminalActions.ts | 31 +++++++++++++++++-- .../electron-browser/terminalPanel.ts | 6 ++-- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts b/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts index 0f5e860dc61..dc1412e510e 100644 --- a/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts +++ b/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts @@ -14,6 +14,8 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; import { stripWildcards } from 'vs/base/common/strings'; import { matchesFuzzy } from 'vs/base/common/filters'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; export class TerminalEntry extends QuickOpenEntry { @@ -49,7 +51,8 @@ export class CreateTerminal extends QuickOpenEntry { constructor( private label: string, - private terminalService: ITerminalService + private terminalService: ITerminalService, + private commandService: ICommandService ) { super(); } @@ -65,9 +68,14 @@ export class CreateTerminal extends QuickOpenEntry { public run(mode: Mode, context: IEntryRunContext): boolean { if (mode === Mode.OPEN) { setTimeout(() => { - const newTerminal = this.terminalService.createInstance(); - this.terminalService.setActiveInstance(newTerminal); - this.terminalService.showPanel(true); + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { + const instance = this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true); + if (!instance) { + return TPromise.as(void 0); + } + this.terminalService.setActiveInstance(instance); + return this.terminalService.showPanel(true); + }); }, 0); return true; } @@ -82,6 +90,7 @@ export class TerminalPickerHandler extends QuickOpenHandler { constructor( @ITerminalService private terminalService: ITerminalService, + @ICommandService private commandService: ICommandService, @IPanelService private panelService: IPanelService ) { super(); @@ -92,7 +101,7 @@ export class TerminalPickerHandler extends QuickOpenHandler { const normalizedSearchValueLowercase = stripWildcards(searchValue).toLowerCase(); const terminalEntries: QuickOpenEntry[] = this.getTerminals(); - terminalEntries.push(new CreateTerminal(nls.localize("'workbench.action.terminal.newplus", "$(plus) Create New Integrated Terminal"), this.terminalService)); + terminalEntries.push(new CreateTerminal(nls.localize("'workbench.action.terminal.newplus", "$(plus) Create New Integrated Terminal"), this.terminalService, this.commandService)); const entries = terminalEntries.filter(e => { if (!searchValue) { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 7a048fb9732..184802fb0da 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -18,7 +18,7 @@ import { TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFA import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, CreateNewSelectWorkspaceTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; @@ -187,6 +187,7 @@ configurationRegistry.registerConfiguration({ QUICKOPEN_ACTION_ID, ShowAllCommandsAction.ID, CreateNewTerminalAction.ID, + CreateNewSelectWorkspaceTerminalAction.ID, CopyTerminalSelectionAction.ID, KillTerminalAction.ID, FocusActiveTerminalAction.ID, @@ -279,6 +280,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTermina primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK } }), 'Terminal: Create New Integrated Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (Select Workspace)', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index b38714c7e04..7bb15300f3a 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -21,6 +21,8 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { ActionBarContributor } from 'vs/workbench/browser/actions'; import { TerminalEntry } from 'vs/workbench/parts/terminal/browser/terminalQuickOpen'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; export const TERMINAL_PICKER_PREFIX = 'term '; @@ -196,14 +198,12 @@ export class CreateNewTerminalAction extends Action { public static ID = 'workbench.action.terminal.new'; public static LABEL = nls.localize('workbench.action.terminal.new', "Create New Integrated Terminal"); - public static PANEL_LABEL = nls.localize('workbench.action.terminal.new.short', "New Terminal"); constructor( id: string, label: string, @ITerminalService private terminalService: ITerminalService ) { super(id, label); - this.class = 'terminal-action new'; } public run(event?: any): TPromise { @@ -216,6 +216,33 @@ export class CreateNewTerminalAction extends Action { } } +export class CreateNewSelectWorkspaceTerminalAction extends Action { + + public static ID = 'workbench.action.terminal.newSelectWorkspace'; + public static LABEL = nls.localize('workbench.action.terminal.newSelectWorkspace', "Create New Integrated Terminal (Select Workspace)"); + public static PANEL_LABEL = nls.localize('workbench.action.terminal.new.short', "New Terminal"); + + constructor( + id: string, label: string, + @ITerminalService private terminalService: ITerminalService, + @ICommandService private commandService: ICommandService + ) { + super(id, label); + this.class = 'terminal-action new'; + } + + public run(event?: any): TPromise { + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { + const instance = this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true); + if (!instance) { + return TPromise.as(void 0); + } + this.terminalService.setActiveInstance(instance); + return this.terminalService.showPanel(true); + }); + } +} + export class FocusActiveTerminalAction extends Action { public static ID = 'workbench.action.terminal.focus'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 9acf376fef2..2ec3fb4ed98 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -19,7 +19,7 @@ import { ITerminalService, ITerminalFont, TERMINAL_PANEL_ID } from 'vs/workbench import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from './terminalFindWidget'; import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { KillTerminalAction, CreateNewTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, CreateNewSelectWorkspaceTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -115,7 +115,7 @@ export class TerminalPanel extends Panel { if (!this._actions) { this._actions = [ this._instantiationService.createInstance(SwitchTerminalInstanceAction, SwitchTerminalInstanceAction.ID, SwitchTerminalInstanceAction.LABEL), - this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.PANEL_LABEL), + this._instantiationService.createInstance(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.PANEL_LABEL), this._instantiationService.createInstance(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.PANEL_LABEL) ]; this._actions.forEach(a => { @@ -129,7 +129,7 @@ export class TerminalPanel extends Panel { if (!this._contextMenuActions) { this._copyContextMenuAction = this._instantiationService.createInstance(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, nls.localize('copy', "Copy")); this._contextMenuActions = [ - this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, nls.localize('createNewTerminal', "New Terminal")), + this._instantiationService.createInstance(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.PANEL_LABEL), new Separator(), this._copyContextMenuAction, this._instantiationService.createInstance(TerminalPasteAction, TerminalPasteAction.ID, nls.localize('paste', "Paste")), From 97e3a85eec2c894f5de56212cac710dac0da83be Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 13 Oct 2017 23:13:06 -0700 Subject: [PATCH 220/303] Notify test bot --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a04880dd308..0854813e23f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ cache: notifications: email: false + webhooks: + - http://vscode-test-probot.westus.cloudapp.azure.com:3450/travis/notifications addons: apt: From 65ab631d5144da4066d9335dc88ce0643ee6b151 Mon Sep 17 00:00:00 2001 From: Nick Snyder Date: Sat, 14 Oct 2017 00:16:14 -0700 Subject: [PATCH 221/303] add missing awaits --- src/vs/workbench/api/node/extHostSCM.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index a9c1e63af2e..9fafcbf368d 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -204,7 +204,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG return; } - this._commands.executeCommand(command.command, ...command.arguments); + await this._commands.executeCommand(command.command, ...command.arguments); } _takeResourceStateSnapshot(): SCMRawResourceSplice[] { @@ -532,6 +532,6 @@ export class ExtHostSCM { return; } - group.$executeResourceCommand(handle); + await group.$executeResourceCommand(handle); } } From 36b598c0472da771ee61b996240f8af64b24f601 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Sat, 14 Oct 2017 17:37:45 -0700 Subject: [PATCH 222/303] Fix typos for descriptions of emmet prefrerences #35676 --- extensions/emmet/package.nls.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 837b936b5b1..52a78763207 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -41,8 +41,8 @@ "emmetPreferencesStylusBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Stylus files", "emmetShowSuggestionsAsSnippets": "If true, then emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.", "emmetPreferencesBemElementSeparator": "Element separator used for classes when using the bem filter", - "emmetPreferencesBemModifierSeparator": "Modifer separator used for classes when using the bem filter", - "emmetPreferencesFilterCommentBefore": "A definition of comment that should be placed before after element when comment filter is applied.", - "emmetPreferencesFilterCommentAfter": "A definition of comment that should be placed before matched element when comment filter is applied.", + "emmetPreferencesBemModifierSeparator": "Modifier separator used for classes when using the bem filter", + "emmetPreferencesFilterCommentBefore": "A definition of comment that should be placed before matched element when comment filter is applied.", + "emmetPreferencesFilterCommentAfter": "A definition of comment that should be placed after matched element when comment filter is applied.", "emmetPreferencesFilterCommentTrigger": "A comma-separated list of attribute names that should exist in abbreviation for the comment filter to be applied" } \ No newline at end of file From de68b077b53d6eeafeaf39699d6384c4b8750a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Tar?= Date: Sun, 15 Oct 2017 19:56:52 +0200 Subject: [PATCH 223/303] Improve consistency of Emmet messages (#36251) - Start Emmet with capital E - Write BEM with all caps like in the official documentation --- extensions/emmet/package.nls.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 52a78763207..07ffacf4b44 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -23,13 +23,13 @@ "command.incrementNumberByTen": "Increment by 10", "command.decrementNumberByTen": "Decrement by 10", "emmetSyntaxProfiles": "Define profile for specified syntax or use your own profile with specific rules.", - "emmetExclude": "An array of languages where emmet abbreviations should not be expanded.", - "emmetExtensionsPath": "Path to a folder containing emmet profiles and snippets.'", - "emmetShowExpandedAbbreviation": "Shows expanded emmet abbreviations as suggestions.\nThe option \"inMarkupAndStylesheetFilesOnly\" applies to html, haml, jade, slim, xml, xsl, css, scss, sass, less and stylus.\nThe option \"always\" applies to all parts of the file regardless of markup/css.", - "emmetShowAbbreviationSuggestions": "Shows possible emmet abbreviations as suggestions. Not applicable in stylesheets or when emmet.showExpandedAbbreviation is set to \"never\".", - "emmetIncludeLanguages": "Enable emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and emmet supported language.\n Eg: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variables to be used in emmet snippets", - "emmetTriggerExpansionOnTab": "When enabled, emmet abbreviations are expanded when pressing TAB.", + "emmetExclude": "An array of languages where Emmet abbreviations should not be expanded.", + "emmetExtensionsPath": "Path to a folder containing Emmet profiles and snippets.'", + "emmetShowExpandedAbbreviation": "Shows expanded Emmet abbreviations as suggestions.\nThe option \"inMarkupAndStylesheetFilesOnly\" applies to html, haml, jade, slim, xml, xsl, css, scss, sass, less and stylus.\nThe option \"always\" applies to all parts of the file regardless of markup/css.", + "emmetShowAbbreviationSuggestions": "Shows possible Emmet abbreviations as suggestions. Not applicable in stylesheets or when emmet.showExpandedAbbreviation is set to \"never\".", + "emmetIncludeLanguages": "Enable Emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and emmet supported language.\n Eg: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Variables to be used in Emmet snippets", + "emmetTriggerExpansionOnTab": "When enabled, Emmet abbreviations are expanded when pressing TAB.", "emmetPreferences": "Preferences used to modify behavior of some actions and resolvers of Emmet.", "emmetPreferencesIntUnit": "Default unit for integer values", "emmetPreferencesFloatUnit": "Default unit for float values", @@ -39,10 +39,10 @@ "emmetPreferencesCssBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations", "emmetPreferencesSassBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Sass files", "emmetPreferencesStylusBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Stylus files", - "emmetShowSuggestionsAsSnippets": "If true, then emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.", - "emmetPreferencesBemElementSeparator": "Element separator used for classes when using the bem filter", - "emmetPreferencesBemModifierSeparator": "Modifier separator used for classes when using the bem filter", + "emmetShowSuggestionsAsSnippets": "If true, then Emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.", + "emmetPreferencesBemElementSeparator": "Element separator used for classes when using the BEM filter", + "emmetPreferencesBemModifierSeparator": "Modifier separator used for classes when using the BEM filter", "emmetPreferencesFilterCommentBefore": "A definition of comment that should be placed before matched element when comment filter is applied.", "emmetPreferencesFilterCommentAfter": "A definition of comment that should be placed after matched element when comment filter is applied.", "emmetPreferencesFilterCommentTrigger": "A comma-separated list of attribute names that should exist in abbreviation for the comment filter to be applied" -} \ No newline at end of file +} From 4b539d4d6474548b2ff28dd7e2aa3eb42ceb24d9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 09:25:23 +0200 Subject: [PATCH 224/303] :lipstick: --- src/vs/workbench/browser/labels.ts | 8 ++-- .../workbench/electron-browser/workbench.ts | 4 +- .../markers/browser/markersFileDecorations.ts | 8 ++-- .../electron-browser/scmFileDecorations.ts | 8 ++-- .../decorations/browser/decorations.ts | 14 +++---- .../decorations/browser/decorationsService.ts | 40 +++++++++---------- .../test/browser/decorationsService.test.ts | 20 +++++----- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 8a312fa3457..08a68da883c 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -20,7 +20,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IResourceDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; import { FileKind } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; @@ -53,7 +53,7 @@ export class ResourceLabel extends IconLabel { @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, @IEnvironmentService protected environmentService: IEnvironmentService, - @IResourceDecorationsService protected decorationsService: IResourceDecorationsService, + @IDecorationsService protected decorationsService: IDecorationsService, @IThemeService private themeService: IThemeService ) { super(container, options); @@ -183,7 +183,7 @@ export class ResourceLabel extends IconLabel { } if (this.options && this.options.fileDecorations) { - let deco = this.decorationsService.getTopDecoration( + let deco = this.decorationsService.getDecoration( resource, this.options.fileKind !== FileKind.FILE ); @@ -240,7 +240,7 @@ export class FileLabel extends ResourceLabel { @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IEnvironmentService environmentService: IEnvironmentService, - @IResourceDecorationsService decorationsService: IResourceDecorationsService, + @IDecorationsService decorationsService: IDecorationsService, @IThemeService themeService: IThemeService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, ) { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index c88d5d05d54..25ddf4ea5ef 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -97,7 +97,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; -import { IResourceDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import URI from 'vs/base/common/uri'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); @@ -585,7 +585,7 @@ export class Workbench implements IPartService { serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService)); // File Decorations - serviceCollection.set(IResourceDecorationsService, new SyncDescriptor(FileDecorationsService)); + serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService)); // SCM Service serviceCollection.set(ISCMService, new SyncDescriptor(SCMService)); diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 46f91a0b701..670e1db47da 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; -import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService, IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; @@ -29,7 +29,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { this.onDidChange = _markerService.onMarkerChanged; } - provideDecorations(resource: URI): IResourceDecorationData { + provideDecorations(resource: URI): IDecorationData { let markers = this._markerService.read({ resource }); let first: IMarker; for (const marker of markers) { @@ -59,7 +59,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { constructor( @IMarkerService private _markerService: IMarkerService, - @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, + @IDecorationsService private _decorationsService: IDecorationsService, @IConfigurationService private _configurationService: IConfigurationService ) { // @@ -86,7 +86,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { this._enabled = value.decorations.enabled; if (this._enabled) { const provider = new MarkersDecorationsProvider(this._markerService); - this._provider = this._decorationsService.registerDecortionsProvider(provider); + this._provider = this._decorationsService.registerDecorationsProvider(provider); } else if (this._provider) { this._enabled = value.decorations.enabled; this._provider.dispose(); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 97c1c66a212..ebfd9f55cd9 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -6,7 +6,7 @@ 'use strict'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IResourceDecorationsService, IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService, IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import URI from 'vs/base/common/uri'; @@ -60,7 +60,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { this._onDidChange.fire(uris); } - provideDecorations(uri: URI): IResourceDecorationData { + provideDecorations(uri: URI): IDecorationData { const resource = this._data.get(uri.toString()); if (!resource || !resource.decorations.color || !resource.decorations.tooltip) { return undefined; @@ -88,7 +88,7 @@ export class FileDecorations implements IWorkbenchContribution { private _currentConfig: ISCMConfiguration; constructor( - @IResourceDecorationsService private _decorationsService: IResourceDecorationsService, + @IDecorationsService private _decorationsService: IDecorationsService, @IConfigurationService private _configurationService: IConfigurationService, @ISCMService private _scmService: ISCMService, ) { @@ -127,7 +127,7 @@ export class FileDecorations implements IWorkbenchContribution { private _onDidAddRepository(repo: ISCMRepository): void { const provider = new SCMDecorationsProvider(repo.provider, this._configurationService.getConfiguration('scm')); - const registration = this._decorationsService.registerDecortionsProvider(provider); + const registration = this._decorationsService.registerDecorationsProvider(provider); this._providers.set(repo, combinedDisposable([registration, provider])); } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 110b0e39b2a..1c42c362433 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -10,9 +10,9 @@ import Event from 'vs/base/common/event'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; -export const IResourceDecorationsService = createDecorator('IFileDecorationsService'); +export const IDecorationsService = createDecorator('IFileDecorationsService'); -export interface IResourceDecorationData { +export interface IDecorationData { readonly weight?: number; readonly color?: ColorIdentifier; readonly opacity?: number; @@ -20,7 +20,7 @@ export interface IResourceDecorationData { readonly tooltip?: string; } -export interface IResourceDecoration { +export interface IDecoration { readonly _decoBrand: undefined; readonly weight?: number; readonly tooltip?: string; @@ -31,20 +31,20 @@ export interface IResourceDecoration { export interface IDecorationsProvider { readonly label: string; readonly onDidChange: Event; - provideDecorations(uri: URI): IResourceDecorationData | Thenable; + provideDecorations(uri: URI): IDecorationData | Thenable; } export interface IResourceDecorationChangeEvent { affectsResource(uri: URI): boolean; } -export interface IResourceDecorationsService { +export interface IDecorationsService { readonly _serviceBrand: any; readonly onDidChangeDecorations: Event; - registerDecortionsProvider(provider: IDecorationsProvider): IDisposable; + registerDecorationsProvider(provider: IDecorationsProvider): IDisposable; - getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration; + getDecoration(uri: URI, includeChildren: boolean): IDecoration; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 0203f93a682..522181bb4d9 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; -import { IResourceDecorationsService, IResourceDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IResourceDecorationData } from './decorations'; +import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; @@ -19,7 +19,7 @@ import { IIterator } from 'vs/base/common/iterator'; class DecorationRule { - static keyOf(data: IResourceDecorationData | IResourceDecorationData[]): string { + static keyOf(data: IDecorationData | IDecorationData[]): string { if (Array.isArray(data)) { return data.map(DecorationRule.keyOf).join(','); } else { @@ -30,11 +30,11 @@ class DecorationRule { private static readonly _classNames = new IdGenerator('monaco-decorations-style-'); - readonly data: IResourceDecorationData | IResourceDecorationData[]; + readonly data: IDecorationData | IDecorationData[]; readonly labelClassName: string; readonly badgeClassName: string; - constructor(data: IResourceDecorationData | IResourceDecorationData[]) { + constructor(data: IDecorationData | IDecorationData[]) { this.data = data; this.labelClassName = DecorationRule._classNames.nextId(); this.badgeClassName = DecorationRule._classNames.nextId(); @@ -48,7 +48,7 @@ class DecorationRule { } } - private _appendForOne(data: IResourceDecorationData, element: HTMLStyleElement, theme: ITheme): void { + private _appendForOne(data: IDecorationData, element: HTMLStyleElement, theme: ITheme): void { const { color, opacity, letter } = data; // label createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); @@ -60,7 +60,7 @@ class DecorationRule { } } - private _appendForMany(data: IResourceDecorationData[], element: HTMLStyleElement, theme: ITheme): void { + private _appendForMany(data: IDecorationData[], element: HTMLStyleElement, theme: ITheme): void { // label const { color, opacity } = data[0]; createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); @@ -87,9 +87,9 @@ class DecorationRule { } } -class ResourceDecoration implements IResourceDecoration { +class ResourceDecoration implements IDecoration { - static from(data: IResourceDecorationData | IResourceDecorationData[]): ResourceDecoration { + static from(data: IDecorationData | IDecorationData[]): ResourceDecoration { let result = new ResourceDecoration(data); if (Array.isArray(data)) { result.weight = data[0].weight; @@ -102,14 +102,14 @@ class ResourceDecoration implements IResourceDecoration { } _decoBrand: undefined; - _data: IResourceDecorationData | IResourceDecorationData[]; + _data: IDecorationData | IDecorationData[]; weight?: number; tooltip?: string; labelClassName?: string; badgeClassName?: string; - private constructor(data: IResourceDecorationData | IResourceDecorationData[]) { + private constructor(data: IDecorationData | IDecorationData[]) { this._data = data; } } @@ -133,7 +133,7 @@ class DecorationStyles { this._styleElement.parentElement.removeChild(this._styleElement); } - asDecoration(data: IResourceDecorationData | IResourceDecorationData[]): ResourceDecoration { + asDecoration(data: IDecorationData | IDecorationData[]): ResourceDecoration { let key = DecorationRule.keyOf(data); let rule = this._decorationRules.get(key); let result = ResourceDecoration.from(data); @@ -160,7 +160,7 @@ class DecorationStyles { cleanUp(iter: IIterator): void { // remove every rule for which no more // decoration (data) is kept. this isn't cheap - let usedDecorations = new Set(); + let usedDecorations = new Set(); for (let e = iter.next(); !e.done; e = iter.next()) { e.value.data.forEach(value => { if (value instanceof ResourceDecoration) { @@ -216,7 +216,7 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { class DecorationProviderWrapper { - readonly data = TernarySearchTree.forPaths | IResourceDecorationData>(); + readonly data = TernarySearchTree.forPaths | IDecorationData>(); private readonly _dispoable: IDisposable; constructor( @@ -240,7 +240,7 @@ class DecorationProviderWrapper { return Boolean(this.data.get(uri.toString())) || Boolean(this.data.findSuperstr(uri.toString())); } - getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IResourceDecorationData, isChild: boolean) => void): void { + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IDecorationData, isChild: boolean) => void): void { const key = uri.toString(); let item = this.data.get(key); @@ -271,7 +271,7 @@ class DecorationProviderWrapper { } } - private _fetchData(uri: URI): IResourceDecorationData { + private _fetchData(uri: URI): IDecorationData { const dataOrThenable = this._provider.provideDecorations(uri); if (!isThenable(dataOrThenable)) { @@ -289,7 +289,7 @@ class DecorationProviderWrapper { } } - private _keepItem(uri: URI, data: IResourceDecorationData): IResourceDecorationData { + private _keepItem(uri: URI, data: IDecorationData): IDecorationData { let deco = data ? data : null; this.data.set(uri.toString(), deco); this._emitter.fire(uri); @@ -297,7 +297,7 @@ class DecorationProviderWrapper { } } -export class FileDecorationsService implements IResourceDecorationsService { +export class FileDecorationsService implements IDecorationsService { _serviceBrand: any; @@ -340,7 +340,7 @@ export class FileDecorationsService implements IResourceDecorationsService { dispose(this._disposables); } - registerDecortionsProvider(provider: IDecorationsProvider): IDisposable { + registerDecorationsProvider(provider: IDecorationsProvider): IDisposable { const wrapper = new DecorationProviderWrapper( provider, @@ -358,8 +358,8 @@ export class FileDecorationsService implements IResourceDecorationsService { }; } - getTopDecoration(uri: URI, includeChildren: boolean): IResourceDecoration { - let data: IResourceDecorationData[] = []; + getDecoration(uri: URI, includeChildren: boolean): IDecoration { + let data: IDecorationData[] = []; let onlyChildren = true; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index d1611916273..8135a7eceac 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; -import { IDecorationsProvider, IResourceDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import URI from 'vs/base/common/uri'; import Event, { toPromise } from 'vs/base/common/event'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; @@ -28,12 +28,12 @@ suite('DecorationsService', function () { let uri = URI.parse('foo:bar'); let callCounter = 0; - service.registerDecortionsProvider(new class implements IDecorationsProvider { + service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => resolve({ color: 'someBlue', tooltip: 'T' @@ -43,7 +43,7 @@ suite('DecorationsService', function () { }); // trigger -> async - assert.equal(service.getTopDecoration(uri, false), undefined); + assert.equal(service.getDecoration(uri, false), undefined); assert.equal(callCounter, 1); // event when result is computed @@ -51,7 +51,7 @@ suite('DecorationsService', function () { assert.equal(e.affectsResource(uri), true); // sync result - assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'T'); + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'T'); assert.equal(callCounter, 1); }); }); @@ -61,7 +61,7 @@ suite('DecorationsService', function () { let uri = URI.parse('foo:bar'); let callCounter = 0; - service.registerDecortionsProvider(new class implements IDecorationsProvider { + service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { @@ -71,7 +71,7 @@ suite('DecorationsService', function () { }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'Z'); + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'Z'); assert.equal(callCounter, 1); }); @@ -79,7 +79,7 @@ suite('DecorationsService', function () { let uri = URI.parse('foo:bar'); let callCounter = 0; - let reg = service.registerDecortionsProvider(new class implements IDecorationsProvider { + let reg = service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { @@ -89,14 +89,14 @@ suite('DecorationsService', function () { }); // trigger -> sync - assert.deepEqual(service.getTopDecoration(uri, false).tooltip, 'J'); + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'J'); assert.equal(callCounter, 1); // un-register -> ensure good event let didSeeEvent = false; service.onDidChangeDecorations(e => { assert.equal(e.affectsResource(uri), true); - assert.deepEqual(service.getTopDecoration(uri, false), undefined); + assert.deepEqual(service.getDecoration(uri, false), undefined); assert.equal(callCounter, 1); didSeeEvent = true; }); From e8cea009a55dc19b27268573bf3e935747a1c650 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 10:40:10 +0200 Subject: [PATCH 225/303] fix #33526 --- src/vs/platform/quickOpen/common/quickOpen.ts | 1 + .../parts/quickopen/quickOpenController.ts | 20 +++--- .../parts/files/browser/fileActions.ts | 71 ++++++------------- 3 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/vs/platform/quickOpen/common/quickOpen.ts b/src/vs/platform/quickOpen/common/quickOpen.ts index c0611d3dde4..0b3bf170855 100644 --- a/src/vs/platform/quickOpen/common/quickOpen.ts +++ b/src/vs/platform/quickOpen/common/quickOpen.ts @@ -123,6 +123,7 @@ export interface IInputOptions { export interface IShowOptions { quickNavigateConfiguration?: IQuickNavigateConfiguration; inputSelection?: { start: number; end: number; }; + autoFocus?: IAutoFocus; } export const IQuickOpenService = createDecorator('quickOpenService'); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 00bd2d8d83a..2f178d70c51 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -545,6 +545,7 @@ export class QuickOpenController extends Component implements IQuickOpenService public show(prefix?: string, options?: IShowOptions): TPromise { let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : void 0; let inputSelection = options ? options.inputSelection : void 0; + let autoFocus = options ? options.autoFocus : void 0; this.previousValue = prefix; @@ -565,8 +566,7 @@ export class QuickOpenController extends Component implements IQuickOpenService this.telemetryService.publicLog('quickOpenWidgetShown', { mode: handlerDescriptor.getId(), quickNavigate: quickNavigateConfiguration }); // Trigger onOpen - this.resolveHandler(handlerDescriptor) - .done(null, errors.onUnexpectedError); + this.resolveHandler(handlerDescriptor).done(null, errors.onUnexpectedError); // Create upon first open if (!this.quickOpenWidget) { @@ -601,19 +601,21 @@ export class QuickOpenController extends Component implements IQuickOpenService // Show quick open with prefix or editor history if (!this.quickOpenWidget.isVisible() || quickNavigateConfiguration) { if (prefix) { - this.quickOpenWidget.show(prefix, { quickNavigateConfiguration, inputSelection }); + this.quickOpenWidget.show(prefix, { quickNavigateConfiguration, inputSelection, autoFocus }); } else { const editorHistory = this.getEditorHistoryWithGroupLabel(); if (editorHistory.getEntries().length < 2) { quickNavigateConfiguration = null; // If no entries can be shown, default to normal quick open mode } - let autoFocus: IAutoFocus; - if (!quickNavigateConfiguration) { - autoFocus = { autoFocusFirstEntry: true }; - } else { - const visibleEditorCount = this.editorService.getVisibleEditors().length; - autoFocus = { autoFocusFirstEntry: visibleEditorCount === 0, autoFocusSecondEntry: visibleEditorCount !== 0 }; + // Compute auto focus + if (!autoFocus) { + if (!quickNavigateConfiguration) { + autoFocus = { autoFocusFirstEntry: true }; + } else { + const visibleEditorCount = this.editorService.getVisibleEditors().length; + autoFocus = { autoFocusFirstEntry: visibleEditorCount === 0, autoFocusSecondEntry: visibleEditorCount !== 0 }; + } } // Update context diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 8f9afccbafe..6975b962704 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -27,7 +27,7 @@ import { VIEWLET_ID, FileOnDiskContentProvider } from 'vs/workbench/parts/files/ import labels = require('vs/base/common/labels'); import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService, IFileStat } from 'vs/platform/files/common/files'; -import { toResource, IEditorIdentifier, EditorInput } from 'vs/workbench/common/editor'; +import { toResource, IEditorIdentifier } from 'vs/workbench/common/editor'; import { FileStat, Model, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerModel'; import { ExplorerView } from 'vs/workbench/parts/files/browser/views/explorerView'; import { ExplorerViewlet } from 'vs/workbench/parts/files/browser/explorerViewlet'; @@ -35,10 +35,9 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CollapseAction } from 'vs/workbench/browser/viewlet'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IQuickOpenService, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { Position, IResourceInput, IEditorInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; +import { Position, IResourceInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature2, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -52,6 +51,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { once } from 'vs/base/common/event'; export interface IEditableData { action: IAction; @@ -1197,12 +1197,9 @@ export class GlobalCompareResourcesAction extends Action { id: string, label: string, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IHistoryService private historyService: IHistoryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEditorGroupService private editorGroupService: IEditorGroupService ) { super(id, label); } @@ -1212,50 +1209,22 @@ export class GlobalCompareResourcesAction extends Action { const activeResource = activeInput ? activeInput.getResource() : void 0; if (activeResource) { - // Keep as resource to compare - globalResourceToCompare = activeResource; - - // Pick another entry from history - interface IHistoryPickEntry extends IFilePickOpenEntry { - input: IEditorInput | IResourceInput; - } - - const history = this.historyService.getHistory(); - const picks: IHistoryPickEntry[] = history.map(input => { - let resource: URI; - let label: string; - let description: string; - - if (input instanceof EditorInput) { - resource = input.getResource(); - } else { - resource = (input as IResourceInput).resource; + // Compare with next editor that opens + const unbind = once(this.editorGroupService.onEditorOpening)(e => { + const resource = e.input.getResource(); + if (resource) { + e.prevent(() => { + return this.editorService.openEditor({ + leftResource: activeResource, + rightResource: resource + }); + }); } + }); - // Cannot compare file with self - exclude active file - if (!!resource && resource.toString() === globalResourceToCompare.toString()) { - return void 0; - } - - if (!resource) { - return void 0; // only support to compare with files and untitled - } - - label = paths.basename(resource.fsPath); - description = labels.getPathLabel(resources.dirname(resource), this.contextService, this.environmentService); - - return { input, resource, label, description }; - }).filter(p => !!p); - - return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickHistory', "Select a previously opened file to compare with"), autoFocus: { autoFocusFirstEntry: true }, matchOnDescription: true }).then(pick => { - if (pick) { - const compareAction = this.instantiationService.createInstance(CompareResourcesAction, pick.resource, null); - if (compareAction._isEnabled()) { - compareAction.run().done(() => compareAction.dispose()); - } else { - this.messageService.show(Severity.Info, nls.localize('unableToFileToCompare', "The selected file can not be compared with '{0}'.", paths.basename(globalResourceToCompare.fsPath))); - } - } + // Bring up quick open + this.quickOpenService.show('', { autoFocus: { autoFocusSecondEntry: true } }).then(() => { + unbind.dispose(); // make sure to unbind if quick open is closing }); } else { this.messageService.show(Severity.Info, nls.localize('openFileToCompare', "Open a file first to compare it with another file.")); @@ -1305,7 +1274,7 @@ export class CompareResourcesAction extends Action { return nls.localize('compareFiles', "Compare Files"); } - _isEnabled(): boolean { + public _isEnabled(): boolean { // Need at least a resource to compare if (!globalResourceToCompare) { From 46075929b2f273f6339ce9659cb58fd29a7acf1d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 10:48:33 +0200 Subject: [PATCH 226/303] fix #35765 --- npm-shrinkwrap.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index dd103542200..a801e584465 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -566,6 +566,16 @@ "from": "winreg@1.2.0", "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz" }, + "windows-foreground-love": { + "version": "0.1.0", + "from": "windows-foreground-love@0.1.0", + "resolved": "https://registry.npmjs.org/windows-foreground-love/-/windows-foreground-love-0.1.0.tgz" + }, + "windows-mutex": { + "version": "0.2.0", + "from": "windows-mutex@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/windows-mutex/-/windows-mutex-0.2.0.tgz" + }, "windows-process-tree": { "version": "0.1.6", "from": "windows-process-tree@0.1.6", @@ -582,4 +592,4 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz" } } -} +} \ No newline at end of file From 60a493cdc2ebaba842f229563842625054f0e6c2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 10:54:36 +0200 Subject: [PATCH 227/303] Tests for configuration change event --- .../configuration/common/configuration.ts | 5 +- .../common/configurationModels.ts | 93 ++++++++------ .../test/common/configurationModels.test.ts | 116 +++++++++++++++++- 3 files changed, 171 insertions(+), 43 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 8a1daa65929..16e5736bd3f 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -31,10 +31,7 @@ export enum ConfigurationTarget { export interface IConfigurationChangeEvent { affectedKeys: string[]; - affectsConfiugration(configuration: string): boolean; - affectsConfiugration(configuration: string, overrideIdentifier: string): boolean; - affectsConfiugration(configuration: string, resource: URI): boolean; - affectsConfiugration(configuration: string, overrideIdentifier: string, resource: URI): boolean; + affectsConfiugration(configuration: string, resource?: URI): boolean; // Following data is used for telemetry source: ConfigurationTarget; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 7acaca42472..be314db0f04 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -455,15 +455,47 @@ export class Configuration { } } -export class AllKeysConfigurationChangeEvent implements IConfigurationChangeEvent { +export class AbstractConfigurationChangeEvent { - constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { } + protected doesConfigurationContains(configuration: ConfigurationModel, config: string): boolean { + let changedKeysTree = configuration.contents; + let requestedTree = toValuesTree({ [config]: true }, () => { }); - affectsConfiugration: () => true; + let key; + while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property + changedKeysTree = changedKeysTree[key]; + if (!changedKeysTree) { + return false; // Requested tree is not found + } + requestedTree = requestedTree[key]; + } + return true; + } + + protected updateKeys(configuration: ConfigurationModel, keys: string[], resource?: URI): void { + for (const key of keys) { + configuration.setValue(key, true); + } + } +} + +export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { + + private changedConfiguration: ConfigurationModel = null; + + constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); } + + affectsConfiugration(config: string, resource?: URI): boolean { + if (!this.changedConfiguration) { + this.changedConfiguration = new ConfigurationModel(); + this.updateKeys(this.changedConfiguration, this.affectedKeys); + } + return this.doesConfigurationContains(this.changedConfiguration, config); + } } -export class ConfigurationChangeEvent implements IConfigurationChangeEvent { +export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { private changedConfiguration: ConfigurationModel = new ConfigurationModel(); private changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); @@ -483,7 +515,8 @@ export class ConfigurationChangeEvent implements IConfigurationChangeEvent { this.changedConfigurationByResource.set(resource, changedConfigurationByResource); } } - return this.changeWithKeys(arg1, arg2); + this.changeWithKeys(arg1, arg2); + return this; } telemetryData(source: ConfigurationTarget, sourceConfig: any): ConfigurationChangeEvent { @@ -506,46 +539,30 @@ export class ConfigurationChangeEvent implements IConfigurationChangeEvent { return this._sourceConfig; } - affectsConfiugration(config: string): boolean - affectsConfiugration(config: string, overrideIdentifier: string): boolean - affectsConfiugration(config: string, resource: URI): boolean - affectsConfiugration(config: string, overrideIdentifier: string, resource: URI): boolean - affectsConfiugration(config: string, arg1?: any, arg2?: any): boolean { - let resource = arg1 instanceof URI ? arg1 : arg2 instanceof URI ? arg2 : void 0; - let overrideIdentifier = resource && arg1 !== resource ? arg1 : void 0; - let model = resource ? this.changedConfigurationByResource.get(resource) : this.changedConfiguration; - if (model) { + affectsConfiugration(config: string, resource?: URI): boolean { + let configurationModelsToSearch: ConfigurationModel[] = [this.changedConfiguration]; - if (overrideIdentifier) { - return model.overrides.some(override => override.identifiers.indexOf(overrideIdentifier) !== -1); + if (resource) { + let model = this.changedConfigurationByResource.get(resource); + if (model) { + configurationModelsToSearch.push(model); } - - let changedKeysTree = model.contents; - let requestedTree = toValuesTree({ [config]: true }, () => { }); - - let key; - while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property - changedKeysTree = changedKeysTree[key]; - if (!changedKeysTree) { - return false; // Requested tree is not found - } - requestedTree = requestedTree[key]; - } - return true; + } else { + configurationModelsToSearch.push(...this.changedConfigurationByResource.values()); } + + for (const configuration of configurationModelsToSearch) { + if (this.doesConfigurationContains(configuration, config)) { + return true; + } + } + return false; } - private changeWithKeys(keys: string[], resource?: URI): ConfigurationChangeEvent { + private changeWithKeys(keys: string[], resource?: URI): void { let changedConfiguration = resource ? this.getOrSetChangedConfigurationForResource(resource) : this.changedConfiguration; - for (const key of keys) { - if (OVERRIDE_PROPERTY_PATTERN.test(key)) { - changedConfiguration.setValueInOverrides(overrideIdentifierFromKey(key), 'key'/* any key */, true); - } else { - changedConfiguration.setValue(key, true); - } - } - return this; + this.updateKeys(changedConfiguration, keys); } private getOrSetChangedConfigurationForResource(resource: URI): ConfigurationModel { diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts index b4cc2a1d476..294b9d0e69e 100644 --- a/src/vs/platform/configuration/test/common/configurationModels.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -5,9 +5,11 @@ 'use strict'; import * as assert from 'assert'; -import { ConfigurationModel, CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { ConfigurationModel, CustomConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; +import URI from 'vs/base/common/uri'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('ConfigurationModel', () => { @@ -396,4 +398,116 @@ suite('CustomConfigurationModel', () => { assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]')); }); +}); + +suite('ConfigurationChangeEvent', () => { + + test('changeEvent affecting keys for all resources', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); + + assert.deepEqual(testObject.affectedKeys, ['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); + assert.ok(testObject.affectsConfiugration('window.zoomLevel')); + assert.ok(testObject.affectsConfiugration('window')); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiugration('workbench.editor')); + assert.ok(testObject.affectsConfiugration('workbench')); + assert.ok(testObject.affectsConfiugration('files')); + assert.ok(!testObject.affectsConfiugration('files.exclude')); + assert.ok(testObject.affectsConfiugration('[markdown]')); + }); + + test('changeEvent affecting keys for resources', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['window.title']); + testObject.change(['window.zoomLevel'], URI.file('file1')); + testObject.change(['workbench.editor.enablePreview'], URI.file('file2')); + testObject.change(['window.restoreFullscreen'], URI.file('file1')); + testObject.change(['window.restoreWindows'], URI.file('file2')); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + + assert.ok(testObject.affectsConfiugration('window.zoomLevel')); + assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window.restoreWindows')); + assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('window.title')); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window')); + assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor')); + assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('workbench')); + assert.ok(testObject.affectsConfiugration('workbench', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('workbench', URI.file('file1'))); + + assert.ok(!testObject.affectsConfiugration('files')); + assert.ok(!testObject.affectsConfiugration('files', URI.file('file1'))); + assert.ok(!testObject.affectsConfiugration('files', URI.file('file2'))); + }); + +}); + +suite('AllKeysConfigurationChangeEvent', () => { + + test('changeEvent affects keys for any resource', () => { + let testObject = new AllKeysConfigurationChangeEvent(['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows'], ConfigurationTarget.USER, null); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + + assert.ok(testObject.affectsConfiugration('window.zoomLevel')); + assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window.restoreWindows')); + assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('window.title')); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('window')); + assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor')); + assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file1'))); + + assert.ok(testObject.affectsConfiugration('workbench')); + assert.ok(testObject.affectsConfiugration('workbench', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('workbench', URI.file('file1'))); + + assert.ok(!testObject.affectsConfiugration('files')); + assert.ok(!testObject.affectsConfiugration('files', URI.file('file1'))); + }); }); \ No newline at end of file From 9927869cc86ba2307687a124b673dac86d17f7cc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 10:56:27 +0200 Subject: [PATCH 228/303] Fix workspace configuration change event --- .../common/configurationModels.ts | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index b4518c06965..91366479302 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -268,33 +268,21 @@ export class Configuration extends BaseConfiguration { } } -export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { +export class WorkspaceConfigurationChangeEvent extends ConfigurationChangeEvent implements IConfigurationChangeEvent { - constructor(private configurationChangeEvent: ConfigurationChangeEvent, private workspace: Workspace) { + constructor(private workspace: Workspace) { + super(); } - get affectedKeys(): string[] { - return this.configurationChangeEvent.affectedKeys; - } - - get source(): ConfigurationTarget { - return this.configurationChangeEvent.source; - } - - get sourceConfig(): any { - return this.configurationChangeEvent.sourceConfig; - } - - affectsConfiugration(config: string, arg1?: any, arg2?: any): boolean { - if (this.configurationChangeEvent.affectsConfiugration(config, arg1, arg2)) { + affectsConfiugration(config: string, resource?: URI): boolean { + if (super.affectsConfiugration(config, resource)) { return true; } - let resource = arg1 instanceof URI ? arg1 : arg2 instanceof URI ? arg2 : void 0; if (resource) { let workspaceFolder = this.workspace.getFolder(resource); if (workspaceFolder) { - return this.configurationChangeEvent.affectsConfiugration(config, resource && arg1 !== resource ? arg1 : void 0, resource); + return super.affectsConfiugration(config, resource); } } From 8b18ddadf1200dd7ef26a35dfe0e3918c4e05df8 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 11:00:03 +0200 Subject: [PATCH 229/303] move CompositeBar into workbench/parts/compositebar --- src/vs/workbench/browser/parts/activitybar/activitybarPart.ts | 2 +- .../workbench/browser/{ => parts/compositebar}/compositeBar.ts | 2 +- .../browser/{ => parts/compositebar}/compositeBarActions.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/workbench/browser/{ => parts/compositebar}/compositeBar.ts (99%) rename src/vs/workbench/browser/{ => parts/compositebar}/compositeBarActions.ts (100%) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 2130ea88179..857847afc19 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -29,7 +29,7 @@ import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { CompositeBar } from 'vs/workbench/browser/compositeBar'; +import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar'; export class ActivitybarPart extends Part implements IActivityBarService { diff --git a/src/vs/workbench/browser/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts similarity index 99% rename from src/vs/workbench/browser/compositeBar.ts rename to src/vs/workbench/browser/parts/compositebar/compositeBar.ts index 5320747811c..ec5f8f3e640 100644 --- a/src/vs/workbench/browser/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -21,7 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import Event, { Emitter } from 'vs/base/common/event'; -import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem } from 'vs/workbench/browser/compositeBarActions'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; export interface ICompositeBarOptions { label: 'icon' | 'name'; diff --git a/src/vs/workbench/browser/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts similarity index 100% rename from src/vs/workbench/browser/compositeBarActions.ts rename to src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts From 12fa7c85e29a70285a044d5cae973172d4947b53 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 11:07:57 +0200 Subject: [PATCH 230/303] move ActivityActinos into compositeBarActions.ts --- .../parts/activitybar/activitybarActions.ts | 214 +---------------- .../parts/compositebar/compositeBar.ts | 3 +- .../parts/compositebar/compositeBarActions.ts | 217 +++++++++++++++++- 3 files changed, 216 insertions(+), 218 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 69b532ccb46..b20d15c85cb 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -9,11 +9,8 @@ import 'vs/css!./media/activityaction'; import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); import { TPromise } from 'vs/base/common/winjs.base'; -import { Builder, $ } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; -import { BaseActionItem, IBaseActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IActivityBarService, ProgressBadge, TextBadge, NumberBadge, IconBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; -import Event, { Emitter } from 'vs/base/common/event'; +import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; @@ -21,51 +18,11 @@ import { dispose } from 'vs/base/common/lifecycle'; import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; -import { contrastBorder, activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; - -export class ActivityAction extends Action { - private badge: IBadge; - private _onDidChangeBadge = new Emitter(); - - constructor(private _activity: IActivity) { - super(_activity.id, _activity.name, _activity.cssClass); - - this.badge = null; - } - - public get activity(): IActivity { - return this._activity; - } - - public get onDidChangeBadge(): Event { - return this._onDidChangeBadge.event; - } - - public activate(): void { - if (!this.checked) { - this._setChecked(true); - } - } - - public deactivate(): void { - if (this.checked) { - this._setChecked(false); - } - } - - public getBadge(): IBadge { - return this.badge; - } - - public setBadge(badge: IBadge): void { - this.badge = badge; - this._onDidChangeBadge.fire(this); - } -} +import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; export class ViewletActivityAction extends ActivityAction { @@ -105,171 +62,6 @@ export class ViewletActivityAction extends ActivityAction { } } -export class ActivityActionItem extends BaseActionItem { - protected $container: Builder; - protected $label: Builder; - protected $badge: Builder; - - private $badgeContent: Builder; - private mouseUpTimeout: number; - - constructor( - action: ActivityAction, - options: IBaseActionItemOptions, - @IThemeService protected themeService: IThemeService - ) { - super(null, action, options); - - this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); - action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose); - } - - protected get activity(): IActivity { - return (this._action as ActivityAction).activity; - } - - protected updateStyles(): void { - const theme = this.themeService.getTheme(); - - // Label - if (this.$label) { - const background = theme.getColor(ACTIVITY_BAR_FOREGROUND); - - this.$label.style('background-color', background ? background.toString() : null); - } - - // Badge - if (this.$badgeContent) { - const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND); - const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND); - const contrastBorderColor = theme.getColor(contrastBorder); - - this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null); - this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null); - - this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null); - this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null); - this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null); - } - } - - public render(container: HTMLElement): void { - super.render(container); - - // Make the container tab-able for keyboard navigation - this.$container = $(container).attr({ - tabIndex: '0', - role: 'button', - title: this.activity.name - }); - - // Try hard to prevent keyboard only focus feedback when using mouse - this.$container.on(DOM.EventType.MOUSE_DOWN, () => { - this.$container.addClass('clicked'); - }); - - this.$container.on(DOM.EventType.MOUSE_UP, () => { - if (this.mouseUpTimeout) { - clearTimeout(this.mouseUpTimeout); - } - - this.mouseUpTimeout = setTimeout(() => { - this.$container.removeClass('clicked'); - }, 800); // delayed to prevent focus feedback from showing on mouse up - }); - - // Label - this.$label = $('a.action-label').appendTo(this.builder); - if (this.activity.cssClass) { - this.$label.addClass(this.activity.cssClass); - } - - this.$badge = this.builder.clone().div({ 'class': 'badge' }, (badge: Builder) => { - this.$badgeContent = badge.div({ 'class': 'badge-content' }); - }); - - this.$badge.hide(); - - this.updateStyles(); - } - - private onThemeChange(theme: ITheme): void { - this.updateStyles(); - } - - public setBadge(badge: IBadge): void { - this.updateBadge(badge); - } - - protected updateBadge(badge: IBadge): void { - this.$badgeContent.empty(); - this.$badge.hide(); - - if (badge) { - - // Number - if (badge instanceof NumberBadge) { - if (badge.number) { - this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString()); - this.$badge.show(); - } - } - - // Text - else if (badge instanceof TextBadge) { - this.$badgeContent.text(badge.text); - this.$badge.show(); - } - - // Text - else if (badge instanceof IconBadge) { - this.$badge.show(); - } - - // Progress - else if (badge instanceof ProgressBadge) { - this.$badge.show(); - } - } - - // Title - let title: string; - if (badge && badge.getDescription()) { - if (this.activity.name) { - title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); - } else { - title = badge.getDescription(); - } - } else { - title = this.activity.name; - } - - [this.$label, this.$badge, this.$container].forEach(b => { - if (b) { - b.attr('aria-label', title); - b.title(title); - } - }); - } - - private handleBadgeChangeEvenet(): void { - const action = this.getAction(); - if (action instanceof ActivityAction) { - this.updateBadge(action.getBadge()); - } - } - - public dispose(): void { - super.dispose(); - - if (this.mouseUpTimeout) { - clearTimeout(this.mouseUpTimeout); - } - - this.$badge.destroy(); - } -} - export class OpenViewletAction extends Action { constructor( diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index ec5f8f3e640..18b83e8938e 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -18,10 +18,9 @@ import { IBadge } from 'vs/workbench/services/activity/common/activityBarService import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import Event, { Emitter } from 'vs/base/common/event'; -import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; export interface ICompositeBarOptions { label: 'icon' | 'name'; diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts index 6b0986b6b0f..184dd5ae36e 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts @@ -9,24 +9,231 @@ import nls = require('vs/nls'); import { Action } from 'vs/base/common/actions'; import { TPromise } from 'vs/base/common/winjs.base'; import * as dom from 'vs/base/browser/dom'; +import { Builder, $ } from 'vs/base/browser/builder'; +import { BaseActionItem, IBaseActionItemOptions, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { dispose } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IActivityBarService, TextBadge, NumberBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; +import { IActivityBarService, TextBadge, NumberBadge, IBadge, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; -import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; +import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { IActivity } from 'vs/workbench/common/activity'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import Event, { Emitter } from 'vs/base/common/event'; export interface ICompositeActivity { badge: IBadge; clazz: string; } +export class ActivityAction extends Action { + private badge: IBadge; + private _onDidChangeBadge = new Emitter(); + + constructor(private _activity: IActivity) { + super(_activity.id, _activity.name, _activity.cssClass); + + this.badge = null; + } + + public get activity(): IActivity { + return this._activity; + } + + public get onDidChangeBadge(): Event { + return this._onDidChangeBadge.event; + } + + public activate(): void { + if (!this.checked) { + this._setChecked(true); + } + } + + public deactivate(): void { + if (this.checked) { + this._setChecked(false); + } + } + + public getBadge(): IBadge { + return this.badge; + } + + public setBadge(badge: IBadge): void { + this.badge = badge; + this._onDidChangeBadge.fire(this); + } +} + +export class ActivityActionItem extends BaseActionItem { + protected $container: Builder; + protected $label: Builder; + protected $badge: Builder; + + private $badgeContent: Builder; + private mouseUpTimeout: number; + + constructor( + action: ActivityAction, + options: IBaseActionItemOptions, + @IThemeService protected themeService: IThemeService + ) { + super(null, action, options); + + this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); + action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose); + } + + protected get activity(): IActivity { + return (this._action as ActivityAction).activity; + } + + protected updateStyles(): void { + const theme = this.themeService.getTheme(); + + // Label + if (this.$label) { + const background = theme.getColor(ACTIVITY_BAR_FOREGROUND); + + this.$label.style('background-color', background ? background.toString() : null); + } + + // Badge + if (this.$badgeContent) { + const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND); + const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND); + const contrastBorderColor = theme.getColor(contrastBorder); + + this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null); + this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null); + + this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null); + this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null); + this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null); + } + } + + public render(container: HTMLElement): void { + super.render(container); + + // Make the container tab-able for keyboard navigation + this.$container = $(container).attr({ + tabIndex: '0', + role: 'button', + title: this.activity.name + }); + + // Try hard to prevent keyboard only focus feedback when using mouse + this.$container.on(dom.EventType.MOUSE_DOWN, () => { + this.$container.addClass('clicked'); + }); + + this.$container.on(dom.EventType.MOUSE_UP, () => { + if (this.mouseUpTimeout) { + clearTimeout(this.mouseUpTimeout); + } + + this.mouseUpTimeout = setTimeout(() => { + this.$container.removeClass('clicked'); + }, 800); // delayed to prevent focus feedback from showing on mouse up + }); + + // Label + this.$label = $('a.action-label').appendTo(this.builder); + if (this.activity.cssClass) { + this.$label.addClass(this.activity.cssClass); + } + + this.$badge = this.builder.clone().div({ 'class': 'badge' }, (badge: Builder) => { + this.$badgeContent = badge.div({ 'class': 'badge-content' }); + }); + + this.$badge.hide(); + + this.updateStyles(); + } + + private onThemeChange(theme: ITheme): void { + this.updateStyles(); + } + + public setBadge(badge: IBadge): void { + this.updateBadge(badge); + } + + protected updateBadge(badge: IBadge): void { + this.$badgeContent.empty(); + this.$badge.hide(); + + if (badge) { + + // Number + if (badge instanceof NumberBadge) { + if (badge.number) { + this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString()); + this.$badge.show(); + } + } + + // Text + else if (badge instanceof TextBadge) { + this.$badgeContent.text(badge.text); + this.$badge.show(); + } + + // Text + else if (badge instanceof IconBadge) { + this.$badge.show(); + } + + // Progress + else if (badge instanceof ProgressBadge) { + this.$badge.show(); + } + } + + // Title + let title: string; + if (badge && badge.getDescription()) { + if (this.activity.name) { + title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); + } else { + title = badge.getDescription(); + } + } else { + title = this.activity.name; + } + + [this.$label, this.$badge, this.$container].forEach(b => { + if (b) { + b.attr('aria-label', title); + b.title(title); + } + }); + } + + private handleBadgeChangeEvenet(): void { + const action = this.getAction(); + if (action instanceof ActivityAction) { + this.updateBadge(action.getBadge()); + } + } + + public dispose(): void { + super.dispose(); + + if (this.mouseUpTimeout) { + clearTimeout(this.mouseUpTimeout); + } + + this.$badge.destroy(); + } +} + export class CompositeOverflowActivityAction extends ActivityAction { constructor( From 1a87d359d7e0e10dd93f662287f30efba5a6161f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:12:26 +0200 Subject: [PATCH 231/303] tests for workspace configuration change event --- .../common/configurationModels.ts | 2 +- .../test/common/configurationModels.test.ts | 97 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 91366479302..48506da5b83 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -282,7 +282,7 @@ export class WorkspaceConfigurationChangeEvent extends ConfigurationChangeEvent if (resource) { let workspaceFolder = this.workspace.getFolder(resource); if (workspaceFolder) { - return super.affectsConfiugration(config, resource); + return super.affectsConfiugration(config, workspaceFolder.uri); } } diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index 14e684e145e..90091e4f0c1 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -5,8 +5,11 @@ 'use strict'; import * as assert from 'assert'; -import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels'; +import { join } from 'vs/base/common/paths'; +import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; suite('ConfigurationService - Model', () => { @@ -94,4 +97,96 @@ suite('ConfigurationService - Model', () => { assert.deepEqual(new FolderConfigurationModel(settingsConfig, [launchConfig, tasksConfig], ConfigurationScope.WINDOW).contents, expected); assert.deepEqual(new FolderConfigurationModel(settingsConfig, [tasksConfig, launchConfig], ConfigurationScope.WINDOW).contents, expected); }); +}); + +suite('WorkspaceConfigurationChangeEvent', () => { + + test('changeEvent affecting workspace folders', () => { + let testObject = new WorkspaceConfigurationChangeEvent(new Workspace('id', 'name', + [new WorkspaceFolder({ index: 0, name: '1', uri: URI.file('folder1') }), + new WorkspaceFolder({ index: 1, name: '2', uri: URI.file('folder2') }), + new WorkspaceFolder({ index: 2, name: '3', uri: URI.file('folder3') })])); + + testObject.change(['window.title']); + testObject.change(['window.zoomLevel'], URI.file('folder1')); + testObject.change(['workbench.editor.enablePreview'], URI.file('folder2')); + testObject.change(['window.restoreFullscreen'], URI.file('folder1')); + testObject.change(['window.restoreWindows'], URI.file('folder2')); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + + assert.ok(testObject.affectsConfiugration('window.zoomLevel')); + assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('folder1'))); + assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiugration('window.restoreWindows')); + assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiugration('window.title')); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder1'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder3'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('window.title', URI.file('file3'))); + + assert.ok(testObject.affectsConfiugration('window')); + assert.ok(testObject.affectsConfiugration('window', URI.file('folder1'))); + assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiugration('window', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiugration('window', URI.file('folder3'))); + assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); + assert.ok(testObject.affectsConfiugration('window', URI.file('file3'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder3'))); + + assert.ok(testObject.affectsConfiugration('workbench.editor')); + assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('folder3'))); + + assert.ok(testObject.affectsConfiugration('workbench')); + assert.ok(testObject.affectsConfiugration('workbench', URI.file('folder2'))); + assert.ok(testObject.affectsConfiugration('workbench', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('workbench', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiugration('workbench', URI.file('folder3'))); + + assert.ok(!testObject.affectsConfiugration('files')); + assert.ok(!testObject.affectsConfiugration('files', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiugration('files', URI.file('folder2'))); + assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiugration('files', URI.file('folder3'))); + assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder3', 'file3')))); + }); + }); \ No newline at end of file From 788c5c536b32f667419f9a1e458fb29e7e67e27f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:15:23 +0200 Subject: [PATCH 232/303] Correct mistyping --- .../configuration/common/configuration.ts | 2 +- .../common/configurationModels.ts | 4 +- .../test/common/configurationModels.test.ts | 122 ++++++++--------- .../parts/debug/browser/debugActionItems.ts | 2 +- .../watermark/electron-browser/watermark.ts | 2 +- .../common/configurationModels.ts | 6 +- .../test/common/configurationModels.test.ts | 128 +++++++++--------- 7 files changed, 133 insertions(+), 133 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 16e5736bd3f..5cbe7665027 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -31,7 +31,7 @@ export enum ConfigurationTarget { export interface IConfigurationChangeEvent { affectedKeys: string[]; - affectsConfiugration(configuration: string, resource?: URI): boolean; + affectsConfiguration(configuration: string, resource?: URI): boolean; // Following data is used for telemetry source: ConfigurationTarget; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index be314db0f04..a7e62338321 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -485,7 +485,7 @@ export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChange constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); } - affectsConfiugration(config: string, resource?: URI): boolean { + affectsConfiguration(config: string, resource?: URI): boolean { if (!this.changedConfiguration) { this.changedConfiguration = new ConfigurationModel(); this.updateKeys(this.changedConfiguration, this.affectedKeys); @@ -539,7 +539,7 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i return this._sourceConfig; } - affectsConfiugration(config: string, resource?: URI): boolean { + affectsConfiguration(config: string, resource?: URI): boolean { let configurationModelsToSearch: ConfigurationModel[] = [this.changedConfiguration]; if (resource) { diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts index 294b9d0e69e..598b7d6d616 100644 --- a/src/vs/platform/configuration/test/common/configurationModels.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -408,14 +408,14 @@ suite('ConfigurationChangeEvent', () => { testObject.change(['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); assert.deepEqual(testObject.affectedKeys, ['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); - assert.ok(testObject.affectsConfiugration('window.zoomLevel')); - assert.ok(testObject.affectsConfiugration('window')); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); - assert.ok(testObject.affectsConfiugration('workbench.editor')); - assert.ok(testObject.affectsConfiugration('workbench')); - assert.ok(testObject.affectsConfiugration('files')); - assert.ok(!testObject.affectsConfiugration('files.exclude')); - assert.ok(testObject.affectsConfiugration('[markdown]')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files.exclude')); + assert.ok(testObject.affectsConfiguration('[markdown]')); }); test('changeEvent affecting keys for resources', () => { @@ -429,41 +429,41 @@ suite('ConfigurationChangeEvent', () => { assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); - assert.ok(testObject.affectsConfiugration('window.zoomLevel')); - assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.restoreWindows')); - assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.title')); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window')); - assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('workbench.editor')); - assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('workbench')); - assert.ok(testObject.affectsConfiugration('workbench', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('workbench', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('files')); - assert.ok(!testObject.affectsConfiugration('files', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('files', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file2'))); }); }); @@ -475,39 +475,39 @@ suite('AllKeysConfigurationChangeEvent', () => { assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); - assert.ok(testObject.affectsConfiugration('window.zoomLevel')); - assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.restoreWindows')); - assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.title')); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window')); - assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('workbench.editor')); - assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('workbench')); - assert.ok(testObject.affectsConfiugration('workbench', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('workbench', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('files')); - assert.ok(!testObject.affectsConfiugration('files', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file1'))); }); }); \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index 4cba52bfbcc..9467e227330 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -55,7 +55,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { private registerListeners(): void { this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.affectsConfiugration('launch')) { + if (e.affectsConfiguration('launch')) { this.updateOptions(); } })); diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 11538b93dad..ec6aa876b65 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -127,7 +127,7 @@ export class WatermarkContribution implements IWorkbenchContribution { } }); this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.affectsConfiugration(WORKBENCH_TIPS_ENABLED_KEY)) { + if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) { const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (enabled !== this.enabled) { this.enabled = enabled; diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 48506da5b83..1fd4c79e89d 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -274,15 +274,15 @@ export class WorkspaceConfigurationChangeEvent extends ConfigurationChangeEvent super(); } - affectsConfiugration(config: string, resource?: URI): boolean { - if (super.affectsConfiugration(config, resource)) { + affectsConfiguration(config: string, resource?: URI): boolean { + if (super.affectsConfiguration(config, resource)) { return true; } if (resource) { let workspaceFolder = this.workspace.getFolder(resource); if (workspaceFolder) { - return super.affectsConfiugration(config, workspaceFolder.uri); + return super.affectsConfiguration(config, workspaceFolder.uri); } } diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index 90091e4f0c1..58e25f17575 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -115,78 +115,78 @@ suite('WorkspaceConfigurationChangeEvent', () => { assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); - assert.ok(testObject.affectsConfiugration('window.zoomLevel')); - assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file('folder1'))); - assert.ok(testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder1', 'file1')))); - assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('window.zoomLevel', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder3', 'file3')))); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen')); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder1', 'file1')))); - assert.ok(testObject.affectsConfiugration('window.restoreFullscreen', URI.file('folder1'))); - assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file1'))); - assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('window.restoreFullscreen', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder3', 'file3')))); - assert.ok(testObject.affectsConfiugration('window.restoreWindows')); - assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file('file2'))); - assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder1', 'file1')))); - assert.ok(!testObject.affectsConfiugration('window.restoreWindows', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder3', 'file3')))); - assert.ok(testObject.affectsConfiugration('window.title')); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder1'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder1', 'file1')))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder2', 'file2')))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('folder3'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file(join('folder3', 'file3')))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window.title', URI.file('file3'))); + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file3'))); - assert.ok(testObject.affectsConfiugration('window')); - assert.ok(testObject.affectsConfiugration('window', URI.file('folder1'))); - assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder1', 'file1')))); - assert.ok(testObject.affectsConfiugration('window', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder2', 'file2')))); - assert.ok(testObject.affectsConfiugration('window', URI.file('folder3'))); - assert.ok(testObject.affectsConfiugration('window', URI.file(join('folder3', 'file3')))); - assert.ok(testObject.affectsConfiugration('window', URI.file('file1'))); - assert.ok(testObject.affectsConfiugration('window', URI.file('file2'))); - assert.ok(testObject.affectsConfiugration('window', URI.file('file3'))); + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file3'))); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview')); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder1'))); - assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file(join('folder1', 'file1')))); - assert.ok(!testObject.affectsConfiugration('workbench.editor.enablePreview', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder3'))); - assert.ok(testObject.affectsConfiugration('workbench.editor')); - assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('workbench.editor', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('folder1'))); - assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file(join('folder1', 'file1')))); - assert.ok(!testObject.affectsConfiugration('workbench.editor', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('folder3'))); - assert.ok(testObject.affectsConfiugration('workbench')); - assert.ok(testObject.affectsConfiugration('workbench', URI.file('folder2'))); - assert.ok(testObject.affectsConfiugration('workbench', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('workbench', URI.file('folder1'))); - assert.ok(!testObject.affectsConfiugration('workbench', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('folder3'))); - assert.ok(!testObject.affectsConfiugration('files')); - assert.ok(!testObject.affectsConfiugration('files', URI.file('folder1'))); - assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder1', 'file1')))); - assert.ok(!testObject.affectsConfiugration('files', URI.file('folder2'))); - assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder2', 'file2')))); - assert.ok(!testObject.affectsConfiugration('files', URI.file('folder3'))); - assert.ok(!testObject.affectsConfiugration('files', URI.file(join('folder3', 'file3')))); + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder2'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder3'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder3', 'file3')))); }); }); \ No newline at end of file From 0d9e0253582be4c704ce3e684a1307ee3c3e8cce Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:20:11 +0200 Subject: [PATCH 233/303] Use wrapper pattern for Workspace Configuration Change Event --- .../common/configurationModels.ts | 23 ++++++++++++++----- .../test/common/configurationModels.test.ts | 19 +++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 1fd4c79e89d..8b9e5aa53fe 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -268,21 +268,32 @@ export class Configuration extends BaseConfiguration { } } -export class WorkspaceConfigurationChangeEvent extends ConfigurationChangeEvent implements IConfigurationChangeEvent { +export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { - constructor(private workspace: Workspace) { - super(); + constructor(private configurationChangeEvent: ConfigurationChangeEvent, private workspace: Workspace) { + } + + get affectedKeys(): string[] { + return this.configurationChangeEvent.affectedKeys; + } + + get source(): ConfigurationTarget { + return this.configurationChangeEvent.source; + } + + get sourceConfig(): any { + return this.configurationChangeEvent.sourceConfig; } affectsConfiguration(config: string, resource?: URI): boolean { - if (super.affectsConfiguration(config, resource)) { + if (this.configurationChangeEvent.affectsConfiguration(config, resource)) { return true; } if (resource) { let workspaceFolder = this.workspace.getFolder(resource); if (workspaceFolder) { - return super.affectsConfiguration(config, workspaceFolder.uri); + return this.configurationChangeEvent.affectsConfiguration(config, workspaceFolder.uri); } } diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index 58e25f17575..781260d8502 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -10,6 +10,8 @@ import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; +import { ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('ConfigurationService - Model', () => { @@ -102,18 +104,21 @@ suite('ConfigurationService - Model', () => { suite('WorkspaceConfigurationChangeEvent', () => { test('changeEvent affecting workspace folders', () => { - let testObject = new WorkspaceConfigurationChangeEvent(new Workspace('id', 'name', + let configurationChangeEvent = new ConfigurationChangeEvent(); + configurationChangeEvent.change(['window.title']); + configurationChangeEvent.change(['window.zoomLevel'], URI.file('folder1')); + configurationChangeEvent.change(['workbench.editor.enablePreview'], URI.file('folder2')); + configurationChangeEvent.change(['window.restoreFullscreen'], URI.file('folder1')); + configurationChangeEvent.change(['window.restoreWindows'], URI.file('folder2')); + configurationChangeEvent.telemetryData(ConfigurationTarget.WORKSPACE, {}); + + let testObject = new WorkspaceConfigurationChangeEvent(configurationChangeEvent, new Workspace('id', 'name', [new WorkspaceFolder({ index: 0, name: '1', uri: URI.file('folder1') }), new WorkspaceFolder({ index: 1, name: '2', uri: URI.file('folder2') }), new WorkspaceFolder({ index: 2, name: '3', uri: URI.file('folder3') })])); - testObject.change(['window.title']); - testObject.change(['window.zoomLevel'], URI.file('folder1')); - testObject.change(['workbench.editor.enablePreview'], URI.file('folder2')); - testObject.change(['window.restoreFullscreen'], URI.file('folder1')); - testObject.change(['window.restoreWindows'], URI.file('folder2')); - assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + assert.equal(testObject.source, ConfigurationTarget.WORKSPACE); assert.ok(testObject.affectsConfiguration('window.zoomLevel')); assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('folder1'))); From db4031b6d5ced25fb689461cdf9ae4fd0fa5c3ad Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 11:33:03 +0200 Subject: [PATCH 234/303] deco - fallback to tree color only when an element is focused *and* selected --- .../services/decorations/browser/decorationsService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 522181bb4d9..feb0ff47fe3 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -52,7 +52,7 @@ class DecorationRule { const { color, opacity, letter } = data; // label createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); - createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); + createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge if (letter) { createCSSRule(`.${this.badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, element); @@ -64,7 +64,7 @@ class DecorationRule { // label const { color, opacity } = data[0]; createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); - createCSSRule(`.selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); + createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge let letters: string[] = []; From 996d90415e831d8682b6b6ee149b4aee3085097e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:52:50 +0200 Subject: [PATCH 235/303] Revert changes in preferences --- .../parts/preferences/browser/preferencesRenderers.ts | 5 ++--- .../parts/preferences/browser/preferencesService.ts | 4 +--- .../workbench/parts/preferences/common/preferencesModels.ts | 4 +--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 98996425277..6a06a153b61 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -561,9 +561,8 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr range, options: { stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'findMatch', - - }, + className: 'findMatch' + } }; } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 3a786ee208c..c3f74852cee 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -119,7 +119,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic .then(preferencesEditorModel => preferencesEditorModel ? preferencesEditorModel.content : null); } - // vsode://DefaultSettings/1 createPreferencesEditorModel(uri: URI): TPromise> { let promise = this.defaultPreferencesEditorModels.get(uri); if (promise) { @@ -251,7 +250,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { - const openDefaultSettings = !!this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value; + const openDefaultSettings = !!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING); return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource) .then(editableSettingsEditorInput => { if (!options) { @@ -261,7 +260,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic } if (openDefaultSettings) { - // get a new URI for default settings here const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget)); const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, editableSettingsEditorInput); this.lastOpenedSettingsInput = preferencesEditorInput; diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index 26e4c93d348..f17231a589b 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -244,9 +244,7 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti constructor(reference: IReference, private _configurationTarget: ConfigurationTarget, @ITextFileService protected textFileService: ITextFileService) { super(); this.settingsModel = reference.object.textEditorModel; - this._register(this.onDispose(() => { - reference.dispose(); - })); + this._register(this.onDispose(() => reference.dispose())); this._register(this.settingsModel.onDidChangeContent(() => { this._settingsGroups = null; })); From 342f81d2483d79bd86e6722d7976713364bea367 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 11:54:37 +0200 Subject: [PATCH 236/303] quick open - add and use prepareQuery --- .../parts/quickopen/common/quickOpenScorer.ts | 75 ++++--- .../test/common/quickOpenScorer.test.ts | 183 ++++++++++-------- .../browser/parts/editor/editorPicker.ts | 14 +- .../parts/quickopen/quickOpenController.ts | 12 +- .../search/browser/openAnythingHandler.ts | 23 +-- .../services/search/node/rawSearchService.ts | 5 +- 6 files changed, 172 insertions(+), 140 deletions(-) diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index fe804a29d1f..a479c16aa0a 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -16,7 +16,7 @@ export type ScorerCache = { [key: string]: IItemScore }; const NO_SCORE: Score = [0, []]; -export function _doScore(target: string, query: string, fuzzy: boolean): Score { +export function _doScore(target: string, query: string, queryLower: string, fuzzy: boolean): Score { if (!target || !query) { return NO_SCORE; // return early if target or query are undefined } @@ -29,7 +29,6 @@ export function _doScore(target: string, query: string, fuzzy: boolean): Score { const queryLen = query.length; const targetLower = target.toLowerCase(); - const queryLower = query.toLowerCase(); let res = NO_SCORE; @@ -236,8 +235,34 @@ const LABEL_PREFIX_SCORE = 1 << 17; const LABEL_CAMELCASE_SCORE = 1 << 16; const LABEL_SCORE_THRESHOLD = 1 << 15; -export function scoreItem(item: T, query: string, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache): IItemScore { - if (!item || !query) { +export interface IPreparedQuery { + value: string; + lowercase: string; + containsPathSeparator: boolean; +} + +/** + * Helper function to prepare a search value for scoring in quick open by removing unwanted characters. + */ +export function prepareQuery(value: string): IPreparedQuery { + let lowercase: string; + let containsPathSeparator: boolean; + + if (value) { + value = stripWildcards(value).replace(/\s/g, ''); // get rid of all wildcards and whitespace + if (isWindows) { + value = value.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash + } + + lowercase = value.toLowerCase(); + containsPathSeparator = value.indexOf(nativeSep) >= 0; + } + + return { value, lowercase, containsPathSeparator }; +} + +export function scoreItem(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache): IItemScore { + if (!item || !query.value) { return NO_ITEM_SCORE; // we need an item and query to score on at least } @@ -250,9 +275,9 @@ export function scoreItem(item: T, query: string, fuzzy: boolean, accessor: I let cacheHash: string; if (description) { - cacheHash = `${label}${description}${query}${fuzzy}`; + cacheHash = `${label}${description}${query.value}${fuzzy}`; } else { - cacheHash = `${label}${query}${fuzzy}`; + cacheHash = `${label}${query.value}${fuzzy}`; } const cached = cache[cacheHash]; @@ -266,31 +291,31 @@ export function scoreItem(item: T, query: string, fuzzy: boolean, accessor: I return itemScore; } -function doScoreItem(label: string, description: string, path: string, query: string, fuzzy: boolean): IItemScore { +function doScoreItem(label: string, description: string, path: string, query: IPreparedQuery, fuzzy: boolean): IItemScore { // 1.) treat identity matches on full path highest - if (path && isEqual(query, path, true)) { + if (path && isEqual(query.value, path, true)) { return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0 }; } // We only consider label matches if the query is not including file path separators - const preferLabelMatches = !path || query.indexOf(nativeSep) === -1; + const preferLabelMatches = !path || !query.containsPathSeparator; if (preferLabelMatches) { // 2.) treat prefix matches on the label second highest - const prefixLabelMatch = matchesPrefix(query, label); + const prefixLabelMatch = matchesPrefix(query.value, label); if (prefixLabelMatch) { return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch }; } // 3.) treat camelcase matches on the label third highest - const camelcaseLabelMatch = matchesCamelCase(query, label); + const camelcaseLabelMatch = matchesCamelCase(query.value, label); if (camelcaseLabelMatch) { return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch }; } // 4.) prefer scores on the label if any - const [labelScore, labelPositions] = _doScore(label, query, fuzzy); + const [labelScore, labelPositions] = _doScore(label, query.value, query.lowercase, fuzzy); if (labelScore) { return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) }; } @@ -306,7 +331,7 @@ function doScoreItem(label: string, description: string, path: string, query: const descriptionPrefixLength = descriptionPrefix.length; const descriptionAndLabel = `${descriptionPrefix}${label}`; - const [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query, fuzzy); + const [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query.value, query.lowercase, fuzzy); if (labelDescriptionScore) { const labelDescriptionMatches = createMatches(labelDescriptionPositions); const labelMatch: IMatch[] = []; @@ -339,7 +364,7 @@ function doScoreItem(label: string, description: string, path: string, query: return NO_ITEM_SCORE; } -export function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache, fallbackComparer = fallbackCompare): number { +export function compareItemsByScore(itemA: T, itemB: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache, fallbackComparer = fallbackCompare): number { const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache); const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache); @@ -482,7 +507,7 @@ function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number return matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1; } -export function fallbackCompare(itemA: T, itemB: T, query: string, accessor: IItemAccessor): number { +export function fallbackCompare(itemA: T, itemB: T, query: IPreparedQuery, accessor: IItemAccessor): number { // check for label + description length and prefer shorter const labelA = accessor.getItemLabel(itemA); @@ -510,33 +535,19 @@ export function fallbackCompare(itemA: T, itemB: T, query: string, accessor: // compare by label if (labelA !== labelB) { - return compareAnything(labelA, labelB, query); + return compareAnything(labelA, labelB, query.value); } // compare by description if (descriptionA && descriptionB && descriptionA !== descriptionB) { - return compareAnything(descriptionA, descriptionB, query); + return compareAnything(descriptionA, descriptionB, query.value); } // compare by path if (pathA && pathB && pathA !== pathB) { - return compareAnything(pathA, pathB, query); + return compareAnything(pathA, pathB, query.value); } // equal return 0; -} - -/** - * Helper function to prepare a search value for scoring in quick open by removing unwanted characters. - */ -export function massageSearchForScoring(searchValue: string): string { - if (searchValue) { - searchValue = stripWildcards(searchValue).replace(/\s/g, ''); // get rid of all wildcards and whitespace - if (isWindows) { - searchValue = searchValue.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash - } - } - - return searchValue; } \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 8aedf7ce3ea..877f8a0caa0 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import * as scorer from 'vs/base/parts/quickopen/common/quickOpenScorer'; import URI from 'vs/base/common/uri'; -import { basename, dirname } from 'vs/base/common/paths'; +import { basename, dirname, nativeSep } from 'vs/base/common/paths'; import { isWindows } from 'vs/base/common/platform'; class ResourceAccessorClass implements scorer.IItemAccessor { @@ -43,28 +43,44 @@ class NullAccessorClass implements scorer.IItemAccessor { } } +function _doScore(target: string, query: string, fuzzy: boolean): scorer.Score { + return scorer._doScore(target, query, query.toLowerCase(), fuzzy); +} + +function scoreItem(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor, cache: scorer.ScorerCache): scorer.IItemScore { + return scorer.scoreItem(item, scorer.prepareQuery(query), fuzzy, accessor, cache); +} + +function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor, cache: scorer.ScorerCache, fallbackComparer = scorer.fallbackCompare): number { + return scorer.compareItemsByScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, cache, fallbackComparer); +} + const NullAccessor = new NullAccessorClass(); -const cache: scorer.ScorerCache = Object.create(null); +let cache: scorer.ScorerCache = Object.create(null); suite('Quick Open Scorer', () => { + setup(() => { + cache = Object.create(null); + }); + test('score (fuzzy)', function () { const target = 'HeLlo-World'; const scores: scorer.Score[] = []; - scores.push(scorer._doScore(target, 'HelLo-World', true)); // direct case match - scores.push(scorer._doScore(target, 'hello-world', true)); // direct mix-case match - scores.push(scorer._doScore(target, 'HW', true)); // direct case prefix (multiple) - scores.push(scorer._doScore(target, 'hw', true)); // direct mix-case prefix (multiple) - scores.push(scorer._doScore(target, 'H', true)); // direct case prefix - scores.push(scorer._doScore(target, 'h', true)); // direct mix-case prefix - scores.push(scorer._doScore(target, 'ld', true)); // in-string mix-case match (consecutive, avoids scattered hit) - scores.push(scorer._doScore(target, 'W', true)); // direct case word prefix - scores.push(scorer._doScore(target, 'w', true)); // direct mix-case word prefix - scores.push(scorer._doScore(target, 'Ld', true)); // in-string case match (multiple) - scores.push(scorer._doScore(target, 'L', true)); // in-string case match - scores.push(scorer._doScore(target, 'l', true)); // in-string mix-case match - scores.push(scorer._doScore(target, '4', true)); // no match + scores.push(_doScore(target, 'HelLo-World', true)); // direct case match + scores.push(_doScore(target, 'hello-world', true)); // direct mix-case match + scores.push(_doScore(target, 'HW', true)); // direct case prefix (multiple) + scores.push(_doScore(target, 'hw', true)); // direct mix-case prefix (multiple) + scores.push(_doScore(target, 'H', true)); // direct case prefix + scores.push(_doScore(target, 'h', true)); // direct mix-case prefix + scores.push(_doScore(target, 'ld', true)); // in-string mix-case match (consecutive, avoids scattered hit) + scores.push(_doScore(target, 'W', true)); // direct case word prefix + scores.push(_doScore(target, 'w', true)); // direct mix-case word prefix + scores.push(_doScore(target, 'Ld', true)); // in-string case match (multiple) + scores.push(_doScore(target, 'L', true)); // in-string case match + scores.push(_doScore(target, 'l', true)); // in-string mix-case match + scores.push(_doScore(target, '4', true)); // no match // Assert scoring order let sortedScores = scores.concat().sort((a, b) => b[0] - a[0]); @@ -83,28 +99,28 @@ suite('Quick Open Scorer', () => { test('score (non fuzzy)', function () { const target = 'HeLlo-World'; - assert.ok(scorer._doScore(target, 'HelLo-World', false)[0] > 0); - assert.equal(scorer._doScore(target, 'HelLo-World', false)[1].length, 'HelLo-World'.length); + assert.ok(_doScore(target, 'HelLo-World', false)[0] > 0); + assert.equal(_doScore(target, 'HelLo-World', false)[1].length, 'HelLo-World'.length); - assert.ok(scorer._doScore(target, 'hello-world', false)[0] > 0); - assert.equal(scorer._doScore(target, 'HW', false)[0], 0); - assert.ok(scorer._doScore(target, 'h', false)[0] > 0); - assert.ok(scorer._doScore(target, 'ello', false)[0] > 0); - assert.ok(scorer._doScore(target, 'ld', false)[0] > 0); - assert.equal(scorer._doScore(target, 'eo', false)[0], 0); + assert.ok(_doScore(target, 'hello-world', false)[0] > 0); + assert.equal(_doScore(target, 'HW', false)[0], 0); + assert.ok(_doScore(target, 'h', false)[0] > 0); + assert.ok(_doScore(target, 'ello', false)[0] > 0); + assert.ok(_doScore(target, 'ld', false)[0] > 0); + assert.equal(_doScore(target, 'eo', false)[0], 0); }); test('scoreItem - matches are proper', function () { - let res = scorer.scoreItem(null, 'something', true, ResourceAccessor, cache); + let res = scoreItem(null, 'something', true, ResourceAccessor, cache); assert.ok(!res.score); const resource = URI.file('/xyz/some/path/someFile123.txt'); - res = scorer.scoreItem(resource, 'something', true, NullAccessor, cache); + res = scoreItem(resource, 'something', true, NullAccessor, cache); assert.ok(!res.score); // Path Identity - const identityRes = scorer.scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor, cache); + const identityRes = scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor, cache); assert.ok(identityRes.score); assert.equal(identityRes.descriptionMatch.length, 1); assert.equal(identityRes.labelMatch.length, 1); @@ -114,7 +130,7 @@ suite('Quick Open Scorer', () => { assert.equal(identityRes.labelMatch[0].end, ResourceAccessor.getItemLabel(resource).length); // Basename Prefix - const basenamePrefixRes = scorer.scoreItem(resource, 'som', true, ResourceAccessor, cache); + const basenamePrefixRes = scoreItem(resource, 'som', true, ResourceAccessor, cache); assert.ok(basenamePrefixRes.score); assert.ok(!basenamePrefixRes.descriptionMatch); assert.equal(basenamePrefixRes.labelMatch.length, 1); @@ -122,7 +138,7 @@ suite('Quick Open Scorer', () => { assert.equal(basenamePrefixRes.labelMatch[0].end, 'som'.length); // Basename Camelcase - const basenameCamelcaseRes = scorer.scoreItem(resource, 'sF', true, ResourceAccessor, cache); + const basenameCamelcaseRes = scoreItem(resource, 'sF', true, ResourceAccessor, cache); assert.ok(basenameCamelcaseRes.score); assert.ok(!basenameCamelcaseRes.descriptionMatch); assert.equal(basenameCamelcaseRes.labelMatch.length, 2); @@ -132,7 +148,7 @@ suite('Quick Open Scorer', () => { assert.equal(basenameCamelcaseRes.labelMatch[1].end, 5); // Basename Match - const basenameRes = scorer.scoreItem(resource, 'of', true, ResourceAccessor, cache); + const basenameRes = scoreItem(resource, 'of', true, ResourceAccessor, cache); assert.ok(basenameRes.score); assert.ok(!basenameRes.descriptionMatch); assert.equal(basenameRes.labelMatch.length, 2); @@ -142,7 +158,7 @@ suite('Quick Open Scorer', () => { assert.equal(basenameRes.labelMatch[1].end, 5); // Path Match - const pathRes = scorer.scoreItem(resource, 'xyz123', true, ResourceAccessor, cache); + const pathRes = scoreItem(resource, 'xyz123', true, ResourceAccessor, cache); assert.ok(pathRes.score); assert.ok(pathRes.descriptionMatch); assert.ok(pathRes.labelMatch); @@ -154,7 +170,7 @@ suite('Quick Open Scorer', () => { assert.equal(pathRes.descriptionMatch[0].end, 4); // No Match - const noRes = scorer.scoreItem(resource, '987', true, ResourceAccessor, cache); + const noRes = scoreItem(resource, '987', true, ResourceAccessor, cache); assert.ok(!noRes.score); assert.ok(!noRes.labelMatch); assert.ok(!noRes.descriptionMatch); @@ -168,10 +184,10 @@ suite('Quick Open Scorer', () => { test('scoreItem - invalid input', function () { - let res = scorer.scoreItem(null, null, true, ResourceAccessor, cache); + let res = scoreItem(null, null, true, ResourceAccessor, cache); assert.equal(res.score, 0); - res = scorer.scoreItem(null, 'null', true, ResourceAccessor, cache); + res = scoreItem(null, 'null', true, ResourceAccessor, cache); assert.equal(res.score, 0); }); @@ -181,7 +197,7 @@ suite('Quick Open Scorer', () => { // xsp is more relevant to the end of the file path even though it matches // fuzzy also in the beginning. we verify the more relevant match at the // end gets returned. - const pathRes = scorer.scoreItem(resource, 'xspfile123', true, ResourceAccessor, cache); + const pathRes = scoreItem(resource, 'xspfile123', true, ResourceAccessor, cache); assert.ok(pathRes.score); assert.ok(pathRes.descriptionMatch); assert.ok(pathRes.labelMatch); @@ -198,7 +214,7 @@ suite('Quick Open Scorer', () => { // expect "ad" to be matched towards the end of the file because the // match is more compact - const res = scorer.scoreItem(resource, 'ad', true, ResourceAccessor, cache); + const res = scoreItem(resource, 'ad', true, ResourceAccessor, cache); assert.ok(res.score); assert.ok(res.descriptionMatch); assert.ok(!res.labelMatch.length); @@ -217,12 +233,12 @@ suite('Quick Open Scorer', () => { // Full resource A path let query = ResourceAccessor.getItemPath(resourceA); - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -230,12 +246,12 @@ suite('Quick Open Scorer', () => { // Full resource B path query = ResourceAccessor.getItemPath(resourceB); - res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -249,12 +265,12 @@ suite('Quick Open Scorer', () => { // Full resource A basename let query = ResourceAccessor.getItemLabel(resourceA); - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -262,12 +278,12 @@ suite('Quick Open Scorer', () => { // Full resource B basename query = ResourceAccessor.getItemLabel(resourceB); - res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -281,12 +297,12 @@ suite('Quick Open Scorer', () => { // resource A camelcase let query = 'fA'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -294,12 +310,12 @@ suite('Quick Open Scorer', () => { // resource B camelcase query = 'fB'; - res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -313,12 +329,12 @@ suite('Quick Open Scorer', () => { // Resource A part of basename let query = 'fileA'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -326,12 +342,12 @@ suite('Quick Open Scorer', () => { // Resource B part of basename query = 'fileB'; - res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -345,12 +361,12 @@ suite('Quick Open Scorer', () => { // Resource A part of path let query = 'pathfileA'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -358,12 +374,12 @@ suite('Quick Open Scorer', () => { // Resource B part of path query = 'pathfileB'; - res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -377,12 +393,12 @@ suite('Quick Open Scorer', () => { // Resource A part of path let query = 'somepath'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -396,12 +412,12 @@ suite('Quick Open Scorer', () => { // Resource A part of path let query = 'file'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceC); assert.equal(res[2], resourceB); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceC); assert.equal(res[2], resourceB); @@ -415,12 +431,12 @@ suite('Quick Open Scorer', () => { // Resource A part of path let query = 'somepath'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); - res = [resourceC, resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); assert.equal(res[2], resourceC); @@ -433,7 +449,7 @@ suite('Quick Open Scorer', () => { let query = 'co/te'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); assert.equal(res[2], resourceC); @@ -445,11 +461,11 @@ suite('Quick Open Scorer', () => { let query = 'vscode'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); assert.equal(res[0], resourceA); assert.equal(res[1], resourceB); - res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); @@ -460,11 +476,11 @@ suite('Quick Open Scorer', () => { let query = 'AH'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); - res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); @@ -475,11 +491,11 @@ suite('Quick Open Scorer', () => { let query = 'xp'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); - res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); @@ -490,11 +506,11 @@ suite('Quick Open Scorer', () => { let query = 'xp'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); - res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); @@ -505,11 +521,11 @@ suite('Quick Open Scorer', () => { let query = 'exfile'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); - res = [resourceB, resourceA].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); @@ -522,12 +538,12 @@ suite('Quick Open Scorer', () => { let query = isWindows ? 'modu1\\index.js' : 'modu1/index.js'; - let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceC); query = isWindows ? 'un1\\index.js' : 'un1/index.js'; - res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); @@ -538,7 +554,7 @@ suite('Quick Open Scorer', () => { let query = 'StatVideoindex'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceC); }); @@ -549,7 +565,7 @@ suite('Quick Open Scorer', () => { let query = 'bookpageIndex'; - let res = [resourceA, resourceB, resourceC].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceC); }); @@ -559,7 +575,7 @@ suite('Quick Open Scorer', () => { let query = isWindows ? 'ui\\icons' : 'ui/icons'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); @@ -569,7 +585,7 @@ suite('Quick Open Scorer', () => { let query = isWindows ? 'ui\\input\\index' : 'ui/input/index'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); @@ -579,12 +595,15 @@ suite('Quick Open Scorer', () => { let query = 'listview'; - let res = [resourceA, resourceB].sort((r1, r2) => scorer.compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); assert.equal(res[0], resourceB); }); - test('massageSearchForScoring', function () { - assert.equal(scorer.massageSearchForScoring(' f*a '), 'fa'); - assert.equal(scorer.massageSearchForScoring('model tester.ts'), 'modeltester.ts'); + test('prepareSearchForScoring', function () { + assert.equal(scorer.prepareQuery(' f*a ').value, 'fa'); + assert.equal(scorer.prepareQuery('model Tester.ts').value, 'modelTester.ts'); + assert.equal(scorer.prepareQuery('Model Tester.ts').lowercase, 'modeltester.ts'); + assert.equal(scorer.prepareQuery('ModelTester.ts').containsPathSeparator, false); + assert.equal(scorer.prepareQuery('Model' + nativeSep + 'Tester.ts').containsPathSeparator, true); }); }); \ 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 f7c63fa7e08..fe160365da8 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -22,7 +22,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { EditorInput, toResource, IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor'; -import { compareItemsByScore, scoreItem, ScorerCache, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export class EditorPickerEntry extends QuickOpenEntryGroup { private stacks: IEditorStacksModel; @@ -106,15 +106,15 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { return TPromise.as(null); } - // Massage search for scoring - searchValue = massageSearchForScoring(searchValue); + // Prepare search for scoring + const query = prepareQuery(searchValue); const entries = editorEntries.filter(e => { - if (!searchValue) { + if (!query.value) { return true; } - const itemScore = scoreItem(e, searchValue, true, QuickOpenItemAccessor, this.scorerCache); + const itemScore = scoreItem(e, query, true, QuickOpenItemAccessor, this.scorerCache); if (!itemScore.score) { return false; } @@ -126,13 +126,13 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { // Sorting const stacks = this.editorGroupService.getStacksModel(); - if (searchValue) { + if (query.value) { entries.sort((e1, e2) => { if (e1.group !== e2.group) { return stacks.positionOfGroup(e1.group) - stacks.positionOfGroup(e2.group); } - return compareItemsByScore(e1, e2, searchValue, true, QuickOpenItemAccessor, this.scorerCache); + return compareItemsByScore(e1, e2, query, true, QuickOpenItemAccessor, this.scorerCache); }); } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 2f178d70c51..08681245fcd 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -55,7 +55,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { FileKind, IFileService } from 'vs/platform/files/common/files'; -import { scoreItem, ScorerCache, compareItemsByScore, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { scoreItem, ScorerCache, compareItemsByScore, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; const HELP_PREFIX = '?'; @@ -1181,17 +1181,17 @@ class EditorHistoryHandler { public getResults(searchValue?: string): QuickOpenEntry[] { // Massage search for scoring - searchValue = massageSearchForScoring(searchValue); + const query = prepareQuery(searchValue); // Just return all if we are not searching const history = this.historyService.getHistory(); - if (!searchValue) { + if (!query.value) { return history.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input)); } // Otherwise filter by search value and sort by score. Include matches on description // in case the user is explicitly including path separators. - const accessor = searchValue.indexOf(paths.nativeSep) >= 0 ? MatchOnDescription : DoNotMatchOnDescription; + const accessor = query.containsPathSeparator ? MatchOnDescription : DoNotMatchOnDescription; return history // For now, only support to match on inputs that provide resource information @@ -1211,7 +1211,7 @@ class EditorHistoryHandler { // Make sure the search value is matching .filter(e => { - const itemScore = scoreItem(e, searchValue, false, accessor, this.scorerCache); + const itemScore = scoreItem(e, query, false, accessor, this.scorerCache); if (!itemScore.score) { return false; } @@ -1223,7 +1223,7 @@ class EditorHistoryHandler { // Sort by score and provide a fallback sorter that keeps the // recency of items in case the score for items is the same - .sort((e1, e2) => compareItemsByScore(e1, e2, searchValue, false, accessor, this.scorerCache, (e1, e2, searchValue, accessor) => -1)); + .sort((e1, e2) => compareItemsByScore(e1, e2, query, false, accessor, this.scorerCache, (e1, e2, query, accessor) => -1)); } } diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 69c76344f67..16acf16b142 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -23,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchSearchConfiguration } from 'vs/workbench/parts/search/common/search'; import { IRange } from 'vs/editor/common/core/range'; -import { compareItemsByScore, scoreItem, ScorerCache, massageSearchForScoring } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export import OpenSymbolHandler = openSymbolHandler.OpenSymbolHandler; // OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load @@ -173,15 +173,16 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.cancelPendingSearch(); this.isClosed = false; // Treat this call as the handler being in use - // Massage search for scoring - searchValue = massageSearchForScoring(searchValue); + // Prepare search for scoring + const query = prepareQuery(searchValue); - const searchWithRange = this.extractRange(searchValue); // Find a suitable range from the pattern looking for ":" and "#" + const searchWithRange = this.extractRange(query.value); // Find a suitable range from the pattern looking for ":" and "#" if (searchWithRange) { - searchValue = searchWithRange.search; // ignore range portion in query + query.value = searchWithRange.search; // ignore range portion in query + query.lowercase = query.value.toLowerCase(); } - if (!searchValue) { + if (!query.value) { return TPromise.as(new QuickOpenModel()); // Respond directly to empty search } @@ -190,12 +191,12 @@ export class OpenAnythingHandler extends QuickOpenHandler { const resultPromises: TPromise[] = []; // File Results - const filePromise = this.openFileHandler.getResults(searchValue, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); + const filePromise = this.openFileHandler.getResults(query.value, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); resultPromises.push(filePromise); // Symbol Results (unless disabled or a range or absolute path is specified) if (this.includeSymbols && !searchWithRange) { - resultPromises.push(this.openSymbolHandler.getResults(searchValue)); + resultPromises.push(this.openSymbolHandler.getResults(query.value)); } // Join and sort unified @@ -212,7 +213,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Sort const unsortedResultTime = Date.now(); - const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => compareItemsByScore(elementA, elementB, searchValue, true, QuickOpenItemAccessor, this.scorerCache); + const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => compareItemsByScore(elementA, elementB, query, true, QuickOpenItemAccessor, this.scorerCache); const viewResults = arrays.top(mergedResults, compare, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); const sortedResultTime = Date.now(); @@ -221,7 +222,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { if (entry instanceof FileEntry) { entry.setRange(searchWithRange ? searchWithRange.range : null); - const itemScore = scoreItem(entry, searchValue, true, QuickOpenItemAccessor, this.scorerCache); + const itemScore = scoreItem(entry, query, true, QuickOpenItemAccessor, this.scorerCache); entry.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); } }); @@ -229,7 +230,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { const duration = new Date().getTime() - startTime; filePromise.then(fileModel => { const data = this.createTimerEventData(startTime, { - searchLength: searchValue.length, + searchLength: query.value.length, unsortedResultTime, sortedResultTime, resultCount: mergedResults.length, diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 12c6c6e0381..55fb059c48f 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -23,7 +23,7 @@ import { TextSearchWorkerProvider } from 'vs/workbench/services/search/node/text import { IRawSearchService, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchProgressItem, ISerializedSearchComplete, ISearchEngine, IFileSearchProgressItem, ITelemetryEvent } from './search'; import { ICachedSearchStats, IProgress } from 'vs/platform/search/common/search'; import { fuzzyContains } from 'vs/base/common/strings'; -import { compareItemsByScore, IItemAccessor, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import { compareItemsByScore, IItemAccessor, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export class SearchService implements IRawSearchService { @@ -254,7 +254,8 @@ export class SearchService implements IRawSearchService { // this is very important because we are also limiting the number of results by config.maxResults // and as such we want the top items to be included in this result set if the number of items // exceeds config.maxResults. - const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, strings.stripWildcards(config.filePattern), true, FileMatchItemAccessor, scorerCache); + const query = prepareQuery(config.filePattern); + const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache); return arrays.topAsync(results, compare, config.maxResults, 10000); } From 183035fb52a924557ef13502dc0777d062025c49 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:55:48 +0200 Subject: [PATCH 237/303] Fix compilation issues --- src/vs/workbench/parts/files/browser/fileActions.ts | 2 +- src/vs/workbench/parts/files/browser/views/explorerViewer.ts | 2 +- .../parts/preferences/common/preferencesContribution.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 6975b962704..5204850eaee 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -714,7 +714,7 @@ export class BaseDeleteFileAction extends BaseFileAction { let confirmPromise: TPromise; // Check if we need to ask for confirmation at all - if (this.skipConfirm || (this.useTrash && this.configurationService.lookup(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY).value === false)) { + if (this.skipConfirm || (this.useTrash && this.configurationService.getValue(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY) === false)) { confirmPromise = TPromise.as({ confirmed: true } as IConfirmationResult); } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 01b9954702b..4878cedef0b 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -949,7 +949,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { let confirmPromise: TPromise; // Handle confirm setting - const confirmDragAndDrop = !isCopy && this.configurationService.lookup(FileDragAndDrop.CONFIRM_DND_SETTING_KEY).value; + const confirmDragAndDrop = !isCopy && this.configurationService.getValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY); if (confirmDragAndDrop) { confirmPromise = this.messageService.confirm({ message: nls.localize('confirmMove', "Are you sure you want to move '{0}'?", source.name), diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts index 48e0ef167d2..2f91e713b0d 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -50,7 +50,7 @@ export class PreferencesContribution implements IWorkbenchContribution { this.editorOpeningListener = dispose(this.editorOpeningListener); // install editor opening listener unless user has disabled this - if (!!this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value) { + if (!!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING)) { this.editorOpeningListener = this.editorGroupService.onEditorOpening(e => this.onEditorOpening(e)); } } @@ -60,7 +60,7 @@ export class PreferencesContribution implements IWorkbenchContribution { if ( !resource || resource.scheme !== 'file' || // require a file path opening !endsWith(resource.fsPath, 'settings.json') || // file must end in settings.json - !this.configurationService.lookup(DEFAULT_SETTINGS_EDITOR_SETTING).value // user has not disabled default settings editor + !this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING) // user has not disabled default settings editor ) { return; } From 3f1ffd14c8cafde90de8fb165954527932e1dadd Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 11:57:22 +0200 Subject: [PATCH 238/303] Reload after editing --- .../configuration/node/configurationEditingService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index b264dbd9662..d13b326bfc2 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -94,7 +94,9 @@ export class ConfigurationEditingService implements IConfigurationEditingService private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise { const edit = this.getEdits(model, operation)[0]; if (this.applyEditsToBuffer(edit, model) && save) { - return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }); + return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }) + // Reload the configuration so that we make sure all parties are updated + .then(() => this.configurationService.reloadConfiguration()); } return TPromise.as(null); } From 907de42b3e7c52dc7c34d0785b1f00c74da43fe9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 12:33:14 +0200 Subject: [PATCH 239/303] Fix tests --- src/vs/platform/configuration/common/configuration.ts | 7 +++++++ .../configuration/node/configurationService.ts | 10 +--------- .../test/common/testConfigurationService.ts | 5 +++-- .../configuration/node/configurationService.ts | 7 ++++--- .../test/node/configurationService.test.ts | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 5cbe7665027..4ad222fdb0b 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -15,6 +15,13 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co export const IConfigurationService = createDecorator('configurationService'); +export function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { + return thing + && typeof thing === 'object' + && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') + && (!thing.resource || thing.resource instanceof URI); +} + export interface IConfigurationOverrides { overrideIdentifier?: string; resource?: URI; diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 035060db7de..19f78c792ab 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -8,23 +8,15 @@ import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { onUnexpectedError } from 'vs/base/common/errors'; -import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { equals } from 'vs/base/common/objects'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -export function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { - return thing - && typeof thing === 'object' - && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') - && (!thing.resource || thing.resource instanceof URI); -} - export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { _serviceBrand: any; diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 2410406e261..6e0a81519b3 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -9,7 +9,7 @@ import { TernarySearchTree } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService extends EventEmitter implements IConfigurationService { public _serviceBrand: any; @@ -22,7 +22,8 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return TPromise.as(this.getConfiguration()); } - public getConfiguration(section?: any, overrides?: any): C { + public getConfiguration(arg1?: any, arg2?: any): C { + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; if (overrides && overrides.resource) { const configForResource = this.configurationByRoot.findSubstr(overrides.resource.fsPath); return configForResource || this.configuration; diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index f2ed3e415dc..b4902fe2e8e 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -24,10 +24,10 @@ import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { CustomConfigurationModel, ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; -import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; -import { ConfigurationService as GlobalConfigurationService, isConfigurationOverrides } from 'vs/platform/configuration/node/configurationService'; +import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationNode, IConfigurationRegistry, Extensions, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; import { createHash } from 'crypto'; @@ -160,7 +160,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat if (folder) { return this.reloadWorkspaceFolderConfiguration(folder, key); } - return this.loadConfiguration(); + return this.reloadUserConfiguration() + .then(() => this.loadConfiguration()); } inspect(key: string, overrides?: IConfigurationOverrides): { diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts index bef7e75099f..5c6763edb10 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -178,7 +178,7 @@ suite('WorkspaceConfigurationService - Node', () => { return createService(workspaceDir, globalSettingsFile).then(service => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); - service.reloadConfiguration(service.getWorkspace().folders[0]).then(() => { + service.reloadConfiguration().then(() => { const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>(); assert.equal(config.testworkbench.editor.tabs, true); @@ -263,7 +263,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.icons": false, "testworkbench.other.setting": true }'); fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); - service.reloadWorkspaceConfiguration().then(() => { + service.reloadConfiguration().then(() => { const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean }, other: { setting: string } } }>(); assert.equal(config.testworkbench.editor.icons, true); assert.equal(config.testworkbench.other.setting, true); From a71c987a4dd40fb5d05adcb9226747c30f613f2a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 12:38:16 +0200 Subject: [PATCH 240/303] fix #35582 --- .../browser/goToDeclarationCommands.ts | 2 +- .../browser => message}/messageController.css | 0 .../browser => message}/messageController.ts | 6 +++++- .../preferences/browser/preferencesEditor.ts | 15 ++++++++++++++- .../preferences/browser/preferencesRenderers.ts | 2 +- 5 files changed, 21 insertions(+), 4 deletions(-) rename src/vs/editor/contrib/{goToDeclaration/browser => message}/messageController.css (100%) rename src/vs/editor/contrib/{goToDeclaration/browser => message}/messageController.ts (98%) diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts index 0cede0a44db..5db1dae02f9 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts @@ -22,7 +22,7 @@ import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/ import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; import { PeekContext } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { MessageController } from './messageController'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; import * as corePosition from 'vs/editor/common/core/position'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IProgressService } from 'vs/platform/progress/common/progress'; diff --git a/src/vs/editor/contrib/goToDeclaration/browser/messageController.css b/src/vs/editor/contrib/message/messageController.css similarity index 100% rename from src/vs/editor/contrib/goToDeclaration/browser/messageController.css rename to src/vs/editor/contrib/message/messageController.css diff --git a/src/vs/editor/contrib/goToDeclaration/browser/messageController.ts b/src/vs/editor/contrib/message/messageController.ts similarity index 98% rename from src/vs/editor/contrib/goToDeclaration/browser/messageController.ts rename to src/vs/editor/contrib/message/messageController.ts index 693722e4c52..ce5d45af58c 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -47,10 +47,14 @@ export class MessageController { this._visible = MessageController.CONTEXT_SNIPPET_MODE.bindTo(contextKeyService); } - dispose() { + dispose(): void { this._visible.reset(); } + isVisible() { + return this._visible.get(); + } + showMessage(message: string, position: IPosition): void { alert(message); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 411b295653f..b65862ab507 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -58,6 +58,7 @@ import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; export class PreferencesEditorInput extends SideBySideEditorInput { public static ID: string = 'workbench.editorinputs.preferencesEditorInput'; @@ -722,7 +723,19 @@ export class DefaultPreferencesEditor extends BaseTextEditor { } public createEditorControl(parent: Builder, configuration: IEditorOptions): editorCommon.IEditor { - return this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parent.getHTMLElement(), configuration); + const editor = this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parent.getHTMLElement(), configuration); + + // Inform user about editor being readonly if user starts type + this.toUnbind.push(editor.onDidType(() => this.onDidType(editor))); + + return editor; + } + + private onDidType(editor: editorCommon.ICommonCodeEditor): void { + const messageController = MessageController.get(editor); + if (!messageController.isVisible()) { + messageController.showMessage(nls.localize('defaultEditorReadonly', "Edit in the right hand side editor to override defaults."), editor.getSelection().getPosition()); + } } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index d74dd56da46..94d5d61e4b9 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -413,7 +413,7 @@ class DefaultSettingsHeaderRenderer extends Disposable { public render(settingsGroups: ISettingsGroup[]) { if (settingsGroups.length) { - this.settingsHeaderWidget.setMessage(''); + this.settingsHeaderWidget.setMessage(nls.localize('defaultSettings', "Place your settings in the right hand side editor to override.")); } else { this.settingsHeaderWidget.setMessage(nls.localize('noSettingsFound', "No Settings Found.")); } From 65a2d30efe65b508577e3a8ecfeca8b07036c10a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 12:39:20 +0200 Subject: [PATCH 241/303] color - jsdoc and tiny tweaks for color provider api --- extensions/css/client/src/cssMain.ts | 6 +-- extensions/html/client/src/htmlMain.ts | 8 ++-- extensions/json/client/src/jsonMain.ts | 8 ++-- src/vs/vscode.d.ts | 2 + src/vs/vscode.proposed.d.ts | 43 ++++++++++++++++++- .../api/node/extHostLanguageFeatures.ts | 21 +++------ 6 files changed, 61 insertions(+), 27 deletions(-) diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index 6b43c68252f..e86425b2d81 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -66,10 +66,10 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { + provideColorPresentations(color: Color, context): ColorPresentation[] | Thenable { let params: ColorPresentationParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + colorInfo: { range: client.code2ProtocolConverter.asRange(context.range), color } }; return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { return presentations.map(p => { diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 2dc9899c125..4f355644a04 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -83,10 +83,10 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): Thenable { + provideColorPresentations(color, context): Thenable { let params: ColorPresentationParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + colorInfo: { range: client.code2ProtocolConverter.asRange(context.range), color } }; return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { return presentations.map(p => { @@ -175,4 +175,4 @@ function getPackageInfo(context: ExtensionContext): IPackageInfo { }; } return null; -} \ No newline at end of file +} diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 1498820c33d..2509a46e385 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -145,10 +145,10 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): Thenable { + provideColorPresentations(color: Color, context): Thenable { let params: ColorPresentationParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + colorInfo: { range: client.code2ProtocolConverter.asRange(context.range), color } }; return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { return presentations.map(p => { @@ -288,4 +288,4 @@ function getPackageInfo(context: ExtensionContext): IPackageInfo { }; } return null; -} \ No newline at end of file +} diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 4c7756fbfcb..68b3d1b5d45 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2996,6 +2996,8 @@ declare module 'vscode' { resolveDocumentLink?(link: DocumentLink, token: CancellationToken): ProviderResult; } + + /** * A tuple of two characters, like a pair of * opening and closing brackets. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index fd6f8cf68e3..ee6b4bbc923 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -194,6 +194,14 @@ declare module 'vscode' { */ readonly alpha: number; + /** + * Creates a new color instance. + * + * @param red The red component. + * @param green The green component. + * @param blue The bluew component. + * @param alpha The alpha component. + */ constructor(red: number, green: number, blue: number, alpha: number); } @@ -222,19 +230,30 @@ declare module 'vscode' { constructor(range: Range, color: Color); } + /** + * A color presentation object describes how a [`color`](#Color) should be represented as text and what + * edits are required to refer to it from source code. + * + * For some languages one color can have multiple presentations, e.g. css can represent the color red with + * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations + * apply, e.g `System.Drawing.Color.Red`. + */ export class ColorPresentation { + /** * The label of this color presentation. It will be shown on the color * picker header. By default this is also the text that is inserted when selecting * this color presentation. */ label: string; + /** * An [edit](#TextEdit) which is applied to a document when selecting * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) * is used. */ textEdit?: TextEdit; + /** * An optional array of additional [text edits](#TextEdit) that are applied when * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. @@ -254,6 +273,7 @@ declare module 'vscode' { * picking and modifying colors in the editor. */ export interface DocumentColorProvider { + /** * Provide colors for the given document. * @@ -263,13 +283,32 @@ declare module 'vscode' { * can be signaled by returning `undefined`, `null`, or an empty array. */ provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; + /** - * Provide representations for a color. + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. */ - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation, token: CancellationToken): ProviderResult; + provideColorPresentations(color: Color, context: { document: TextDocument, range: Range }, token: CancellationToken): ProviderResult; } export namespace languages { + + /** + * Register a color provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A color provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; } } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 4a6a22e86f0..7718b667dd4 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { mixin } from 'vs/base/common/objects'; import * as vscode from 'vscode'; import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters'; -import { Range, Disposable, CompletionList, SnippetString } from 'vs/workbench/api/node/extHostTypes'; +import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; @@ -721,19 +721,12 @@ class ColorProviderAdapter { }); } - provideColorPresentations(resource: URI, rawColorInfo: IRawColorInfo): TPromise { - let colorInfo: vscode.ColorInformation = { - range: TypeConverters.toRange(rawColorInfo.range), - color: { - red: rawColorInfo.color[0], - green: rawColorInfo.color[1], - blue: rawColorInfo.color[2], - alpha: rawColorInfo.color[3] - } - }; - const doc = this._documents.getDocumentData(resource).document; - return asWinJsPromise(token => this._provider.provideColorPresentations(doc, colorInfo, token)).then(value => { - return value.map(v => TypeConverters.ColorPresentation.from(v)); + provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise { + const document = this._documents.getDocumentData(resource).document; + const range = TypeConverters.toRange(raw.range); + const color = new Color(raw.color[0], raw.color[1], raw.color[2], raw.color[3]); + return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => { + return value.map(TypeConverters.ColorPresentation.from); }); } } From 46b7697866e6eb87bebcfcc8f42107d24d672d37 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 12:42:54 +0200 Subject: [PATCH 242/303] color - move color provider api to stable api --- src/vs/vscode.d.ts | 138 +++++++++++++++++ src/vs/vscode.proposed.d.ts | 143 ------------------ src/vs/workbench/api/node/extHost.api.impl.ts | 9 +- 3 files changed, 142 insertions(+), 148 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 68b3d1b5d45..891b0b2289f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2996,7 +2996,132 @@ declare module 'vscode' { resolveDocumentLink?(link: DocumentLink, token: CancellationToken): ProviderResult; } + /** + * Represents a color in RGBA space. + */ + export class Color { + /** + * The red component of this color in the range [0-1]. + */ + readonly red: number; + + /** + * The green component of this color in the range [0-1]. + */ + readonly green: number; + + /** + * The blue component of this color in the range [0-1]. + */ + readonly blue: number; + + /** + * The alpha component of this color in the range [0-1]. + */ + readonly alpha: number; + + /** + * Creates a new color instance. + * + * @param red The red component. + * @param green The green component. + * @param blue The bluew component. + * @param alpha The alpha component. + */ + constructor(red: number, green: number, blue: number, alpha: number); + } + + /** + * Represents a color range from a document. + */ + export class ColorInformation { + + /** + * The range in the document where this color appers. + */ + range: Range; + + /** + * The actual color value for this color range. + */ + color: Color; + + /** + * Creates a new color range. + * + * @param range The range the color appears in. Must not be empty. + * @param color The value of the color. + * @param format The format in which this color is currently formatted. + */ + constructor(range: Range, color: Color); + } + + /** + * A color presentation object describes how a [`color`](#Color) should be represented as text and what + * edits are required to refer to it from source code. + * + * For some languages one color can have multiple presentations, e.g. css can represent the color red with + * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations + * apply, e.g `System.Drawing.Color.Red`. + */ + export class ColorPresentation { + + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string; + + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + textEdit?: TextEdit; + + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + additionalTextEdits?: TextEdit[]; + + /** + * Creates a new color presentation. + * + * @param label The label of this color presentation. + */ + constructor(label: string); + } + + /** + * The document color provider defines the contract between extensions and feature of + * picking and modifying colors in the editor. + */ + export interface DocumentColorProvider { + + /** + * Provide colors for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [color informations](#ColorInformation) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideColorPresentations(color: Color, context: { document: TextDocument, range: Range }, token: CancellationToken): ProviderResult; + } /** * A tuple of two characters, like a pair of @@ -5587,6 +5712,19 @@ declare module 'vscode' { */ export function registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable; + /** + * Register a color provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A color provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; + /** * Set a [language configuration](#LanguageConfiguration) for a language. * diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ee6b4bbc923..0c5dba2a3e5 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -168,147 +168,4 @@ declare module 'vscode' { */ export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable; } - - /** - * Represents a color in RGBA space. - */ - export class Color { - - /** - * The red component of this color in the range [0-1]. - */ - readonly red: number; - - /** - * The green component of this color in the range [0-1]. - */ - readonly green: number; - - /** - * The blue component of this color in the range [0-1]. - */ - readonly blue: number; - - /** - * The alpha component of this color in the range [0-1]. - */ - readonly alpha: number; - - /** - * Creates a new color instance. - * - * @param red The red component. - * @param green The green component. - * @param blue The bluew component. - * @param alpha The alpha component. - */ - constructor(red: number, green: number, blue: number, alpha: number); - } - - /** - * Represents a color range from a document. - */ - export class ColorInformation { - - /** - * The range in the document where this color appers. - */ - range: Range; - - /** - * The actual color value for this color range. - */ - color: Color; - - /** - * Creates a new color range. - * - * @param range The range the color appears in. Must not be empty. - * @param color The value of the color. - * @param format The format in which this color is currently formatted. - */ - constructor(range: Range, color: Color); - } - - /** - * A color presentation object describes how a [`color`](#Color) should be represented as text and what - * edits are required to refer to it from source code. - * - * For some languages one color can have multiple presentations, e.g. css can represent the color red with - * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations - * apply, e.g `System.Drawing.Color.Red`. - */ - export class ColorPresentation { - - /** - * The label of this color presentation. It will be shown on the color - * picker header. By default this is also the text that is inserted when selecting - * this color presentation. - */ - label: string; - - /** - * An [edit](#TextEdit) which is applied to a document when selecting - * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) - * is used. - */ - textEdit?: TextEdit; - - /** - * An optional array of additional [text edits](#TextEdit) that are applied when - * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. - */ - additionalTextEdits?: TextEdit[]; - - /** - * Creates a new color presentation. - * - * @param label The label of this color presentation. - */ - constructor(label: string); - } - - /** - * The document color provider defines the contract between extensions and feature of - * picking and modifying colors in the editor. - */ - export interface DocumentColorProvider { - - /** - * Provide colors for the given document. - * - * @param document The document in which the command was invoked. - * @param token A cancellation token. - * @return An array of [color informations](#ColorInformation) or a thenable that resolves to such. The lack of a result - * can be signaled by returning `undefined`, `null`, or an empty array. - */ - provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; - - /** - * Provide [representations](#ColorPresentation) for a color. - * - * @param color The color to show and insert. - * @param context A context object with additional information - * @param token A cancellation token. - * @return An array of color presentations or a thenable that resolves to such. The lack of a result - * can be signaled by returning `undefined`, `null`, or an empty array. - */ - provideColorPresentations(color: Color, context: { document: TextDocument, range: Range }, token: CancellationToken): ProviderResult; - } - - export namespace languages { - - /** - * Register a color provider. - * - * Multiple providers can be registered for a language. In that case providers are asked in - * parallel and the results are merged. A failing provider (rejected promise or exception) will - * not cause a failure of the whole operation. - * - * @param selector A selector that defines the documents this provider is applicable to. - * @param provider A color provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. - */ - export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; - } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 0df38e8773f..32af7291dfc 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -269,13 +269,12 @@ export function createApiFactory( registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable { return languageFeatures.registerDocumentLinkProvider(selector, provider); }, + registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable { + return languageFeatures.registerColorProvider(selector, provider); + }, setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => { return languageFeatures.setLanguageConfiguration(language, configuration); - }, - // proposed API - registerColorProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider) => { - return languageFeatures.registerColorProvider(selector, provider); - }) + } }; // namespace: window From 37043bc9d28647e8dd40551e715e0aae9640cb9c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 14:46:40 +0200 Subject: [PATCH 243/303] deco - tooltip -> title --- src/vs/workbench/browser/labels.ts | 2 +- .../parts/markers/browser/markersFileDecorations.ts | 2 +- .../parts/scm/electron-browser/scmFileDecorations.ts | 2 +- .../workbench/services/decorations/browser/decorations.ts | 4 ++-- .../services/decorations/browser/decorationsService.ts | 6 +++--- .../decorations/test/browser/decorationsService.test.ts | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 08a68da883c..ec6920eed22 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -192,7 +192,7 @@ export class ResourceLabel extends IconLabel { } if (deco && deco.badgeClassName && this.options.fileDecorations.badges) { iconLabelOptions.badge = { - title: deco.tooltip, + title: deco.title, className: deco.badgeClassName, }; } diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 670e1db47da..e9a44a611ac 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -44,7 +44,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { return { weight: 100 * first.severity, - tooltip: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), + title: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), letter: markers.length.toString(), color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, }; diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index ebfd9f55cd9..75fcbab94b8 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -67,7 +67,7 @@ class SCMDecorationsProvider implements IDecorationsProvider { } return { weight: 100 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0), - tooltip: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), + title: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), color: resource.decorations.color, letter: resource.decorations.tooltip.charAt(0) }; diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 1c42c362433..25401fd795a 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -17,13 +17,13 @@ export interface IDecorationData { readonly color?: ColorIdentifier; readonly opacity?: number; readonly letter?: string; - readonly tooltip?: string; + readonly title?: string; } export interface IDecoration { readonly _decoBrand: undefined; readonly weight?: number; - readonly tooltip?: string; + readonly title?: string; readonly labelClassName?: string; readonly badgeClassName?: string; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index feb0ff47fe3..9792da756f4 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -93,10 +93,10 @@ class ResourceDecoration implements IDecoration { let result = new ResourceDecoration(data); if (Array.isArray(data)) { result.weight = data[0].weight; - result.tooltip = data.map(d => d.tooltip).join(', '); + result.title = data.map(d => d.title).join(', '); } else { result.weight = data.weight; - result.tooltip = data.tooltip; + result.title = data.title; } return result; } @@ -105,7 +105,7 @@ class ResourceDecoration implements IDecoration { _data: IDecorationData | IDecorationData[]; weight?: number; - tooltip?: string; + title?: string; labelClassName?: string; badgeClassName?: string; diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 8135a7eceac..54f37ccf294 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -36,7 +36,7 @@ suite('DecorationsService', function () { return new Promise(resolve => { setTimeout(() => resolve({ color: 'someBlue', - tooltip: 'T' + title: 'T' })); }); } @@ -51,7 +51,7 @@ suite('DecorationsService', function () { assert.equal(e.affectsResource(uri), true); // sync result - assert.deepEqual(service.getDecoration(uri, false).tooltip, 'T'); + assert.deepEqual(service.getDecoration(uri, false).title, 'T'); assert.equal(callCounter, 1); }); }); @@ -71,7 +71,7 @@ suite('DecorationsService', function () { }); // trigger -> sync - assert.deepEqual(service.getDecoration(uri, false).tooltip, 'Z'); + assert.deepEqual(service.getDecoration(uri, false).title, 'Z'); assert.equal(callCounter, 1); }); @@ -89,7 +89,7 @@ suite('DecorationsService', function () { }); // trigger -> sync - assert.deepEqual(service.getDecoration(uri, false).tooltip, 'J'); + assert.deepEqual(service.getDecoration(uri, false).title, 'J'); assert.equal(callCounter, 1); // un-register -> ensure good event From 9cdb5bb4806c7f1e7971247a4eaf071819b8fd1f Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 14:54:49 +0200 Subject: [PATCH 244/303] debug: enable / disable all breakpoints should not touch exception breakpoints fixes #36349 --- src/vs/workbench/parts/debug/common/debugModel.ts | 1 - .../parts/debug/electron-browser/debugViewer.ts | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 2859af8fc30..c8ef0226454 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -916,7 +916,6 @@ export class Model implements IModel { bp.verified = false; } }); - this.exceptionBreakpoints.forEach(ebp => ebp.enabled = enable); this.functionBreakpoints.forEach(fbp => fbp.enabled = enable); this._onDidChangeBreakpoints.fire(); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index d8104fbc3a2..521ebfd16d0 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -1062,11 +1062,12 @@ export class BreakpointsActionProvider implements IActionProvider { } public getSecondaryActions(tree: ITree, element: any): TPromise { - const actions: IAction[] = []; - - if (element instanceof Breakpoint || element instanceof FunctionBreakpoint) { - actions.push(this.instantiationService.createInstance(RemoveBreakpointAction, RemoveBreakpointAction.ID, RemoveBreakpointAction.LABEL)); + if (element instanceof ExceptionBreakpoint) { + return TPromise.as([]); } + + const actions: IAction[] = []; + actions.push(this.instantiationService.createInstance(RemoveBreakpointAction, RemoveBreakpointAction.ID, RemoveBreakpointAction.LABEL)); if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) { actions.push(this.instantiationService.createInstance(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL)); actions.push(new Separator()); From 10a0e425693dfdc949441aeccf50f0c0178f2565 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 15:26:00 +0200 Subject: [PATCH 245/303] bump node debug version --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 9f7088b945e..e424881eaab 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,7 +45,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.18' }, + { name: 'ms-vscode.node-debug', version: '1.18.1' }, { name: 'ms-vscode.node-debug2', version: '1.18.1' } ]; From 9a9c8c7afb7753fdf71bee9193718448ea8c8179 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 15:30:30 +0200 Subject: [PATCH 246/303] show message when no formatter is installed, #36303 --- .../editor/common/editorCommonExtensions.ts | 3 ++- .../contrib/format/browser/formatActions.ts | 19 ++++++++++++++++--- src/vs/editor/contrib/format/common/format.ts | 15 +++++++++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/common/editorCommonExtensions.ts b/src/vs/editor/common/editorCommonExtensions.ts index fee9cdfbd3a..aaea4371983 100644 --- a/src/vs/editor/common/editorCommonExtensions.ts +++ b/src/vs/editor/common/editorCommonExtensions.ts @@ -153,6 +153,7 @@ export abstract class EditorCommand extends Command { export interface IEditorCommandMenuOptions { group?: string; order?: number; + when?: ContextKeyExpr; } export interface IActionOptions extends ICommandOptions { label: string; @@ -182,7 +183,7 @@ export abstract class EditorAction extends EditorCommand { id: this.id, title: this.label }, - when: this.precondition, + when: ContextKeyExpr.and(this.precondition, this.menuOpts.when), group: this.menuOpts.group, order: this.menuOpts.order }; diff --git a/src/vs/editor/contrib/format/browser/formatActions.ts b/src/vs/editor/contrib/format/browser/formatActions.ts index de620bc090b..62cd203a97b 100644 --- a/src/vs/editor/contrib/format/browser/formatActions.ts +++ b/src/vs/editor/contrib/format/browser/formatActions.ts @@ -13,7 +13,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { editorAction, ServicesAccessor, EditorAction, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions'; import { OnTypeFormattingEditProviderRegistry, DocumentRangeFormattingEditProviderRegistry } from 'vs/editor/common/modes'; -import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits } from '../common/format'; +import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits, NoProviderError } from '../common/format'; import { EditOperationsCommand } from '../common/formatCommand'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; @@ -23,6 +23,7 @@ import { Range } from 'vs/editor/common/core/range'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { EditorState, CodeEditorStateFlag } from 'vs/editor/common/core/editorState'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; function alertFormattingEdits(edits: editorCommon.ISingleEditOperation[]): void { @@ -263,6 +264,7 @@ export abstract class AbstractFormatAction extends EditorAction { public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): TPromise { const workerService = accessor.get(IEditorWorkerService); + const messageService = accessor.get(IMessageService); const formattingPromise = this._getFormattingEdits(editor); if (!formattingPromise) { @@ -281,6 +283,15 @@ export abstract class AbstractFormatAction extends EditorAction { EditOperationsCommand.execute(editor, edits); alertFormattingEdits(edits); editor.focus(); + }, err => { + if (err instanceof Error && err.name === NoProviderError.Name) { + messageService.show( + Severity.Info, + nls.localize('no.provider', "Sorry, but there is no formatter for '{0}'-files installed.", editor.getModel().getLanguageIdentifier().language), + ); + } else { + throw err; + } }); } @@ -296,7 +307,7 @@ export class FormatDocumentAction extends AbstractFormatAction { id: 'editor.action.formatDocument', label: nls.localize('formatDocument.label', "Format Document"), alias: 'Format Document', - precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider), + precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F, @@ -304,6 +315,7 @@ export class FormatDocumentAction extends AbstractFormatAction { linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I } }, menuOpts: { + when: EditorContextKeys.hasDocumentFormattingProvider, group: '1_modification', order: 1.3 } @@ -325,12 +337,13 @@ export class FormatSelectionAction extends AbstractFormatAction { id: 'editor.action.formatSelection', label: nls.localize('formatSelection.label', "Format Selection"), alias: 'Format Code', - precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasNonEmptySelection), + precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasNonEmptySelection), kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F) }, menuOpts: { + when: ContextKeyExpr.and(EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasNonEmptySelection), group: '1_modification', order: 1.31 } diff --git a/src/vs/editor/contrib/format/common/format.ts b/src/vs/editor/contrib/format/common/format.ts index 0f8bb567719..37c0f0246fd 100644 --- a/src/vs/editor/contrib/format/common/format.ts +++ b/src/vs/editor/contrib/format/common/format.ts @@ -17,12 +17,23 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { asWinJsPromise, sequence } from 'vs/base/common/async'; import { Position } from 'vs/editor/common/core/position'; -export function getDocumentRangeFormattingEdits(model: IReadOnlyModel, range: Range, options: FormattingOptions): TPromise { +export class NoProviderError extends Error { + + static readonly Name = 'NOPRO'; + + constructor(message?: string) { + super(); + this.name = NoProviderError.Name; + this.message = message; + } +} + +export function getDocumentRangeFormattingEdits(model: IReadOnlyModel, range: Range, options: FormattingOptions): TPromise { const providers = DocumentRangeFormattingEditProviderRegistry.ordered(model); if (providers.length === 0) { - return TPromise.as(undefined); + return TPromise.wrapError(new NoProviderError()); } let result: TextEdit[]; From abff32ca6c1daf1e2b9bf02b9fff3f309b26e25d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 15:38:33 +0200 Subject: [PATCH 247/303] deco - tweak config listening --- .../electron-browser/scmFileDecorations.ts | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 75fcbab94b8..02616fb2a13 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -13,7 +13,6 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; -import { equals } from 'vs/base/common/objects'; class SCMDecorationsProvider implements IDecorationsProvider { @@ -85,14 +84,13 @@ export class FileDecorations implements IWorkbenchContribution { private _providers = new Map(); private _configListener: IDisposable; private _repoListeners: IDisposable[]; - private _currentConfig: ISCMConfiguration; constructor( @IDecorationsService private _decorationsService: IDecorationsService, @IConfigurationService private _configurationService: IConfigurationService, @ISCMService private _scmService: ISCMService, ) { - this._configListener = this._configurationService.onDidUpdateConfiguration(this._update, this); + this._configListener = this._configurationService.onDidUpdateConfiguration(e => e.affectsConfiguration('scm.fileDecorations.enabled') && this._update()); this._update(); } @@ -108,20 +106,16 @@ export class FileDecorations implements IWorkbenchContribution { private _update(): void { const config = this._configurationService.getConfiguration('scm'); - if (!equals(config, this._currentConfig)) { - this._currentConfig = config; - - if (this._currentConfig.fileDecorations.enabled) { - this._scmService.repositories.forEach(this._onDidAddRepository, this); - this._repoListeners = [ - this._scmService.onDidAddRepository(this._onDidAddRepository, this), - this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) - ]; - } else { - this._repoListeners = dispose(this._repoListeners); - this._providers.forEach(value => dispose(value)); - this._providers.clear(); - } + if (config.fileDecorations.enabled) { + this._scmService.repositories.forEach(this._onDidAddRepository, this); + this._repoListeners = [ + this._scmService.onDidAddRepository(this._onDidAddRepository, this), + this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) + ]; + } else { + this._repoListeners = dispose(this._repoListeners); + this._providers.forEach(value => dispose(value)); + this._providers.clear(); } } From 5276a4fcc85370a7131fd0a2d5a0e8d357ff9287 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 15:47:19 +0200 Subject: [PATCH 248/303] deco - proper explorer update on config change --- .../parts/files/browser/views/explorerView.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index ca642768b2b..f522ebcea6d 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -33,7 +33,7 @@ import { IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -204,7 +204,7 @@ export class ExplorerView extends ViewsViewletPanel { this.disposables.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); // Also handle configuration updates - this.disposables.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true))); + this.disposables.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), e))); }); } @@ -251,7 +251,7 @@ export class ExplorerView extends ViewsViewletPanel { } } - private onConfigurationUpdated(configuration: IFilesConfiguration, refresh?: boolean): void { + private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void { if (this.isDisposed) { return; // guard against possible race condition when config change causes recreate of views } @@ -270,8 +270,13 @@ export class ExplorerView extends ViewsViewletPanel { needsRefresh = true; } + if (event && !needsRefresh) { + needsRefresh = event.affectsConfiguration('explorer.decorations.colors') + || event.affectsConfiguration('explorer.decorations.badges'); + } + // Refresh viewer as needed - if (refresh && needsRefresh) { + if (needsRefresh) { this.doRefresh().done(null, errors.onUnexpectedError); } } From f704a6c7101f998a24690b8678c199ca96952921 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 16:01:05 +0200 Subject: [PATCH 249/303] composite part: move pin / unpin / mode to compositePart --- .../parts/activitybar/activitybarActions.ts | 2 +- .../parts/activitybar/activitybarPart.ts | 60 ++----------- .../parts/compositebar/compositeBar.ts | 86 +++++++++++++------ 3 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index b20d15c85cb..20c50332d10 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -62,7 +62,7 @@ export class ViewletActivityAction extends ActivityAction { } } -export class OpenViewletAction extends Action { +export class ToggleViewletAction extends Action { constructor( private _viewlet: ViewletDescriptor, diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 857847afc19..c8c4dbafb07 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -15,7 +15,7 @@ import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/act import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; import { Part } from 'vs/workbench/browser/part'; -import { ToggleViewletPinnedAction, GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, OpenViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { ToggleViewletPinnedAction, GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService'; @@ -64,9 +64,12 @@ export class ActivitybarPart extends Part implements IActivityBarService { orientation: ActionsOrientation.VERTICAL, composites: this.viewletService.getViewlets(), getCompositeSize: (compositeId: string) => ActivitybarPart.ACTIVITY_ACTION_HEIGHT, + openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)), getCompositePinnedAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletPinnedAction, this.viewletService.getViewlet(compositeId)), - getOpenCompositeAction: (compositeId: string) => this.instantiationService.createInstance(OpenViewletAction, this.viewletService.getViewlet(compositeId)) + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, this.viewletService.getViewlet(compositeId)), + getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(), + hidePart: () => this.partService.setSideBarHidden(true) }); this.registerListeners(); } @@ -78,7 +81,6 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId()))); - this.toUnbind.push(this.compositeBar.onDidDropComposite(data => this.move(data.compositeId, data.toCompositeId))); this.toUnbind.push(this.compositeBar.onDidContextMenu(e => this.showContextMenu(e))); } @@ -176,44 +178,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } public unpin(viewletId: string): void { - if (!this.compositeBar.isPinned(viewletId)) { - return; - } - - const activeViewlet = this.viewletService.getActiveViewlet(); - const defaultViewletId = this.viewletService.getDefaultViewletId(); - const visibleViewlets = this.compositeBar.getVisibleComposites(); - - let unpinPromise: TPromise; - - // Case: viewlet is not the active one or the active one is a different one - // Solv: we do nothing - if (!activeViewlet || activeViewlet.getId() !== viewletId) { - unpinPromise = TPromise.as(null); - } - - // Case: viewlet is not the default viewlet and default viewlet is still showing - // Solv: we open the default viewlet - else if (defaultViewletId !== viewletId && this.compositeBar.isPinned(defaultViewletId)) { - unpinPromise = this.viewletService.openViewlet(defaultViewletId, true); - } - - // Case: we closed the last visible viewlet - // Solv: we hide the sidebar - else if (visibleViewlets.length === 1) { - unpinPromise = this.partService.setSideBarHidden(true); - } - - // Case: we closed the default viewlet - // Solv: we open the next visible viewlet from top - else { - unpinPromise = this.viewletService.openViewlet(visibleViewlets.filter(viewletId => viewletId !== viewletId)[0], true); - } - - unpinPromise.then(() => { - // then remove from pinned and update switcher - this.compositeBar.unpin(viewletId); - }); + this.compositeBar.unpin(viewletId); } public isPinned(viewletId: string): boolean { @@ -221,21 +186,10 @@ export class ActivitybarPart extends Part implements IActivityBarService { } public pin(viewletId: string, update = true): void { - if (this.isPinned(viewletId)) { - return; - } - - // first open that viewlet - this.viewletService.openViewlet(viewletId, true) - .then(() => this.compositeBar.pin(viewletId, update)); + this.compositeBar.pin(viewletId, update); } public move(viewletId: string, toViewletId: string): void { - // Make sure a moved viewlet gets pinned - if (!this.isPinned(viewletId)) { - this.pin(viewletId, false /* defer update, we take care of it */); - } - this.compositeBar.move(viewletId, toViewletId); } diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index 18b83e8938e..fac2c91cf0c 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -12,15 +12,13 @@ import * as dom from 'vs/base/browser/dom'; import * as arrays from 'vs/base/common/arrays'; import { Dimension } from 'vs/base/browser/builder'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IBadge } from 'vs/workbench/services/activity/common/activityBarService'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import Event, { Emitter } from 'vs/base/common/event'; import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { TPromise } from 'vs/base/common/winjs.base'; export interface ICompositeBarOptions { label: 'icon' | 'name'; @@ -29,14 +27,16 @@ export interface ICompositeBarOptions { composites: { id: string, name: string }[]; getActivityAction: (compositeId: string) => ActivityAction; getCompositePinnedAction: (compositeId: string) => Action; - getOpenCompositeAction: (compositeId: string) => Action; + getOnCompositeClickAction: (compositeId: string) => Action; + openComposite: (compositeId: string) => TPromise; + getDefaultCompositeId: () => string; getCompositeSize: (compositeId: string) => number; + hidePart: () => TPromise; } export class CompositeBar { private _onDidContextMenu: Emitter; - private _onDidDropComposite: Emitter<{ compositeId: string, toCompositeId: string }>; private dimension: Dimension; private toDispose: IDisposable[]; @@ -55,11 +55,8 @@ export class CompositeBar { constructor( private options: ICompositeBarOptions, - @IContextMenuService private contextMenuService: IContextMenuService, @IInstantiationService private instantiationService: IInstantiationService, @IStorageService private storageService: IStorageService, - @IPartService private partService: IPartService, - @IThemeService themeService: IThemeService, ) { this.toDispose = []; this.compositeIdToActionItems = Object.create(null); @@ -67,7 +64,6 @@ export class CompositeBar { this.compositeIdToActivityStack = Object.create(null); this._onDidContextMenu = new Emitter(); - this._onDidDropComposite = new Emitter<{ compositeId: string, toCompositeId: string }>(); const pinnedComposites = JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, null)) as string[]; if (pinnedComposites) { @@ -81,10 +77,6 @@ export class CompositeBar { return this._onDidContextMenu.event; } - public get onDidDropComposite(): Event<{ compositeId: string, toCompositeId: string }> { - return this._onDidDropComposite.event; - } - public activateComposite(id: string): void { if (this.compositeIdToActions[id]) { this.compositeIdToActions[id].activate(); @@ -184,7 +176,7 @@ export class CompositeBar { const targetId = this.pinnedComposites[this.pinnedComposites.length - 1]; if (targetId !== draggedCompositeId) { - this._onDidDropComposite.fire({ compositeId: draggedCompositeId, toCompositeId: this.pinnedComposites[this.pinnedComposites.length - 1] }); + this.move(draggedCompositeId, this.pinnedComposites[this.pinnedComposites.length - 1]); } } })); @@ -279,7 +271,7 @@ export class CompositeBar { () => this.getOverflowingComposites(), () => this.activeCompositeId, (compositeId: string) => this.compositeIdToActivityStack[compositeId] && this.compositeIdToActivityStack[compositeId][0].badge, - this.options.getOpenCompositeAction + this.options.getOnCompositeClickAction ); this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: true, icon: true }); @@ -297,7 +289,7 @@ export class CompositeBar { return this.options.composites.filter(c => overflowingIds.indexOf(c.id) !== -1); } - public getVisibleComposites(): string[] { + private getVisibleComposites(): string[] { return Object.keys(this.compositeIdToActions); } @@ -326,10 +318,46 @@ export class CompositeBar { } public unpin(compositeId: string): void { - const index = this.pinnedComposites.indexOf(compositeId); - this.pinnedComposites.splice(index, 1); + if (!this.isPinned(compositeId)) { + return; + } - this.updateCompositeSwitcher(); + const defaultCompositeId = this.options.getDefaultCompositeId(); + const visibleComposites = this.getVisibleComposites(); + + let unpinPromise: TPromise; + + // Case: composite is not the active one or the active one is a different one + // Solv: we do nothing + if (!this.activeCompositeId || this.activeCompositeId !== compositeId) { + unpinPromise = TPromise.as(null); + } + + // Case: composite is not the default composite and default composite is still showing + // Solv: we open the default composite + else if (defaultCompositeId !== compositeId && this.isPinned(defaultCompositeId)) { + unpinPromise = this.options.openComposite(defaultCompositeId); + } + + // Case: we closed the last visible composite + // Solv: we hide the part + else if (visibleComposites.length === 1) { + unpinPromise = this.options.hidePart(); + } + + // Case: we closed the default composite + // Solv: we open the next visible composite from top + else { + unpinPromise = this.options.openComposite(visibleComposites.filter(cid => cid !== compositeId)[0]); + } + + unpinPromise.then(() => { + // then remove from pinned and update switcher + const index = this.pinnedComposites.indexOf(compositeId); + this.pinnedComposites.splice(index, 1); + + this.updateCompositeSwitcher(); + }); } public isPinned(compositeId: string): boolean { @@ -337,15 +365,25 @@ export class CompositeBar { } public pin(compositeId: string, update = true): void { - this.pinnedComposites.push(compositeId); - this.pinnedComposites = arrays.distinct(this.pinnedComposites); - - if (update) { - this.updateCompositeSwitcher(); + if (this.isPinned(compositeId)) { + return; } + + this.options.openComposite(compositeId).then(() => { + this.pinnedComposites.push(compositeId); + this.pinnedComposites = arrays.distinct(this.pinnedComposites); + + if (update) { + this.updateCompositeSwitcher(); + } + }); } public move(compositeId: string, toCompositeId: string): void { + // Make sure a moved composite gets pinned + if (!this.isPinned(compositeId)) { + this.pin(compositeId, false /* defer update, we take care of it */); + } const fromIndex = this.pinnedComposites.indexOf(compositeId); const toIndex = this.pinnedComposites.indexOf(toCompositeId); From 3170a7f5f9f1ec83d8af413841d42d8500b352be Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 16:07:40 +0200 Subject: [PATCH 250/303] Do not overload getConfiguration for sending it to extension host. Use getConfigurationData --- src/vs/platform/configuration/common/configuration.ts | 2 ++ .../configuration/node/configurationService.ts | 6 +++++- .../api/electron-browser/mainThreadConfiguration.ts | 2 +- .../configuration/node/configurationService.ts | 10 ++++++---- .../extensions/electron-browser/extensionHost.ts | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 4ad222fdb0b..5f50cf05077 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -50,6 +50,8 @@ export interface IConfigurationService { onDidUpdateConfiguration: Event; + getConfigurationData(): IConfigurationData; + getConfiguration(): T; getConfiguration(section: string): T; getConfiguration(overrides: IConfigurationOverrides): T; diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 19f78c792ab..6b1d5954fa5 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -8,7 +8,7 @@ import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration'; import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -52,6 +52,10 @@ export class ConfigurationService extends Disposable implements IConfigurationSe return this._configuration; } + getConfigurationData(): IConfigurationData { + return this.configuration.toData(); + } + getConfiguration(): T getConfiguration(section: string): T getConfiguration(overrides: IConfigurationOverrides): T diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 46648b2b1ae..71f54113cfd 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -29,7 +29,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); this._configurationListener = configurationService.onDidUpdateConfiguration(() => { - proxy.$acceptConfigurationChanged(configurationService.getConfiguration()); + proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); }); } diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index b4902fe2e8e..5c83bdddbbb 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -24,7 +24,7 @@ import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { CustomConfigurationModel, ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; -import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration'; import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService'; @@ -128,6 +128,10 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // Workspace Configuration Service Impl + getConfigurationData(): IConfigurationData { + return this._configuration.toData(); + } + getConfiguration(): T getConfiguration(section: string): T getConfiguration(overrides: IConfigurationOverrides): T @@ -135,9 +139,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - const contents = this._configuration.getSection(section, overrides); - return typeof contents === 'object' ? { toJSON: () => this._configuration.toData(), ...contents } - : contents; + return this._configuration.getSection(section, overrides); } getValue(key: string, overrides?: IConfigurationOverrides): T { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 553e69ad627..d4b17a7fbc3 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -360,7 +360,7 @@ export class ExtensionHostProcessWorker { }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace(), extensions: extensionDescriptions, - configuration: this._configurationService.getConfiguration(), + configuration: this._configurationService.getConfigurationData(), telemetryInfo }; return r; From 8f4e125ab8204f88d782478a98e4e588f5390333 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 16:09:19 +0200 Subject: [PATCH 251/303] Fix compilation errors --- src/vs/editor/standalone/browser/simpleServices.ts | 4 ++++ .../configuration/test/common/testConfigurationService.ts | 4 ++++ .../telemetry/test/electron-browser/telemetryService.test.ts | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 4705eac59a4..abc268c123e 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -493,6 +493,10 @@ export class SimpleConfigurationService implements IConfigurationService { public reloadConfiguration(): TPromise { return TPromise.as(null); } + + public getConfigurationData() { + return null; + } } export class SimpleResourceConfigurationService implements ITextResourceConfigurationService { diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 6e0a81519b3..52363535b85 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -82,4 +82,8 @@ export class TestConfigurationService extends EventEmitter implements IConfigura workspaceFolder: [] }; } + + public getConfigurationData() { + return null; + } } diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index 45173045d9a..d97577a72b3 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -698,7 +698,8 @@ suite('TelemetryService', () => { }, keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, onDidUpdateConfiguration: emitter.event, - reloadConfiguration() { return null; } + reloadConfiguration() { return null; }, + getConfigurationData() { return null; } }); assert.equal(service.isOptedIn, false); From 42e1d19ab5206aca4886eb7d4d1766dc0fbff97b Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 16 Oct 2017 16:16:23 +0200 Subject: [PATCH 252/303] composite bar polish css classes --- src/vs/workbench/browser/parts/activitybar/activitybarPart.ts | 4 ++-- src/vs/workbench/browser/parts/compositebar/compositeBar.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index c8c4dbafb07..72b3f6e451a 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -112,10 +112,10 @@ export class ActivitybarPart extends Part implements IActivityBarService { const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.compositeBar.create($result.clone().getHTMLElement()); + this.compositeBar.create($('.viewlets').appendTo($result).getHTMLElement()); // Top Actionbar with action items for each viewlet action - this.createGlobalActivityActionBar($result.getHTMLElement()); + this.createGlobalActivityActionBar($('.global-activity').appendTo($result).getHTMLElement()); return $result; } diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index fac2c91cf0c..12c90a5638a 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -153,6 +153,7 @@ export class CompositeBar { } public create(container: HTMLElement): void { + dom.addClass(container, 'composite-bar'); this.compositeSwitcherBar = new ActionBar(container, { actionItemProvider: (action: Action) => action instanceof CompositeOverflowActivityAction ? this.compositeOverflowActionItem : this.compositeIdToActionItems[action.id], orientation: this.options.orientation, From 9613370d5f8bdbf9e350946ce3284381e95b859d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 16:19:23 +0200 Subject: [PATCH 253/303] update title area faster when opening a new group --- .../parts/editor/editorGroupsControl.ts | 41 ++++++++++++------- .../browser/parts/editor/editorPart.ts | 22 ++++++++-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index ff6acd7892e..9f8ff8ce901 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -73,6 +73,7 @@ export interface IEditorGroupsControl { getInstantiationService(position: Position): IInstantiationService; getProgressBar(position: Position): ProgressBar; updateProgress(position: Position, state: ProgressState): void; + updateTitleAreaControls(): void; layout(dimension: Dimension): void; layout(position: Position): void; @@ -321,7 +322,6 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro public show(editor: BaseEditor, position: Position, preserveActive: boolean, ratio?: number[]): void { const visibleEditorCount = this.getVisibleEditorCount(); - const currentActivePosition = this.getActivePosition(); // Store into editor bucket this.visibleEditors[position] = editor; @@ -392,7 +392,6 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro this.sashOne.layout(); this.layoutContainers(); - this.updateInactiveEditorGroupActions(currentActivePosition); // prevent some ugly flickering when opening a group } // Adjust layout: []|[] -> []|[]|[!] @@ -406,7 +405,6 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro this.sashTwo.layout(); this.layoutContainers(); - this.updateInactiveEditorGroupActions(currentActivePosition); // prevent some ugly flickering when opening a group } // Show editor container @@ -2065,18 +2063,6 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro } } - private updateInactiveEditorGroupActions(position: Position): void { - const activePosition = this.getActivePosition(); - if (activePosition === position) { - return; // this position is actually active - } - - const titleArea = this.getTitleAreaControl(position); - if (titleArea) { - titleArea.updateEditorActionsToolbar(); - } - } - public getInstantiationService(position: Position): IInstantiationService { return this.getFromContainer(position, EditorGroupsControl.INSTANTIATION_SERVICE_KEY); } @@ -2089,6 +2075,31 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro return this.getFromContainer(position, EditorGroupsControl.TITLE_AREA_CONTROL_KEY); } + public updateTitleAreaControls(): void { + POSITIONS.forEach(position => { + const group = this.stacks.groupAt(position); + if (!group) { + return; + } + + const titleControl = this.getTitleAreaControl(position); + if (!titleControl) { + return; + } + + // Make sure the active group is shown in the title and refresh it + if (group.isActive) { + titleControl.setContext(group); + titleControl.refresh(true); + } + + // For inactive groups, just refresh the toolbar + else { + titleControl.updateEditorActionsToolbar(); + } + }); + } + private getFromContainer(position: Position, key: string): any { const silo = this.silos[position]; diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index e1a28c2dd1d..07f8e82161f 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -372,7 +372,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // This can however cause a race condition where the stacks model indicates the opened editor is there // while the UI is not yet ready. Clients have to deal with this fact and we have to make sure that the // stacks model gets updated if any of the UI updating fails with an error. - const group = this.ensureGroup(position, !options || !options.preserveFocus); + const [group, newGroupOpened] = this.ensureGroup(position, !options || !options.preserveFocus); const pinned = !this.tabOptions.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); const active = (group.count === 0) || !options || !options.inactive; @@ -401,7 +401,19 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } // Set input to editor - return this.doSetInput(group, editor, input, options, monitor); + const inputPromise = this.doSetInput(group, editor, input, options, monitor); + + // A new active group got opened. Since this involves updating the title area controls to show + // the new editor and actions we trigger a direct update of title controls from here to avoid + // some UI flickering if we rely on the event handlers that all use schedulers. + // The reason we can trigger this now is that after the input is set to the editor group, the + // resource context is updated and the correct number of actions will be resolved from the title + // area. + if (newGroupOpened && this.stacks.isActive(group)) { + this.editorGroupsControl.updateTitleAreaControls(); + } + + return inputPromise; } private doShowEditor(group: EditorGroup, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[], monitor: ProgressMonitor): BaseEditor { @@ -1523,9 +1535,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService array[from] = empty; } - private ensureGroup(position: Position, activate = true): EditorGroup { + private ensureGroup(position: Position, activate = true): [EditorGroup, boolean /* new group opened */] { + let newGroupOpened = false; let group = this.stacks.groupAt(position); if (!group) { + newGroupOpened = true; // Race condition: it could be that someone quickly opens editors one after // the other and we are asked to open an editor in position 2 before position @@ -1548,7 +1562,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.stacks.setActive(group); } - return group; + return [group, newGroupOpened]; } private modifyGroups(modification: () => void) { From 45a7108337c0ba3d0bc33469429a14043177f40c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2017 19:01:50 +0200 Subject: [PATCH 254/303] :lipstick: --- .../parts/editor/editorGroupsControl.ts | 23 ++++++++++--------- .../browser/parts/editor/editorPart.ts | 13 +++++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index 9f8ff8ce901..af1a3ec1a9d 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -73,7 +73,7 @@ export interface IEditorGroupsControl { getInstantiationService(position: Position): IInstantiationService; getProgressBar(position: Position): ProgressBar; updateProgress(position: Position, state: ProgressState): void; - updateTitleAreaControls(): void; + updateTitleAreas(refreshActive?: boolean): void; layout(dimension: Dimension): void; layout(position: Position): void; @@ -2075,7 +2075,13 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro return this.getFromContainer(position, EditorGroupsControl.TITLE_AREA_CONTROL_KEY); } - public updateTitleAreaControls(): void { + private getFromContainer(position: Position, key: string): any { + const silo = this.silos[position]; + + return silo ? silo.child().getProperty(key) : void 0; + } + + public updateTitleAreas(refreshActive?: boolean): void { POSITIONS.forEach(position => { const group = this.stacks.groupAt(position); if (!group) { @@ -2087,25 +2093,20 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro return; } - // Make sure the active group is shown in the title and refresh it - if (group.isActive) { + // Make sure the active group is shown in the title + // and refresh it if we are instructed to refresh it + if (refreshActive && group.isActive) { titleControl.setContext(group); titleControl.refresh(true); } - // For inactive groups, just refresh the toolbar + // Otherwise, just refresh the toolbar else { titleControl.updateEditorActionsToolbar(); } }); } - private getFromContainer(position: Position, key: string): any { - const silo = this.silos[position]; - - return silo ? silo.child().getProperty(key) : void 0; - } - public updateProgress(position: Position, state: ProgressState): void { const progressbar = this.getProgressBar(position); if (!progressbar) { diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 07f8e82161f..3b01b41686a 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -327,10 +327,10 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Some conditions under which we prevent the request if ( - !input || // no input - position === null || // invalid position - !this.editorGroupsControl || // too early - this.editorGroupsControl.isDragging() // pending editor DND + !input || // no input + position === null || // invalid position + !this.editorGroupsControl || // too early + this.editorGroupsControl.isDragging() // pending editor DND ) { return TPromise.as(null); } @@ -410,7 +410,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // resource context is updated and the correct number of actions will be resolved from the title // area. if (newGroupOpened && this.stacks.isActive(group)) { - this.editorGroupsControl.updateTitleAreaControls(); + this.editorGroupsControl.updateTitleAreas(true /* refresh new active group */); } return inputPromise; @@ -655,6 +655,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Explicitly trigger the focus changed handler because the side by side control will not trigger it unless // the user is actively changing focus with the mouse from left/top to right/bottom. this.onGroupFocusChanged(); + + // Update title area sync to avoid some flickering with actions + this.editorGroupsControl.updateTitleAreas(); } } From a4ae83754b19ca38a027954183e65250b50fe4e2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 16 Oct 2017 19:38:54 +0200 Subject: [PATCH 255/303] fix decorations service test --- .../decorations/test/browser/decorationsService.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 54f37ccf294..21708a3b55d 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -66,7 +66,7 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { color: 'someBlue', tooltip: 'Z' }; + return { color: 'someBlue', title: 'Z' }; } }); @@ -84,7 +84,7 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return { color: 'someBlue', tooltip: 'J' }; + return { color: 'someBlue', title: 'J' }; } }); From b5774640f1c056c115027f5755c78e7496fbfc47 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 23:01:02 +0200 Subject: [PATCH 256/303] Use IConfigurationService.updateValue instead of IConfigurationEditingService --- .../configuration/common/configuration.ts | 6 +- .../common/configurationModels.ts | 10 ++-- .../mainThreadConfiguration.ts | 9 ++- src/vs/workbench/api/node/extHost.protocol.ts | 3 +- .../api/node/extHostConfiguration.ts | 5 +- .../actions/toggleActivityBarVisibility.ts | 8 +-- .../browser/actions/toggleSidebarPosition.ts | 10 ++-- .../actions/toggleStatusbarVisibility.ts | 8 +-- .../browser/parts/editor/editorStatus.ts | 21 ++----- src/vs/workbench/electron-browser/actions.ts | 33 ++++------- src/vs/workbench/electron-browser/window.ts | 5 +- .../electron-browser/accessibility.ts | 9 +-- .../electron-browser/toggleMinimap.ts | 6 +- .../toggleMultiCursorModifier.ts | 12 +--- .../toggleRenderControlCharacter.ts | 6 +- .../toggleRenderWhitespace.ts | 6 +- .../electron-browser/extensionTipsService.ts | 8 +-- .../node/extensionsWorkbenchService.ts | 6 +- .../parts/files/browser/explorerViewlet.ts | 2 - .../parts/files/browser/fileActions.ts | 13 ++--- .../files/browser/views/explorerViewer.ts | 8 +-- .../preferences/browser/preferencesEditor.ts | 6 +- .../browser/preferencesRenderers.ts | 30 +++------- .../preferences/browser/preferencesService.ts | 17 +++--- .../preferences/browser/preferencesWidgets.ts | 6 +- .../parts/preferences/common/preferences.ts | 5 +- .../preferences/common/preferencesModels.ts | 2 +- .../electron-browser/task.contribution.ts | 25 +++----- .../parts/terminal/common/terminalService.ts | 2 +- .../electron-browser/terminalService.ts | 7 +-- .../electron-browser/themes.contribution.ts | 2 +- .../page/electron-browser/welcomePage.ts | 6 +- .../node/configurationEditingService.ts | 4 +- .../node/configurationService.ts | 30 ++-------- .../node/configurationEditingService.test.ts | 4 ++ .../themes/common/workbenchThemeService.ts | 2 +- .../electron-browser/workbenchThemeService.ts | 7 +-- .../api/extHostConfiguration.test.ts | 4 +- .../api/mainThreadConfiguration.test.ts | 58 +++++++++---------- 39 files changed, 153 insertions(+), 258 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 5f50cf05077..fd78d7e71a1 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -28,10 +28,10 @@ export interface IConfigurationOverrides { } export enum ConfigurationTarget { - DEFAULT = 1, - USER, + USER = 1, WORKSPACE, WORKSPACE_FOLDER, + DEFAULT, MEMORY } @@ -62,7 +62,7 @@ export interface IConfigurationService { updateValue(key: string, value: any): TPromise; updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise; updateValue(key: string, value: any, target: ConfigurationTarget): TPromise; - updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError?: boolean): TPromise; reloadConfiguration(): TPromise; reloadConfiguration(folder: IWorkspaceFolder): TPromise; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index a7e62338321..7bfc0852a5e 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -310,12 +310,12 @@ export class Configuration { getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { const configModel = this.getConsolidateConfigurationModel(overrides); - return Object.freeze(section ? configModel.getSectionContents(section) : configModel.contents); + return objects.clone(section ? configModel.getSectionContents(section) : configModel.contents); } getValue(key: string, overrides: IConfigurationOverrides = {}): any { const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - return Object.freeze(getConfigurationValue(consolidateConfigurationModel.contents, key)); + return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); } updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { @@ -352,7 +352,7 @@ export class Configuration { const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; - return Object.freeze({ + return objects.clone({ default: getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key), user: getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key), workspace: this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null @@ -369,12 +369,12 @@ export class Configuration { workspaceFolder: string[]; } { const folderConfigurationModel = this.getFolderConfigurationModelForResource(); - return { + return objects.clone({ default: this._defaults.keys, user: this._user.keys, workspace: this._workspaceConfiguration.keys, workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : [] - }; + }); } private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 71f54113cfd..79d793d416c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -11,9 +11,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @extHostNamedCustomer(MainContext.MainThreadConfiguration) export class MainThreadConfiguration implements MainThreadConfigurationShape { @@ -22,9 +22,8 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { constructor( extHostContext: IExtHostContext, - @IConfigurationEditingService private readonly _configurationEditingService: IConfigurationEditingService, @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); @@ -47,14 +46,14 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise { target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource); - return this._configurationEditingService.writeConfiguration(target, { key, value }, { donotNotifyError: true, scopes: { resource } }); + return this.configurationService.updateValue(key, value, { resource }, target, true); } private deriveConfigurationTarget(key: string, resource: URI): ConfigurationTarget { if (resource && this._workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.RESOURCE) { - return ConfigurationTarget.FOLDER; + return ConfigurationTarget.WORKSPACE_FOLDER; } } return ConfigurationTarget.WORKSPACE; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index db5a8dd1a97..d07165fce5a 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -28,8 +28,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ITextSource } from 'vs/editor/common/model/textSource'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 6d3aee7186e..55677b2d360 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -11,9 +11,8 @@ import { WorkspaceConfiguration } from 'vscode'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; -import { IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { Configuration } from 'vs/platform/configuration/common/configurationModels'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; function lookUp(tree: any, key: string) { if (key) { @@ -72,7 +71,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { switch (arg) { case ExtHostConfigurationTarget.Global: return ConfigurationTarget.USER; case ExtHostConfigurationTarget.Workspace: return ConfigurationTarget.WORKSPACE; - case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.FOLDER; + case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.WORKSPACE_FOLDER; } } diff --git a/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts b/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts index bd78ed75df5..9ae30a6d59b 100644 --- a/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts @@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; export class ToggleActivityBarVisibilityAction extends Action { @@ -24,7 +24,7 @@ export class ToggleActivityBarVisibilityAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); @@ -35,9 +35,7 @@ export class ToggleActivityBarVisibilityAction extends Action { const visibility = this.partService.isVisible(Parts.ACTIVITYBAR_PART); const newVisibilityValue = !visibility; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleActivityBarVisibilityAction.activityBarVisibleKey, value: newVisibilityValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts index 6e62c166319..fc94e997424 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts @@ -10,8 +10,8 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IPartService, Position } from 'vs/workbench/services/part/common/partService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ToggleSidebarPositionAction extends Action { @@ -24,20 +24,18 @@ export class ToggleSidebarPositionAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); - this.enabled = !!this.partService && !!this.configurationEditingService; + this.enabled = !!this.partService && !!this.configurationService; } public run(): TPromise { const position = this.partService.getSideBarPosition(); const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleSidebarPositionAction.sidebarPositionConfigurationKey, value: newPositionValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts index ddaadd0e277..5949ea28756 100644 --- a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts @@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; export class ToggleStatusbarVisibilityAction extends Action { @@ -24,7 +24,7 @@ export class ToggleStatusbarVisibilityAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); @@ -35,9 +35,7 @@ export class ToggleStatusbarVisibilityAction extends Action { const visibility = this.partService.isVisible(Parts.STATUSBAR_PART); const newVisibilityValue = !visibility; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleStatusbarVisibilityAction.statusbarVisibleKey, value: newVisibilityValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index ab16b258da8..ee23ffe9df8 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -23,7 +23,6 @@ import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorIn import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput } from 'vs/workbench/common/editor'; import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IEditorAction, ICommonCodeEditor, EndOfLineSequence, IModel } from 'vs/editor/common/editorCommon'; import { IModelLanguageChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { TrimTrailingWhitespaceAction } from 'vs/editor/contrib/linesOperations/common/linesOperations'; @@ -56,6 +55,7 @@ import { widgetShadow, editorWidgetBackground } from 'vs/platform/theme/common/c // TODO@Sandeep layer breaker // tslint:disable-next-line:import-patterns import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport { if (input instanceof SideBySideEditorInput) { @@ -793,14 +793,12 @@ export class ChangeModeAction extends Action { @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, @IQuickOpenService private quickOpenService: IQuickOpenService, @IPreferencesService private preferencesService: IPreferencesService, @IInstantiationService private instantiationService: IInstantiationService, @ICommandService private commandService: ICommandService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IConfigurationEditingService private configurationEditService: IConfigurationEditingService + @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { super(actionId, actionLabel); } @@ -989,8 +987,7 @@ export class ChangeModeAction extends Action { currentAssociations[associationKey] = language.id; - // Write config - this.configurationEditingService.writeConfiguration(target, { key: ChangeModeAction.FILE_ASSOCIATION_KEY, value: currentAssociations }); + this.configurationService.updateValue(ChangeModeAction.FILE_ASSOCIATION_KEY, currentAssociations, target); } }); }); @@ -1229,7 +1226,7 @@ class ScreenReaderDetectedExplanation { anchorElement: HTMLElement, @IThemeService private readonly themeService: IThemeService, @IContextViewService private readonly contextViewService: IContextViewService, - @IConfigurationEditingService private readonly configurationEditingService: IConfigurationEditingService, + @IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService, ) { this._isDisposed = false; this._toDispose = []; @@ -1281,20 +1278,14 @@ class ScreenReaderDetectedExplanation { const yesBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerYes', "Yes")); this._toDispose.push(addDisposableListener(yesBtn, 'click', () => { - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { - key: 'editor.accessibilitySupport', - value: 'on' - }); + this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); this.contextViewService.hideContextView(); })); domNode.appendChild(yesBtn); const noBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerNo', "No")); this._toDispose.push(addDisposableListener(noBtn, 'click', () => { - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { - key: 'editor.accessibilitySupport', - value: 'off' - }); + this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER); this.contextViewService.hideContextView(); })); domNode.appendChild(noBtn); diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 70406345142..95281cf2338 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -20,8 +20,7 @@ import errors = require('vs/base/common/errors'); import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IExtensionManagementService, LocalExtensionType, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import paths = require('vs/base/common/paths'); @@ -157,8 +156,7 @@ export class ToggleMenuBarAction extends Action { id: string, label: string, @IMessageService private messageService: IMessageService, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); } @@ -176,7 +174,7 @@ export class ToggleMenuBarAction extends Action { newVisibilityValue = 'default'; } - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMenuBarAction.menuBarVisibilityKey, value: newVisibilityValue }); + this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER); return TPromise.as(null); } @@ -202,18 +200,12 @@ export abstract class BaseZoomAction extends Action { constructor( id: string, label: string, - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { super(id, label); } protected setConfiguredZoomLevel(level: number): void { - let target = ConfigurationTarget.USER; - if (typeof this.configurationService.inspect(BaseZoomAction.SETTING_KEY).workspace === 'number') { - target = ConfigurationTarget.WORKSPACE; - } - level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels const applyZoom = () => { @@ -225,7 +217,7 @@ export abstract class BaseZoomAction extends Action { browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); }; - this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }, { donotNotifyError: true }).done(() => applyZoom(), error => applyZoom()); + this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level).done(() => applyZoom()); } } @@ -237,10 +229,9 @@ export class ZoomInAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { @@ -258,10 +249,9 @@ export class ZoomOutAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { @@ -279,10 +269,9 @@ export class ZoomResetAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d90e9c76efc..e1dfbbe2a03 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -29,7 +29,6 @@ import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileReque import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IWorkbenchThemeService, VS_HC_THEME, VS_DARK_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as browser from 'vs/base/browser/browser'; @@ -47,6 +46,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)), @@ -81,7 +81,6 @@ export class ElectronWindow extends Themable { @ITitleService private titleService: ITitleService, @IWorkbenchThemeService protected themeService: IWorkbenchThemeService, @IMessageService private messageService: IMessageService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @ICommandService private commandService: ICommandService, @IExtensionService private extensionService: IExtensionService, @IViewletService private viewletService: IViewletService, @@ -511,7 +510,7 @@ export class ElectronWindow extends Themable { newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; } - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ElectronWindow.AUTO_SAVE_SETTING, value: newAutoSaveValue }); + this.configurationService.updateValue(ElectronWindow.AUTO_SAVE_SETTING, newAutoSaveValue, ConfigurationTarget.USER); } public dispose(): void { diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts b/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts index ddbc5ae45e6..aaf8113fe70 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts @@ -25,10 +25,9 @@ import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/common/toggleTabFocusMode'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorWidgetBackground, widgetShadow, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import * as platform from 'vs/base/common/platform'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import URI from 'vs/base/common/uri'; @@ -87,7 +86,6 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { @IContextKeyService private _contextKeyService: IContextKeyService, @IKeybindingService private _keybindingService: IKeybindingService, @IConfigurationService private _configurationService: IConfigurationService, - @IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService, @IOpenerService private _openerService: IOpenerService ) { super(); @@ -124,10 +122,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_E)) { alert(nls.localize('emergencyConfOn', "Now changing the setting `editor.accessibilitySupport` to 'on'.")); - this._configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { - key: 'editor.accessibilitySupport', - value: 'on' - }); + this._configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); e.preventDefault(); e.stopPropagation(); diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts index 86cdf51939a..247b6b2e73b 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleMinimapAction extends EditorAction { @@ -22,10 +22,10 @@ export class ToggleMinimapAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); const newValue = !editor.getConfiguration().viewInfo.minimap.enabled; - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.minimap.enabled', value: newValue }); + configurationService.updateValue('editor.minimap.enabled', newValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts index 214f40e3a53..a2022660076 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts @@ -10,8 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ToggleMultiCursorModifierAction extends Action { @@ -23,21 +22,16 @@ export class ToggleMultiCursorModifierAction extends Action { constructor( id: string, label: string, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); - - this.enabled = !!this.configurationService && !!this.configurationEditingService; } public run(): TPromise { const editorConf = this.configurationService.getConfiguration<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor'); const newValue: 'ctrlCmd' | 'alt' = (editorConf.multiCursorModifier === 'ctrlCmd' ? 'alt' : 'ctrlCmd'); - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, value: newValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, newValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts index dc51edcbf3d..5eff950044a 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleRenderControlCharacterAction extends EditorAction { @@ -22,10 +22,10 @@ export class ToggleRenderControlCharacterAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); let newRenderControlCharacters = !editor.getConfiguration().viewInfo.renderControlCharacters; - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderControlCharacters', value: newRenderControlCharacters }); + configurationService.updateValue('editor.renderControlCharacters', newRenderControlCharacters, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts index 1ce47241da5..c95eca4cc60 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleRenderWhitespaceAction extends EditorAction { @@ -22,7 +22,7 @@ export class ToggleRenderWhitespaceAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); let renderWhitespace = editor.getConfiguration().viewInfo.renderWhitespace; let newRenderWhitespace: string; @@ -32,6 +32,6 @@ export class ToggleRenderWhitespaceAction extends EditorAction { newRenderWhitespace = 'none'; } - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderWhitespace', value: newRenderWhitespace }); + configurationService.updateValue('editor.renderWhitespace', newRenderWhitespace, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index a365c3fe77d..c6f10cffca4 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -23,8 +23,7 @@ import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace } from 'vs/platf import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import * as pfs from 'vs/base/node/pfs'; import * as os from 'os'; @@ -59,7 +58,6 @@ export class ExtensionTipsService implements IExtensionTipsService { @IFileService private fileService: IFileService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService ) { @@ -449,9 +447,7 @@ export class ExtensionTipsService implements IExtensionTipsService { } private setIgnoreRecommendationsConfig(configVal: boolean) { - let target = ConfigurationTarget.USER; - const configKey = 'extensions.ignoreRecommendations'; - this.configurationEditingService.writeConfiguration(target, { key: configKey, value: configVal }); + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); if (configVal) { const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index 91edacaad0a..b55058ebf56 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -24,9 +24,8 @@ import { } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; @@ -323,7 +322,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { @IExtensionManagementService private extensionService: IExtensionManagementService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @ITelemetryService private telemetryService: ITelemetryService, @IMessageService private messageService: IMessageService, @IChoiceService private choiceService: IChoiceService, @@ -464,7 +462,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { if (this.isAutoUpdateEnabled === autoUpdate) { return TPromise.as(null); } - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'extensions.autoUpdate', value: autoUpdate }); + return this.configurationService.updateValue('extensions.autoUpdate', autoUpdate, ConfigurationTarget.USER); } private eventuallySyncWithGallery(immediate = false): void { diff --git a/src/vs/workbench/parts/files/browser/explorerViewlet.ts b/src/vs/workbench/parts/files/browser/explorerViewlet.ts index 74da9b16cd4..340a269b289 100644 --- a/src/vs/workbench/parts/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/parts/files/browser/explorerViewlet.ts @@ -14,7 +14,6 @@ import { Builder } from 'vs/base/browser/builder'; import { VIEWLET_ID, ExplorerViewletVisibleContext, IFilesConfiguration, OpenEditorsVisibleContext, OpenEditorsVisibleCondition } from 'vs/workbench/parts/files/common/files'; import { PersistentViewsViewlet, ViewsViewletPanel, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ActionRunner, FileViewletState } from 'vs/workbench/parts/files/browser/views/explorerViewer'; import { ExplorerView, IExplorerViewOptions } from 'vs/workbench/parts/files/browser/views/explorerView'; import { EmptyView } from 'vs/workbench/parts/files/browser/views/emptyView'; @@ -51,7 +50,6 @@ export class ExplorerViewlet extends PersistentViewsViewlet { @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService protected instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IThemeService themeService: IThemeService, @IContextMenuService contextMenuService: IContextMenuService, @IExtensionService extensionService: IExtensionService diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 5204850eaee..c56c5a48fa7 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -49,8 +49,7 @@ import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, c import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { once } from 'vs/base/common/event'; export interface IEditableData { @@ -641,8 +640,7 @@ export class BaseDeleteFileAction extends BaseFileAction { @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, @ITextFileService textFileService: ITextFileService, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label, fileService, messageService, textFileService); @@ -746,7 +744,7 @@ export class BaseDeleteFileAction extends BaseFileAction { // Check for confirmation checkbox let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); if (confirmation.checkboxChecked === true) { - updateConfirmSettingsPromise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY, value: false }); + updateConfirmSettingsPromise = this.configurationService.updateValue(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY, false, ConfigurationTarget.USER); } return updateConfirmSettingsPromise.then(() => { @@ -792,10 +790,9 @@ export class MoveFileToTrashAction extends BaseDeleteFileAction { @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, @ITextFileService textFileService: ITextFileService, - @IConfigurationService configurationService: IConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IConfigurationService configurationService: IConfigurationService ) { - super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService, configurationService, configurationEditingService); + super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService, configurationService); } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 4878cedef0b..a095ecd2a5a 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -37,7 +37,7 @@ import { DragMouseEvent, IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -57,7 +57,6 @@ import { distinct } from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; export class FileDataSource implements IDataSource { constructor( @@ -746,8 +745,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { @IBackupFileService private backupFileService: IBackupFileService, @IWindowService private windowService: IWindowService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IEnvironmentService private environmentService: IEnvironmentService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IEnvironmentService private environmentService: IEnvironmentService ) { super(stat => this.statToResource(stat)); @@ -967,7 +965,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // Check for confirmation checkbox let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); if (confirmation.checkboxChecked === true) { - updateConfirmSettingsPromise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: FileDragAndDrop.CONFIRM_DND_SETTING_KEY, value: false }); + updateConfirmSettingsPromise = this.configurationService.updateValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY, false, ConfigurationTarget.USER); } return updateConfirmSettingsPromise.then(() => { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index b65862ab507..44875020629 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -39,7 +39,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { VSash } from 'vs/base/browser/ui/sash/sash'; import { Widget } from 'vs/base/browser/ui/widget'; @@ -59,6 +58,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { MessageController } from 'vs/editor/contrib/message/messageController'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class PreferencesEditorInput extends SideBySideEditorInput { public static ID: string = 'workbench.editorinputs.preferencesEditorInput'; @@ -248,7 +248,7 @@ export class PreferencesEditor extends BaseEditor { } if (this.workspaceContextService.getWorkspaceFolder(resource)) { - return ConfigurationTarget.FOLDER; + return ConfigurationTarget.WORKSPACE_FOLDER; } return null; @@ -918,7 +918,7 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); case ConfigurationTarget.WORKSPACE: return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); } } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 1d69bbae93b..02c4e1a85c6 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -22,7 +22,6 @@ import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/bro import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; -import { IConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; @@ -32,7 +31,7 @@ import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorE import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { MarkdownString } from 'vs/base/common/htmlContent'; -import { overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; +import { overrideIdentifierFromKey, IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export interface IPreferencesRenderer extends IDisposable { preferencesModel: IPreferencesEditorModel; @@ -72,7 +71,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend @IPreferencesService protected preferencesService: IPreferencesService, @ITelemetryService private telemetryService: ITelemetryService, @ITextFileService private textFileService: ITextFileService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, + @IConfigurationService private configurationService: IConfigurationService, @IMessageService private messageService: IMessageService, @IInstantiationService protected instantiationService: IInstantiationService ) { @@ -116,19 +115,8 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] }); const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null; const resource = this.preferencesModel.uri; - this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value }, { donotSave: this.textFileService.isDirty(resource), donotNotifyError: true, scopes: { overrideIdentifier, resource } }) - .then(() => this.onSettingUpdated(source), error => { - this.messageService.show(Severity.Error, this.toErrorMessage(error, this.preferencesModel.configurationTarget)); - }); - } - - private toErrorMessage(error: ConfigurationEditingError, target: ConfigurationTarget): string { - switch (error.code) { - case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: { - return nls.localize('errorInvalidConfiguration', "Unable to write into settings. Correct errors/warnings in the file and try again."); - }; - } - return error.message; + this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget) + .then(() => this.onSettingUpdated(source)); } private onModelChanged(): void { @@ -192,11 +180,11 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, + @IConfigurationService configurationService: IConfigurationService, @IMessageService messageService: IMessageService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationEditingService, messageService, instantiationService); + super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); this.untrustedSettingRenderer = this._register(instantiationService.createInstance(UnsupportedWorkspaceSettingsRenderer, editor, preferencesModel)); this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel)); } @@ -220,11 +208,11 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, + @IConfigurationService configurationService: IConfigurationService, @IMessageService messageService: IMessageService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationEditingService, messageService, instantiationService); + super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); this.unsupportedWorkbenchSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedWorkbenchSettingsRenderer, editor, preferencesModel)); } @@ -809,7 +797,7 @@ class EditSettingRenderer extends Disposable { return true; } if (configurationNode.type === 'boolean' || configurationNode.enum) { - if ((this.masterSettingsModel).configurationTarget !== ConfigurationTarget.FOLDER) { + if ((this.masterSettingsModel).configurationTarget !== ConfigurationTarget.WORKSPACE_FOLDER) { return true; } if (configurationNode.scope === ConfigurationScope.RESOURCE) { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index c3f74852cee..fdf08f805c2 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -26,7 +26,6 @@ import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/c import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -40,6 +39,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; const emptyEditableSettingsContent = '{\n}'; @@ -66,7 +66,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, @ITextModelService private textModelResolverService: ITextModelService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IExtensionService private extensionService: IExtensionService, @IKeybindingService keybindingService: IKeybindingService, @IModelService private modelService: IModelService, @@ -107,7 +106,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } getFolderSettingsResource(resource: URI): URI { - return this.getEditableSettingsURI(ConfigurationTarget.FOLDER, resource); + return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); } resolveContent(uri: URI): TPromise { @@ -170,7 +169,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.FOLDER, uri); + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); } return TPromise.wrap>(null); @@ -189,7 +188,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } openFolderSettings(folder: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { - return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder), options, position); + return this.doOpenSettings(ConfigurationTarget.WORKSPACE_FOLDER, this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder), options, position); } switchSettings(target: ConfigurationTarget, resource: URI): TPromise { @@ -270,7 +269,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } private getDefaultSettingsResource(configurationTarget: ConfigurationTarget): URI { - if (configurationTarget === ConfigurationTarget.FOLDER) { + if (configurationTarget === ConfigurationTarget.WORKSPACE_FOLDER) { return this.defaultResourceSettingsResource; } return this.defaultSettingsResource; @@ -278,7 +277,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string { const name = getSettingsTargetName(target, resource, this.contextService); - return target === ConfigurationTarget.FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name; + return target === ConfigurationTarget.WORKSPACE_FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name; } private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget, resource: URI): TPromise { @@ -322,7 +321,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } const workspace = this.contextService.getWorkspace(); return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: const folder = this.contextService.getWorkspaceFolder(resource); return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } @@ -389,7 +388,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } return { lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 }; } - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: languageKey, value: {} }, { donotSave: true }) + return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER) .then(() => { setting = settingsModel.getPreference(languageKey); let content = eol + this.spaces(2, configuration) + eol + this.spaces(1, configuration); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index f2df5ec870c..81cc7dbdf4f 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -32,9 +32,9 @@ import { ISelectBoxStyles, defaultStyles } from 'vs/base/browser/ui/selectBox/se import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Color } from 'vs/base/common/color'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class SettingsHeaderWidget extends Widget implements IViewZone { @@ -313,7 +313,7 @@ export class SettingsTargetsWidget extends Widget { private updateLabel(): void { this.targetLabel.textContent = getSettingsTargetName(this._configuartionTarget, this._uri, this.workspaceContextService); - const details = ConfigurationTarget.FOLDER === this._configuartionTarget ? localize('folderSettingsDetails', "Folder Settings") : ''; + const details = ConfigurationTarget.WORKSPACE_FOLDER === this._configuartionTarget ? localize('folderSettingsDetails', "Folder Settings") : ''; this.targetDetails.textContent = details; DOM.toggleClass(this.targetDetails, 'empty', !details); } @@ -358,7 +358,7 @@ export class SettingsTargetsWidget extends Widget { actions.push(...workspaceFolders.map((folder, index) => { return { id: 'folderSettingsTarget' + index, - label: getSettingsTargetName(ConfigurationTarget.FOLDER, folder.uri, this.workspaceContextService), + label: getSettingsTargetName(ConfigurationTarget.WORKSPACE_FOLDER, folder.uri, this.workspaceContextService), checked: this._uri.toString() === folder.uri.toString(), enabled: true, run: () => this.onTargetClicked(folder.uri) diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index d75d4737b73..4bd6f7acdef 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -11,9 +11,9 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditor, Position, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IKeybindingItemEntry } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel'; import { IRange } from 'vs/editor/common/core/range'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { join } from 'vs/base/common/paths'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export interface ISettingsGroup { id: string; @@ -107,10 +107,11 @@ export function getSettingsTargetName(target: ConfigurationTarget, resource: URI return localize('userSettingsTarget', "User Settings"); case ConfigurationTarget.WORKSPACE: return localize('workspaceSettingsTarget', "Workspace Settings"); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: const folder = workspaceContextService.getWorkspaceFolder(resource); return folder ? folder.name : ''; } + return ''; } export const CONTEXT_SETTINGS_EDITOR = new RawContextKey('inSettingsEditor', false); diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index f17231a589b..1233bd69199 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -18,7 +18,6 @@ import { EditorModel } from 'vs/workbench/common/editor'; import { IConfigurationNode, IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN, IConfigurationPropertySchema, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { IRange } from 'vs/editor/common/core/range'; @@ -26,6 +25,7 @@ import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/co import { TPromise } from 'vs/base/common/winjs.base'; import { Queue } from 'vs/base/common/async'; import { IFileService } from 'vs/platform/files/common/files'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; class SettingMatches { diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 69ae1d21ee8..3ccba8cd491 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -35,7 +35,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IMessageService, IChoiceService } from 'vs/platform/message/common/message'; import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -63,7 +63,6 @@ import Constants from 'vs/workbench/parts/markers/common/constants'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IConfigurationEditingService, ConfigurationTarget, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -551,7 +550,6 @@ class TaskService extends EventEmitter implements ITaskService { private modeService: IModeService; private configurationService: IConfigurationService; - private configurationEditingService: IConfigurationEditingService; private markerService: IMarkerService; private outputService: IOutputService; private messageService: IMessageService; @@ -582,7 +580,6 @@ class TaskService extends EventEmitter implements ITaskService { private _outputChannel: IOutputChannel; constructor( @IModeService modeService: IModeService, @IConfigurationService configurationService: IConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, @IMarkerService markerService: IMarkerService, @IOutputService outputService: IOutputService, @IMessageService messageService: IMessageService, @IChoiceService choiceService: IChoiceService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @@ -604,7 +601,6 @@ class TaskService extends EventEmitter implements ITaskService { super(); this.modeService = modeService; this.configurationService = configurationService; - this.configurationEditingService = configurationEditingService; this.markerService = markerService; this.outputService = outputService; this.messageService = messageService; @@ -1108,32 +1104,25 @@ class TaskService extends EventEmitter implements ITaskService { } promise = this.fileService.createFile(workspaceFolder.toResource('.vscode/tasks.json'), content).then(() => { }); } else { - let value: IConfigurationValue = { key: undefined, value: undefined }; // We have a global task configuration if (index === -1) { if (properties.problemMatcher !== void 0) { fileConfig.problemMatcher = properties.problemMatcher; - value.key = 'tasks.problemMatchers'; - value.value = fileConfig.problemMatcher; - promise = this.writeConfiguration(workspaceFolder, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.problemMatchers', fileConfig.problemMatcher); } else if (properties.group !== void 0) { fileConfig.group = properties.group; - value.key = 'tasks.group'; - value.value = fileConfig.group; - promise = this.writeConfiguration(workspaceFolder, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.group', fileConfig.group); } } else { if (!Array.isArray(fileConfig.tasks)) { fileConfig.tasks = []; } - value.key = 'tasks.tasks'; - value.value = fileConfig.tasks; if (index === void 0) { fileConfig.tasks.push(toCustomize); } else { fileConfig.tasks[index] = toCustomize; } - promise = this.writeConfiguration(workspaceFolder, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.tasks', fileConfig.tasks); } }; if (!promise) { @@ -1162,11 +1151,11 @@ class TaskService extends EventEmitter implements ITaskService { }); } - private writeConfiguration(workspaceFolder: IWorkspaceFolder, value: IConfigurationValue): TPromise { + private writeConfiguration(workspaceFolder: IWorkspaceFolder, key: string, value: any): TPromise { if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.WORKSPACE, value); + return this.configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, ConfigurationTarget.WORKSPACE); } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.FOLDER, value, { scopes: { resource: workspaceFolder.uri } }); + return this.configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, ConfigurationTarget.WORKSPACE_FOLDER); } else { return undefined; } diff --git a/src/vs/workbench/parts/terminal/common/terminalService.ts b/src/vs/workbench/parts/terminal/common/terminalService.ts index 305ac98c424..5ccb2a29e65 100644 --- a/src/vs/workbench/parts/terminal/common/terminalService.ts +++ b/src/vs/workbench/parts/terminal/common/terminalService.ts @@ -43,7 +43,7 @@ export abstract class TerminalService implements ITerminalService { constructor( @IContextKeyService private _contextKeyService: IContextKeyService, - @IConfigurationService private _configurationService: IConfigurationService, + @IConfigurationService protected _configurationService: IConfigurationService, @IPanelService protected _panelService: IPanelService, @IPartService private _partService: IPartService, @ILifecycleService lifecycleService: ILifecycleService diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts index 512c65ed2d4..66d5340d584 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts @@ -11,8 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IQuickOpenService, IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; import { TerminalService as AbstractTerminalService } from 'vs/workbench/parts/terminal/common/terminalService'; @@ -39,7 +38,6 @@ export class TerminalService extends AbstractTerminalService implements ITermina @IInstantiationService private _instantiationService: IInstantiationService, @IWindowService private _windowService: IWindowService, @IQuickOpenService private _quickOpenService: IQuickOpenService, - @IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService, @IChoiceService private _choiceService: IChoiceService, @IStorageService private _storageService: IStorageService, @IMessageService private _messageService: IMessageService @@ -163,8 +161,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina return null; } const shell = value.description; - const configChange = { key: 'terminal.integrated.shell.windows', value: shell }; - return this._configurationEditingService.writeConfiguration(ConfigurationTarget.USER, configChange).then(() => shell); + return this._configurationService.updateValue('terminal.integrated.shell.windows', shell, ConfigurationTarget.USER).then(() => shell); }); }); } diff --git a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts index 10069d1f991..d8f6bebd750 100644 --- a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts +++ b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts @@ -20,11 +20,11 @@ import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/co import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { Delayer } from 'vs/base/common/async'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IColorRegistry, Extensions as ColorRegistryExtensions } from 'vs/platform/theme/common/colorRegistry'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Color } from 'vs/base/common/color'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class SelectColorThemeAction extends Action { diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index c54020a8d3f..dff17826c3b 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -19,8 +19,7 @@ import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -237,7 +236,6 @@ class WelcomePage { @IWindowsService private windowsService: IWindowsService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IEnvironmentService private environmentService: IEnvironmentService, @IMessageService private messageService: IMessageService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @@ -279,7 +277,7 @@ class WelcomePage { showOnStartup.setAttribute('checked', 'checked'); } showOnStartup.addEventListener('click', e => { - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: configurationKey, value: showOnStartup.checked ? 'welcomePage' : 'newUntitledFile' }); + this.configurationService.updateValue(configurationKey, showOnStartup.checked ? 'welcomePage' : 'newUntitledFile', ConfigurationTarget.USER); }); recentlyOpened.then(({ workspaces }) => { diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index d13b326bfc2..b264dbd9662 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -94,9 +94,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise { const edit = this.getEdits(model, operation)[0]; if (this.applyEditsToBuffer(edit, model) && save) { - return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }) - // Reload the configuration so that we make sure all parties are updated - .then(() => this.configurationService.reloadConfiguration()); + return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }); } return TPromise.as(null); } diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 5c83bdddbbb..76c93c968ee 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -150,11 +150,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise updateValue(key: string, value: any, target: ConfigurationTarget): TPromise updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise - updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + updateValue(key: string, value: any, arg3?: any, arg4?: any, donotNotifyError?: any): TPromise { assert.ok(this.configurationEditingService, 'Workbench is not initialized yet'); const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); - return target ? this.writeConfigurationValue(key, value, target, overrides) + return target ? this.writeConfigurationValue(key, value, target, overrides, donotNotifyError) : TPromise.as(null); } @@ -463,23 +463,18 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat })]); } - private writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationOverrides): TPromise { + private writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationOverrides, donotNotifyError: boolean): TPromise { if (target === ConfigurationTarget.DEFAULT) { return TPromise.wrapError(new Error('Invalid configuration target')); } - let currentTargetValue = this.getTargetValue(key, target, overrides); - if (equals(currentTargetValue, value)) { - return TPromise.as(null); - } - if (target === ConfigurationTarget.MEMORY) { this._configuration.updateValue(key, value, overrides); this.triggerConfigurationChange(new ConfigurationChangeEvent().change(overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier)] : [key], overrides.resource), target); return TPromise.as(null); } - return this.configurationEditingService.writeConfiguration(this.toEditableConfigurationTarget(target), { key, value }, { scopes: overrides }) + return this.configurationEditingService.writeConfiguration(this.toEditableConfigurationTarget(target), { key, value }, { scopes: overrides, donotNotifyError }) .then(() => { switch (target) { case ConfigurationTarget.USER: @@ -543,23 +538,6 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } } - private getTargetValue(key: string, target: ConfigurationTarget, overrides?: IConfigurationOverrides): any { - const inspect = this.inspect(key, overrides); - switch (target) { - case ConfigurationTarget.DEFAULT: - return inspect.default; - case ConfigurationTarget.USER: - return inspect.user; - case ConfigurationTarget.WORKSPACE: - return inspect.workspace; - case ConfigurationTarget.WORKSPACE_FOLDER: - return inspect.workspaceFolder; - case ConfigurationTarget.MEMORY: - return inspect.memory; - } - return void 0; - } - private getTargetConfiguration(target: ConfigurationTarget): any { switch (target) { case ConfigurationTarget.DEFAULT: diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index b486834f14e..ca8bf742618 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -224,6 +224,7 @@ suite('ConfigurationEditingService', () => { test('write one setting - empty file', () => { return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + .then(() => instantiationService.get(IConfigurationService).reloadConfiguration()) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -235,6 +236,7 @@ suite('ConfigurationEditingService', () => { test('write one setting - existing file', () => { fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value" }'); return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + .then(() => instantiationService.get(IConfigurationService).reloadConfiguration()) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -249,6 +251,7 @@ suite('ConfigurationEditingService', () => { test('write workspace standalone setting - empty file', () => { return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' }) + .then(() => instantiationService.get(IConfigurationService).reloadConfiguration()) .then(() => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']); const contents = fs.readFileSync(target).toString('utf8'); @@ -263,6 +266,7 @@ suite('ConfigurationEditingService', () => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']); fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }'); return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' }) + .then(() => instantiationService.get(IConfigurationService).reloadConfiguration()) .then(() => { const contents = fs.readFileSync(target).toString('utf8'); const parsed = json.parse(contents); diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 2334ac25ae4..f8f97e35a74 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -7,9 +7,9 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { Color } from 'vs/base/common/color'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export const IWorkbenchThemeService = createDecorator('themeService'); diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 233dab9d10f..702a85b0baf 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -14,8 +14,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; import errors = require('vs/base/common/errors'); -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -507,7 +506,7 @@ colorThemeSchema.register(); fileIconThemeSchema.register(); class ConfigurationWriter { - constructor( @IConfigurationService private configurationService: IConfigurationService, @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService) { + constructor( @IConfigurationService private configurationService: IConfigurationService) { } public writeConfiguration(key: string, value: any, settingsTarget: ConfigurationTarget): TPromise { @@ -526,7 +525,7 @@ class ConfigurationWriter { return TPromise.as(null); // nothing to do } } - return this.configurationEditingService.writeConfiguration(settingsTarget, { key, value }); + return this.configurationService.updateValue(key, value, settingsTarget); } } diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index 54fa31a10d4..098ad1ccde8 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -11,11 +11,11 @@ import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { MainThreadConfigurationShape } from 'vs/workbench/api/node/extHost.protocol'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('ExtHostConfiguration', function () { @@ -394,7 +394,7 @@ suite('ExtHostConfiguration', function () { const shape = new class extends mock() { $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise { - return TPromise.wrapError(new ConfigurationEditingError('Unknown Key', ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY)); // something !== OK + return TPromise.wrapError(new Error('Unknown Key')); // something !== OK } }; diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts index 425dd180872..5cd09140d48 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts @@ -13,13 +13,11 @@ import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platf import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MainThreadConfiguration } from 'vs/workbench/api/electron-browser/mainThreadConfiguration'; -import { ConfigurationTarget, IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { OneGetThreadService } from './testThreadService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; -suite('ExtHostConfiguration', function () { +suite('MainThreadConfiguration', function () { let instantiationService: TestInstantiationService; let target: sinon.SinonSpy; @@ -47,12 +45,12 @@ suite('ExtHostConfiguration', function () { }); setup(() => { - instantiationService = new TestInstantiationService(); - instantiationService.stub(IConfigurationService, new TestConfigurationService()); - target = sinon.spy(); - instantiationService.stub(IConfigurationEditingService, ConfigurationEditingService); - instantiationService.stub(IConfigurationEditingService, 'writeConfiguration', target); + + instantiationService = new TestInstantiationService(); + instantiationService.stub(IConfigurationService, WorkspaceService); + instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', sinon.mock()); + instantiationService.stub(IConfigurationService, 'updateValue', target); }); test('update resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -61,7 +59,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -70,7 +68,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -79,7 +77,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -88,7 +86,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { @@ -97,7 +95,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -106,7 +104,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -115,7 +113,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to folder', function () { @@ -124,7 +122,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('update configuration with user configuration target', function () { @@ -133,7 +131,7 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(ConfigurationTarget.USER, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.USER, target.args[0][0]); + assert.equal(ConfigurationTarget.USER, target.args[0][3]); }); test('update configuration with workspace configuration target', function () { @@ -142,16 +140,16 @@ suite('ExtHostConfiguration', function () { testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update configuration with folder configuration target', function () { instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); - testObject.$updateConfigurationOption(ConfigurationTarget.FOLDER, 'extHostConfiguration.window', 'value', URI.file('abc')); + testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE_FOLDER, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -160,7 +158,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -169,7 +167,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -178,7 +176,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -187,7 +185,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { @@ -196,7 +194,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -205,7 +203,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -214,7 +212,7 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove configuration without configuration target defaults to folder', function () { @@ -223,6 +221,6 @@ suite('ExtHostConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); }); From fe37067d31a50799274c6fe392bf7fe7c410f3f6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2017 23:07:05 +0200 Subject: [PATCH 257/303] Clean up - Remove configuration target in configuration editing service - Remove configuration editing service --- .../workbench/electron-browser/workbench.ts | 7 -- .../common/configurationEditing.ts | 104 ------------------ .../node/configurationEditingService.ts | 84 ++++++++++++-- .../node/configurationService.ts | 18 +-- .../node/configurationEditingService.test.ts | 5 +- 5 files changed, 78 insertions(+), 140 deletions(-) delete mode 100644 src/vs/workbench/services/configuration/common/configurationEditing.ts diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 6f009ebb6d6..8f5e5fbe60d 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -46,8 +46,6 @@ import { ContextMenuService } from 'vs/workbench/services/contextview/electron-b import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; -import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; @@ -177,7 +175,6 @@ export class Workbench implements IPartService { private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private backupFileService: IBackupFileService; - private configurationEditingService: IConfigurationEditingService; private fileService: IFileService; private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; @@ -597,10 +594,6 @@ export class Workbench implements IPartService { const jsonEditingService = this.instantiationService.createInstance(JSONEditingService); serviceCollection.set(IJSONEditingService, jsonEditingService); - // Configuration Editing - this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService); - serviceCollection.set(IConfigurationEditingService, this.configurationEditingService); - // Workspace Editing serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService)); diff --git a/src/vs/workbench/services/configuration/common/configurationEditing.ts b/src/vs/workbench/services/configuration/common/configurationEditing.ts deleted file mode 100644 index 5cd14ca3229..00000000000 --- a/src/vs/workbench/services/configuration/common/configurationEditing.ts +++ /dev/null @@ -1,104 +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 { TPromise } from 'vs/base/common/winjs.base'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; - -export const IConfigurationEditingService = createDecorator('configurationEditingService'); - -export enum ConfigurationEditingErrorCode { - - /** - * Error when trying to write a configuration key that is not registered. - */ - ERROR_UNKNOWN_KEY, - - /** - * Error when trying to write an invalid folder configuration key to folder settings. - */ - ERROR_INVALID_FOLDER_CONFIGURATION, - - /** - * Error when trying to write to user target but not supported for provided key. - */ - ERROR_INVALID_USER_TARGET, - - /** - * Error when trying to write a configuration key to folder target - */ - ERROR_INVALID_FOLDER_TARGET, - - /** - * Error when trying to write to the workspace configuration without having a workspace opened. - */ - ERROR_NO_WORKSPACE_OPENED, - - /** - * Error when trying to write and save to the configuration file while it is dirty in the editor. - */ - ERROR_CONFIGURATION_FILE_DIRTY, - - /** - * Error when trying to write to a configuration file that contains JSON errors. - */ - ERROR_INVALID_CONFIGURATION -} - -export class ConfigurationEditingError extends Error { - constructor(message: string, public code: ConfigurationEditingErrorCode) { - super(message); - } -} - -export enum ConfigurationTarget { - - /** - * Targets the user configuration file for writing. - */ - USER, - - /** - * Targets the workspace configuration file for writing. This only works if a workspace is opened. - */ - WORKSPACE, - - /** - * Targets the folder configuration file for writing. This only works if a workspace is opened. - */ - FOLDER -} - -export interface IConfigurationValue { - key: string; - value: any; -} - -export interface IConfigurationEditingOptions { - /** - * If `true`, do not saves the configuration. Default is `false`. - */ - donotSave?: boolean; - /** - * If `true`, do not notifies the error to user by showing the message box. Default is `false`. - */ - donotNotifyError?: boolean; - /** - * Scope of configuration to be written into. - */ - scopes?: IConfigurationOverrides; -} - -export interface IConfigurationEditingService { - - _serviceBrand: ServiceIdentifier; - - /** - * Allows to write the configuration value to either the user or workspace configuration file and save it if asked to save. - * The returned promise will be in error state in any of the error cases from [ConfigurationEditingErrorCode](#ConfigurationEditingErrorCode) - */ - writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options?: IConfigurationEditingOptions): TPromise; -} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index b264dbd9662..e4b1cd4e7a0 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -23,16 +23,79 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; -import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError, IConfigurationValue, IConfigurationEditingOptions, IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +export enum ConfigurationEditingErrorCode { + + /** + * Error when trying to write a configuration key that is not registered. + */ + ERROR_UNKNOWN_KEY, + + /** + * Error when trying to write an invalid folder configuration key to folder settings. + */ + ERROR_INVALID_FOLDER_CONFIGURATION, + + /** + * Error when trying to write to user target but not supported for provided key. + */ + ERROR_INVALID_USER_TARGET, + + /** + * Error when trying to write a configuration key to folder target + */ + ERROR_INVALID_FOLDER_TARGET, + + /** + * Error when trying to write to the workspace configuration without having a workspace opened. + */ + ERROR_NO_WORKSPACE_OPENED, + + /** + * Error when trying to write and save to the configuration file while it is dirty in the editor. + */ + ERROR_CONFIGURATION_FILE_DIRTY, + + /** + * Error when trying to write to a configuration file that contains JSON errors. + */ + ERROR_INVALID_CONFIGURATION +} + +export class ConfigurationEditingError extends Error { + constructor(message: string, public code: ConfigurationEditingErrorCode) { + super(message); + } +} + +export interface IConfigurationValue { + key: string; + value: any; +} + +export interface IConfigurationEditingOptions { + /** + * If `true`, do not saves the configuration. Default is `false`. + */ + donotSave?: boolean; + /** + * If `true`, do not notifies the error to user by showing the message box. Default is `false`. + */ + donotNotifyError?: boolean; + /** + * Scope of configuration to be written into. + */ + scopes?: IConfigurationOverrides; +} + interface IConfigurationEditOperation extends IConfigurationValue { target: ConfigurationTarget; jsonPath: json.JSONPath; @@ -50,7 +113,7 @@ interface ConfigurationEditingOptions extends IConfigurationEditingOptions { force?: boolean; } -export class ConfigurationEditingService implements IConfigurationEditingService { +export class ConfigurationEditingService { public _serviceBrand: any; @@ -190,7 +253,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService case ConfigurationTarget.WORKSPACE: this.commandService.executeCommand('workbench.action.openWorkspaceSettings'); break; - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: if (operation.resource) { const workspaceFolder = this.contextService.getWorkspaceFolder(operation.resource); if (workspaceFolder) { @@ -234,7 +297,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open **User Settings** file to correct errors/warnings in it and try again."); case ConfigurationTarget.WORKSPACE: return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open **Workspace Settings** file to correct errors/warnings in the file and try again."); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name; return nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open **Folder Settings** file under **{0}** folder to correct errors/warnings in it and try again.", workspaceFolderName); } @@ -252,7 +315,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the **User Settings** file and try again."); case ConfigurationTarget.WORKSPACE: return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the **Workspace Settings** file and try again."); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name; return nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the **Folder Settings** file under **{0}** folder and try again.", workspaceFolderName); } @@ -267,9 +330,10 @@ export class ConfigurationEditingService implements IConfigurationEditingService return nls.localize('userTarget', "User Settings"); case ConfigurationTarget.WORKSPACE: return nls.localize('workspaceTarget', "Workspace Settings"); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: return nls.localize('folderTarget', "Folder Settings"); } + return ''; } private getEdits(model: editorCommon.IModel, edit: IConfigurationEditOperation): Edit[] { @@ -325,11 +389,11 @@ export class ConfigurationEditingService implements IConfigurationEditingService } // Target cannot be workspace or folder if no workspace opened - if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { return this.wrapError(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target, operation); } - if (target === ConfigurationTarget.FOLDER) { + if (target === ConfigurationTarget.WORKSPACE_FOLDER) { if (!operation.resource) { return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation); } @@ -416,7 +480,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService } } - if (target === ConfigurationTarget.FOLDER) { + if (target === ConfigurationTarget.WORKSPACE_FOLDER) { if (resource) { const folder = this.contextService.getWorkspaceFolder(resource); if (folder) { diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 76c93c968ee..d83c8b0d642 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -37,7 +37,6 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; -import { IConfigurationEditingService, ConfigurationTarget as EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; @@ -74,7 +73,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat protected readonly _onDidChangeWorkbenchState: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; - private configurationEditingService: IConfigurationEditingService; + private configurationEditingService: ConfigurationEditingService; constructor(private environmentService: IEnvironmentService, private workspacesService: IWorkspacesService, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) { super(); @@ -474,7 +473,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return TPromise.as(null); } - return this.configurationEditingService.writeConfiguration(this.toEditableConfigurationTarget(target), { key, value }, { scopes: overrides, donotNotifyError }) + return this.configurationEditingService.writeConfiguration(target, { key, value }, { scopes: overrides, donotNotifyError }) .then(() => { switch (target) { case ConfigurationTarget.USER: @@ -518,19 +517,6 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return ConfigurationTarget.USER; } - private toEditableConfigurationTarget(target: ConfigurationTarget): EditableConfigurationTarget { - switch (target) { - case ConfigurationTarget.USER: - return EditableConfigurationTarget.USER; - case ConfigurationTarget.WORKSPACE: - return EditableConfigurationTarget.WORKSPACE; - case ConfigurationTarget.WORKSPACE_FOLDER: - return EditableConfigurationTarget.FOLDER; - default: - return EditableConfigurationTarget.WORKSPACE; - } - } - private triggerConfigurationChange(configurationEvent: ConfigurationChangeEvent, target: ConfigurationTarget): void { if (configurationEvent.affectedKeys.length) { configurationEvent.telemetryData(target, this.getTargetConfiguration(target)); diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index ca8bf742618..bc24a60429e 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -23,11 +23,10 @@ import uuid = require('vs/base/common/uuid'); import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; -import { ConfigurationTarget, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { IFileService } from 'vs/platform/files/common/files'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; From a101ae181774824799b704f82966b61a9e43aa92 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Oct 2017 14:24:51 -0700 Subject: [PATCH 258/303] Change a few more ts providers to use async --- .../src/features/definitionProviderBase.ts | 22 +++++++++---------- .../src/features/documentHighlightProvider.ts | 18 ++++++++++----- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index bf5ffabd704..ee3a086a4fa 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -13,7 +13,7 @@ export default class TypeScriptDefinitionProviderBase { constructor( private client: ITypescriptServiceClient) { } - protected getSymbolLocations( + protected async getSymbolLocations( definitionType: 'definition' | 'implementation' | 'typeDefinition', document: TextDocument, position: Position, @@ -21,24 +21,24 @@ export default class TypeScriptDefinitionProviderBase { ): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { - return Promise.resolve(null); + return null; } + const args = vsPositionToTsFileLocation(filepath, position); - return this.client.execute(definitionType, args, token).then(response => { + try { + const response = await this.client.execute(definitionType, args, token); const locations: Proto.FileSpan[] = (response && response.body) || []; if (!locations || locations.length === 0) { return []; } return locations.map(location => { const resource = this.client.asUrl(location.file); - if (resource === null) { - return null; - } else { - return new Location(resource, tsTextSpanToVsRange(location)); - } - }).filter(x => x !== null) as Location[]; - }, () => { + return !resource + ? null + : new Location(resource, tsTextSpanToVsRange(location)); + }).filter(x => x) as Location[]; + } catch { return []; - }); + } } } \ No newline at end of file diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts index d91cb8fd90b..871629630dc 100644 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ b/extensions/typescript/src/features/documentHighlightProvider.ts @@ -13,14 +13,20 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh public constructor( private client: ITypescriptServiceClient) { } - public provideDocumentHighlights(resource: TextDocument, position: Position, token: CancellationToken): Promise { + public async provideDocumentHighlights( + resource: TextDocument, + position: Position, + token: CancellationToken + ): Promise { const filepath = this.client.normalizePath(resource.uri); if (!filepath) { - return Promise.resolve([]); + return []; } + const args = vsPositionToTsFileLocation(filepath, position); - return this.client.execute('occurrences', args, token).then((response): DocumentHighlight[] => { - let data = response.body; + try { + const response = await this.client.execute('occurrences', args, token); + const data = response.body; if (data && data.length) { // Workaround for https://github.com/Microsoft/TypeScript/issues/12780 // Don't highlight string occurrences @@ -39,8 +45,8 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read)); } return []; - }, () => { + } catch { return []; - }); + } } } \ No newline at end of file From f8bac907b7d9d922d6f52ffec51b9eaa3fef9854 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Oct 2017 14:44:32 -0700 Subject: [PATCH 259/303] Mark markdown yaml frontmatter as yaml embedded language Fixes #30873 --- extensions/markdown/package.json | 1 + extensions/markdown/syntaxes/markdown.tmLanguage | 2 ++ extensions/markdown/syntaxes/markdown.tmLanguage.base | 2 ++ 3 files changed, 5 insertions(+) diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 769c6091855..5cb34c4c662 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -46,6 +46,7 @@ "meta.embedded.block.html": "html", "source.js": "javascript", "source.css": "css", + "meta.embedded.block.frontmatter": "yaml", "meta.embedded.block.css": "css", "meta.embedded.block.ini": "ini", diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage b/extensions/markdown/syntaxes/markdown.tmLanguage index 7d5448a80d2..5e7d26dea2b 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage +++ b/extensions/markdown/syntaxes/markdown.tmLanguage @@ -3691,6 +3691,8 @@ frontMatter + contentName + meta.embedded.block.frontmatter begin \A-{3}\s*$ while diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage.base b/extensions/markdown/syntaxes/markdown.tmLanguage.base index 6d0a8510217..d501f50a86f 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage.base +++ b/extensions/markdown/syntaxes/markdown.tmLanguage.base @@ -1181,6 +1181,8 @@ frontMatter + contentName + meta.embedded.block.frontmatter begin \A-{3}\s*$ while From 3495b0b185acbe8188e821ccb3ae807274703a9c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 16 Oct 2017 15:49:25 -0700 Subject: [PATCH 260/303] node-debug2@1.18.3 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index e424881eaab..beb618c5195 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -46,7 +46,7 @@ const nodeModules = ['electron', 'original-fs'] const builtInExtensions = [ { name: 'ms-vscode.node-debug', version: '1.18.1' }, - { name: 'ms-vscode.node-debug2', version: '1.18.1' } + { name: 'ms-vscode.node-debug2', version: '1.18.3' } ]; const excludedExtensions = [ From 7d3ee8ab43c6656adc27a0292c93660c4e9bb04f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2017 10:18:59 +0200 Subject: [PATCH 261/303] telemetry - delay fileGet until model is loaded to properly resolve mimetype --- .../textfile/common/textFileEditorModel.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 90b96f490d5..8076fc12f2a 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -364,16 +364,25 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private loadWithContent(content: IRawTextContent | IContent, backup?: URI): TPromise { - diag('load() - resolved content', this.resource, new Date()); + return this.doLoadWithContent(content, backup).then(model => { - /* __GDPR__ - "fileGet" : { - "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + // We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype + + /* __GDPR__ + "fileGet" : { + "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + + return model; + }); + } + + private doLoadWithContent(content: IRawTextContent | IContent, backup?: URI): TPromise { + diag('load() - resolved content', this.resource, new Date()); // Update our resolved disk stat model const resolvedStat: IFileStat = { From b0a7b57d46a2dc1bafeb256006f71897ca9cfcb2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2017 10:46:33 +0200 Subject: [PATCH 262/303] Rename IConfigurationService onDidUpdateConfiguration to onDidChangeConfiguration --- src/vs/code/electron-main/menus.ts | 2 +- src/vs/code/electron-main/window.ts | 2 +- src/vs/editor/common/services/modelServiceImpl.ts | 2 +- .../editor/common/services/resourceConfiguration.ts | 3 ++- .../common/services/resourceConfigurationImpl.ts | 8 ++++---- src/vs/editor/standalone/browser/simpleServices.ts | 12 ++++++------ .../platform/configuration/common/configuration.ts | 2 +- .../configuration/node/configurationService.ts | 6 +++--- .../test/common/testConfigurationService.ts | 2 +- .../platform/contextkey/browser/contextKeyService.ts | 2 +- src/vs/platform/request/node/requestService.ts | 2 +- src/vs/platform/telemetry/common/telemetryService.ts | 2 +- src/vs/platform/telemetry/common/telemetryUtils.ts | 2 +- .../test/electron-browser/telemetryService.test.ts | 2 +- .../api/electron-browser/mainThreadConfiguration.ts | 2 +- src/vs/workbench/browser/labels.ts | 2 +- src/vs/workbench/browser/parts/editor/editorPart.ts | 2 +- src/vs/workbench/browser/parts/editor/textEditor.ts | 2 +- .../browser/parts/quickopen/quickOpenController.ts | 2 +- .../workbench/browser/parts/titlebar/titlebarPart.ts | 2 +- src/vs/workbench/common/editor/editorStacksModel.ts | 2 +- .../workbench/common/editor/untitledEditorModel.ts | 2 +- src/vs/workbench/common/resources.ts | 2 +- src/vs/workbench/electron-browser/window.ts | 2 +- src/vs/workbench/electron-browser/workbench.ts | 2 +- .../parts/backup/common/backupModelTracker.ts | 2 +- .../parts/debug/browser/debugActionItems.ts | 2 +- .../parts/debug/browser/debugActionsWidget.ts | 2 +- .../electron-browser/debugConfigurationManager.ts | 2 +- .../parts/extensions/browser/extensionsActions.ts | 2 +- .../extensions/electron-browser/extensionsViewlet.ts | 2 +- .../extensions/node/extensionsWorkbenchService.ts | 2 +- .../workbench/parts/files/browser/explorerViewlet.ts | 2 +- .../parts/files/browser/views/explorerView.ts | 2 +- .../parts/files/browser/views/explorerViewer.ts | 4 ++-- .../parts/files/browser/views/openEditorsView.ts | 2 +- .../parts/files/common/editors/fileEditorTracker.ts | 2 +- .../parts/markers/browser/markersFileDecorations.ts | 2 +- .../workbench/parts/markers/browser/markersPanel.ts | 2 +- .../preferences/browser/preferencesRenderers.ts | 2 +- .../preferences/common/preferencesContribution.ts | 2 +- .../parts/quickopen/browser/commandsHandler.ts | 4 ++-- .../electron-browser/relauncher.contribution.ts | 2 +- .../parts/scm/electron-browser/scmFileDecorations.ts | 2 +- .../parts/search/browser/openAnythingHandler.ts | 2 +- .../tasks/electron-browser/task.contribution.ts | 2 +- .../parts/terminal/common/terminalService.ts | 2 +- .../parts/terminal/electron-browser/terminalPanel.ts | 2 +- .../electron-browser/terminalConfigHelper.test.ts | 2 +- .../unsupportedWorkspaceSettings.contribution.ts | 2 +- .../parts/watermark/electron-browser/watermark.ts | 2 +- .../walkThrough/electron-browser/walkThroughPart.ts | 4 ++-- .../configuration/node/configurationService.ts | 10 +++++----- .../test/node/configurationService.test.ts | 10 +++++----- .../test/node/configurationResolverService.test.ts | 2 +- .../services/files/electron-browser/fileService.ts | 2 +- .../files/node/watcher/nsfw/watcherService.ts | 2 +- .../keybinding/electron-browser/keybindingService.ts | 2 +- .../services/mode/common/workbenchModeService.ts | 2 +- .../services/textfile/common/textFileService.ts | 2 +- .../themes/electron-browser/workbenchThemeService.ts | 2 +- src/vs/workbench/test/workbenchTestServices.ts | 2 +- 62 files changed, 84 insertions(+), 83 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 327dcba23b3..68af45f2186 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -136,7 +136,7 @@ export class CodeMenu { }); // Update when auto save config changes - this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true /* update menu if changed */)); + this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true /* update menu if changed */)); // Listen to update service this.updateService.onStateChange(() => this.updateMenu()); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 50570fd57b9..e1999859678 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -409,7 +409,7 @@ export class CodeWindow implements ICodeWindow { } // Handle configuration changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated())); // Handle Workspace events this.toDispose.push(this.workspaceService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e))); diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index fe046a165d5..1fbc491f271 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -224,7 +224,7 @@ export class ModelServiceImpl implements IModelService { this._markerServiceSubscription = this._markerService.onMarkerChanged(this._handleMarkerChange, this); } - this._configurationServiceSubscription = this._configurationService.onDidUpdateConfiguration(e => this._updateModelOptions()); + this._configurationServiceSubscription = this._configurationService.onDidChangeConfiguration(e => this._updateModelOptions()); this._updateModelOptions(); } diff --git a/src/vs/editor/common/services/resourceConfiguration.ts b/src/vs/editor/common/services/resourceConfiguration.ts index 2a959539e9b..e65c4a12104 100644 --- a/src/vs/editor/common/services/resourceConfiguration.ts +++ b/src/vs/editor/common/services/resourceConfiguration.ts @@ -7,6 +7,7 @@ import Event from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IPosition } from 'vs/editor/common/core/position'; +import { IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; export const ITextResourceConfigurationService = createDecorator('textResourceConfigurationService'); @@ -17,7 +18,7 @@ export interface ITextResourceConfigurationService { /** * Event that fires when the configuration changes. */ - onDidUpdateConfiguration: Event; + onDidChangeConfiguration: Event; /** * Fetches the appropriate section of the for the given resource with appropriate overrides (e.g. language). diff --git a/src/vs/editor/common/services/resourceConfigurationImpl.ts b/src/vs/editor/common/services/resourceConfigurationImpl.ts index 453395b6488..6124db46a06 100644 --- a/src/vs/editor/common/services/resourceConfigurationImpl.ts +++ b/src/vs/editor/common/services/resourceConfigurationImpl.ts @@ -6,7 +6,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -16,8 +16,8 @@ export class TextResourceConfigurationService extends Disposable implements ITex public _serviceBrand: any; - private readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( @IConfigurationService private configurationService: IConfigurationService, @@ -25,7 +25,7 @@ export class TextResourceConfigurationService extends Disposable implements ITex @IModeService private modeService: IModeService, ) { super(); - this._register(this.configurationService.onDidUpdateConfiguration(() => this._onDidUpdateConfiguration.fire())); + this._register(this.configurationService.onDidChangeConfiguration(e => this._onDidChangeConfiguration.fire(e))); } getConfiguration(resource: URI, section?: string): T diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index abc268c123e..88a323b05be 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -445,8 +445,8 @@ export class SimpleConfigurationService implements IConfigurationService { _serviceBrand: any; - private _onDidUpdateConfiguration = new Emitter(); - public onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidChangeConfiguration = new Emitter(); + public onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; private _configuration: Configuration; @@ -503,12 +503,12 @@ export class SimpleResourceConfigurationService implements ITextResourceConfigur _serviceBrand: any; - public readonly onDidUpdateConfiguration: Event; - private readonly _onDidUpdateConfigurationEmitter = new Emitter(); + public readonly onDidChangeConfiguration: Event; + private readonly _onDidChangeConfigurationEmitter = new Emitter(); constructor(private configurationService: SimpleConfigurationService) { - this.configurationService.onDidUpdateConfiguration(() => { - this._onDidUpdateConfigurationEmitter.fire(); + this.configurationService.onDidChangeConfiguration((e) => { + this._onDidChangeConfigurationEmitter.fire(e); }); } diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index fd78d7e71a1..5f5145c0ed3 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -48,7 +48,7 @@ export interface IConfigurationChangeEvent { export interface IConfigurationService { _serviceBrand: any; - onDidUpdateConfiguration: Event; + onDidChangeConfiguration: Event; getConfigurationData(): IConfigurationData; diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 6b1d5954fa5..9fb8cfc6fa6 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -24,8 +24,8 @@ export class ConfigurationService extends Disposable implements IConfigurationSe private _configuration: Configuration; private userConfigModelWatcher: ConfigWatcher; - private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( @IEnvironmentService environmentService: IEnvironmentService @@ -128,7 +128,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe } private trigger(keys: string[], source: ConfigurationTarget): void { - this._onDidUpdateConfiguration.fire(new ConfigurationChangeEvent().change(keys).telemetryData(source, this.getTargetConfiguration(source))); + this._onDidChangeConfiguration.fire(new ConfigurationChangeEvent().change(keys).telemetryData(source, this.getTargetConfiguration(source))); } private getTargetConfiguration(target: ConfigurationTarget): any { diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 52363535b85..dcb88e2eb1d 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -52,7 +52,7 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return TPromise.as(null); } - public onDidUpdateConfiguration() { + public onDidChangeConfiguration() { return { dispose() { } }; } diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index df96f3c0c0d..39d1f8cc654 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -58,7 +58,7 @@ class ConfigAwareContextValuesContainer extends Context { super(id, null); this._emitter = emitter; - this._subscription = configurationService.onDidUpdateConfiguration(e => this._updateConfigurationContext(configurationService.getConfiguration())); + this._subscription = configurationService.onDidChangeConfiguration(e => this._updateConfigurationContext(configurationService.getConfiguration())); this._updateConfigurationContext(configurationService.getConfiguration()); } diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index de5f75fbbd6..a6e58846724 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -29,7 +29,7 @@ export class RequestService implements IRequestService { @IConfigurationService configurationService: IConfigurationService ) { this.configure(configurationService.getConfiguration()); - configurationService.onDidUpdateConfiguration(() => this.configure(configurationService.getConfiguration()), this, this.disposables); + configurationService.onDidChangeConfiguration(() => this.configure(configurationService.getConfiguration()), this, this.disposables); } private configure(config: IHTTPConfiguration) { diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 0ebdb46ff38..45c89aa945a 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -64,7 +64,7 @@ export class TelemetryService implements ITelemetryService { if (this._configurationService) { this._updateUserOptIn(); - this._configurationService.onDidUpdateConfiguration(this._updateUserOptIn, this, this._disposables); + this._configurationService.onDidChangeConfiguration(this._updateUserOptIn, this, this._disposables); /* __GDPR__ "optInStatus" : { "optIn" : { "classification": "SystemMetaData", "purpose": "BusinessInsight" } diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 9ef38db2fa9..4f177bbb2e2 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -185,7 +185,7 @@ const configurationValueWhitelist = [ ]; export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable { - return configurationService.onDidUpdateConfiguration(event => { + return configurationService.onDidChangeConfiguration(event => { if (event.source !== ConfigurationTarget.DEFAULT) { /* __GDPR__ "updateConfiguration" : { diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index d97577a72b3..69d2f789bb6 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -697,7 +697,7 @@ suite('TelemetryService', () => { }; }, keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, - onDidUpdateConfiguration: emitter.event, + onDidChangeConfiguration: emitter.event, reloadConfiguration() { return null; }, getConfigurationData() { return null; } }); diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 79d793d416c..a8b5cf06253 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -27,7 +27,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { ) { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); - this._configurationListener = configurationService.onDidUpdateConfiguration(() => { + this._configurationListener = configurationService.onDidChangeConfiguration(() => { proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); }); } diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index ec6920eed22..5c0a40f1752 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -65,7 +65,7 @@ export class ResourceLabel extends IconLabel { private registerListeners(): void { this.extensionService.onReady().then(() => this.render(true /* clear cache */)); // update when extensions are loaded with potentially new languages - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change + this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); // react to model mode changes this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); // react to file decoration changes this.toDispose.push(this.themeService.onThemeChange(() => this.render(false))); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 3b01b41686a..0899f3bd851 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -205,7 +205,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.toUnbind.push(this.stacks.onEditorClosed(event => this.onEditorClosed(event))); this.toUnbind.push(this.stacks.onGroupOpened(event => this.onEditorGroupOpenedOrClosed())); this.toUnbind.push(this.stacks.onGroupClosed(event => this.onEditorGroupOpenedOrClosed())); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onEditorGroupOpenedOrClosed(): void { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index b70eced071c..13522be113f 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -66,7 +66,7 @@ export abstract class BaseTextEditor extends BaseEditor { ) { super(id, telemetryService, themeService); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration(this.getResource())))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration(this.getResource())))); } protected get instantiationService(): IInstantiationService { diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 08681245fcd..3a666cfbc1c 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -137,7 +137,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.updateConfiguration(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration(this.configurationService.getConfiguration()))); this.toUnbind.push(this.partService.onTitleBarVisibilityChange(() => this.positionQuickOpenWidget())); this.toUnbind.push(browser.onDidChangeZoomLevel(() => this.positionQuickOpenWidget())); } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index bfba7464b3d..62741f2adfc 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -99,7 +99,7 @@ export class TitlebarPart extends Part implements ITitleService { private registerListeners(): void { this.toUnbind.push(DOM.addDisposableListener(window, DOM.EventType.BLUR, () => this.onBlur())); this.toUnbind.push(DOM.addDisposableListener(window, DOM.EventType.FOCUS, () => this.onFocus())); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.onConfigurationChanged(true))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(() => this.onConfigurationChanged(true))); this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.setTitle(this.getWindowTitle()))); this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.setTitle(this.getWindowTitle()))); diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 26d0dca609d..148a01d2c41 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -110,7 +110,7 @@ export class EditorGroup implements IEditorGroup { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 5442ba80ab6..278e1bdcad8 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -94,7 +94,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin private registerListeners(): void { // Config Changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange())); } private onConfigurationChange(): void { diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index ec82d07b99b..9ffaef6c14f 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -95,7 +95,7 @@ export class ResourceGlobMatcher { } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.updateExcludes(true))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(() => this.updateExcludes(true))); this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateExcludes(true))); } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index e1dfbbe2a03..5049e7db79e 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -240,7 +240,7 @@ export class ElectronWindow extends Themable { }); // Configuration changes - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onDidUpdateConfiguration(e))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onDidUpdateConfiguration(e))); // Context menu support in input/textarea window.document.addEventListener('contextmenu', e => this.onContextMenu(e)); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 8f5e5fbe60d..89a41c79fb2 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -986,7 +986,7 @@ export class Workbench implements IPartService { this.toDispose.push(this.quickOpen.onHide(() => (this.messageService).resume())); // resume messages once quick open is closed again // Configuration changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.onDidUpdateConfiguration())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); // Fullscreen changes this.toDispose.push(browser.onDidChangeFullscreen(() => this.onFullscreenChanged())); diff --git a/src/vs/workbench/parts/backup/common/backupModelTracker.ts b/src/vs/workbench/parts/backup/common/backupModelTracker.ts index 787897cd389..4b1408847d2 100644 --- a/src/vs/workbench/parts/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/parts/backup/common/backupModelTracker.ts @@ -50,7 +50,7 @@ export class BackupModelTracker implements IWorkbenchContribution { this.toDispose.push(this.untitledEditorService.onDidDisposeModel((e) => this.discardBackup(e))); // Listen to config changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); } private onConfigurationChange(configuration: IFilesConfiguration): void { diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index 9467e227330..81af57279a2 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -54,7 +54,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('launch')) { this.updateOptions(); } diff --git a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts index 5818d30bd3b..3c68f376e9c 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts @@ -93,7 +93,7 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi private registerListeners(): void { this.toUnbind.push(this.debugService.onDidChangeState(state => this.update(state))); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.update(this.debugService.state))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(() => this.update(this.debugService.state))); this.toUnbind.push(this.actionBar.actionRunner.addListener(EventType.RUN, (e: any) => { // check for error if (e.error && !errors.isPromiseCanceledError(e.error)) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index d303e2417ff..78cecbd98bf 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -323,7 +323,7 @@ export class ConfigurationManager implements IConfigurationManager { this.initLaunches(); this.selectConfiguration(); })); - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => { + this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => { this.selectConfiguration(); })); diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 1217632d2ab..e32066bcf7a 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -709,7 +709,7 @@ export class ToggleAutoUpdateAction extends Action { ) { super(id, label, '', true); this.updateEnablement(); - configurationService.onDidUpdateConfiguration(() => this.updateEnablement()); + configurationService.onDidChangeConfiguration(() => this.updateEnablement()); } private updateEnablement(): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index ccbee9dd3a1..6a9c5ce9481 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -111,7 +111,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens this.disposables.push(viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables)); this.isAutoUpdateEnabled = this.extensionsWorkbenchService.isAutoUpdateEnabled; - this.configurationService.onDidUpdateConfiguration(() => { + this.configurationService.onDidChangeConfiguration(() => { const isAutoUpdateEnabled = this.extensionsWorkbenchService.isAutoUpdateEnabled; if (this.isAutoUpdateEnabled !== isAutoUpdateEnabled) { this.isAutoUpdateEnabled = isAutoUpdateEnabled; diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index b55058ebf56..7808d2d4c4c 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -347,7 +347,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { .on(this.onOpenExtensionUrl, this, this.disposables); this._isAutoUpdateEnabled = this.configurationService.getConfiguration(ConfigurationKey).autoUpdate; - this.configurationService.onDidUpdateConfiguration(() => { + this.configurationService.onDidChangeConfiguration(() => { const isAutoUpdateEnabled = this.configurationService.getConfiguration(ConfigurationKey).autoUpdate; if (this._isAutoUpdateEnabled !== isAutoUpdateEnabled) { this._isAutoUpdateEnabled = isAutoUpdateEnabled; diff --git a/src/vs/workbench/parts/files/browser/explorerViewlet.ts b/src/vs/workbench/parts/files/browser/explorerViewlet.ts index 340a269b289..8855798cefa 100644 --- a/src/vs/workbench/parts/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/parts/files/browser/explorerViewlet.ts @@ -62,7 +62,7 @@ export class ExplorerViewlet extends PersistentViewsViewlet { this.registerViews(); this.onConfigurationUpdated(); - this._register(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated())); + this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated())); this._register(this.contextService.onDidChangeWorkspaceName(e => this.updateTitleArea())); this._register(this.contextService.onDidChangeWorkbenchState(() => this.registerViews())); this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.registerViews())); diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index f522ebcea6d..b831fcb8ac4 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -204,7 +204,7 @@ export class ExplorerView extends ViewsViewletPanel { this.disposables.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); // Also handle configuration updates - this.disposables.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), e))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), e))); }); } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index a095ecd2a5a..0328d3ef7ea 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -568,7 +568,7 @@ export class FileSorter implements ISorter { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onConfigurationUpdated(configuration: IFilesConfiguration): void { @@ -769,7 +769,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onConfigurationUpdated(config: IFilesConfiguration): void { diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts index 51b5ab51ba9..541fd1adb78 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts @@ -183,7 +183,7 @@ export class OpenEditorsView extends ViewsViewletPanel { this.disposables.push(this.model.onModelChanged(e => this.onEditorStacksModelChanged(e))); // Also handle configuration updates - this.disposables.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); // Handle dirty counter this.disposables.push(this.untitledEditorService.onDidChangeDirty(e => this.updateDirtyIndicator())); diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index c07ed76b795..3209fbc2a2e 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -75,7 +75,7 @@ export class FileEditorTracker implements IWorkbenchContribution { this.lifecycleService.onShutdown(this.dispose, this); // Configuration - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void { diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index e9a44a611ac..d9a6ce584da 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -64,7 +64,7 @@ class MarkersFileDecorations implements IWorkbenchContribution { ) { // this._disposables = [ - this._configurationService.onDidUpdateConfiguration(this._updateEnablement, this), + this._configurationService.onDidChangeConfiguration(this._updateEnablement, this), ]; this._updateEnablement(); } diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index a4060b88693..13305518c4e 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -253,7 +253,7 @@ export class MarkersPanel extends Panel { } private createListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationsUpdated(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationsUpdated(this.configurationService.getConfiguration()))); this.toUnbind.push(this.markerService.onMarkerChanged(this.onMarkerChanged, this)); this.toUnbind.push(this.editorGroupService.onEditorsChanged(this.onEditorsChanged, this)); this.toUnbind.push(this.tree.addListener('selection', () => this.onSelected())); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 02c4e1a85c6..151446902f8 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -950,7 +950,7 @@ class UnsupportedWorkspaceSettingsRenderer extends Disposable { @IMarkerService private markerService: IMarkerService ) { super(); - this._register(this.configurationService.onDidUpdateConfiguration(() => this.render())); + this._register(this.configurationService.onDidChangeConfiguration(() => this.render())); } private getMarkerMessage(settingKey: string): string { diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts index 2f91e713b0d..db5b54b3fb7 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -38,7 +38,7 @@ export class PreferencesContribution implements IWorkbenchContribution { @IWorkspaceContextService private workspaceService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService ) { - this.settingsListener = this.configurationService.onDidUpdateConfiguration(() => this.handleSettingsEditorOverride()); + this.settingsListener = this.configurationService.onDidChangeConfiguration(() => this.handleSettingsEditorOverride()); this.handleSettingsEditorOverride(); this.start(); diff --git a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts index f5e99434096..8b5d93e1438 100644 --- a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts @@ -95,7 +95,7 @@ class CommandsHistory { } private registerListeners(): void { - this.configurationService.onDidUpdateConfiguration(e => this.updateConfiguration()); + this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration()); once(this.lifecycleService.onShutdown)(reason => this.save()); } @@ -404,7 +404,7 @@ export class CommandsHandler extends QuickOpenHandler { this.commandsHistory = this.instantiationService.createInstance(CommandsHistory); - this.configurationService.onDidUpdateConfiguration(e => this.updateConfiguration()); + this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration()); this.updateConfiguration(); } diff --git a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts index 854fbca08ae..988464d7332 100644 --- a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts +++ b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts @@ -58,7 +58,7 @@ export class SettingsChangeRelauncher implements IWorkbenchContribution { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration(), true))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration(), true))); this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => setTimeout(() => this.handleWorkbenchState()))); } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index 02616fb2a13..e69496fafdb 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -90,7 +90,7 @@ export class FileDecorations implements IWorkbenchContribution { @IConfigurationService private _configurationService: IConfigurationService, @ISCMService private _scmService: ISCMService, ) { - this._configListener = this._configurationService.onDidUpdateConfiguration(e => e.affectsConfiguration('scm.fileDecorations.enabled') && this._update()); + this._configListener = this._configurationService.onDidChangeConfiguration(e => e.affectsConfiguration('scm.fileDecorations.enabled') && this._update()); this._update(); } diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 16acf16b142..7e9faa28fd4 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -148,7 +148,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { } private registerListeners(): void { - this.configurationService.onDidUpdateConfiguration(e => this.updateHandlers(this.configurationService.getConfiguration())); + this.configurationService.onDidChangeConfiguration(e => this.updateHandlers(this.configurationService.getConfiguration())); } private updateHandlers(configuration: IWorkbenchSearchConfiguration): void { diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 3ccba8cd491..14c8cddf519 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -620,7 +620,7 @@ class TaskService extends EventEmitter implements ITaskService { this._taskSystemListeners = []; this._outputChannel = this.outputService.getChannel(TaskService.OutputChannelId); this._providers = new Map(); - this.configurationService.onDidUpdateConfiguration(() => { + this.configurationService.onDidChangeConfiguration(() => { if (!this._taskSystem && !this._workspaceTasksPromise) { return; } diff --git a/src/vs/workbench/parts/terminal/common/terminalService.ts b/src/vs/workbench/parts/terminal/common/terminalService.ts index 5ccb2a29e65..44815065a04 100644 --- a/src/vs/workbench/parts/terminal/common/terminalService.ts +++ b/src/vs/workbench/parts/terminal/common/terminalService.ts @@ -59,7 +59,7 @@ export abstract class TerminalService implements ITerminalService { this._onInstanceTitleChanged = new Emitter(); this._onInstancesChanged = new Emitter(); - this._configurationService.onDidUpdateConfiguration(() => this.updateConfig()); + this._configurationService.onDidChangeConfiguration(() => this.updateConfig()); lifecycleService.onWillShutdown(event => event.veto(this._onWillShutdown())); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 2ec3fb4ed98..d382d1f2aa5 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -74,7 +74,7 @@ export class TerminalPanel extends Panel { this._terminalService.setContainers(this.getContainer().getHTMLElement(), this._terminalContainer); this._register(this.themeService.onThemeChange(theme => this._updateTheme(theme))); - this._register(this._configurationService.onDidUpdateConfiguration(() => this._updateFont())); + this._register(this._configurationService.onDidChangeConfiguration(() => this._updateFont())); this._updateFont(); this._updateTheme(); diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts index d38ab62eea9..2fb9993bf0a 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -23,7 +23,7 @@ class MockConfigurationService implements IConfigurationService { public getValue(key: string, overrides?: IConfigurationOverrides): T { return getConfigurationValue(this.getConfiguration(), key); } public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } - public onDidUpdateConfiguration() { return { dispose() { } }; } + public onDidChangeConfiguration() { return { dispose() { } }; } public reloadConfiguration() { return null; } } diff --git a/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts b/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts index 21dbeb9472c..a008c9c954f 100644 --- a/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts +++ b/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts @@ -35,7 +35,7 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution @IStorageService private storageService: IStorageService ) { lifecycleService.onShutdown(this.dispose, this); - this.toDispose.push(this.workspaceConfigurationService.onDidUpdateConfiguration(e => this.checkWorkspaceSettings())); + this.toDispose.push(this.workspaceConfigurationService.onDidChangeConfiguration(e => this.checkWorkspaceSettings())); } getId(): string { diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index ec6aa876b65..8acbac70b41 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -126,7 +126,7 @@ export class WatermarkContribution implements IWorkbenchContribution { this.create(); } }); - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) { const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (enabled !== this.enabled) { diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts index 173483768ba..8c3e14e3123 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts @@ -401,7 +401,7 @@ export class WalkThroughPart extends BaseEditor { } })); - this.contentDisposables.push(this.configurationService.onDidUpdateConfiguration(() => { + this.contentDisposables.push(this.configurationService.onDidChangeConfiguration(() => { if (snippet.textEditorModel) { editor.updateOptions(this.getEditorOptions(snippet.textEditorModel.getModeId())); } @@ -452,7 +452,7 @@ export class WalkThroughPart extends BaseEditor { }); this.updateSizeClasses(); this.multiCursorModifier(); - this.contentDisposables.push(this.configurationService.onDidUpdateConfiguration(() => this.multiCursorModifier())); + this.contentDisposables.push(this.configurationService.onDidChangeConfiguration(() => this.multiCursorModifier())); if (input.onReady) { input.onReady(innerContent); } diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index d83c8b0d642..262151b6a7b 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -61,8 +61,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private workspaceConfiguration: WorkspaceConfiguration; private cachedFolderConfigs: StrictResourceMap; - protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; protected readonly _onDidChangeWorkspaceFolders: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; @@ -82,7 +82,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged())); this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); - this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); + this._register(this.baseConfigurationService.onDidChangeConfiguration(e => this.onBaseConfigurationChanged(e))); this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(e => this.registerConfigurationSchemas())); } @@ -328,7 +328,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat // TODO Sandy: compare with old values?? const keys = this._configuration.keys(); - this._onDidUpdateConfiguration.fire(new AllKeysConfigurationChangeEvent([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); + this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent([...keys.default, ...keys.user, ...keys.workspace, ...keys.workspaceFolder], ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); }); } @@ -520,7 +520,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private triggerConfigurationChange(configurationEvent: ConfigurationChangeEvent, target: ConfigurationTarget): void { if (configurationEvent.affectedKeys.length) { configurationEvent.telemetryData(target, this.getTargetConfiguration(target)); - this._onDidUpdateConfiguration.fire(new WorkspaceConfigurationChangeEvent(configurationEvent, this.workspace)); + this._onDidChangeConfiguration.fire(new WorkspaceConfigurationChangeEvent(configurationEvent, this.workspace)); } } diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts index 5c6763edb10..211e1f66128 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -196,7 +196,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); return service.initialize(workspaceDir).then(() => { - service.onDidUpdateConfiguration(event => { + service.onDidChangeConfiguration(event => { const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>(); assert.equal(config.testworkbench.editor.tabs, false); @@ -279,7 +279,7 @@ suite('WorkspaceConfigurationService - Node', () => { test('workspace change triggers event', (done: () => void) => { createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { - service.onDidUpdateConfiguration(event => { + service.onDidChangeConfiguration(event => { const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean } } }>(); assert.equal(config.testworkbench.editor.icons, true); assert.equal(service.getConfiguration().testworkbench.editor.icons, true); @@ -305,7 +305,7 @@ suite('WorkspaceConfigurationService - Node', () => { fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": true }'); const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); + service.onDidChangeConfiguration(event => target()); fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": false }'); @@ -327,7 +327,7 @@ suite('WorkspaceConfigurationService - Node', () => { service.reloadWorkspaceConfiguration().done(() => { const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); + service.onDidChangeConfiguration(event => target()); service.reloadWorkspaceConfiguration().done(() => { assert.ok(!target.called); @@ -344,7 +344,7 @@ suite('WorkspaceConfigurationService - Node', () => { createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); + service.onDidChangeConfiguration(event => target()); service.reloadUserConfiguration().done(() => { assert.ok(!target.called); service.dispose(); diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 2360f632988..fce774139c1 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -354,7 +354,7 @@ class MockConfigurationService implements IConfigurationService { public getValue(key: string): any { return getConfigurationValue(this.getConfiguration(), key); } public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } - public onDidUpdateConfiguration() { return { dispose() { } }; } + public onDidChangeConfiguration() { return { dispose() { } }; } public reloadConfiguration() { return null; } } diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index d2c61424a26..270f2367a64 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -119,7 +119,7 @@ export class FileService implements IFileService { this.toUnbind.push(this.raw.onAfterOperation(e => this._onAfterOperation.fire(e))); // Config changes - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); // Root changes this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders())); diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts index 05a68b0cb7a..6c54ae8d675 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts @@ -83,7 +83,7 @@ export class FileWatcher { // Start watching this.updateFolders(); this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateFolders())); - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.updateFolders())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.updateFolders())); return () => this.dispose(); } diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index 9634a27da63..562e8972512 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -268,7 +268,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { super(contextKeyService, commandService, telemetryService, messageService, statusBarService); let dispatchConfig = getDispatchConfig(configurationService); - configurationService.onDidUpdateConfiguration((e) => { + configurationService.onDidChangeConfiguration((e) => { let newDispatchConfig = getDispatchConfig(configurationService); if (dispatchConfig === newDispatchConfig) { return; diff --git a/src/vs/workbench/services/mode/common/workbenchModeService.ts b/src/vs/workbench/services/mode/common/workbenchModeService.ts index 7b59087af60..abd67ba5a18 100644 --- a/src/vs/workbench/services/mode/common/workbenchModeService.ts +++ b/src/vs/workbench/services/mode/common/workbenchModeService.ts @@ -123,7 +123,7 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { }); - this._configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this._configurationService.getConfiguration())); + this._configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this._configurationService.getConfiguration())); this.onDidCreateMode((mode) => { this._extensionService.activateByEvent(`onLanguage:${mode.getId()}`).done(null, onUnexpectedError); diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 5dfbcde38a9..27a19245296 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -124,7 +124,7 @@ export abstract class TextFileService implements ITextFileService { this.lifecycleService.onShutdown(this.dispose, this); // Configuration changes - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); } private beforeShutdown(reason: ShutdownReason): boolean | TPromise { diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 702a85b0baf..572299fd514 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -235,7 +235,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private installConfigurationListener() { - this.configurationService.onDidUpdateConfiguration(e => { + this.configurationService.onDidChangeConfiguration(e => { let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); if (colorThemeSetting !== this.currentColorTheme.settingsId) { this.colorThemeStore.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b07ab0b7f95..8bfdf7f0f46 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -1211,7 +1211,7 @@ export class TestTextResourceConfigurationService implements ITextResourceConfig constructor(private configurationService = new TestConfigurationService()) { } - public onDidUpdateConfiguration() { + public onDidChangeConfiguration() { return { dispose() { } }; } From 572c7ba2b4650b8626a65b3cccb7f5bfc65b31e2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 Oct 2017 11:15:46 +0200 Subject: [PATCH 263/303] deco - expose decorations as proposed api --- src/vs/vscode.proposed.d.ts | 22 +++++++ .../extensionHost.contribution.ts | 1 + .../electron-browser/mainThreadDecorations.ts | 64 +++++++++++++++++++ src/vs/workbench/api/node/extHost.api.impl.ts | 5 ++ src/vs/workbench/api/node/extHost.protocol.ts | 15 +++++ .../workbench/api/node/extHostDecorations.ts | 47 ++++++++++++++ .../markers/browser/markersFileDecorations.ts | 1 + .../electron-browser/scmFileDecorations.ts | 3 +- .../decorations/browser/decorations.ts | 1 + .../decorations/browser/decorationsService.ts | 13 +++- .../test/browser/decorationsService.test.ts | 39 +++++++++++ 11 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 src/vs/workbench/api/electron-browser/mainThreadDecorations.ts create mode 100644 src/vs/workbench/api/node/extHostDecorations.ts diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 0c5dba2a3e5..e8485b673fc 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -168,4 +168,26 @@ declare module 'vscode' { */ export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable; } + + //#region decorations + + //todo@joh -> make class + export interface DecorationData { + priority?: number; + title?: string; + abbreviation?: string; + color?: ThemeColor; + opacity?: number; + } + + export interface DecorationProvider { + onDidChangeDecorations: Event; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; + } + + export namespace window { + export function registerDecorationProvider(provider: DecorationProvider, label: string): Disposable; + } + + //#endregion } diff --git a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index be065d33308..2940cda2e51 100644 --- a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -19,6 +19,7 @@ import './mainThreadCommands'; import './mainThreadConfiguration'; import './mainThreadCredentials'; import './mainThreadDebugService'; +import './mainThreadDecorations'; import './mainThreadDiagnostics'; import './mainThreadDialogs'; import './mainThreadDocumentContentProviders'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts new file mode 100644 index 00000000000..1dd8523ff44 --- /dev/null +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import { Emitter } from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape } from '../node/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; + +@extHostNamedCustomer(MainContext.MainThreadDecorations) +export class MainThreadDecorations implements MainThreadDecorationsShape { + + private readonly _provider = new Map, IDisposable]>(); + private readonly _proxy: ExtHostDecorationsShape; + + constructor( + context: IExtHostContext, + @IDecorationsService private readonly _decorationsService: IDecorationsService + ) { + this._proxy = context.get(ExtHostContext.ExtHostDecorations); + } + + dispose() { + this._provider.forEach(value => dispose(value)); + this._provider.clear(); + } + + $registerDecorationProvider(handle: number, label: string): void { + let emitter = new Emitter(); + let registration = this._decorationsService.registerDecorationsProvider({ + label, + onDidChange: emitter.event, + provideDecorations: (uri) => { + return this._proxy.$providerDecorations(handle, uri).then(data => { + const [weight, title, letter, opacity, themeColor] = data; + return { + weight: weight || 0, + title, + letter, + opacity, + color: themeColor && themeColor.id + }; + }); + } + }); + this._provider.set(handle, [emitter, registration]); + } + + $onDidChange(handle: number, resources: URI[]): void { + const [emitter] = this._provider.get(handle); + emitter.fire(resources); + } + + $unregisterDecorationProvider(handle: number): void { + if (this._provider.has(handle)) { + dispose(this._provider.get(handle)); + this._provider.delete(handle); + } + } +} diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 32af7291dfc..73c966c463e 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -55,6 +55,7 @@ import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadServi import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs'; import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem'; import { FileChangeType, FileType } from 'vs/platform/files/common/files'; +import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations'; export interface IExtensionApiFactory { (extension: IExtensionDescription): typeof vscode; @@ -83,6 +84,7 @@ export function createApiFactory( // Addressable instances const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService()); + const extHostDecorations = threadService.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(threadService)); const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService)); const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors)); @@ -376,6 +378,9 @@ export function createApiFactory( sampleFunction: proposedApiFunction(extension, () => { return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []); }), + registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider, label: string) => { + return extHostDecorations.registerDecorationProvider(provider, label); + }) }; // namespace: workspace diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index d07165fce5a..eee71c3f13d 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -135,6 +135,12 @@ export interface MainThreadDiaglogsShape extends IDisposable { $showSaveDialog(options: MainThreadDialogSaveOptions): TPromise; } +export interface MainThreadDecorationsShape extends IDisposable { + $registerDecorationProvider(handle: number, label: string): void; + $unregisterDecorationProvider(handle: number): void; + $onDidChange(handle: number, resources: URI[]): void; +} + export interface MainThreadDocumentContentProvidersShape extends IDisposable { $registerTextContentProvider(handle: number, scheme: string): void; $unregisterTextContentProvider(handle: number): void; @@ -596,6 +602,13 @@ export interface ExtHostDebugServiceShape { $acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void; } + +export type DecorationData = [number, string, string, number, ThemeColor]; + +export interface ExtHostDecorationsShape { + $providerDecorations(handle: number, uri: URI): TPromise; +} + export interface ExtHostCredentialsShape { } @@ -609,6 +622,7 @@ export const MainContext = { MainThreadCommands: createMainId('MainThreadCommands'), MainThreadConfiguration: createMainId('MainThreadConfiguration'), MainThreadDebugService: createMainId('MainThreadDebugService'), + MainThreadDecorations: createMainId('MainThreadDecorations'), MainThreadDiagnostics: createMainId('MainThreadDiagnostics'), MainThreadDialogs: createMainId('MainThreadDiaglogs'), MainThreadDocuments: createMainId('MainThreadDocuments'), @@ -640,6 +654,7 @@ export const ExtHostContext = { ExtHostConfiguration: createExtId('ExtHostConfiguration'), ExtHostDiagnostics: createExtId('ExtHostDiagnostics'), ExtHostDebugService: createExtId('ExtHostDebugService'), + ExtHostDecorations: createExtId('ExtHostDecorations'), ExtHostDocumentsAndEditors: createExtId('ExtHostDocumentsAndEditors'), ExtHostDocuments: createExtId('ExtHostDocuments'), ExtHostDocumentContentProviders: createExtId('ExtHostDocumentContentProviders'), diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts new file mode 100644 index 00000000000..05b93b96f33 --- /dev/null +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * 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 vscode from 'vscode'; +import URI from 'vs/base/common/uri'; +import { MainContext, IMainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData } from 'vs/workbench/api/node/extHost.protocol'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Disposable } from 'vs/workbench/api/node/extHostTypes'; +import { asWinJsPromise } from 'vs/base/common/async'; + +export class ExtHostDecorations implements ExtHostDecorationsShape { + + private static _handlePool = 0; + + private readonly _provider = new Map(); + private readonly _proxy: MainThreadDecorationsShape; + + constructor(mainContext: IMainContext) { + this._proxy = mainContext.get(MainContext.MainThreadDecorations); + } + + registerDecorationProvider(provider: vscode.DecorationProvider, label: string): vscode.Disposable { + const handle = ExtHostDecorations._handlePool++; + this._provider.set(handle, provider); + this._proxy.$registerDecorationProvider(handle, label); + + const listener = provider.onDidChangeDecorations(e => { + this._proxy.$onDidChange(handle, Array.isArray(e) ? e : [e]); + }); + + return new Disposable(() => { + listener.dispose(); + this._proxy.$unregisterDecorationProvider(handle); + this._provider.delete(handle); + }); + } + + $providerDecorations(handle: number, uri: URI): TPromise { + const provider = this._provider.get(handle); + return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => { + return [data.priority, data.title, data.abbreviation, data.opacity, data.color]; + }); + } +} diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index d9a6ce584da..9dd0ce444fb 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -44,6 +44,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { return { weight: 100 * first.severity, + bubble: true, title: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), letter: markers.length.toString(), color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts index e69496fafdb..23e0d15fdae 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts @@ -65,7 +65,8 @@ class SCMDecorationsProvider implements IDecorationsProvider { return undefined; } return { - weight: 100 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0), + bubble: true, + weight: 255 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0), title: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), color: resource.decorations.color, letter: resource.decorations.tooltip.charAt(0) diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 25401fd795a..6a5b7993205 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -18,6 +18,7 @@ export interface IDecorationData { readonly opacity?: number; readonly letter?: string; readonly title?: string; + readonly bubble?: boolean; } export interface IDecoration { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 9792da756f4..ddbf12c6133 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -347,6 +347,12 @@ export class FileDecorationsService implements IDecorationsService { this._onDidChangeDecorationsDelayed ); const remove = this._data.push(wrapper); + + this._onDidChangeDecorations.fire({ + // everything might have changed + affectsResource() { return true; } + }); + return { dispose: () => { // fire event that says 'yes' for any resource @@ -363,9 +369,10 @@ export class FileDecorationsService implements IDecorationsService { let onlyChildren = true; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { - // top = FileDecorationsService._pickBest(top, candidate); - data.push(deco); - onlyChildren = onlyChildren && isChild; + if (!isChild || deco.bubble) { + data.push(deco); + onlyChildren = onlyChildren && isChild; + } }); } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 21708a3b55d..721051fb31a 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -103,4 +103,43 @@ suite('DecorationsService', function () { reg.dispose(); assert.equal(didSeeEvent, true); }); + + test('No default bubbling', function () { + + let reg = service.registerDecorationsProvider({ + label: 'Test', + onDidChange: Event.None, + provideDecorations(uri: URI) { + return uri.path.match(/\.txt/) + ? { title: '.txt' } + : undefined; + } + }); + + let childUri = URI.parse('file:///some/path/some/file.txt'); + + let deco = service.getDecoration(childUri, false); + assert.equal(deco.title, '.txt'); + + deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); + assert.equal(deco, undefined); + reg.dispose(); + + // bubble + reg = service.registerDecorationsProvider({ + label: 'Test', + onDidChange: Event.None, + provideDecorations(uri: URI) { + return uri.path.match(/\.txt/) + ? { title: '.txt.bubble', bubble: true } + : undefined; + } + }); + + deco = service.getDecoration(childUri, false); + assert.equal(deco.title, '.txt.bubble'); + + deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); + assert.equal(deco.title, '.txt.bubble'); + }); }); From 506eea19ef5d6038995dd7bf4fc5bd7a685257ca Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2017 11:27:14 +0200 Subject: [PATCH 264/303] fix explorer exploding --- src/vs/workbench/parts/files/browser/views/explorerView.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index b831fcb8ac4..2c2d45cb9c6 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -275,8 +275,8 @@ export class ExplorerView extends ViewsViewletPanel { || event.affectsConfiguration('explorer.decorations.badges'); } - // Refresh viewer as needed - if (needsRefresh) { + // Refresh viewer as needed if this originates from a config event + if (event && needsRefresh) { this.doRefresh().done(null, errors.onUnexpectedError); } } From 015901f14b5268c9874753cd7695f408b55052e9 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Oct 2017 11:27:52 +0200 Subject: [PATCH 265/303] return threadId as the context for actions in the callstack view fixes #36394 --- src/vs/workbench/parts/debug/electron-browser/debugViewer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index 521ebfd16d0..bc97bf770ba 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -282,6 +282,9 @@ export class CallStackController extends BaseDebugController { return element.source.uri.toString(); } + if (element instanceof Thread) { + return element.threadId; + } } // user clicked / pressed on 'Load More Stack Frames', get those stack frames and refresh the tree. From 41f0ff15d7327da30fdae73aa04ca570ce34fa0a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 Oct 2017 12:47:39 +0200 Subject: [PATCH 266/303] deco - move scm decorations to git extension --- extensions/git/src/decorationProvider.ts | 96 +++++++++++++ extensions/git/src/main.ts | 4 +- extensions/git/src/repository.ts | 32 +++-- src/vs/vscode.d.ts | 6 - src/vs/vscode.proposed.d.ts | 1 + .../electron-browser/mainThreadDecorations.ts | 6 +- .../api/electron-browser/mainThreadSCM.ts | 5 +- src/vs/workbench/api/node/extHost.protocol.ts | 5 +- .../workbench/api/node/extHostDecorations.ts | 2 +- src/vs/workbench/api/node/extHostSCM.ts | 3 +- .../scm/electron-browser/scm.contribution.ts | 19 --- .../electron-browser/scmFileDecorations.ts | 136 ------------------ src/vs/workbench/services/scm/common/scm.ts | 2 - 13 files changed, 128 insertions(+), 189 deletions(-) create mode 100644 extensions/git/src/decorationProvider.ts delete mode 100644 src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts new file mode 100644 index 00000000000..ed4bad8aef0 --- /dev/null +++ b/extensions/git/src/decorationProvider.ts @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider } from 'vscode'; +import { Repository, GitResourceGroup } from './repository'; +import { Model } from './model'; + +class GitDecorationProvider implements DecorationProvider { + + private readonly _onDidChangeDecorations = new EventEmitter(); + readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; + + private disposables: Disposable[] = []; + private decorations = new Map(); + + constructor(private repository: Repository) { + this.disposables.push( + window.registerDecorationProvider(this, repository.root), + repository.onDidRunOperation(this.onDidRunOperation, this) + ); + } + + private onDidRunOperation(): void { + let newDecorations = new Map(); + this.collectDecorationData(this.repository.indexGroup, newDecorations); + this.collectDecorationData(this.repository.workingTreeGroup, newDecorations); + + let uris: Uri[] = []; + newDecorations.forEach((value, uriString) => { + if (this.decorations.has(uriString)) { + this.decorations.delete(uriString); + } else { + uris.push(Uri.parse(uriString)); + } + }); + this.decorations.forEach((value, uriString) => { + uris.push(Uri.parse(uriString)); + }); + this.decorations = newDecorations; + this._onDidChangeDecorations.fire(uris); + } + + private collectDecorationData(group: GitResourceGroup, bucket: Map): void { + group.resourceStates.forEach(r => { + if (r.resourceDecoration) { + bucket.set(r.original.toString(), r.resourceDecoration); + } + }); + } + + provideDecoration(uri: Uri): DecorationData | undefined { + return this.decorations.get(uri.toString()); + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + } +} + + +export class GitDecorations { + + private disposables: Disposable[] = []; + private providers = new Map(); + + constructor(private model: Model) { + this.disposables.push( + model.onDidOpenRepository(this.onDidOpenRepository, this), + model.onDidCloseRepository(this.onDidCloseRepository, this) + ); + model.repositories.forEach(this.onDidOpenRepository, this); + } + + private onDidOpenRepository(repository: Repository): void { + const provider = new GitDecorationProvider(repository); + this.providers.set(repository, provider); + } + + private onDidCloseRepository(repository: Repository): void { + const provider = this.providers.get(repository); + if (provider) { + provider.dispose(); + this.providers.delete(repository); + } + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + this.providers.forEach(value => value.dispose); + this.providers.clear(); + } +} diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index acc30eeb81d..b090495be71 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -12,6 +12,7 @@ import { findGit, Git, IGit } from './git'; import { Model } from './model'; import { CommandCenter } from './commands'; import { GitContentProvider } from './contentProvider'; +import { GitDecorations } from './decorationProvider'; import { Askpass } from './askpass'; import { toDisposable } from './util'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -54,6 +55,7 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi disposables.push( new CommandCenter(git, model, outputChannel, telemetryReporter), new GitContentProvider(model), + new GitDecorations(model) ); await checkGitVersion(info); @@ -93,4 +95,4 @@ async function checkGitVersion(info: IGit): Promise { } else if (choice === neverShowAgain) { await config.update('ignoreLegacyWarning', true, true); } -} \ No newline at end of file +} diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 6c9f781c58f..319edc3a07e 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -5,7 +5,7 @@ 'use strict'; -import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor } from 'vscode'; +import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode'; import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; import { memoize, throttle, debounce } from './decorators'; @@ -170,27 +170,29 @@ export class Resource implements SourceControlResourceState { // return this.resourceUri.fsPath.substr(0, workspaceRootPath.length) !== workspaceRootPath; } - private get color(): ThemeColor | undefined { - switch (this.type) { - case Status.INDEX_MODIFIED: - case Status.MODIFIED: - return new ThemeColor('git.color.modified'); - case Status.UNTRACKED: - return new ThemeColor('git.color.untracked'); - default: - return undefined; - } - } - get decorations(): SourceControlResourceDecorations { const light = { iconPath: this.getIconPath('light') }; const dark = { iconPath: this.getIconPath('dark') }; const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; - const color = this.color; - return { strikeThrough, faded, tooltip, light, dark, color }; + return { strikeThrough, faded, tooltip, light, dark }; + } + + get resourceDecoration(): DecorationData | undefined { + const title = this.tooltip; + switch (this.type) { + case Status.IGNORED: + return { priority: 3, title, opacity: 0.75 }; + case Status.UNTRACKED: + return { priority: 1, title, abbreviation: localize('untracked, short', "U"), bubble: true, color: new ThemeColor('git.color.untracked') }; + case Status.INDEX_MODIFIED: + case Status.MODIFIED: + return { priority: 2, title, abbreviation: localize('modified, short', "M"), bubble: true, color: new ThemeColor('git.color.modified') }; + default: + return undefined; + } } constructor( diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 891b0b2289f..09c84d07fc1 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5795,12 +5795,6 @@ declare module 'vscode' { */ readonly tooltip?: string; - /** - * A color for a specific - * [source control resource state](#SourceControlResourceState). - */ - readonly color?: ThemeColor; - /** * The light theme decorations. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index e8485b673fc..d48b0f9020a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -175,6 +175,7 @@ declare module 'vscode' { export interface DecorationData { priority?: number; title?: string; + bubble?: boolean; abbreviation?: string; color?: ThemeColor; opacity?: number; diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts index 1dd8523ff44..b2ae08b829c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -36,9 +36,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { onDidChange: emitter.event, provideDecorations: (uri) => { return this._proxy.$providerDecorations(handle, uri).then(data => { - const [weight, title, letter, opacity, themeColor] = data; + if (!data) { + return undefined; + } + const [weight, bubble, title, letter, opacity, themeColor] = data; return { weight: weight || 0, + bubble: bubble || false, title, letter, opacity, diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index 69b253930b7..64253cfa2d4 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -182,7 +182,7 @@ class MainThreadSCMProvider implements ISCMProvider { for (const [start, deleteCount, rawResources] of groupSlices) { const resources = rawResources.map(rawResource => { - const [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] = rawResource; + const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource; const icon = icons[0]; const iconDark = icons[1] || icon; const decorations = { @@ -190,8 +190,7 @@ class MainThreadSCMProvider implements ISCMProvider { iconDark: iconDark && URI.parse(iconDark), tooltip, strikeThrough, - faded, - color: color && color.id + faded }; return new MainThreadSCMResource( diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index eee71c3f13d..5de663decdf 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -362,8 +362,7 @@ export type SCMRawResource = [ string[] /*icons: light, dark*/, string /*tooltip*/, boolean /*strike through*/, - boolean /*faded*/, - { id: string } /*ThemeColor*/ + boolean /*faded*/ ]; export type SCMRawResourceSplice = [ @@ -603,7 +602,7 @@ export interface ExtHostDebugServiceShape { } -export type DecorationData = [number, string, string, number, ThemeColor]; +export type DecorationData = [number, boolean, string, string, number, ThemeColor]; export interface ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise; diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts index 05b93b96f33..ad428987404 100644 --- a/src/vs/workbench/api/node/extHostDecorations.ts +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -41,7 +41,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise { const provider = this._provider.get(handle); return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => { - return [data.priority, data.title, data.abbreviation, data.opacity, data.color]; + return data && [data.priority, data.bubble, data.title, data.abbreviation, data.opacity, data.color]; }); } } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 9fafcbf368d..310ea752f91 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -243,9 +243,8 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG const tooltip = (r.decorations && r.decorations.tooltip) || ''; const strikeThrough = r.decorations && !!r.decorations.strikeThrough; const faded = r.decorations && !!r.decorations.faded; - const color = r.decorations && r.decorations.color; - return [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] as SCMRawResource; + return [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource; }); handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles)); diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 9405fdb123c..b5465c83f69 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -17,9 +17,7 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StatusUpdater, StatusBarController } from './scmActivity'; -import { FileDecorations } from './scmFileDecorations'; import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet'; -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; class OpenSCMViewletAction extends ToggleViewletAction { @@ -51,9 +49,6 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(StatusBarController); -Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(FileDecorations); - // Register Action to Open Viewlet Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { @@ -65,17 +60,3 @@ Registry.as(WorkbenchActionExtensions.WorkbenchActions 'View: Show SCM', localize('view', "View") ); - - -Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'scm', - 'order': 101, - 'type': 'object', - 'properties': { - 'scm.fileDecorations.enabled': { - 'description': localize('scm.fileDecorations.enabled', "Show source control status on files and folders"), - 'type': 'boolean', - 'default': true - } - } -}); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts b/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts deleted file mode 100644 index 23e0d15fdae..00000000000 --- a/src/vs/workbench/parts/scm/electron-browser/scmFileDecorations.ts +++ /dev/null @@ -1,136 +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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IDecorationsService, IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm'; -import URI from 'vs/base/common/uri'; -import Event, { Emitter } from 'vs/base/common/event'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { localize } from 'vs/nls'; - -class SCMDecorationsProvider implements IDecorationsProvider { - - private readonly _disposable: IDisposable; - private readonly _onDidChange = new Emitter(); - private _data = new Map(); - - readonly label: string; - readonly onDidChange: Event = this._onDidChange.event; - - constructor( - private readonly _provider: ISCMProvider, - private readonly _config: ISCMConfiguration - ) { - this.label = this._provider.label; - this._disposable = this._provider.onDidChangeResources(this._updateGroups, this); - this._updateGroups(); - } - - dispose(): void { - this._disposable.dispose(); - } - - private _updateGroups(): void { - const uris: URI[] = []; - const newData = new Map(); - for (const group of this._provider.resources) { - for (const resource of group.resourceCollection.resources) { - newData.set(resource.sourceUri.toString(), resource); - - if (!this._data.has(resource.sourceUri.toString())) { - uris.push(resource.sourceUri); // added - } - } - } - - this._data.forEach((value, key) => { - if (!newData.has(key)) { - uris.push(value.sourceUri); // removed - } - }); - - this._data = newData; - this._onDidChange.fire(uris); - } - - provideDecorations(uri: URI): IDecorationData { - const resource = this._data.get(uri.toString()); - if (!resource || !resource.decorations.color || !resource.decorations.tooltip) { - return undefined; - } - return { - bubble: true, - weight: 255 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0), - title: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label), - color: resource.decorations.color, - letter: resource.decorations.tooltip.charAt(0) - }; - } -} - -interface ISCMConfiguration { - fileDecorations: { - enabled: boolean; - }; -} - -export class FileDecorations implements IWorkbenchContribution { - - private _providers = new Map(); - private _configListener: IDisposable; - private _repoListeners: IDisposable[]; - - constructor( - @IDecorationsService private _decorationsService: IDecorationsService, - @IConfigurationService private _configurationService: IConfigurationService, - @ISCMService private _scmService: ISCMService, - ) { - this._configListener = this._configurationService.onDidChangeConfiguration(e => e.affectsConfiguration('scm.fileDecorations.enabled') && this._update()); - this._update(); - } - - getId(): string { - throw new Error('smc.SCMFileDecorations'); - } - - dispose(): void { - this._providers.forEach(value => dispose(value)); - dispose(this._repoListeners); - dispose(this._configListener, this._configListener); - } - - private _update(): void { - const config = this._configurationService.getConfiguration('scm'); - if (config.fileDecorations.enabled) { - this._scmService.repositories.forEach(this._onDidAddRepository, this); - this._repoListeners = [ - this._scmService.onDidAddRepository(this._onDidAddRepository, this), - this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this) - ]; - } else { - this._repoListeners = dispose(this._repoListeners); - this._providers.forEach(value => dispose(value)); - this._providers.clear(); - } - } - - private _onDidAddRepository(repo: ISCMRepository): void { - const provider = new SCMDecorationsProvider(repo.provider, this._configurationService.getConfiguration('scm')); - const registration = this._decorationsService.registerDecorationsProvider(provider); - this._providers.set(repo, combinedDisposable([registration, provider])); - } - - private _onDidRemoveRepository(repo: ISCMRepository): void { - let listener = this._providers.get(repo); - if (listener) { - this._providers.delete(repo); - listener.dispose(); - } - } -} diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index e5dda8e6e2b..b659bfeedc4 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -11,7 +11,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Command } from 'vs/editor/common/modes'; -import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export interface IBaselineResourceProvider { getBaselineResource(resource: URI): TPromise; @@ -25,7 +24,6 @@ export interface ISCMResourceDecorations { tooltip?: string; strikeThrough?: boolean; faded?: boolean; - color?: ColorIdentifier; } export interface ISCMResourceSplice { From 828dd97c2dc6096c5289147fd4a0959ca7941dee Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 17 Oct 2017 14:39:54 +0200 Subject: [PATCH 267/303] fixes #36340 --- src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts | 6 +++++- .../parts/scm/electron-browser/dirtydiffDecorator.ts | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index 24acb8e2eba..da7e44b07dd 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -395,7 +395,11 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // Reveal the line above or below the zone widget, to get the zone widget in the viewport const revealLineNumber = Math.min(this.editor.getModel().getLineCount(), Math.max(1, where.endLineNumber + 1)); - this.editor.revealLineInCenterIfOutsideViewport(revealLineNumber, ScrollType.Smooth); + this.revealLine(revealLineNumber); + } + + protected revealLine(lineNumber: number) { + this.editor.revealLine(lineNumber, ScrollType.Smooth); } protected setCssClass(className: string, classToReplace?: string): void { diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index cdb0a5ab4a4..7096a5a7c00 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -315,6 +315,10 @@ class DirtyDiffWidget extends PeekViewWidget { secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) }); } + + protected revealLine(lineNumber: number) { + this.editor.revealLineInCenterIfOutsideViewport(lineNumber, ScrollType.Smooth); + } } @editorAction From 2ce576d8a1c4c660e54f7dcc675811901e2a9ed2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2017 15:38:36 +0200 Subject: [PATCH 268/303] fix tests --- .../extensions/test/electron-browser/extensionsActions.test.ts | 2 +- .../test/electron-browser/extensionsWorkbenchService.test.ts | 2 +- .../services/keybinding/test/node/keybindingEditing.test.ts | 1 + .../test/electron-browser/api/mainThreadConfiguration.test.ts | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts index 405be3a135f..17f180eedc1 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts @@ -53,7 +53,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); - instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, getConfiguration: () => ({}) }); + instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}) }); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 3cfe083cd16..2fad5c275f0 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -56,7 +56,7 @@ suite('ExtensionsWorkbenchService Test', () => { instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); - instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, getConfiguration: () => ({}) }); + instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}) }); instantiationService.stub(IExtensionManagementService, ExtensionManagementService); instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); diff --git a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts index 9ee62bfdc44..6f003bde491 100644 --- a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts @@ -67,6 +67,7 @@ suite('Keybindings Editing', () => { instantiationService.stub(IConfigurationService, ConfigurationService); instantiationService.stub(IConfigurationService, 'getConfiguration', { 'eol': '\n' }); instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); + instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { }); instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(ILifecycleService, new TestLifecycleService()); instantiationService.stub(IEditorGroupService, new TestEditorGroupService()); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts index 5cd09140d48..b91637eeeae 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts @@ -50,6 +50,7 @@ suite('MainThreadConfiguration', function () { instantiationService = new TestInstantiationService(); instantiationService.stub(IConfigurationService, WorkspaceService); instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', sinon.mock()); + instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', sinon.mock()); instantiationService.stub(IConfigurationService, 'updateValue', target); }); From fcd266b58670db7e13c24c53ee3755ee46298871 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Tue, 17 Oct 2017 16:15:37 +0200 Subject: [PATCH 269/303] Log 0 for count telementries not undefined --- src/vs/workbench/electron-browser/shell.ts | 6 +++--- .../workbench/services/telemetry/common/workspaceStats.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index c5eb4b88f20..0430727fa3e 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -225,9 +225,9 @@ export class WorkbenchShell { userAgent: navigator.userAgent, windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY, - 'workbench.filesToOpen': filesToOpen && filesToOpen.length || void 0, - 'workbench.filesToCreate': filesToCreate && filesToCreate.length || void 0, - 'workbench.filesToDiff': filesToDiff && filesToDiff.length || void 0, + 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, + 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, + 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, customKeybindingsCount: info.customKeybindingsCount, theme: this.themeService.getColorTheme().id, language: platform.language, diff --git a/src/vs/workbench/services/telemetry/common/workspaceStats.ts b/src/vs/workbench/services/telemetry/common/workspaceStats.ts index 5bdecfc2d37..9275928cd44 100644 --- a/src/vs/workbench/services/telemetry/common/workspaceStats.ts +++ b/src/vs/workbench/services/telemetry/common/workspaceStats.ts @@ -176,9 +176,9 @@ export class WorkspaceStats { const tags: Tags = Object.create(null); const { filesToOpen, filesToCreate, filesToDiff } = configuration; - tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || undefined; - tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || undefined; - tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || undefined; + tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || 0; + tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || 0; + tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0; const isEmpty = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY; const workspace = this.contextService.getWorkspace(); From 281bfeb0781cc8709d88403d98f6efaa6d43c48c Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Oct 2017 16:19:39 +0200 Subject: [PATCH 270/303] activityService: move pin methods to composite bar --- .../parts/activitybar/activitybarActions.ts | 26 --------- .../parts/activitybar/activitybarPart.ts | 23 ++------ .../parts/compositebar/compositeBar.ts | 6 +-- .../parts/compositebar/compositeBarActions.ts | 54 +++++++++++++++++-- .../activity/common/activityBarService.ts | 20 ------- 5 files changed, 57 insertions(+), 72 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 20c50332d10..2b03a25ffec 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -6,11 +6,9 @@ 'use strict'; import 'vs/css!./media/activityaction'; -import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; -import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; @@ -85,30 +83,6 @@ export class ToggleViewletAction extends Action { } } -export class ToggleViewletPinnedAction extends Action { - - constructor( - private activity: IActivity, - @IActivityBarService private activityBarService: IActivityBarService - ) { - super('activitybar.show.toggleViewletPinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned")); - - this.checked = this.activity && this.activityBarService.isPinned(this.activity.id); - } - - public run(context: string): TPromise { - const id = this.activity ? this.activity.id : context; - - if (this.activityBarService.isPinned(id)) { - this.activityBarService.unpin(id); - } else { - this.activityBarService.pin(id); - } - - return TPromise.as(true); - } -} - export class GlobalActivityAction extends ActivityAction { constructor(activity: IGlobalActivity) { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 72b3f6e451a..fea8ca6ef32 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -15,7 +15,7 @@ import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/act import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; import { Part } from 'vs/workbench/browser/part'; -import { ToggleViewletPinnedAction, GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService'; @@ -30,6 +30,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar'; +import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; export class ActivitybarPart extends Part implements IActivityBarService { @@ -66,7 +67,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { getCompositeSize: (compositeId: string) => ActivitybarPart.ACTIVITY_ACTION_HEIGHT, openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)), - getCompositePinnedAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletPinnedAction, this.viewletService.getViewlet(compositeId)), + getCompositePinnedAction: (compositeId: string) => new ToggleCompositePinnedAction(this.viewletService.getViewlet(compositeId), this.compositeBar), getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, this.viewletService.getViewlet(compositeId)), getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(), hidePart: () => this.partService.setSideBarHidden(true) @@ -142,7 +143,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private showContextMenu(e: MouseEvent): void { const event = new StandardMouseEvent(e); - const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleViewletPinnedAction, viewlet)); + const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleCompositePinnedAction, viewlet, this.compositeBar)); actions.push(new Separator()); actions.push(this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar"))); @@ -177,22 +178,6 @@ export class ActivitybarPart extends Part implements IActivityBarService { return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id));; } - public unpin(viewletId: string): void { - this.compositeBar.unpin(viewletId); - } - - public isPinned(viewletId: string): boolean { - return this.compositeBar.isPinned(viewletId); - } - - public pin(viewletId: string, update = true): void { - this.compositeBar.pin(viewletId, update); - } - - public move(viewletId: string, toViewletId: string): void { - this.compositeBar.move(viewletId, toViewletId); - } - /** * Layout title, content and status area in the given dimension. */ diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index 12c90a5638a..04db733600d 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -17,7 +17,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import Event, { Emitter } from 'vs/base/common/event'; -import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; import { TPromise } from 'vs/base/common/winjs.base'; export interface ICompositeBarOptions { @@ -34,7 +34,7 @@ export interface ICompositeBarOptions { hidePart: () => TPromise; } -export class CompositeBar { +export class CompositeBar implements ICompositeBar { private _onDidContextMenu: Emitter; @@ -312,7 +312,7 @@ export class CompositeBar { private toAction(compositeId: string): ActivityAction { const compositeActivityAction = this.options.getActivityAction(compositeId); const pinnedAction = this.options.getCompositePinnedAction(compositeId); - this.compositeIdToActionItems[compositeId] = this.instantiationService.createInstance(CompositeActionItem, compositeActivityAction, pinnedAction); + this.compositeIdToActionItems[compositeId] = this.instantiationService.createInstance(CompositeActionItem, compositeActivityAction, pinnedAction, this); this.compositeIdToActions[compositeId] = compositeActivityAction; return compositeActivityAction; diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts index 184dd5ae36e..617c17f714d 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts @@ -15,7 +15,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { dispose } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; -import { IActivityBarService, TextBadge, NumberBadge, IBadge, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { TextBadge, NumberBadge, IBadge, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; @@ -29,6 +29,28 @@ export interface ICompositeActivity { clazz: string; } +export interface ICompositeBar { + /** + * Unpins a viewlet from the activitybar. + */ + unpin(viewletId: string): void; + + /** + * Pin a viewlet inside the activity bar. + */ + pin(viewletId: string): void; + + /** + * Find out if a viewlet is pinned in the activity bar. + */ + isPinned(viewletId: string): boolean; + + /** + * Reorder viewlet ordering by moving a viewlet to the location of another viewlet. + */ + move(viewletId: string, toViewletId: string): void; +} + export class ActivityAction extends Action { private badge: IBadge; private _onDidChangeBadge = new Emitter(); @@ -342,8 +364,8 @@ export class CompositeActionItem extends ActivityActionItem { constructor( private compositeActivityAction: ActivityAction, private toggleCompositePinnedAction: Action, + private compositeBar: ICompositeBar, @IContextMenuService private contextMenuService: IContextMenuService, - @IActivityBarService private activityBarService: IActivityBarService, @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService instantiationService: IInstantiationService, @IThemeService themeService: IThemeService @@ -448,7 +470,7 @@ export class CompositeActionItem extends ActivityActionItem { this.updateFromDragging(container, false); CompositeActionItem.clearDraggedComposite(); - this.activityBarService.move(draggedCompositeId, this.activity.id); + this.compositeBar.move(draggedCompositeId, this.activity.id); } }); @@ -488,7 +510,7 @@ export class CompositeActionItem extends ActivityActionItem { actions.push(CompositeActionItem.manageExtensionAction); } - const isPinned = this.activityBarService.isPinned(this.activity.id); + const isPinned = this.compositeBar.isPinned(this.activity.id); if (isPinned) { this.toggleCompositePinnedAction.label = nls.localize('removeFromActivityBar', "Hide from Activity Bar"); this.toggleCompositePinnedAction.checked = false; @@ -540,3 +562,27 @@ export class CompositeActionItem extends ActivityActionItem { this.$label.destroy(); } } + +export class ToggleCompositePinnedAction extends Action { + + constructor( + private activity: IActivity, + private compositeBar: ICompositeBar + ) { + super('activitybar.show.toggleViewletPinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned")); + + this.checked = this.activity && this.compositeBar.isPinned(this.activity.id); + } + + public run(context: string): TPromise { + const id = this.activity ? this.activity.id : context; + + if (this.compositeBar.isPinned(id)) { + this.compositeBar.unpin(id); + } else { + this.compositeBar.pin(id); + } + + return TPromise.as(true); + } +} diff --git a/src/vs/workbench/services/activity/common/activityBarService.ts b/src/vs/workbench/services/activity/common/activityBarService.ts index 35732c5c1c4..2d7d55ce74b 100644 --- a/src/vs/workbench/services/activity/common/activityBarService.ts +++ b/src/vs/workbench/services/activity/common/activityBarService.ts @@ -67,24 +67,4 @@ export interface IActivityBarService { * Show activity in the activitybar for the given viewlet or global action. */ showActivity(viewletOrActionId: string, badge: IBadge, clazz?: string): IDisposable; - - /** - * Unpins a viewlet from the activitybar. - */ - unpin(viewletId: string): void; - - /** - * Pin a viewlet inside the activity bar. - */ - pin(viewletId: string): void; - - /** - * Find out if a viewlet is pinned in the activity bar. - */ - isPinned(viewletId: string): boolean; - - /** - * Reorder viewlet ordering by moving a viewlet to the location of another viewlet. - */ - move(viewletId: string, toViewletId: string): void; } From 5b90c9f13ccb0ed97e5caf43ab5b120cf1e93c6c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2017 16:25:22 +0200 Subject: [PATCH 271/303] electron 1.7.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2133570b711..417c30f2a2a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.18.0", - "electronVersion": "1.7.7", + "electronVersion": "1.7.9", "distro": "59a68f7780bb6571a1460ea00ca7b994126baeda", "author": { "name": "Microsoft Corporation" From 68797abd3146c005e90d3aa111d9cec4cb87a237 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Oct 2017 16:44:42 +0200 Subject: [PATCH 272/303] fix activity bar context menu --- .../browser/parts/activitybar/activitybarPart.ts | 2 +- .../browser/parts/compositebar/compositeBar.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index fea8ca6ef32..49b1cb6a684 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -113,7 +113,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.compositeBar.create($('.viewlets').appendTo($result).getHTMLElement()); + this.compositeBar.create($result.getHTMLElement()); // Top Actionbar with action items for each viewlet action this.createGlobalActivityActionBar($('.global-activity').appendTo($result).getHTMLElement()); diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index 04db733600d..74ea9884843 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -152,9 +152,9 @@ export class CompositeBar implements ICompositeBar { } } - public create(container: HTMLElement): void { - dom.addClass(container, 'composite-bar'); - this.compositeSwitcherBar = new ActionBar(container, { + public create(parent: HTMLElement): void { + const actionBarDiv = parent.appendChild(dom.$('composite-bar')); + this.compositeSwitcherBar = new ActionBar(actionBarDiv, { actionItemProvider: (action: Action) => action instanceof CompositeOverflowActivityAction ? this.compositeOverflowActionItem : this.compositeIdToActionItems[action.id], orientation: this.options.orientation, ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), @@ -163,13 +163,13 @@ export class CompositeBar implements ICompositeBar { this.updateCompositeSwitcher(); // Contextmenu for composites - this.toDispose.push(dom.addDisposableListener(container, dom.EventType.CONTEXT_MENU, (e: MouseEvent) => { + this.toDispose.push(dom.addDisposableListener(parent, dom.EventType.CONTEXT_MENU, (e: MouseEvent) => { dom.EventHelper.stop(e, true); this._onDidContextMenu.fire(e); })); // Allow to drop at the end to move composites to the end - this.toDispose.push(dom.addDisposableListener(container, dom.EventType.DROP, (e: DragEvent) => { + this.toDispose.push(dom.addDisposableListener(parent, dom.EventType.DROP, (e: DragEvent) => { const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); if (draggedCompositeId) { dom.EventHelper.stop(e, true); From d5880b1a5948b3bffd40f932dfb63ec8a4be58f9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 Oct 2017 17:19:24 +0200 Subject: [PATCH 273/303] deco - decorate ignored files --- extensions/git/src/decorationProvider.ts | 56 ++++++++++++++++++- extensions/git/src/repository.ts | 36 ++++++++++++ .../decorations/browser/decorationsService.ts | 7 ++- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index ed4bad8aef0..7adbb51003d 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -8,6 +8,57 @@ import { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider } from 'vscode'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; +import { debounce } from './decorators'; + +class GitIgnoreDecorationProvider implements DecorationProvider { + + private readonly _onDidChangeDecorations = new EventEmitter(); + readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; + + private checkIgnoreQueue = new Map void, reject: (err: any) => void }>(); + private disposables: Disposable[] = []; + + constructor(private repository: Repository) { + this.disposables.push( + window.registerDecorationProvider(this, '.gitignore') + //todo@joh -> events when the ignore status actually changes, not when the file changes + ); + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + this.checkIgnoreQueue.clear(); + } + + provideDecoration(uri: Uri): Promise { + return new Promise((resolve, reject) => { + this.checkIgnoreQueue.set(uri.fsPath, { resolve, reject }); + this.checkIgnoreSoon(); + }).then(ignored => { + if (ignored) { + return { + priority: 3, + opacity: 0.75 + }; + } + }); + } + + @debounce(500) + private checkIgnoreSoon(): void { + const queue = new Map(this.checkIgnoreQueue.entries()); + this.checkIgnoreQueue.clear(); + this.repository.checkIgnore([...queue.keys()]).then(ignoreSet => { + for (const [key, value] of queue.entries()) { + value.resolve(ignoreSet.has(key)); + } + }, err => { + for (const [, value] of queue.entries()) { + value.reject(err); + } + }); + } +} class GitDecorationProvider implements DecorationProvider { @@ -65,7 +116,7 @@ class GitDecorationProvider implements DecorationProvider { export class GitDecorations { private disposables: Disposable[] = []; - private providers = new Map(); + private providers = new Map(); constructor(private model: Model) { this.disposables.push( @@ -77,7 +128,8 @@ export class GitDecorations { private onDidOpenRepository(repository: Repository): void { const provider = new GitDecorationProvider(repository); - this.providers.set(repository, provider); + const ignoreProvider = new GitIgnoreDecorationProvider(repository); + this.providers.set(repository, Disposable.from(provider, ignoreProvider)); } private onDidCloseRepository(repository: Repository): void { diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 319edc3a07e..74cd6c48bfd 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -646,6 +646,42 @@ export class Repository implements Disposable { }); } + checkIgnore(filePaths: string[]): Promise> { + return this.run(Operation.Ignore, () => { + return new Promise>((resolve, reject) => { + + const child = this.repository.stream(['check-ignore', ...filePaths]); + + const onExit = exitCode => { + if (exitCode === 1) { + // nothing ignored + resolve(new Set()); + } else if (exitCode === 0) { + // each line is something ignored + resolve(new Set(data.split('\n'))); + } else { + reject(); + } + }; + + let data = ''; + const onStdoutData = (raw: string) => { + data += raw; + }; + + child.stdout.setEncoding('utf8'); + child.stdout.on('data', onStdoutData); + + // const stderrData: string[] = []; + // child.stderr.setEncoding('utf8'); + // child.stderr.on('data', raw => stderrData.push(raw as string)); + + child.on('error', reject); + child.on('exit', onExit); + }); + }); + } + private async run(operation: Operation, runOperation: () => Promise = () => Promise.resolve(null)): Promise { if (this.state !== RepositoryState.Idle) { throw new Error('Repository not initialized'); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index ddbf12c6133..a6320b0fe65 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -249,15 +249,16 @@ class DecorationProviderWrapper { return; } - if (item === undefined && !includeChildren) { - // unknown, a leaf node -> trigger request + if (item === undefined) { + // unknown -> trigger request item = this._fetchData(uri); } if (item) { - // leaf node + // found something callback(item, false); } + if (includeChildren) { // (resolved) children const childTree = this.data.findSuperstr(key); From 12f9753dc4b516595f740e9ed170af8be3e772b7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2017 17:42:39 +0200 Subject: [PATCH 274/303] force a change --- src/typings/electron.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 75bf1761b46..e9530251310 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 1.7.7 +// Type definitions for Electron 1.7.9 // Project: http://electron.atom.io/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions From 9dc080f80b943a1cd3df6432c6b16ad885bfa7aa Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2017 11:08:08 -0700 Subject: [PATCH 275/303] Change "Remove" to "Dismiss" - fix #36440 --- src/vs/workbench/parts/search/browser/searchActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 8c65a7a44b1..e50b636779e 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -507,7 +507,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { export class RemoveAction extends AbstractSearchAndReplaceAction { constructor(private viewer: ITree, private element: RenderableMatch) { - super('remove', nls.localize('RemoveAction.label', "Remove"), 'action-remove'); + super('remove', nls.localize('RemoveAction.label', "Dismiss"), 'action-remove'); } public run(): TPromise { From f6ab9915c7c7a27a456cb386aa355b8d835db4b7 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 17 Oct 2017 12:50:12 -0700 Subject: [PATCH 276/303] Configure for 1.17.2 --- .github/new_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/new_release.yml b/.github/new_release.yml index 1a0465c011d..902078aa79c 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', - newReleases: ['1.17.1'], + newReleases: ['1.17.2'], perform: true } \ No newline at end of file From 4d09bef3c510bb23800de1b6d2ee5ad4e42e4a0c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 17 Oct 2017 12:53:09 -0700 Subject: [PATCH 277/303] Update coffeescript grammar Fixes #36422 --- .../syntaxes/coffeescript.tmLanguage.json | 154 ++++++++++++++---- 1 file changed, 118 insertions(+), 36 deletions(-) diff --git a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json index 86441c11dd8..68e1bc4e83b 100644 --- a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json +++ b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-coffee-script/commit/da81e3f537ccbbb70e542fa5af79583eb58ec50b", + "version": "https://github.com/atom/language-coffee-script/commit/8873cbc4e2f3b790603cbe7102d60f41fc82f726", "scopeName": "source.coffee", "name": "CoffeeScript", "fileTypes": [ @@ -535,13 +535,13 @@ "arguments": { "patterns": [ { - "begin": "(?=(@|@?[\\w$]+|[=-]>|\\-\\d|\\[|{|\"|'))|\\(", + "begin": "\\(", "beginCaptures": { "0": { "name": "punctuation.definition.arguments.begin.bracket.round.coffee" } }, - "end": "\\)|(?=\\s*(?|\\-\\d|\\[|{|\"|'))", + "end": "(?=\\s*(?|\\-\\d|\\[|\\{|\"|'))|(?=\\())", + "begin": "(@)?([\\w$]+)(?=\\()", "beginCaptures": { "1": { "name": "variable.other.readwrite.instance.coffee" @@ -600,27 +610,56 @@ "2": { "patterns": [ { - "match": "(?x)\n\\b(isNaN|isFinite|eval|uneval|parseInt|parseFloat|decodeURI|\ndecodeURIComponent|encodeURI|encodeURIComponent|escape|unescape|\nrequire|set(Interval|Timeout)|clear(Interval|Timeout))\\b", - "name": "support.function.coffee" - }, - { - "match": "[a-zA-Z_$][\\w$]*", - "name": "entity.name.function.coffee" - }, - { - "match": "\\d[\\w$]*", - "name": "invalid.illegal.identifier.coffee" + "include": "#function_names" } ] } }, - "end": "(?<=\\))|(?=\\s*(?|\\-\\d|\\[|{|\"|')))", + "beginCaptures": { + "1": { + "name": "variable.other.readwrite.instance.coffee" + }, + "2": { + "patterns": [ + { + "include": "#function_names" + } + ] + } + }, + "end": "(?=\\s*(?|\\-\\d|\\[|\\{|\"|'))|(?=\\())", + "begin": "(?:(\\.)|(::))\\s*([\\w$]+)\\s*(?=\\()", "beginCaptures": { "1": { "name": "punctuation.separator.method.period.coffee" @@ -724,35 +763,67 @@ "3": { "patterns": [ { - "match": "(?x)\n\\bon(Rowsinserted|Rowsdelete|Rowenter|Rowexit|Resize|Resizestart|Resizeend|Reset|\nReadystatechange|Mouseout|Mouseover|Mousedown|Mouseup|Mousemove|\nBefore(cut|deactivate|unload|update|paste|print|editfocus|activate)|\nBlur|Scrolltop|Submit|Select|Selectstart|Selectionchange|Hover|Help|\nChange|Contextmenu|Controlselect|Cut|Cellchange|Clock|Close|Deactivate|\nDatasetchanged|Datasetcomplete|Dataavailable|Drop|Drag|Dragstart|Dragover|\nDragdrop|Dragenter|Dragend|Dragleave|Dblclick|Unload|Paste|Propertychange|Error|\nErrorupdate|Keydown|Keyup|Keypress|Focus|Load|Activate|Afterupdate|Afterprint|Abort)\\b", - "name": "support.function.event-handler.coffee" - }, - { - "match": "(?x)\n\\b(shift|showModelessDialog|showModalDialog|showHelp|scroll|scrollX|scrollByPages|\nscrollByLines|scrollY|scrollTo|stop|strike|sizeToContent|sidebar|signText|sort|\nsup|sub|substr|substring|splice|split|send|set(Milliseconds|Seconds|Minutes|Hours|\nMonth|Year|FullYear|Date|UTC(Milliseconds|Seconds|Minutes|Hours|Month|FullYear|Date)|\nTime|Hotkeys|Cursor|ZOptions|Active|Resizable|RequestHeader)|search|slice|\nsavePreferences|small|home|handleEvent|navigate|char|charCodeAt|charAt|concat|\ncontextual|confirm|compile|clear|captureEvents|call|createStyleSheet|createPopup|\ncreateEventObject|to(GMTString|UTCString|String|Source|UpperCase|LowerCase|LocaleString)|\ntest|taint|taintEnabled|indexOf|italics|disableExternalCapture|dump|detachEvent|unshift|\nuntaint|unwatch|updateCommands|join|javaEnabled|pop|push|plugins.refresh|paddings|parse|\nprint|prompt|preference|enableExternalCapture|exec|execScript|valueOf|UTC|find|file|\nfileModifiedDate|fileSize|fileCreatedDate|fileUpdatedDate|fixed|fontsize|fontcolor|\nforward|fromCharCode|watch|link|load|lastIndexOf|anchor|attachEvent|atob|apply|alert|\nabort|routeEvents|resize|resizeBy|resizeTo|recalc|returnValue|replace|reverse|reload|\nreleaseCapture|releaseEvents|go|get(Milliseconds|Seconds|Minutes|Hours|Month|Day|Year|FullYear|\nTime|Date|TimezoneOffset|UTC(Milliseconds|Seconds|Minutes|Hours|Day|Month|FullYear|Date)|\nAttention|Selection|ResponseHeader|AllResponseHeaders)|moveBy|moveBelow|moveTo|\nmoveToAbsolute|moveAbove|mergeAttributes|match|margins|btoa|big|bold|borderWidths|blink|back)\\b", - "name": "support.function.coffee" - }, - { - "match": "(?x)\n\\b(acceptNode|add|addEventListener|addTextTrack|adoptNode|after|animate|append|\nappendChild|appendData|before|blur|canPlayType|captureStream|\ncaretPositionFromPoint|caretRangeFromPoint|checkValidity|clear|click|\ncloneContents|cloneNode|cloneRange|close|closest|collapse|\ncompareBoundaryPoints|compareDocumentPosition|comparePoint|contains|\nconvertPointFromNode|convertQuadFromNode|convertRectFromNode|createAttribute|\ncreateAttributeNS|createCaption|createCDATASection|createComment|\ncreateContextualFragment|createDocument|createDocumentFragment|\ncreateDocumentType|createElement|createElementNS|createEntityReference|\ncreateEvent|createExpression|createHTMLDocument|createNodeIterator|\ncreateNSResolver|createProcessingInstruction|createRange|createShadowRoot|\ncreateTBody|createTextNode|createTFoot|createTHead|createTreeWalker|delete|\ndeleteCaption|deleteCell|deleteContents|deleteData|deleteRow|deleteTFoot|\ndeleteTHead|detach|disconnect|dispatchEvent|elementFromPoint|elementsFromPoint|\nenableStyleSheetsForSet|entries|evaluate|execCommand|exitFullscreen|\nexitPointerLock|expand|extractContents|fastSeek|firstChild|focus|forEach|get|\ngetAll|getAnimations|getAttribute|getAttributeNames|getAttributeNode|\ngetAttributeNodeNS|getAttributeNS|getBoundingClientRect|getBoxQuads|\ngetClientRects|getContext|getDestinationInsertionPoints|getElementById|\ngetElementsByClassName|getElementsByName|getElementsByTagName|\ngetElementsByTagNameNS|getItem|getNamedItem|getSelection|getStartDate|\ngetVideoPlaybackQuality|has|hasAttribute|hasAttributeNS|hasAttributes|\nhasChildNodes|hasFeature|hasFocus|importNode|initEvent|insertAdjacentElement|\ninsertAdjacentHTML|insertAdjacentText|insertBefore|insertCell|insertData|\ninsertNode|insertRow|intersectsNode|isDefaultNamespace|isEqualNode|\nisPointInRange|isSameNode|item|key|keys|lastChild|load|lookupNamespaceURI|\nlookupPrefix|matches|move|moveAttribute|moveAttributeNode|moveChild|\nmoveNamedItem|namedItem|nextNode|nextSibling|normalize|observe|open|\nparentNode|pause|play|postMessage|prepend|preventDefault|previousNode|\npreviousSibling|probablySupportsContext|queryCommandEnabled|\nqueryCommandIndeterm|queryCommandState|queryCommandSupported|queryCommandValue|\nquerySelector|querySelectorAll|registerContentHandler|registerElement|\nregisterProtocolHandler|releaseCapture|releaseEvents|remove|removeAttribute|\nremoveAttributeNode|removeAttributeNS|removeChild|removeEventListener|\nremoveItem|replace|replaceChild|replaceData|replaceWith|reportValidity|\nrequestFullscreen|requestPointerLock|reset|scroll|scrollBy|scrollIntoView|\nscrollTo|seekToNextFrame|select|selectNode|selectNodeContents|set|setAttribute|\nsetAttributeNode|setAttributeNodeNS|setAttributeNS|setCapture|\nsetCustomValidity|setEnd|setEndAfter|setEndBefore|setItem|setNamedItem|\nsetRangeText|setSelectionRange|setSinkId|setStart|setStartAfter|setStartBefore|\nslice|splitText|stepDown|stepUp|stopImmediatePropagation|stopPropagation|\nsubmit|substringData|supports|surroundContents|takeRecords|terminate|toBlob|\ntoDataURL|toggle|toString|values|write|writeln)\\b", - "name": "support.function.dom.coffee" - }, - { - "match": "[a-zA-Z_$][\\w$]*", - "name": "entity.name.function.coffee" - }, - { - "match": "\\d[\\w$]*", - "name": "invalid.illegal.identifier.coffee" + "include": "#method_names" } ] } }, - "end": "(?<=\\))|(?=\\s*(?|\\-\\d|\\[|{|\"|')))", + "beginCaptures": { + "1": { + "name": "punctuation.separator.method.period.coffee" + }, + "2": { + "name": "keyword.operator.prototype.coffee" + }, + "3": { + "patterns": [ + { + "include": "#method_names" + } + ] + } + }, + "end": "(?=\\s*(? Date: Tue, 17 Oct 2017 16:00:03 -0700 Subject: [PATCH 278/303] Add "code" to copied marker metadata info Fixes #36449 --- .../workbench/parts/markers/common/markersModel.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/markers/common/markersModel.ts b/src/vs/workbench/parts/markers/common/markersModel.ts index 561705c5a60..735d45e845b 100644 --- a/src/vs/workbench/parts/markers/common/markersModel.ts +++ b/src/vs/workbench/parts/markers/common/markersModel.ts @@ -58,11 +58,14 @@ export class Marker { } public toString(): string { - return [`file: '${this.marker.resource}'`, - `severity: '${Severity.toString(this.marker.severity)}'`, - `message: '${this.marker.message}'`, - `at: '${this.marker.startLineNumber},${this.marker.startColumn}'`, - `source: '${this.marker.source ? this.marker.source : ''}'`].join('\n'); + return [ + `file: '${this.marker.resource}'`, + `severity: '${Severity.toString(this.marker.severity)}'`, + `message: '${this.marker.message}'`, + `at: '${this.marker.startLineNumber},${this.marker.startColumn}'`, + `source: '${this.marker.source ? this.marker.source : ''}'`, + `code: '${this.marker.code ? this.marker.code : ''}'` + ].join('\n'); } } From c5bf0096b44d7ae8b5220ec1dcf342525850dcf1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 17 Oct 2017 16:12:11 -0700 Subject: [PATCH 279/303] Allow term workspace selector command to work when no folder is opened Fixes #36392 --- .../parts/terminal/electron-browser/terminalActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index 7bb15300f3a..13ad6995359 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -233,7 +233,7 @@ export class CreateNewSelectWorkspaceTerminalAction extends Action { public run(event?: any): TPromise { return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { - const instance = this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true); + const instance = this.terminalService.createInstance(workspace ? { cwd: workspace.uri.fsPath } : undefined, true); if (!instance) { return TPromise.as(void 0); } From 1ff751a12b8a1646ac19375126e106a3df4df8cc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 17 Oct 2017 22:14:53 -0700 Subject: [PATCH 280/303] Fix marker test for toString --- .../parts/markers/test/common/markersModel.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts index 450eb2d2ff9..eacdf1fcc13 100644 --- a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts +++ b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts @@ -121,10 +121,12 @@ suite('MarkersModel Test', () => { }); test('toString()', function () { - assert.equal(`file: 'file:///a/res1'\nseverity: 'Error'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res1')).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: 'Warning'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res2', Severity.Warning)).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: 'Info'\nmessage: 'Info'\nat: '1,2'\nsource: ''`, new Marker('', aMarker('a/res2', Severity.Info, 1, 2, 1, 8, 'Info', '')).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: ''\nmessage: 'Ignore message'\nat: '1,2'\nsource: 'Ignore'`, new Marker('', aMarker('a/res2', Severity.Ignore, 1, 2, 1, 8, 'Ignore message', 'Ignore')).toString()); + const res1Marker = aMarker('a/res1'); + res1Marker.code = '1234'; + assert.equal(`file: 'file:///a/res1'\nseverity: 'Error'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'\ncode: '1234'`, new Marker('', res1Marker).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Warning'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Warning)).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Info'\nmessage: 'Info'\nat: '1,2'\nsource: ''\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Info, 1, 2, 1, 8, 'Info', '')).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: ''\nmessage: 'Ignore message'\nat: '1,2'\nsource: 'Ignore'\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Ignore, 1, 2, 1, 8, 'Ignore message', 'Ignore')).toString()); }); function hasMarker(markers: Marker[], marker: IMarker): boolean { From 2cbaa8c7d5a0e808362b5a1cd6b8f0919b5d49cd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 17 Oct 2017 22:32:27 -0700 Subject: [PATCH 281/303] Pick up TS 2.6.1-insiders.20171016 --- extensions/npm-shrinkwrap.json | 6 +++--- extensions/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/npm-shrinkwrap.json b/extensions/npm-shrinkwrap.json index 3a586ecad98..6241de07cd9 100644 --- a/extensions/npm-shrinkwrap.json +++ b/extensions/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "0.0.1", "dependencies": { "typescript": { - "version": "2.6.0-insiders.20171013", - "from": "typescript@2.6.0-insiders.20171013", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.0-insiders.20171013.tgz" + "version": "2.6.1-insiders.20171016", + "from": "typescript@2.6.1-insiders.20171016", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.1-insiders.20171016.tgz" } } } diff --git a/extensions/package.json b/extensions/package.json index ce960b5b23b..bcf3e8b0dc8 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "2.6.0-insiders.20171013" + "typescript": "2.6.1-insiders.20171016" }, "scripts": { "postinstall": "node ./postinstall" From 64992dee5cfd22c2533c04f24ccea2f3906b15bc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2017 20:44:07 +0200 Subject: [PATCH 282/303] Adopt menus using new configuration change event --- src/vs/code/electron-main/menus.ts | 148 +++++++++++------------------ 1 file changed, 58 insertions(+), 90 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 68af45f2186..df337ac6675 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -11,8 +11,8 @@ import * as arrays from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem, BrowserWindow } from 'electron'; import { OpenContext, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { AutoSaveConfiguration } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IUpdateService, State as UpdateState } from 'vs/platform/update/common/update'; import product from 'vs/platform/node/product'; @@ -29,27 +29,6 @@ interface IExtensionViewlet { label: string; } -interface IConfiguration extends IFilesConfiguration { - window: { - enableMenuBarMnemonics: boolean; - nativeTabs: boolean; - }; - workbench: { - sideBar: { - location: 'left' | 'right'; - }, - statusBar: { - visible: boolean; - }, - activityBar: { - visible: boolean; - } - }; - editor: { - multiCursorModifier: 'ctrlCmd' | 'alt' - }; -} - interface IMenuItemClickHandler { inDevTools: (contents: Electron.WebContents) => void; inNoWindow: () => void; @@ -61,13 +40,15 @@ export class CodeMenu { private static MAX_MENU_RECENT_ENTRIES = 10; - private currentAutoSaveSetting: string; - private currentMultiCursorModifierSetting: string; - private currentSidebarLocation: 'left' | 'right'; - private currentStatusbarVisible: boolean; - private currentActivityBarVisible: boolean; - private currentEnableMenuBarMnemonics: boolean; - private currentEnableNativeTabs: boolean; + private keys = [ + 'files.autoSave', + 'editor.multiCursorModifier', + 'workbench.sideBar.location', + 'workbench.statusBar.visible', + 'workbench.activityBar.visible', + 'window.enableMenuBarMnemonics', + 'window.nativeTabs' + ]; private isQuitting: boolean; private appMenuInstalled: boolean; @@ -99,8 +80,6 @@ export class CodeMenu { this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); this.keybindingsResolver = instantiationService.createInstance(KeybindingsResolver); - this.onConfigurationUpdated(this.configurationService.getConfiguration()); - this.install(); this.registerListeners(); @@ -136,7 +115,7 @@ export class CodeMenu { }); // Update when auto save config changes - this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true /* update menu if changed */)); + this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)); // Listen to update service this.updateService.onStateChange(() => this.updateMenu()); @@ -145,67 +124,56 @@ export class CodeMenu { this.keybindingsResolver.onKeybindingsChanged(() => this.updateMenu()); } - private onConfigurationUpdated(config: IConfiguration, handleMenu?: boolean): void { - let updateMenu = false; - const newAutoSaveSetting = config && config.files && config.files.autoSave; - if (newAutoSaveSetting !== this.currentAutoSaveSetting) { - this.currentAutoSaveSetting = newAutoSaveSetting; - updateMenu = true; - } - - const newMultiCursorModifierSetting = config && config.editor && config.editor.multiCursorModifier; - if (newMultiCursorModifierSetting !== this.currentMultiCursorModifierSetting) { - this.currentMultiCursorModifierSetting = newMultiCursorModifierSetting; - updateMenu = true; - } - - const newSidebarLocation = config && config.workbench && config.workbench.sideBar && config.workbench.sideBar.location || 'left'; - if (newSidebarLocation !== this.currentSidebarLocation) { - this.currentSidebarLocation = newSidebarLocation; - updateMenu = true; - } - - let newStatusbarVisible = config && config.workbench && config.workbench.statusBar && config.workbench.statusBar.visible; - if (typeof newStatusbarVisible !== 'boolean') { - newStatusbarVisible = true; - } - if (newStatusbarVisible !== this.currentStatusbarVisible) { - this.currentStatusbarVisible = newStatusbarVisible; - updateMenu = true; - } - - let newActivityBarVisible = config && config.workbench && config.workbench.activityBar && config.workbench.activityBar.visible; - if (typeof newActivityBarVisible !== 'boolean') { - newActivityBarVisible = true; - } - if (newActivityBarVisible !== this.currentActivityBarVisible) { - this.currentActivityBarVisible = newActivityBarVisible; - updateMenu = true; - } - - let newEnableMenuBarMnemonics = config && config.window && config.window.enableMenuBarMnemonics; - if (typeof newEnableMenuBarMnemonics !== 'boolean') { - newEnableMenuBarMnemonics = true; - } - if (newEnableMenuBarMnemonics !== this.currentEnableMenuBarMnemonics) { - this.currentEnableMenuBarMnemonics = newEnableMenuBarMnemonics; - updateMenu = true; - } - - let newEnableNativeTabs = config && config.window && config.window.nativeTabs; - if (typeof newEnableNativeTabs !== 'boolean') { - newEnableNativeTabs = false; - } - if (newEnableNativeTabs !== this.currentEnableNativeTabs) { - this.currentEnableNativeTabs = newEnableNativeTabs; - updateMenu = true; - } - - if (handleMenu && updateMenu) { + private onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (this.keys.some(key => event.affectsConfiguration(key))) { this.updateMenu(); } } + private get currentAutoSaveSetting(): string { + return this.configurationService.getValue('files.autoSave'); + } + + private get currentMultiCursorModifierSetting(): string { + return this.configurationService.getValue('editor.multiCursorModifier'); + } + + private get currentSidebarLocation(): string { + return this.configurationService.getValue('workbench.sideBar.location') || 'left'; + } + + private get currentStatusbarVisible(): boolean { + let statusbarVisible = this.configurationService.getValue('workbench.statusBar.visible'); + if (typeof statusbarVisible !== 'boolean') { + statusbarVisible = true; + } + return statusbarVisible; + } + + private get currentActivityBarVisible(): boolean { + let activityBarVisible = this.configurationService.getValue('workbench.activityBar.visible'); + if (typeof activityBarVisible !== 'boolean') { + activityBarVisible = true; + } + return activityBarVisible; + } + + private get currentEnableMenuBarMnemonics(): boolean { + let enableMenuBarMnemonics = this.configurationService.getValue('window.enableMenuBarMnemonics'); + if (typeof enableMenuBarMnemonics !== 'boolean') { + enableMenuBarMnemonics = true; + } + return enableMenuBarMnemonics; + } + + private get currentEnableNativeTabs(): boolean { + let enableNativeTabs = this.configurationService.getValue('window.nativeTabs'); + if (typeof enableNativeTabs !== 'boolean') { + enableNativeTabs = false; + } + return enableNativeTabs; + } + private updateMenu(): void { this.menuUpdater.schedule(); // buffer multiple attempts to update the menu } From 56a9f4e652440e5f19b8be8d48e5784f81c4eeb7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2017 21:20:28 +0200 Subject: [PATCH 283/303] Update context key service to listen only on config section changes --- .../platform/contextkey/browser/contextKeyService.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 39d1f8cc654..032b7f49d77 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -8,7 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { IContextKey, IContext, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context'; @@ -53,12 +53,14 @@ class ConfigAwareContextValuesContainer extends Context { private _emitter: Emitter; private _subscription: IDisposable; + private _configurationService: IConfigurationService; constructor(id: number, configurationService: IConfigurationService, emitter: Emitter) { super(id, null); this._emitter = emitter; - this._subscription = configurationService.onDidChangeConfiguration(e => this._updateConfigurationContext(configurationService.getConfiguration())); + this._configurationService = configurationService; + this._subscription = configurationService.onDidChangeConfiguration(e => this._onConfigurationUpdated(e)); this._updateConfigurationContext(configurationService.getConfiguration()); } @@ -66,6 +68,12 @@ class ConfigAwareContextValuesContainer extends Context { this._subscription.dispose(); } + private _onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration('config')) { + this._updateConfigurationContext(this._configurationService.getConfiguration()); + } + } + private _updateConfigurationContext(config: any) { // remove old config.xyz values From b65cb01b3defb19f4403f62a9fdf6ff0f8dc4174 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Oct 2017 08:39:29 +0200 Subject: [PATCH 284/303] Send the configuration change event data to Extension host --- .../configuration/common/configuration.ts | 8 +++ .../common/configurationModels.ts | 52 +++++++++++++++---- .../mainThreadConfiguration.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 4 +- .../api/node/extHostConfiguration.ts | 12 ++--- .../common/configurationModels.ts | 22 +++++++- 6 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 5f5145c0ed3..41093f27f8a 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -43,6 +43,9 @@ export interface IConfigurationChangeEvent { // Following data is used for telemetry source: ConfigurationTarget; sourceConfig: any; + + // Following data is used for Extension host configuration event + toJSON(): IConfigurationChangeEventData; } export interface IConfigurationService { @@ -103,6 +106,11 @@ export interface IConfigurationData { folders: { [folder: string]: IConfiguraionModel }; } +export interface IConfigurationChangeEventData { + changedConfiguration: IConfiguraionModel; + changedConfigurationByResource: { [folder: string]: IConfiguraionModel }; +} + export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { const added = to.keys.filter(key => from.keys.indexOf(key) === -1); const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 7bfc0852a5e..c58669e9dec 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; export class ConfigurationModel implements IConfiguraionModel { @@ -481,29 +481,46 @@ export class AbstractConfigurationChangeEvent { export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { - private changedConfiguration: ConfigurationModel = null; + private _changedConfiguration: ConfigurationModel = null; constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); } - affectsConfiguration(config: string, resource?: URI): boolean { - if (!this.changedConfiguration) { - this.changedConfiguration = new ConfigurationModel(); - this.updateKeys(this.changedConfiguration, this.affectedKeys); + get changedConfiguration(): ConfigurationModel { + if (!this._changedConfiguration) { + this._changedConfiguration = new ConfigurationModel(); + this.updateKeys(this._changedConfiguration, this.affectedKeys); } + return this._changedConfiguration; + } + + affectsConfiguration(config: string, resource?: URI): boolean { return this.doesConfigurationContains(this.changedConfiguration, config); } + toJSON(): IConfigurationChangeEventData { + return { + changedConfiguration: { + contents: this.changedConfiguration.contents, + overrides: this.changedConfiguration.overrides, + keys: this.changedConfiguration.keys + }, + changedConfigurationByResource: Object.create({}) + }; + } } export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { - private changedConfiguration: ConfigurationModel = new ConfigurationModel(); - private changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); - private resources: URI[] = []; - private _source: ConfigurationTarget; private _sourceConfig: any; + constructor( + private changedConfiguration: ConfigurationModel = new ConfigurationModel(), + private resources: URI[] = [], + private changedConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { + super(); + } + change(event: ConfigurationChangeEvent): ConfigurationChangeEvent change(keys: string[], resource?: URI): ConfigurationChangeEvent change(arg1: any, arg2?: any): ConfigurationChangeEvent { @@ -574,4 +591,19 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i } return changedConfigurationByResource; } + + toJSON(): IConfigurationChangeEventData { + return { + changedConfiguration: { + contents: this.changedConfiguration.contents, + overrides: this.changedConfiguration.overrides, + keys: this.changedConfiguration.keys + }, + changedConfigurationByResource: this.changedConfigurationByResource.keys().reduce((result, resource) => { + const { contents, overrides, keys } = this.changedConfigurationByResource.get(resource); + result[resource.toString()] = { contents, overrides, keys }; + return result; + }, Object.create({})) + }; + } } \ No newline at end of file diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index a8b5cf06253..af38672d4b8 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -27,8 +27,8 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { ) { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); - this._configurationListener = configurationService.onDidChangeConfiguration(() => { - proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); + this._configurationListener = configurationService.onDidChangeConfiguration(e => { + proxy.$acceptConfigurationChanged(configurationService.getConfigurationData(), e.toJSON()); }); } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 5de663decdf..17980ed5b35 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -28,7 +28,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ITextSource } from 'vs/editor/common/model/textSource'; -import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -418,7 +418,7 @@ export interface ExtHostCommandsShape { } export interface ExtHostConfigurationShape { - $acceptConfigurationChanged(data: IConfigurationData): void; + $acceptConfigurationChanged(data: IConfigurationData, eventData: IConfigurationChangeEventData): void; } export interface ExtHostDiagnosticsShape { diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 55677b2d360..5a8dae4f23a 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -7,11 +7,11 @@ import { mixin } from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; -import { WorkspaceConfiguration } from 'vscode'; +import * as vscode from 'vscode'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; -import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; import { Configuration } from 'vs/platform/configuration/common/configurationModels'; function lookUp(tree: any, key: string) { @@ -50,12 +50,12 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - $acceptConfigurationChanged(data: IConfigurationData) { + $acceptConfigurationChanged(data: IConfigurationData, eventData: IConfigurationChangeEventData) { this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace); this._onDidChangeConfiguration.fire(undefined); } - getConfiguration(section?: string, resource?: URI): WorkspaceConfiguration { + getConfiguration(section?: string, resource?: URI): vscode.WorkspaceConfiguration { const config = section ? lookUp(this._configuration.getSection(null, { resource }), section) : this._configuration.getSection(null, { resource }); @@ -75,7 +75,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } } - const result: WorkspaceConfiguration = { + const result: vscode.WorkspaceConfiguration = { has(key: string): boolean { return typeof lookUp(config, key) !== 'undefined'; }, @@ -115,6 +115,6 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { mixin(result, config, false); } - return Object.freeze(result); + return Object.freeze(result); } } diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 8b9e5aa53fe..3cef3209dfe 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -270,7 +270,7 @@ export class Configuration extends BaseConfiguration { export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { - constructor(private configurationChangeEvent: ConfigurationChangeEvent, private workspace: Workspace) { + constructor(private configurationChangeEvent: IConfigurationChangeEvent, private workspace: Workspace) { } get affectedKeys(): string[] { @@ -299,4 +299,22 @@ export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEv return false; } + + toJSON(): IConfigurationChangeEventData { + return this.configurationChangeEvent.toJSON(); + } + + public static parse(data: IConfigurationChangeEventData, workspace: Workspace): WorkspaceConfigurationChangeEvent { + const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides); + const resources: URI[] = []; + const changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); + for (const key of Object.keys(data.changedConfigurationByResource)) { + const resource = URI.parse(key); + const model = data.changedConfigurationByResource[key]; + resources.push(resource); + changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides)); + } + const event = new ConfigurationChangeEvent(changedConfiguration, resources, changedConfigurationByResource); + return new WorkspaceConfigurationChangeEvent(event, workspace); + } } \ No newline at end of file From 5faa72ac39f5f56ec57a6a17ee34f0ee8ff840f3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 09:03:15 +0200 Subject: [PATCH 285/303] deco - use a color for ignored files --- extensions/git/package.json | 11 ++++++++++- extensions/git/src/decorationProvider.ts | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index abb7f5400ea..a69c16b2429 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -850,6 +850,15 @@ "dark": "#73C991", "highContrast": "#73C991" } + }, + { + "id": "git.color.ignored", + "description": "Color for ignored resources", + "defaults": { + "light": "#8E8E90", + "dark": "#A7A8A9", + "highContrast": "#A7A8A9" + } } ] }, @@ -864,4 +873,4 @@ "@types/node": "7.0.43", "mocha": "^3.2.0" } -} \ No newline at end of file +} diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 7adbb51003d..5ae257473b3 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -5,7 +5,7 @@ 'use strict'; -import { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider } from 'vscode'; +import { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; import { debounce } from './decorators'; @@ -38,7 +38,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { if (ignored) { return { priority: 3, - opacity: 0.75 + color: new ThemeColor('git.color.ignored') }; } }); From 4b610b1f45b67d3d39a2a0460ea853a94750b80a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 09:17:14 +0200 Subject: [PATCH 286/303] update electron.d.ts (1.7.9) --- src/typings/electron.d.ts | 150 ++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 80 deletions(-) diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index e9530251310..ce604fb1bf0 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -37,91 +37,81 @@ declare namespace Electron { shiftKey?: boolean; altKey?: boolean; } + interface CommonInterface { - clipboard: Electron.Clipboard; - crashReporter: Electron.CrashReporter; - nativeImage: typeof Electron.NativeImage; - screen: Electron.Screen; - shell: Electron.Shell; + clipboard: Clipboard; + crashReporter: CrashReporter; + nativeImage: typeof NativeImage; + screen: Screen; + shell: Shell; } interface MainInterface extends CommonInterface { - app: Electron.App; - autoUpdater: Electron.AutoUpdater; - BrowserView: typeof Electron.BrowserView; - BrowserWindow: typeof Electron.BrowserWindow; - ClientRequest: typeof Electron.ClientRequest; - contentTracing: Electron.ContentTracing; - Cookies: typeof Electron.Cookies; - Debugger: typeof Electron.Debugger; - dialog: Electron.Dialog; - DownloadItem: typeof Electron.DownloadItem; - globalShortcut: Electron.GlobalShortcut; - IncomingMessage: typeof Electron.IncomingMessage; - ipcMain: Electron.IpcMain; - Menu: typeof Electron.Menu; - MenuItem: typeof Electron.MenuItem; - net: Electron.Net; - Notification: typeof Electron.Notification; - powerMonitor: Electron.PowerMonitor; - powerSaveBlocker: Electron.PowerSaveBlocker; - protocol: Electron.Protocol; - session: typeof Electron.Session; - systemPreferences: Electron.SystemPreferences; - TouchBar: typeof Electron.TouchBar; - Tray: typeof Electron.Tray; - webContents: typeof Electron.WebContents; - WebRequest: typeof Electron.WebRequest; + app: App; + autoUpdater: AutoUpdater; + BrowserView: typeof BrowserView; + BrowserWindow: typeof BrowserWindow; + ClientRequest: typeof ClientRequest; + contentTracing: ContentTracing; + Cookies: typeof Cookies; + Debugger: typeof Debugger; + dialog: Dialog; + DownloadItem: typeof DownloadItem; + globalShortcut: GlobalShortcut; + IncomingMessage: typeof IncomingMessage; + ipcMain: IpcMain; + Menu: typeof Menu; + MenuItem: typeof MenuItem; + net: Net; + Notification: typeof Notification; + powerMonitor: PowerMonitor; + powerSaveBlocker: PowerSaveBlocker; + protocol: Protocol; + session: typeof Session; + systemPreferences: SystemPreferences; + TouchBar: typeof TouchBar; + Tray: typeof Tray; + webContents: typeof WebContents; + WebRequest: typeof WebRequest; } interface RendererInterface extends CommonInterface { - BrowserWindowProxy: typeof Electron.BrowserWindowProxy; - desktopCapturer: Electron.DesktopCapturer; - ipcRenderer: Electron.IpcRenderer; - remote: Electron.Remote; - webFrame: Electron.WebFrame; - webviewTag: Electron.WebviewTag; + BrowserWindowProxy: typeof BrowserWindowProxy; + desktopCapturer: DesktopCapturer; + ipcRenderer: IpcRenderer; + remote: Remote; + webFrame: WebFrame; + webviewTag: WebviewTag; } - interface AllElectron { - app: Electron.App; - autoUpdater: Electron.AutoUpdater; - BrowserView: typeof Electron.BrowserView; - BrowserWindow: typeof Electron.BrowserWindow; - BrowserWindowProxy: typeof Electron.BrowserWindowProxy; - ClientRequest: typeof Electron.ClientRequest; - clipboard: Electron.Clipboard; - contentTracing: Electron.ContentTracing; - Cookies: typeof Electron.Cookies; - crashReporter: Electron.CrashReporter; - Debugger: typeof Electron.Debugger; - desktopCapturer: Electron.DesktopCapturer; - dialog: Electron.Dialog; - DownloadItem: typeof Electron.DownloadItem; - globalShortcut: Electron.GlobalShortcut; - IncomingMessage: typeof Electron.IncomingMessage; - ipcMain: Electron.IpcMain; - ipcRenderer: Electron.IpcRenderer; - Menu: typeof Electron.Menu; - MenuItem: typeof Electron.MenuItem; - nativeImage: typeof Electron.NativeImage; - net: Electron.Net; - Notification: typeof Electron.Notification; - powerMonitor: Electron.PowerMonitor; - powerSaveBlocker: Electron.PowerSaveBlocker; - protocol: Electron.Protocol; - remote: Electron.Remote; - screen: Electron.Screen; - session: typeof Electron.Session; - shell: Electron.Shell; - systemPreferences: Electron.SystemPreferences; - TouchBar: typeof Electron.TouchBar; - Tray: typeof Electron.Tray; - webContents: typeof Electron.WebContents; - webFrame: Electron.WebFrame; - WebRequest: typeof Electron.WebRequest; - webviewTag: Electron.WebviewTag; - } + interface AllElectron extends MainInterface, RendererInterface { } + + const app: App; + const autoUpdater: AutoUpdater; + const clipboard: Clipboard; + const contentTracing: ContentTracing; + const crashReporter: CrashReporter; + const desktopCapturer: DesktopCapturer; + const dialog: Dialog; + const globalShortcut: GlobalShortcut; + const ipcMain: IpcMain; + const ipcRenderer: IpcRenderer; + type nativeImage = NativeImage; + const nativeImage: typeof NativeImage; + const net: Net; + const powerMonitor: PowerMonitor; + const powerSaveBlocker: PowerSaveBlocker; + const protocol: Protocol; + const remote: Remote; + const screen: Screen; + type session = Session; + const session: typeof Session; + const shell: Shell; + const systemPreferences: SystemPreferences; + type webContents = WebContents; + const webContents: typeof WebContents; + const webFrame: WebFrame; + const webviewTag: WebviewTag; interface App extends EventEmitter { @@ -6362,7 +6352,8 @@ declare namespace Electron { ignoreSystemCrashHandler?: boolean; /** * An object you can define that will be sent along with the report. Only string - * properties are sent correctly. Nested objects are not supported. + * properties are sent correctly. Nested objects are not supported and the property + * names and values must be less than 64 characters long. */ extra?: any; /** @@ -8089,12 +8080,11 @@ declare namespace Electron { } declare module 'electron' { - const electron: Electron.AllElectron; - export = electron; + export = Electron; } interface NodeRequireFunction { - (moduleName: 'electron'): Electron.AllElectron; + (moduleName: 'electron'): typeof Electron; } interface File { From 47bd309a7bcabaff59d09593eeacb79698e5cf62 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 09:40:33 +0200 Subject: [PATCH 287/303] deco - show file decoration also in open editors sections --- .../parts/files/browser/views/openEditorsView.ts | 11 ++++++++--- .../parts/files/browser/views/openEditorsViewer.ts | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts index 541fd1adb78..301fe2a0081 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts @@ -14,7 +14,7 @@ import { IItemCollapseEvent } from 'vs/base/parts/tree/browser/treeModel'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorStacksModel, IStacksModelChangeEvent, IEditorGroup } from 'vs/workbench/common/editor'; import { SaveAllAction } from 'vs/workbench/parts/files/browser/fileActions'; @@ -183,7 +183,7 @@ export class OpenEditorsView extends ViewsViewletPanel { this.disposables.push(this.model.onModelChanged(e => this.onEditorStacksModelChanged(e))); // Also handle configuration updates - this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), e))); // Handle dirty counter this.disposables.push(this.untitledEditorService.onDidChangeDirty(e => this.updateDirtyIndicator())); @@ -259,7 +259,7 @@ export class OpenEditorsView extends ViewsViewletPanel { } } - private onConfigurationUpdated(configuration: IFilesConfiguration): void { + private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void { if (this.isDisposed) { return; // guard against possible race condition when config change causes recreate of views } @@ -280,6 +280,11 @@ export class OpenEditorsView extends ViewsViewletPanel { // Adjust expanded body size this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(this.model); + + // Trigger a 'repaint' when decoration settings change + if (event && event.affectsConfiguration('explorer.decorations')) { + this.tree.refresh(); + } } private updateDirtyIndicator(): void { diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts index a67a4d87ea6..c72ae86cbaa 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts @@ -24,13 +24,14 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor'; import { OpenEditor } from 'vs/workbench/parts/files/common/explorerModel'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; -import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; +import { explorerItemToFileResource, IFilesConfiguration } from 'vs/workbench/parts/files/common/files'; import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorStacksModel, EditorGroup } from 'vs/workbench/common/editor/editorStacksModel'; import { SaveFileAction, RevertFileAction, SaveFileAsAction, OpenToSideAction, SelectResourceForCompareAction, CompareResourcesAction, SaveAllInGroupAction, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { CloseOtherEditorsInGroupAction, CloseEditorAction, CloseEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction } from 'vs/workbench/browser/parts/editor/editorActions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const $ = dom.$; @@ -86,7 +87,8 @@ export class Renderer implements IRenderer { constructor( private actionProvider: ActionProvider, @IInstantiationService private instantiationService: IInstantiationService, - @IKeybindingService private keybindingService: IKeybindingService + @IKeybindingService private keybindingService: IKeybindingService, + @IConfigurationService private configurationService: IConfigurationService ) { // noop } @@ -149,7 +151,11 @@ export class Renderer implements IRenderer { private renderOpenEditor(tree: ITree, editor: OpenEditor, templateData: IOpenEditorTemplateData): void { editor.isDirty() ? dom.addClass(templateData.container, 'dirty') : dom.removeClass(templateData.container, 'dirty'); - templateData.root.setEditor(editor.editorInput, { italic: editor.isPreview(), extraClasses: ['open-editor'] }); + templateData.root.setEditor(editor.editorInput, { + italic: editor.isPreview(), + extraClasses: ['open-editor'], + fileDecorations: this.configurationService.getConfiguration().explorer.decorations + }); templateData.actionBar.context = { group: editor.editorGroup, editor: editor.editorInput }; } From b2f4ba4dd79068ef17431685acda8fd31472cd07 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Oct 2017 10:00:06 +0200 Subject: [PATCH 288/303] debug: change start without debugging keybinding --- .../parts/debug/electron-browser/debug.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index a88503d3faf..0b2665666de 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -6,7 +6,7 @@ import 'vs/css!../browser/media/debug.contribution'; import 'vs/css!../browser/media/debugHover'; import * as nls from 'vs/nls'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; +import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -132,7 +132,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(PauseAction, PauseActi registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5 }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Without Debugging', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_X) } }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Without Debugging', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory); From ca2c1073246e7fcbdc76f4a665bfd0f76cb460e0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 10:06:02 +0200 Subject: [PATCH 289/303] deco - update decorations when gitignore-file changes --- extensions/git/src/decorationProvider.ts | 8 ++++--- src/vs/vscode.proposed.d.ts | 2 +- .../workbench/api/node/extHostDecorations.ts | 2 +- .../decorations/browser/decorationsService.ts | 22 ++++++++++++++----- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 5ae257473b3..19ef25fb811 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -5,10 +5,11 @@ 'use strict'; -import { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; +import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; import { debounce } from './decorators'; +import { filterEvent } from './util'; class GitIgnoreDecorationProvider implements DecorationProvider { @@ -20,8 +21,9 @@ class GitIgnoreDecorationProvider implements DecorationProvider { constructor(private repository: Repository) { this.disposables.push( - window.registerDecorationProvider(this, '.gitignore') - //todo@joh -> events when the ignore status actually changes, not when the file changes + window.registerDecorationProvider(this, '.gitignore'), + filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore'))(_ => this._onDidChangeDecorations.fire()) + //todo@joh -> events when the ignore status actually changes, not only when the file changes ); } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index d48b0f9020a..63ebd06f1b4 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -182,7 +182,7 @@ declare module 'vscode' { } export interface DecorationProvider { - onDidChangeDecorations: Event; + onDidChangeDecorations: Event; provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; } diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts index ad428987404..971896c96dd 100644 --- a/src/vs/workbench/api/node/extHostDecorations.ts +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -28,7 +28,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape { this._proxy.$registerDecorationProvider(handle, label); const listener = provider.onDidChangeDecorations(e => { - this._proxy.$onDidChange(handle, Array.isArray(e) ? e : [e]); + this._proxy.$onDidChange(handle, !e ? null : Array.isArray(e) ? e : [e]); }); return new Disposable(() => { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index a6320b0fe65..63992705c3d 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -221,12 +221,21 @@ class DecorationProviderWrapper { constructor( private readonly _provider: IDecorationsProvider, - private readonly _emitter: Emitter + private readonly _uriEmitter: Emitter, + private readonly _flushEmitter: Emitter ) { this._dispoable = this._provider.onDidChange(uris => { - for (const uri of uris) { - this.data.delete(uri.toString()); - this._fetchData(uri); + if (!uris) { + // flush event -> drop all data, can affect everything + this.data.clear(); + this._flushEmitter.fire({ affectsResource() { return true; } }); + + } else { + // selective changes -> drop for resource, fetch again, send event + for (const uri of uris) { + this.data.delete(uri.toString()); + this._fetchData(uri); + } } }); } @@ -293,7 +302,7 @@ class DecorationProviderWrapper { private _keepItem(uri: URI, data: IDecorationData): IDecorationData { let deco = data ? data : null; this.data.set(uri.toString(), deco); - this._emitter.fire(uri); + this._uriEmitter.fire(uri); return deco; } } @@ -345,7 +354,8 @@ export class FileDecorationsService implements IDecorationsService { const wrapper = new DecorationProviderWrapper( provider, - this._onDidChangeDecorationsDelayed + this._onDidChangeDecorationsDelayed, + this._onDidChangeDecorations ); const remove = this._data.push(wrapper); From b98939c0304b828edac1fd2ae446515766352dc8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 10:08:16 +0200 Subject: [PATCH 290/303] fix #36244 --- .../browser/parts/activitybar/activitybarActions.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 2b03a25ffec..04c486ec533 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -121,6 +121,12 @@ export class GlobalActivityActionItem extends ActivityActionItem { public onClick(event?: MouseEvent | KeyboardEvent): void { DOM.EventHelper.stop(event, true); + // Prevent duplicate menu showing because we already handle MOUSE_DOWN + // (refs: // https://github.com/Microsoft/vscode/issues/36244) + if (event.type === DOM.EventType.CLICK) { + return; + } + let location: HTMLElement | { x: number, y: number }; if (event instanceof MouseEvent) { const mouseEvent = new StandardMouseEvent(event); From 01a35abcc72959d5ae1c3c0df22e993387bd221d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 10:15:45 +0200 Subject: [PATCH 291/303] telemetry: do not log fileGet on settings JSON files --- .../textfile/common/textFileEditorModel.ts | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 8076fc12f2a..10cc2553f19 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -366,16 +366,22 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private loadWithContent(content: IRawTextContent | IContent, backup?: URI): TPromise { return this.doLoadWithContent(content, backup).then(model => { - // We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype - - /* __GDPR__ - "fileGet" : { - "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype + if (this.isSettingsFile()) { + /* __GDPR__ + "settingsRead" : {} + */ + this.telemetryService.publicLog('settingsRead'); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data + } else { + /* __GDPR__ + "fileGet" : { + "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + } return model; }); From 71d332b4645da2c7cf91ea54eaebc4f792ac556d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 10:36:47 +0200 Subject: [PATCH 292/303] deco - remove opacity, use colors only, remove provider label from proposed api --- extensions/git/src/decorationProvider.ts | 4 ++-- extensions/git/src/repository.ts | 2 -- src/vs/vscode.proposed.d.ts | 3 +-- .../api/electron-browser/mainThreadDecorations.ts | 7 +++---- src/vs/workbench/api/node/extHost.api.impl.ts | 4 ++-- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostDecorations.ts | 2 +- .../services/decorations/browser/decorations.ts | 1 - .../decorations/browser/decorationsService.ts | 12 ++++++------ 9 files changed, 16 insertions(+), 21 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 19ef25fb811..44789b518b5 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -21,7 +21,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { constructor(private repository: Repository) { this.disposables.push( - window.registerDecorationProvider(this, '.gitignore'), + window.registerDecorationProvider(this), filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore'))(_ => this._onDidChangeDecorations.fire()) //todo@joh -> events when the ignore status actually changes, not only when the file changes ); @@ -72,7 +72,7 @@ class GitDecorationProvider implements DecorationProvider { constructor(private repository: Repository) { this.disposables.push( - window.registerDecorationProvider(this, repository.root), + window.registerDecorationProvider(this), repository.onDidRunOperation(this.onDidRunOperation, this) ); } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 74cd6c48bfd..ccd92bf005f 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -183,8 +183,6 @@ export class Resource implements SourceControlResourceState { get resourceDecoration(): DecorationData | undefined { const title = this.tooltip; switch (this.type) { - case Status.IGNORED: - return { priority: 3, title, opacity: 0.75 }; case Status.UNTRACKED: return { priority: 1, title, abbreviation: localize('untracked, short', "U"), bubble: true, color: new ThemeColor('git.color.untracked') }; case Status.INDEX_MODIFIED: diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 63ebd06f1b4..3ff70ed91db 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -178,7 +178,6 @@ declare module 'vscode' { bubble?: boolean; abbreviation?: string; color?: ThemeColor; - opacity?: number; } export interface DecorationProvider { @@ -187,7 +186,7 @@ declare module 'vscode' { } export namespace window { - export function registerDecorationProvider(provider: DecorationProvider, label: string): Disposable; + export function registerDecorationProvider(provider: DecorationProvider): Disposable; } //#endregion diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts index b2ae08b829c..7ac2b8c92ef 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -29,23 +29,22 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { this._provider.clear(); } - $registerDecorationProvider(handle: number, label: string): void { + $registerDecorationProvider(handle: number): void { let emitter = new Emitter(); let registration = this._decorationsService.registerDecorationsProvider({ - label, + label: 'extension-provider', onDidChange: emitter.event, provideDecorations: (uri) => { return this._proxy.$providerDecorations(handle, uri).then(data => { if (!data) { return undefined; } - const [weight, bubble, title, letter, opacity, themeColor] = data; + const [weight, bubble, title, letter, themeColor] = data; return { weight: weight || 0, bubble: bubble || false, title, letter, - opacity, color: themeColor && themeColor.id }; }); diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 73c966c463e..128eb4a907e 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -378,8 +378,8 @@ export function createApiFactory( sampleFunction: proposedApiFunction(extension, () => { return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []); }), - registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider, label: string) => { - return extHostDecorations.registerDecorationProvider(provider, label); + registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => { + return extHostDecorations.registerDecorationProvider(provider, extension.id); }) }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 17980ed5b35..2071ea617db 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -602,7 +602,7 @@ export interface ExtHostDebugServiceShape { } -export type DecorationData = [number, boolean, string, string, number, ThemeColor]; +export type DecorationData = [number, boolean, string, string, ThemeColor]; export interface ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise; diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts index 971896c96dd..e327dbe4995 100644 --- a/src/vs/workbench/api/node/extHostDecorations.ts +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -41,7 +41,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise { const provider = this._provider.get(handle); return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => { - return data && [data.priority, data.bubble, data.title, data.abbreviation, data.opacity, data.color]; + return data && [data.priority, data.bubble, data.title, data.abbreviation, data.color]; }); } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 6a5b7993205..6356737cb2d 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -15,7 +15,6 @@ export const IDecorationsService = createDecorator('IFileDe export interface IDecorationData { readonly weight?: number; readonly color?: ColorIdentifier; - readonly opacity?: number; readonly letter?: string; readonly title?: string; readonly bubble?: boolean; diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 63992705c3d..cd004e68f20 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -23,8 +23,8 @@ class DecorationRule { if (Array.isArray(data)) { return data.map(DecorationRule.keyOf).join(','); } else { - const { color, opacity, letter } = data; - return `${color}/${opacity}/${letter}`; + const { color, letter } = data; + return `${color}/${letter}`; } } @@ -49,9 +49,9 @@ class DecorationRule { } private _appendForOne(data: IDecorationData, element: HTMLStyleElement, theme: ITheme): void { - const { color, opacity, letter } = data; + const { color, letter } = data; // label - createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); + createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge if (letter) { @@ -62,8 +62,8 @@ class DecorationRule { private _appendForMany(data: IDecorationData[], element: HTMLStyleElement, theme: ITheme): void { // label - const { color, opacity } = data[0]; - createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'}; opacity: ${opacity || 1};`, element); + const { color } = data[0]; + createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge From 619e5f93bc8090765343416d7339a4812b8fd944 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 10:49:36 +0200 Subject: [PATCH 293/303] config context fixes --- src/vs/platform/contextkey/browser/contextKeyService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 032b7f49d77..a3109b1e2c8 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -69,9 +69,9 @@ class ConfigAwareContextValuesContainer extends Context { } private _onConfigurationUpdated(event: IConfigurationChangeEvent): void { - if (event.affectsConfiguration('config')) { - this._updateConfigurationContext(this._configurationService.getConfiguration()); - } + // if (event.affectsConfiguration('config')) { + this._updateConfigurationContext(this._configurationService.getConfiguration()); + // } } private _updateConfigurationContext(config: any) { From 993043440d1bbf257d5456e2bf561f728820f26f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Oct 2017 10:53:13 +0200 Subject: [PATCH 294/303] Send workspace configuration change event data to extension host --- .../configuration/common/configuration.ts | 9 +-- .../common/configurationModels.ts | 78 +++++++++---------- .../mainThreadConfiguration.ts | 16 +++- src/vs/workbench/api/node/extHost.protocol.ts | 9 ++- .../api/node/extHostConfiguration.ts | 22 +++++- .../common/configurationModels.ts | 29 +++---- 6 files changed, 85 insertions(+), 78 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 41093f27f8a..9da18eb08a4 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -12,6 +12,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { StrictResourceMap } from 'vs/base/common/map'; export const IConfigurationService = createDecorator('configurationService'); @@ -45,7 +46,8 @@ export interface IConfigurationChangeEvent { sourceConfig: any; // Following data is used for Extension host configuration event - toJSON(): IConfigurationChangeEventData; + changedConfiguration: IConfiguraionModel; + changedConfigurationByResource: StrictResourceMap; } export interface IConfigurationService { @@ -106,11 +108,6 @@ export interface IConfigurationData { folders: { [folder: string]: IConfiguraionModel }; } -export interface IConfigurationChangeEventData { - changedConfiguration: IConfiguraionModel; - changedConfigurationByResource: { [folder: string]: IConfiguraionModel }; -} - export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { const added = to.keys.filter(key => from.keys.indexOf(key) === -1); const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index c58669e9dec..3ce3d66a3cd 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; export class ConfigurationModel implements IConfiguraionModel { @@ -133,6 +133,14 @@ export class ConfigurationModel implements IConfiguraionModel { } return false; } + + toJSON(): IConfiguraionModel { + return { + contents: this.contents, + overrides: this.overrides, + keys: this.keys + }; + } } export class DefaultConfigurationModel extends ConfigurationModel { @@ -493,19 +501,12 @@ export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChange return this._changedConfiguration; } - affectsConfiguration(config: string, resource?: URI): boolean { - return this.doesConfigurationContains(this.changedConfiguration, config); + get changedConfigurationByResource(): StrictResourceMap { + return new StrictResourceMap(); } - toJSON(): IConfigurationChangeEventData { - return { - changedConfiguration: { - contents: this.changedConfiguration.contents, - overrides: this.changedConfiguration.overrides, - keys: this.changedConfiguration.keys - }, - changedConfigurationByResource: Object.create({}) - }; + affectsConfiguration(config: string, resource?: URI): boolean { + return this.doesConfigurationContains(this.changedConfiguration, config); } } @@ -515,21 +516,28 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i private _sourceConfig: any; constructor( - private changedConfiguration: ConfigurationModel = new ConfigurationModel(), - private resources: URI[] = [], - private changedConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { + private _changedConfiguration: ConfigurationModel = new ConfigurationModel(), + private _changedConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { super(); } + get changedConfiguration(): IConfiguraionModel { + return this._changedConfiguration; + } + + get changedConfigurationByResource(): StrictResourceMap { + return this._changedConfigurationByResource; + } + change(event: ConfigurationChangeEvent): ConfigurationChangeEvent change(keys: string[], resource?: URI): ConfigurationChangeEvent change(arg1: any, arg2?: any): ConfigurationChangeEvent { if (arg1 instanceof ConfigurationChangeEvent) { - this.changedConfiguration = this.changedConfiguration.merge(arg1.changedConfiguration); - for (const resource of arg1.resources) { + this._changedConfiguration = this._changedConfiguration.merge(arg1._changedConfiguration); + for (const resource of this.changedConfigurationByResource.keys()) { let changedConfigurationByResource = this.getOrSetChangedConfigurationForResource(resource); - changedConfigurationByResource = changedConfigurationByResource.merge(arg1.changedConfigurationByResource.get(resource)); - this.changedConfigurationByResource.set(resource, changedConfigurationByResource); + changedConfigurationByResource = changedConfigurationByResource.merge(arg1._changedConfigurationByResource.get(resource)); + this._changedConfigurationByResource.set(resource, changedConfigurationByResource); } } this.changeWithKeys(arg1, arg2); @@ -543,8 +551,8 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i } get affectedKeys(): string[] { - const keys = [...this.changedConfiguration.keys]; - this.changedConfigurationByResource.forEach(model => keys.push(...model.keys)); + const keys = [...this._changedConfiguration.keys]; + this._changedConfigurationByResource.forEach(model => keys.push(...model.keys)); return keys; } @@ -557,15 +565,15 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i } affectsConfiguration(config: string, resource?: URI): boolean { - let configurationModelsToSearch: ConfigurationModel[] = [this.changedConfiguration]; + let configurationModelsToSearch: ConfigurationModel[] = [this._changedConfiguration]; if (resource) { - let model = this.changedConfigurationByResource.get(resource); + let model = this._changedConfigurationByResource.get(resource); if (model) { configurationModelsToSearch.push(model); } } else { - configurationModelsToSearch.push(...this.changedConfigurationByResource.values()); + configurationModelsToSearch.push(...this._changedConfigurationByResource.values()); } for (const configuration of configurationModelsToSearch) { @@ -578,32 +586,16 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i } private changeWithKeys(keys: string[], resource?: URI): void { - let changedConfiguration = resource ? this.getOrSetChangedConfigurationForResource(resource) : this.changedConfiguration; + let changedConfiguration = resource ? this.getOrSetChangedConfigurationForResource(resource) : this._changedConfiguration; this.updateKeys(changedConfiguration, keys); } private getOrSetChangedConfigurationForResource(resource: URI): ConfigurationModel { - let changedConfigurationByResource = this.changedConfigurationByResource.get(resource); + let changedConfigurationByResource = this._changedConfigurationByResource.get(resource); if (!changedConfigurationByResource) { changedConfigurationByResource = new ConfigurationModel(); - this.changedConfigurationByResource.set(resource, changedConfigurationByResource); - this.resources.push(resource); + this._changedConfigurationByResource.set(resource, changedConfigurationByResource); } return changedConfigurationByResource; } - - toJSON(): IConfigurationChangeEventData { - return { - changedConfiguration: { - contents: this.changedConfiguration.contents, - overrides: this.changedConfiguration.overrides, - keys: this.changedConfiguration.keys - }, - changedConfigurationByResource: this.changedConfigurationByResource.keys().reduce((result, resource) => { - const { contents, overrides, keys } = this.changedConfigurationByResource.get(resource); - result[resource.toString()] = { contents, overrides, keys }; - return result; - }, Object.create({})) - }; - } } \ No newline at end of file diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index af38672d4b8..5133d7125a9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -11,9 +11,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext } from '../node/extHost.protocol'; +import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext, IWorkspaceConfigurationChangeEventData } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; -import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; @extHostNamedCustomer(MainContext.MainThreadConfiguration) export class MainThreadConfiguration implements MainThreadConfigurationShape { @@ -28,7 +28,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); this._configurationListener = configurationService.onDidChangeConfiguration(e => { - proxy.$acceptConfigurationChanged(configurationService.getConfigurationData(), e.toJSON()); + proxy.$acceptConfigurationChanged(configurationService.getConfigurationData(), this.toConfigurationChangeEventData(e)); }); } @@ -58,4 +58,14 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { } return ConfigurationTarget.WORKSPACE; } + + private toConfigurationChangeEventData(event: IConfigurationChangeEvent): IWorkspaceConfigurationChangeEventData { + return { + changedConfiguration: event.changedConfiguration, + changedConfigurationByResource: event.changedConfigurationByResource.keys().reduce((result, resource) => { + result[resource.toString()] = event.changedConfigurationByResource.get(resource); + return result; + }, Object.create({})) + }; + } } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 2071ea617db..4320e059494 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -28,7 +28,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ITextSource } from 'vs/editor/common/model/textSource'; -import { IConfigurationData, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget, IConfiguraionModel } from 'vs/platform/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -77,6 +77,11 @@ export interface IInitData { telemetryInfo: ITelemetryInfo; } +export interface IWorkspaceConfigurationChangeEventData { + changedConfiguration: IConfiguraionModel; + changedConfigurationByResource: { [folder: string]: IConfiguraionModel }; +} + export interface IExtHostContext { /** * Returns a proxy to an object addressable/named in the extension host process. @@ -418,7 +423,7 @@ export interface ExtHostCommandsShape { } export interface ExtHostConfigurationShape { - $acceptConfigurationChanged(data: IConfigurationData, eventData: IConfigurationChangeEventData): void; + $acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData): void; } export interface ExtHostDiagnosticsShape { diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 5a8dae4f23a..fde9013ed78 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -9,10 +9,12 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import * as vscode from 'vscode'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; -import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; +import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; -import { IConfigurationData, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; -import { Configuration } from 'vs/platform/configuration/common/configurationModels'; +import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { Configuration, ConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; +import { StrictResourceMap } from 'vs/base/common/map'; function lookUp(tree: any, key: string) { if (key) { @@ -50,7 +52,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - $acceptConfigurationChanged(data: IConfigurationData, eventData: IConfigurationChangeEventData) { + $acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData) { this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace); this._onDidChangeConfiguration.fire(undefined); } @@ -117,4 +119,16 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { return Object.freeze(result); } + + protected toConfigurationChangeEvent(data: IWorkspaceConfigurationChangeEventData): WorkspaceConfigurationChangeEvent { + const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides); + const changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); + for (const key of Object.keys(data.changedConfigurationByResource)) { + const resource = URI.parse(key); + const model = data.changedConfigurationByResource[key]; + changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides)); + } + const event = new ConfigurationChangeEvent(changedConfiguration, changedConfigurationByResource); + return new WorkspaceConfigurationChangeEvent(event, this._extHostWorkspace.workspace); + } } diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 3cef3209dfe..fb32e490494 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationChangeEventData } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfiguraionModel } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -270,7 +270,14 @@ export class Configuration extends BaseConfiguration { export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { - constructor(private configurationChangeEvent: IConfigurationChangeEvent, private workspace: Workspace) { + constructor(private configurationChangeEvent: IConfigurationChangeEvent, private workspace: Workspace) { } + + get changedConfiguration(): IConfiguraionModel { + return this.configurationChangeEvent.changedConfiguration; + } + + get changedConfigurationByResource(): StrictResourceMap { + return this.configurationChangeEvent.changedConfigurationByResource; } get affectedKeys(): string[] { @@ -299,22 +306,4 @@ export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEv return false; } - - toJSON(): IConfigurationChangeEventData { - return this.configurationChangeEvent.toJSON(); - } - - public static parse(data: IConfigurationChangeEventData, workspace: Workspace): WorkspaceConfigurationChangeEvent { - const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides); - const resources: URI[] = []; - const changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); - for (const key of Object.keys(data.changedConfigurationByResource)) { - const resource = URI.parse(key); - const model = data.changedConfigurationByResource[key]; - resources.push(resource); - changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides)); - } - const event = new ConfigurationChangeEvent(changedConfiguration, resources, changedConfigurationByResource); - return new WorkspaceConfigurationChangeEvent(event, workspace); - } } \ No newline at end of file From 1fbd298cdc594e772be21ab717b6cd279908e525 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 11:00:16 +0200 Subject: [PATCH 295/303] fix tests --- .../services/textfile/test/textFileService.test.ts | 4 ++-- src/vs/workbench/test/workbenchTestServices.ts | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 777b42a5b71..38b5749c179 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -19,7 +19,7 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace'; class ServiceAccessor { constructor( @@ -380,7 +380,7 @@ suite('Files - TextFileService', () => { service.onConfigurationChange({ files: { hotExit: setting } }); // Set empty workspace if required if (!workspace) { - accessor.contextService.setWorkspace(null); + accessor.contextService.setWorkspace(new Workspace('empty:1508317022751')); } // Set multiple windows if required if (multipleWindows) { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 8bfdf7f0f46..b4d7d8cf3df 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -102,12 +102,14 @@ export class TestContextService implements IWorkspaceContextService { } public getWorkbenchState(): WorkbenchState { - if (this.workspace) { - if (this.workspace.configuration) { - return WorkbenchState.WORKSPACE; - } + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } + + if (this.workspace.folders.length) { return WorkbenchState.FOLDER; } + return WorkbenchState.EMPTY; } From 9c97b8002db556b0e8d2cf1b7df362356e8f585e Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Oct 2017 11:05:00 +0200 Subject: [PATCH 296/303] debug: decodeURI before sending it out to adapter fixes #36471 --- src/vs/workbench/parts/debug/electron-browser/debugService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 2b5446c6602..d3d1386f87f 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -1119,7 +1119,8 @@ export class DebugService implements debug.IDebugService { const breakpointsToSend = this.model.getBreakpoints().filter(bp => this.model.areBreakpointsActivated() && bp.enabled && bp.uri.toString() === modelUri.toString()); const source = process.sources.get(modelUri.toString()); - const rawSource = source ? source.raw : { path: modelUri.scheme === 'file' || modelUri.scheme === debug.DEBUG_SCHEME ? paths.normalize(modelUri.fsPath, true) : modelUri.toString(), name: resources.basenameOrAuthority(modelUri) }; + const path = modelUri.scheme === 'file' || modelUri.scheme === debug.DEBUG_SCHEME ? paths.normalize(modelUri.fsPath, true) : modelUri.toString(); + const rawSource = source ? source.raw : { path: decodeURIComponent(path), name: resources.basenameOrAuthority(modelUri) }; if (breakpointsToSend.length && !rawSource.adapterData) { rawSource.adapterData = breakpointsToSend[0].adapterData; } From d4b5e8a7cd90112aaa463fb2f4cbba8f05220bf0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 11:25:01 +0200 Subject: [PATCH 297/303] context - more precise config change event listening --- .../contextkey/browser/contextKeyService.ts | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index a3109b1e2c8..f12ad44deeb 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -8,7 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { IContextKey, IContext, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context'; @@ -51,17 +51,17 @@ export class Context implements IContext { class ConfigAwareContextValuesContainer extends Context { - private _emitter: Emitter; - private _subscription: IDisposable; - private _configurationService: IConfigurationService; + private readonly _emitter: Emitter; + private readonly _subscription: IDisposable; + private readonly _configurationService: IConfigurationService; constructor(id: number, configurationService: IConfigurationService, emitter: Emitter) { super(id, null); this._emitter = emitter; this._configurationService = configurationService; - this._subscription = configurationService.onDidChangeConfiguration(e => this._onConfigurationUpdated(e)); - this._updateConfigurationContext(configurationService.getConfiguration()); + this._subscription = configurationService.onDidChangeConfiguration(this._onConfigurationUpdated, this); + this._initFromConfiguration(); } public dispose() { @@ -69,12 +69,24 @@ class ConfigAwareContextValuesContainer extends Context { } private _onConfigurationUpdated(event: IConfigurationChangeEvent): void { - // if (event.affectsConfiguration('config')) { - this._updateConfigurationContext(this._configurationService.getConfiguration()); - // } + if (event.source === ConfigurationTarget.DEFAULT) { + // new setting, rebuild everything + this._initFromConfiguration(); + } else { + // update those that we know + for (const configKey of event.affectedKeys) { + const contextKey = `config.${configKey}`; + if (contextKey in this._value) { + this._value[contextKey] = this._configurationService.getValue(configKey); + this._emitter.fire(configKey); + } + } + } } - private _updateConfigurationContext(config: any) { + private _initFromConfiguration() { + + const config = this._configurationService.getConfiguration(); // remove old config.xyz values for (let key in this._value) { From e6e9092fb67a4540fa7c3bf7a29807f14c2c0023 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 11:28:42 +0200 Subject: [PATCH 298/303] fix layering rules in workbench services --- src/vs/workbench/electron-browser/shell.ts | 2 +- .../{common => node}/workspaceStats.ts | 0 .../telemetry/test/workspaceStats.test.ts | 2 +- tslint.json | 47 +++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) rename src/vs/workbench/services/telemetry/{common => node}/workspaceStats.ts (100%) diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 0430727fa3e..44543f77bd1 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -31,7 +31,7 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; import { ElectronWindow } from 'vs/workbench/electron-browser/window'; import { resolveWorkbenchCommonProperties, getOrCreateMachineId } from 'vs/platform/telemetry/node/workbenchCommonProperties'; import { machineIdIpcChannel } from 'vs/platform/telemetry/node/commonProperties'; -import { WorkspaceStats } from 'vs/workbench/services/telemetry/common/workspaceStats'; +import { WorkspaceStats } from 'vs/workbench/services/telemetry/node/workspaceStats'; import { IWindowsService, IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService'; diff --git a/src/vs/workbench/services/telemetry/common/workspaceStats.ts b/src/vs/workbench/services/telemetry/node/workspaceStats.ts similarity index 100% rename from src/vs/workbench/services/telemetry/common/workspaceStats.ts rename to src/vs/workbench/services/telemetry/node/workspaceStats.ts diff --git a/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts b/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts index 5647af87623..7bb6e7d3d8f 100644 --- a/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts +++ b/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as crypto from 'crypto'; -import { getDomainsOfRemotes, getRemotes, getHashedRemotes } from 'vs/workbench/services/telemetry/common/workspaceStats'; +import { getDomainsOfRemotes, getRemotes, getHashedRemotes } from 'vs/workbench/services/telemetry/node/workspaceStats'; function hash(value: string): string { return crypto.createHash('sha1').update(value.toString()).digest('hex'); diff --git a/tslint.json b/tslint.json index d4df6618424..1264f2b5cf0 100644 --- a/tslint.json +++ b/tslint.json @@ -348,15 +348,52 @@ ] }, { - "target": "**/vs/workbench/services/**", + "target": "**/vs/workbench/services/**/common/**", "restrictions": [ "vs/nls", "vs/css!./**/*", - "**/vs/base/**", - "**/vs/platform/**", - "**/vs/editor/**", + "**/vs/base/**/common/**", + "**/vs/platform/**/common/**", + "**/vs/editor/common/**", + "**/vs/workbench/common/**", + "**/vs/workbench/services/**/common/**" + ] + }, + { + "target": "**/vs/workbench/services/**/browser/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,browser}/**", + "**/vs/platform/**/{common,browser}/**", + "**/vs/editor/{common,browser}/**", + "**/vs/workbench/{common,browser}/**", + "**/vs/workbench/services/**/{common,browser}/**" + ] + }, + { + "target": "**/vs/workbench/services/**/node/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,node}/**", + "**/vs/platform/**/{common,node}/**", + "**/vs/editor/{common,node}/**", + "**/vs/workbench/{common,node}/**", + "**/vs/workbench/services/**/{common,node}/**", + "*" // node modules + ] + }, + { + "target": "**/vs/workbench/services/**/electron-browser/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,browser,node,electron-browser}/**", + "**/vs/platform/**/{common,browser,node,electron-browser}/**", + "**/vs/editor/**/{common,browser,node,electron-browser}/**", "**/vs/workbench/{common,browser,node,electron-browser,api}/**", - "**/vs/workbench/services/**", + "**/vs/workbench/services/**/{common,browser,node,electron-browser}/**", "*" // node modules ] }, From 3b960a89e3699eda006bda226c8805e3add584d1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 11:39:37 +0200 Subject: [PATCH 299/303] telemetry - add a workspace ID tag to workspace stats --- .../services/telemetry/node/workspaceStats.ts | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/telemetry/node/workspaceStats.ts b/src/vs/workbench/services/telemetry/node/workspaceStats.ts index 9275928cd44..e81862ca195 100644 --- a/src/vs/workbench/services/telemetry/node/workspaceStats.ts +++ b/src/vs/workbench/services/telemetry/node/workspaceStats.ts @@ -36,7 +36,7 @@ const SecondLevelDomainWhitelist = [ 'google.com' ]; -type Tags = { [index: string]: boolean | number }; +type Tags = { [index: string]: boolean | number | string }; function stripLowLevelDomains(domain: string): string { let match = domain.match(SecondLevelDomainMatcher); @@ -149,6 +149,7 @@ export class WorkspaceStats { "workbench.filesToOpen" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "workbench.filesToCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workspace.id" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, "workspace.roots" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, "workspace.empty" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, "workspace.grunt" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, @@ -175,13 +176,29 @@ export class WorkspaceStats { private getWorkspaceTags(configuration: IWindowConfiguration): TPromise { const tags: Tags = Object.create(null); + const state = this.contextService.getWorkbenchState(); + const workspace = this.contextService.getWorkspace(); + + let workspaceId: string; + switch (state) { + case WorkbenchState.EMPTY: + workspaceId = void 0; + break; + case WorkbenchState.FOLDER: + workspaceId = crypto.createHash('sha1').update(workspace.folders[0].uri.fsPath).digest('hex'); + break; + case WorkbenchState.WORKSPACE: + workspaceId = crypto.createHash('sha1').update(workspace.configuration.fsPath).digest('hex'); + } + + tags['workspace.id'] = workspaceId; + const { filesToOpen, filesToCreate, filesToDiff } = configuration; tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || 0; tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || 0; tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0; - const isEmpty = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY; - const workspace = this.contextService.getWorkspace(); + const isEmpty = state === WorkbenchState.EMPTY; tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length; tags['workspace.empty'] = isEmpty; From 44bd7e3176fa9b9f1572429812a7c64d938d9136 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2017 11:44:45 +0200 Subject: [PATCH 300/303] deco - don't check for ignored files outside the repo --- extensions/git/src/decorationProvider.ts | 1 + extensions/git/src/repository.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 44789b518b5..813a035b519 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -55,6 +55,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { value.resolve(ignoreSet.has(key)); } }, err => { + console.error(err); for (const [, value] of queue.entries()) { value.reject(err); } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index ccd92bf005f..6e16bf9d44c 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -6,7 +6,7 @@ 'use strict'; import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode'; -import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType } from './git'; +import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; import { memoize, throttle, debounce } from './decorators'; import { toGitUri } from './uri'; @@ -648,6 +648,8 @@ export class Repository implements Disposable { return this.run(Operation.Ignore, () => { return new Promise>((resolve, reject) => { + filePaths = filePaths.filter(filePath => !path.relative(this.root, filePath).startsWith('..')); + const child = this.repository.stream(['check-ignore', ...filePaths]); const onExit = exitCode => { @@ -658,7 +660,7 @@ export class Repository implements Disposable { // each line is something ignored resolve(new Set(data.split('\n'))); } else { - reject(); + reject(new GitError({ stdout: data, stderr, exitCode })); } }; @@ -670,9 +672,9 @@ export class Repository implements Disposable { child.stdout.setEncoding('utf8'); child.stdout.on('data', onStdoutData); - // const stderrData: string[] = []; - // child.stderr.setEncoding('utf8'); - // child.stderr.on('data', raw => stderrData.push(raw as string)); + let stderr: string = ''; + child.stderr.setEncoding('utf8'); + child.stderr.on('data', raw => stderr += raw); child.on('error', reject); child.on('exit', onExit); From 104a4d1bb64111c0a6a56d06f987372829beb089 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2017 11:56:59 +0200 Subject: [PATCH 301/303] :lipstick: --- .../telemetry/common/telemetryUtils.ts | 31 ++----------------- .../common/editor/resourceEditorInput.ts | 6 ++-- .../common/editor/untitledEditorInput.ts | 6 ++-- src/vs/workbench/electron-browser/shell.ts | 5 +++ .../files/common/editors/fileEditorInput.ts | 6 ++-- .../workbench/parts/html/common/htmlInput.ts | 6 ++-- .../preferences/browser/preferencesEditor.ts | 6 ++-- .../walkThrough/node/walkThroughInput.ts | 6 ++-- .../services/hash/common/hashService.ts | 19 ++++++++++++ .../services/hash/node/hashService.ts | 18 +++++++++++ .../test/node/keybindingEditing.test.ts | 4 ++- .../textfile/common/textFileEditorModel.ts | 5 +-- .../workbench/test/workbenchTestServices.ts | 10 ++++++ 13 files changed, 84 insertions(+), 44 deletions(-) create mode 100644 src/vs/workbench/services/hash/common/hashService.ts create mode 100644 src/vs/workbench/services/hash/node/hashService.ts diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 4f177bbb2e2..904d9602127 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -39,33 +39,6 @@ export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetry export const NullAppender: ITelemetryAppender = { log: () => null }; -// --- util - -export function anonymize(input: string): string { - if (!input) { - return input; - } - - let r = ''; - for (let i = 0; i < input.length; i++) { - let ch = input[i]; - if (ch >= '0' && ch <= '9') { - r += '0'; - continue; - } - if (ch >= 'a' && ch <= 'z') { - r += 'a'; - continue; - } - if (ch >= 'A' && ch <= 'Z') { - r += 'A'; - continue; - } - r += ch; - } - return r; -} - /* __GDPR__FRAGMENT__ "URIDescriptor" : { "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -79,9 +52,9 @@ export interface URIDescriptor { path?: string; } -export function telemetryURIDescriptor(uri: URI): URIDescriptor { +export function telemetryURIDescriptor(uri: URI, hashPath: (path: string) => string): URIDescriptor { const fsPath = uri && uri.fsPath; - return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), ext: paths.extname(fsPath), path: anonymize(fsPath) } : {}; + return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), ext: paths.extname(fsPath), path: hashPath(fsPath) } : {}; } /** diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index ea19725e484..4f9a57314ec 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -11,6 +11,7 @@ import { IReference } from 'vs/base/common/lifecycle'; import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * A read-only text editor input whos contents are made of the provided resource that points to an existing @@ -29,7 +30,8 @@ export class ResourceEditorInput extends EditorInput { name: string, description: string, resource: URI, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); @@ -70,7 +72,7 @@ export class ResourceEditorInput extends EditorInput { public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.resource); + descriptor['resource'] = telemetryURIDescriptor(this.resource, path => this.hashService.createSHA1(path)); /* __GDPR__FRAGMENT__ "EditorTelemetryDescriptor" : { diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 8057bef0160..45092f33e98 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -22,6 +22,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Verbosity } from 'vs/platform/editor/common/editor'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * An editor input to be used for untitled text buffers. @@ -48,7 +49,8 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextFileService private textFileService: ITextFileService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IHashService private hashService: IHashService ) { super(); @@ -252,7 +254,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.getResource()); + descriptor['resource'] = telemetryURIDescriptor(this.getResource(), path => this.hashService.createSHA1(path)); /* __GDPR__FRAGMENT__ "EditorTelemetryDescriptor" : { diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 44543f77bd1..b0a9dff094c 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -91,6 +91,8 @@ import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollba import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; import { IBroadcastService, BroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * Services that we require for the Shell @@ -293,6 +295,9 @@ export class WorkbenchShell { restoreFontInfo(this.storageService); readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getConfiguration('editor'), browser.getZoomLevel())); + // Hash + serviceCollection.set(IHashService, new SyncDescriptor(HashService)); + // Experiments this.experimentService = instantiationService.createInstance(ExperimentService); serviceCollection.set(IExperimentService, this.experimentService); diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index f84e67a1176..c6ac6973969 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -24,6 +24,7 @@ import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUt import { Verbosity } from 'vs/platform/editor/common/editor'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * A file editor input is the input type for the file editor of file system resources. @@ -47,7 +48,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextFileService private textFileService: ITextFileService, @IEnvironmentService private environmentService: IEnvironmentService, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); @@ -274,7 +276,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.getResource()); + descriptor['resource'] = telemetryURIDescriptor(this.getResource(), path => this.hashService.createSHA1(path)); /* __GDPR__FRAGMENT__ "EditorTelemetryDescriptor" : { diff --git a/src/vs/workbench/parts/html/common/htmlInput.ts b/src/vs/workbench/parts/html/common/htmlInput.ts index fe8955dc0c7..8338d4fd5b6 100644 --- a/src/vs/workbench/parts/html/common/htmlInput.ts +++ b/src/vs/workbench/parts/html/common/htmlInput.ts @@ -7,6 +7,7 @@ import URI from 'vs/base/common/uri'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export interface HtmlInputOptions { @@ -25,8 +26,9 @@ export class HtmlInput extends ResourceEditorInput { description: string, resource: URI, public readonly options: HtmlInputOptions, - @ITextModelService textModelResolverService: ITextModelService + @ITextModelService textModelResolverService: ITextModelService, + @IHashService hashService: IHashService ) { - super(name, description, resource, textModelResolverService); + super(name, description, resource, textModelResolverService, hashService); } } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 44875020629..910dcb09831 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -59,6 +59,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { MessageController } from 'vs/editor/contrib/message/messageController'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class PreferencesEditorInput extends SideBySideEditorInput { public static ID: string = 'workbench.editorinputs.preferencesEditorInput'; @@ -75,9 +76,10 @@ export class PreferencesEditorInput extends SideBySideEditorInput { export class DefaultPreferencesEditorInput extends ResourceEditorInput { public static ID = 'workbench.editorinputs.defaultpreferences'; constructor(defaultSettingsResource: URI, - @ITextModelService textModelResolverService: ITextModelService + @ITextModelService textModelResolverService: ITextModelService, + @IHashService hashService: IHashService ) { - super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService); + super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService, hashService); } getTypeId(): string { diff --git a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts index 98a5ffc7c8d..a534a77b13b 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts @@ -15,6 +15,7 @@ import { marked } from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class WalkThroughModel extends EditorModel { @@ -63,7 +64,8 @@ export class WalkThroughInput extends EditorInput { private options: WalkThroughInputOptions, @ITelemetryService private telemetryService: ITelemetryService, @ILifecycleService lifecycleService: ILifecycleService, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); this.disposables.push(lifecycleService.onShutdown(e => this.disposeTelemetry(e))); @@ -92,7 +94,7 @@ export class WalkThroughInput extends EditorInput { getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); descriptor['target'] = this.getTelemetryFrom(); - descriptor['resource'] = telemetryURIDescriptor(this.options.resource); + descriptor['resource'] = telemetryURIDescriptor(this.options.resource, path => this.hashService.createSHA1(path)); /* __GDPR__FRAGMENT__ "EditorTelemetryDescriptor" : { "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, diff --git a/src/vs/workbench/services/hash/common/hashService.ts b/src/vs/workbench/services/hash/common/hashService.ts new file mode 100644 index 00000000000..e8e2ee18d9d --- /dev/null +++ b/src/vs/workbench/services/hash/common/hashService.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IHashService = createDecorator('hashService'); + +export interface IHashService { + _serviceBrand: any; + + /** + * Produce a SHA1 hash of the provided content. + */ + createSHA1(content: string): string; +} \ No newline at end of file diff --git a/src/vs/workbench/services/hash/node/hashService.ts b/src/vs/workbench/services/hash/node/hashService.ts new file mode 100644 index 00000000000..fec0cab111f --- /dev/null +++ b/src/vs/workbench/services/hash/node/hashService.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createHash } from 'crypto'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; + +export class HashService implements IHashService { + + _serviceBrand: any; + + public createSHA1(content: string): string { + return createHash('sha1').update(content).digest('hex'); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts index 6f003bde491..a3f9d2f1c0f 100644 --- a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts @@ -16,7 +16,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { KeyCode, SimpleKeybinding, ChordKeybinding } from 'vs/base/common/keyCodes'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import extfs = require('vs/base/node/extfs'); -import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; +import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService, TestHashService } from 'vs/workbench/test/workbenchTestServices'; import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import uuid = require('vs/base/common/uuid'); import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; @@ -42,6 +42,7 @@ import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/comm import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; interface Modifiers { metaKey?: boolean; @@ -70,6 +71,7 @@ suite('Keybindings Editing', () => { instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { }); instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(ILifecycleService, new TestLifecycleService()); + instantiationService.stub(IHashService, new TestHashService()); instantiationService.stub(IEditorGroupService, new TestEditorGroupService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 10cc2553f19..6c3cd249763 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -31,9 +31,9 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { anonymize } from 'vs/platform/telemetry/common/telemetryUtils'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IRawTextSource } from 'vs/editor/common/model/textSource'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk. @@ -87,6 +87,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IBackupFileService private backupFileService: IBackupFileService, @IEnvironmentService private environmentService: IEnvironmentService, @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IHashService private hashService: IHashService ) { super(modelService, modeService); @@ -380,7 +381,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } } */ - this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: this.hashService.createSHA1(this.resource.fsPath) }); } return model; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b4d7d8cf3df..5a105e010f7 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -59,6 +59,7 @@ import { IRecentlyOpened } from 'vs/platform/history/common/history'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IPosition } from 'vs/editor/common/core/position'; import { ICommandAction } from 'vs/platform/actions/common/actions'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, void 0); @@ -259,6 +260,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(IEnvironmentService, TestEnvironmentService); instantiationService.stub(IThemeService, new TestThemeService()); + instantiationService.stub(IHashService, new TestHashService()); return instantiationService; } @@ -1223,4 +1225,12 @@ export class TestTextResourceConfigurationService implements ITextResourceConfig public getConfiguration(resource: any, position?: any, section?: any): any { return this.configurationService.getConfiguration(section, { resource }); } +} + +export class TestHashService implements IHashService { + _serviceBrand: any; + + createSHA1(content: string): string { + return content; + } } \ No newline at end of file From 91b9b413074d5b0d8fda330ba5c1ffb26e9d53d5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Oct 2017 11:57:32 +0200 Subject: [PATCH 302/303] Check for workspace existence - Extension host will not contain workspace object in empty workspace scenario --- .../services/configuration/common/configurationModels.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index fb32e490494..27c03b4821d 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -297,7 +297,7 @@ export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEv return true; } - if (resource) { + if (resource && this.workspace) { let workspaceFolder = this.workspace.getFolder(resource); if (workspaceFolder) { return this.configurationChangeEvent.affectsConfiguration(config, workspaceFolder.uri); From fd42d99117ad42239c90eb24ccf057e258926778 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Oct 2017 11:58:50 +0200 Subject: [PATCH 303/303] :lipstick: --- .../configuration/common/configuration.ts | 20 +++++++++---------- .../common/configurationModels.ts | 14 ++++++------- src/vs/workbench/api/node/extHost.protocol.ts | 6 +++--- .../common/configurationModels.ts | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 9da18eb08a4..0fb11cd76f5 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -37,17 +37,17 @@ export enum ConfigurationTarget { } export interface IConfigurationChangeEvent { - affectedKeys: string[]; + source: ConfigurationTarget; + affectedKeys: string[]; affectsConfiguration(configuration: string, resource?: URI): boolean; // Following data is used for telemetry - source: ConfigurationTarget; sourceConfig: any; // Following data is used for Extension host configuration event - changedConfiguration: IConfiguraionModel; - changedConfigurationByResource: StrictResourceMap; + changedConfiguration: IConfigurationModel; + changedConfigurationByResource: StrictResourceMap; } export interface IConfigurationService { @@ -90,7 +90,7 @@ export interface IConfigurationService { }; } -export interface IConfiguraionModel { +export interface IConfigurationModel { contents: any; keys: string[]; overrides: IOverrides[]; @@ -102,13 +102,13 @@ export interface IOverrides { } export interface IConfigurationData { - defaults: IConfiguraionModel; - user: IConfiguraionModel; - workspace: IConfiguraionModel; - folders: { [folder: string]: IConfiguraionModel }; + defaults: IConfigurationModel; + user: IConfigurationModel; + workspace: IConfigurationModel; + folders: { [folder: string]: IConfigurationModel }; } -export function compare(from: IConfiguraionModel, to: IConfiguraionModel): { added: string[], removed: string[], updated: string[] } { +export function compare(from: IConfigurationModel, to: IConfigurationModel): { added: string[], removed: string[], updated: string[] } { const added = to.keys.filter(key => from.keys.indexOf(key) === -1); const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); const updated = []; diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 3ce3d66a3cd..56ec4b29832 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -11,10 +11,10 @@ import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfiguraionModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; import { Workspace } from 'vs/platform/workspace/common/workspace'; -export class ConfigurationModel implements IConfiguraionModel { +export class ConfigurationModel implements IConfigurationModel { constructor(protected _contents: any = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { } @@ -134,7 +134,7 @@ export class ConfigurationModel implements IConfiguraionModel { return false; } - toJSON(): IConfiguraionModel { + toJSON(): IConfigurationModel { return { contents: this.contents, overrides: this.overrides, @@ -458,7 +458,7 @@ export class Configuration { return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap(), workspace); } - private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { + private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel { return new ConfigurationModel(model.contents, model.keys, model.overrides); } } @@ -501,7 +501,7 @@ export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChange return this._changedConfiguration; } - get changedConfigurationByResource(): StrictResourceMap { + get changedConfigurationByResource(): StrictResourceMap { return new StrictResourceMap(); } @@ -521,11 +521,11 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i super(); } - get changedConfiguration(): IConfiguraionModel { + get changedConfiguration(): IConfigurationModel { return this._changedConfiguration; } - get changedConfigurationByResource(): StrictResourceMap { + get changedConfigurationByResource(): StrictResourceMap { return this._changedConfigurationByResource; } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 4320e059494..a6c002ae30f 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -28,7 +28,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ITextSource } from 'vs/editor/common/model/textSource'; -import { IConfigurationData, ConfigurationTarget, IConfiguraionModel } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -78,8 +78,8 @@ export interface IInitData { } export interface IWorkspaceConfigurationChangeEventData { - changedConfiguration: IConfiguraionModel; - changedConfigurationByResource: { [folder: string]: IConfiguraionModel }; + changedConfiguration: IConfigurationModel; + changedConfigurationByResource: { [folder: string]: IConfigurationModel }; } export interface IExtHostContext { diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 27c03b4821d..69fd5bd628a 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfiguraionModel } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -272,11 +272,11 @@ export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEv constructor(private configurationChangeEvent: IConfigurationChangeEvent, private workspace: Workspace) { } - get changedConfiguration(): IConfiguraionModel { + get changedConfiguration(): IConfigurationModel { return this.configurationChangeEvent.changedConfiguration; } - get changedConfigurationByResource(): StrictResourceMap { + get changedConfigurationByResource(): StrictResourceMap { return this.configurationChangeEvent.changedConfigurationByResource; }