Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -2,9 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { Registry } from 'vs/platform/registry/common/platform';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands';
@@ -13,6 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
export const Extensions = {
WorkbenchActions: 'workbench.contributions.actions'
@@ -24,30 +23,29 @@ export interface IWorkbenchActionRegistry {
* Registers a workbench action to the platform. Workbench actions are not
* visible by default and can only be invoked through a keybinding if provided.
*/
registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable;
registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable;
}
Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionRegistry {
registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable {
return this._registerWorkbenchCommandFromAction(descriptor, alias, category);
registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable {
return this.registerWorkbenchCommandFromAction(descriptor, alias, category, when);
}
private _registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable {
private registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable {
let registrations: IDisposable[] = [];
// command
registrations.push(CommandsRegistry.registerCommand(descriptor.id, this._createCommandHandler(descriptor)));
registrations.push(CommandsRegistry.registerCommand(descriptor.id, this.createCommandHandler(descriptor)));
// keybinding
const when = descriptor.keybindingContext;
const weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingWeight.WorkbenchContrib : descriptor.keybindingWeight);
const keybindings = descriptor.keybindings;
KeybindingsRegistry.registerKeybindingRule({
id: descriptor.id,
weight: weight,
when: when,
primary: keybindings && keybindings.primary,
when: descriptor.keybindingContext,
primary: keybindings ? keybindings.primary : 0,
secondary: keybindings && keybindings.secondary,
win: keybindings && keybindings.win,
mac: keybindings && keybindings.mac,
@@ -74,7 +72,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR
MenuRegistry.addCommand(command);
registrations.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }));
registrations.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when }));
}
// TODO@alex,joh
@@ -83,21 +81,22 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR
return combinedDisposable(registrations);
}
private _createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler {
private createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler {
return (accessor, args) => {
const notificationService = accessor.get(INotificationService);
const instantiationService = accessor.get(IInstantiationService);
const lifecycleService = accessor.get(ILifecycleService);
TPromise.as(this._triggerAndDisposeAction(instantiationService, lifecycleService, descriptor, args)).then(null, err => {
Promise.resolve(this.triggerAndDisposeAction(instantiationService, lifecycleService, descriptor, args)).then(null, err => {
notificationService.error(err);
});
};
}
private _triggerAndDisposeAction(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: any): Thenable<void> {
private triggerAndDisposeAction(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: any): Thenable<void> {
// run action when workbench is created
return lifecycleService.when(LifecyclePhase.Running).then(() => {
return lifecycleService.when(LifecyclePhase.Ready).then(() => {
const actionInstance = instantiationService.createInstance(descriptor.syncDescriptor);
try {
actionInstance.label = descriptor.label || actionInstance.label;
@@ -111,15 +110,17 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR
const from = args && args.from || 'keybinding';
return TPromise.as(actionInstance.run(undefined, { from })).then(() => {
return Promise.resolve(actionInstance.run(undefined, { from })).then(() => {
actionInstance.dispose();
}, (err) => {
}, err => {
actionInstance.dispose();
return TPromise.wrapError(err);
return Promise.reject(err);
});
} catch (err) {
actionInstance.dispose();
return TPromise.wrapError(err);
return Promise.reject(err);
}
});
}

View File

@@ -2,80 +2,45 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Scope, Memento } from 'vs/workbench/common/memento';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Memento } from 'vs/workbench/common/memento';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Themable } from 'vs/workbench/common/theme';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
/**
* Base class of any core/ui component in the workbench. Examples include services, extensions, parts, viewlets and quick open.
* Provides some convinience methods to participate in the workbench lifecycle (dispose, shutdown) and
* loading and saving settings through memento.
*/
export interface IWorkbenchComponent extends IDisposable {
/**
* The unique identifier of this component.
*/
getId(): string;
/**
* Called when the browser containing the container is closed.
*
* Use this function to store settings that you want to restore next time. Should not be used to free resources
* because dispose() is being called for this purpose and shutdown() has a chance to be vetoed by the user.
*/
shutdown(): void;
}
export class Component extends Themable implements IWorkbenchComponent {
export class Component extends Themable {
private id: string;
private componentMemento: Memento;
private memento: Memento;
constructor(
id: string,
themeService: IThemeService
themeService: IThemeService,
storageService: IStorageService
) {
super(themeService);
this.id = id;
this.componentMemento = new Memento(this.id);
this.memento = new Memento(this.id, storageService);
this._register(storageService.onWillSaveState(() => {
// Ask the component to persist state into the memento
this.saveState();
// Then save the memento into storage
this.memento.saveMemento();
}));
}
getId(): string {
return this.id;
}
/**
* Returns a JSON Object that represents the data of this memento. The optional
* parameter scope allows to specify the scope of the memento to load. If not
* provided, the scope will be global, Scope.WORKSPACE can be used to
* scope the memento to the workspace.
*
* Mementos are shared across components with the same id. This means that multiple components
* with the same id will store data into the same data structure.
*/
protected getMemento(storageService: IStorageService, scope: Scope = Scope.GLOBAL): object {
return this.componentMemento.getMemento(storageService, scope);
protected getMemento(scope: StorageScope): object {
return this.memento.getMemento(scope);
}
/**
* Saves all data of the mementos that have been loaded to the local storage. This includes
* global and workspace scope.
*
* Mementos are shared across components with the same id. This means that multiple components
* with the same id will store data into the same data structure.
*/
protected saveMemento(): void {
this.componentMemento.saveMemento();
}
shutdown(): void {
// Save Memento
this.saveMemento();
protected saveState(): void {
// Subclasses to implement for storing state
}
}

View File

@@ -2,11 +2,11 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { runWhenIdle, IdleDeadline } from 'vs/base/common/async';
// --- Workbench Contribution Registry
@@ -39,7 +39,8 @@ export interface IWorkbenchContributionsRegistry {
start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void;
}
export class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry {
class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry {
private instantiationService: IInstantiationService;
private lifecycleService: ILifecycleService;
@@ -68,7 +69,7 @@ export class WorkbenchContributionsRegistry implements IWorkbenchContributionsRe
this.instantiationService = instantiationService;
this.lifecycleService = lifecycleService;
[LifecyclePhase.Starting, LifecyclePhase.Restoring, LifecyclePhase.Running, LifecyclePhase.Eventually].forEach(phase => {
[LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => {
this.instantiateByPhase(instantiationService, lifecycleService, phase);
});
}
@@ -91,11 +92,33 @@ export class WorkbenchContributionsRegistry implements IWorkbenchContributionsRe
private doInstantiateByPhase(instantiationService: IInstantiationService, phase: LifecyclePhase): void {
const toBeInstantiated = this.toBeInstantiated.get(phase);
if (toBeInstantiated) {
while (toBeInstantiated.length > 0) {
instantiationService.createInstance(toBeInstantiated.shift());
this.toBeInstantiated.delete(phase);
if (phase !== LifecyclePhase.Eventually) {
// instantiate everything synchronously and blocking
for (const ctor of toBeInstantiated) {
instantiationService.createInstance(ctor);
}
} else {
// for the Eventually-phase we instantiate contributions
// only when idle. this might take a few idle-busy-cycles
// but will finish within the timeouts
let forcedTimeout = 3000;
let i = 0;
let instantiateSome = (idle: IdleDeadline) => {
while (i < toBeInstantiated.length) {
const ctor = toBeInstantiated[i++];
instantiationService.createInstance(ctor);
if (idle.timeRemaining() < 1) {
// time is up -> reschedule
runWhenIdle(instantiateSome, forcedTimeout);
break;
}
}
};
runWhenIdle(instantiateSome, forcedTimeout);
}
}
}
}
Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry());
Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry());

View File

@@ -2,13 +2,12 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { Event, Emitter, once } from 'vs/base/common/event';
import * as objects from 'vs/base/common/objects';
import * as types from 'vs/base/common/types';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput } from 'vs/platform/editor/common/editor';
@@ -21,10 +20,12 @@ import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsSer
import { ICompositeControl } from 'vs/workbench/common/composite';
import { ActionRunner, IAction } from 'vs/base/common/actions';
export const ActiveEditorContext = new RawContextKey<string>('activeEditor', null);
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
export const EditorGroupActiveEditorDirtyContext = new RawContextKey<boolean>('groupActiveEditorDirty', false);
export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated();
export const TextCompareEditorVisibleContext = new RawContextKey<boolean>('textCompareEditorVisible', false);
export const TextCompareEditorActiveContext = new RawContextKey<boolean>('textCompareEditorActive', false);
export const ActiveEditorGroupEmptyContext = new RawContextKey<boolean>('activeEditorGroupEmpty', false);
export const MultipleEditorGroupsContext = new RawContextKey<boolean>('multipleEditorGroups', false);
export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated();
@@ -247,7 +248,7 @@ export interface IResourceSideBySideInput extends IBaseResourceInput {
detailResource: URI;
}
export enum Verbosity {
export const enum Verbosity {
SHORT,
MEDIUM,
LONG
@@ -278,6 +279,11 @@ export interface IEditorInput extends IDisposable {
*/
getResource(): URI;
/**
* Unique type identifier for this inpput.
*/
getTypeId(): string;
/**
* Returns the display name of this input.
*/
@@ -296,7 +302,7 @@ export interface IEditorInput extends IDisposable {
/**
* Resolves the input.
*/
resolve(): TPromise<IEditorModel>;
resolve(): Thenable<IEditorModel>;
/**
* Returns if this input is dirty or not.
@@ -397,7 +403,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
* Returns a type of EditorModel that represents the resolved input. Subclasses should
* override to provide a meaningful model.
*/
abstract resolve(): TPromise<IEditorModel>;
abstract resolve(): Thenable<IEditorModel>;
/**
* An editor that is dirty will be asked to be saved once it closes.
@@ -478,13 +484,13 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
}
}
export enum ConfirmResult {
export const enum ConfirmResult {
SAVE,
DONT_SAVE,
CANCEL
}
export enum EncodingMode {
export const enum EncodingMode {
/**
* Instructs the encoding support to encode the current input with the provided encoding
@@ -591,8 +597,8 @@ export class SideBySideEditorInput extends EditorInput {
this._register(this.master.onDidChangeLabel(() => this._onDidChangeLabel.fire()));
}
resolve(): TPromise<EditorModel> {
return TPromise.as(null);
resolve(): Thenable<EditorModel> {
return Promise.resolve(null);
}
getTypeId(): string {
@@ -642,8 +648,8 @@ export class EditorModel extends Disposable implements IEditorModel {
/**
* Causes this model to load returning a promise when loading is completed.
*/
load(): TPromise<EditorModel> {
return TPromise.as(this);
load(): Thenable<EditorModel> {
return Promise.resolve(this);
}
/**
@@ -921,7 +927,7 @@ export class EditorCommandsContextActionRunner extends ActionRunner {
super();
}
run(action: IAction, context?: any): TPromise<void> {
run(action: IAction, context?: any): Thenable<void> {
return super.run(action, this.context);
}
}
@@ -942,6 +948,7 @@ export interface IWorkbenchEditorConfiguration {
export interface IWorkbenchEditorPartConfiguration {
showTabs?: boolean;
highlightModifiedTabs?: boolean;
tabCloseButton?: 'left' | 'right' | 'off';
tabSizing?: 'fit' | 'shrink';
showIcons?: boolean;
@@ -954,6 +961,7 @@ export interface IWorkbenchEditorPartConfiguration {
revealIfOpen?: boolean;
swipeToNavigate?: boolean;
labelFormat?: 'default' | 'short' | 'medium' | 'long';
restoreViewState?: boolean;
}
export interface IResourceOptions {
@@ -1001,21 +1009,21 @@ export function toResource(editor: IEditorInput, options?: IResourceOptions): UR
return null;
}
export enum CloseDirection {
export const enum CloseDirection {
LEFT,
RIGHT
}
export interface IEditorMemento<T> {
saveState(group: IEditorGroup, resource: URI, state: T): void;
saveState(group: IEditorGroup, editor: EditorInput, state: T): void;
saveEditorState(group: IEditorGroup, resource: URI, state: T): void;
saveEditorState(group: IEditorGroup, editor: EditorInput, state: T): void;
loadState(group: IEditorGroup, resource: URI): T;
loadState(group: IEditorGroup, editor: EditorInput): T;
loadEditorState(group: IEditorGroup, resource: URI): T;
loadEditorState(group: IEditorGroup, editor: EditorInput): T;
clearState(resource: URI): void;
clearState(editor: EditorInput): void;
clearEditorState(resource: URI, group?: IEditorGroup): void;
clearEditorState(editor: EditorInput, group?: IEditorGroup): void;
}
class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry {

View File

@@ -2,14 +2,12 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorModel } from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { Schemas } from 'vs/base/common/network';
import { DataUri } from 'vs/workbench/common/resources';
import { DataUri } from 'vs/base/common/resources';
/**
* An editor model that just represents a resource that can be loaded.
@@ -76,7 +74,7 @@ export class BinaryEditorModel extends EditorModel {
return this.etag;
}
load(): TPromise<EditorModel> {
load(): Thenable<EditorModel> {
// Make sure to resolve up to date stat for file resources
if (this.fileService.canHandleResource(this.resource)) {
@@ -88,6 +86,6 @@ export class BinaryEditorModel extends EditorModel {
});
}
return TPromise.wrap(this);
return Promise.resolve(this);
}
}
}

View File

@@ -3,14 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorInput } from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
import { DataUri } from 'vs/workbench/common/resources';
import { DataUri } from 'vs/base/common/resources';
/**
* An editor input to present data URIs in a binary editor. Data URIs have the form of:
@@ -65,7 +62,7 @@ export class DataUriEditorInput extends EditorInput {
return this.description;
}
resolve(): TPromise<BinaryEditorModel> {
resolve(): Thenable<BinaryEditorModel> {
return this.instantiationService.createInstance(BinaryEditorModel, this.resource, this.getName()).load().then(m => m as BinaryEditorModel);
}

View File

@@ -2,9 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorModel, EditorInput, SideBySideEditorInput, TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel';
@@ -36,7 +34,7 @@ export class DiffEditorInput extends SideBySideEditorInput {
return this.master;
}
resolve(): TPromise<EditorModel> {
resolve(): Thenable<EditorModel> {
// Create Model - we never reuse our cached model if refresh is true because we cannot
// decide for the inputs within if the cached model can be reused or not. There may be
@@ -57,10 +55,10 @@ export class DiffEditorInput extends SideBySideEditorInput {
return this.forceOpenAsBinary ? BINARY_DIFF_EDITOR_ID : TEXT_DIFF_EDITOR_ID;
}
private createModel(refresh?: boolean): TPromise<DiffEditorModel> {
private createModel(): Thenable<DiffEditorModel> {
// Join resolve call over two inputs and build diff editor model
return TPromise.join([
return Promise.all([
this.originalInput.resolve(),
this.modifiedInput.resolve()
]).then(models => {

View File

@@ -2,9 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorModel } from 'vs/workbench/common/editor';
import { IEditorModel } from 'vs/platform/editor/common/editor';
@@ -31,13 +29,11 @@ export class DiffEditorModel extends EditorModel {
return this._modifiedModel as EditorModel;
}
load(): TPromise<EditorModel> {
return TPromise.join([
load(): Thenable<EditorModel> {
return Promise.all([
this._originalModel.load(),
this._modifiedModel.load()
]).then(() => {
return this;
});
]).then(() => this);
}
isResolved(): boolean {

View File

@@ -3,11 +3,9 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Event, Emitter, once } from 'vs/base/common/event';
import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection } from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
@@ -632,13 +630,13 @@ export class EditorGroup extends Disposable {
editors.forEach(e => {
let factory = registry.getEditorInputFactory(e.getTypeId());
if (factory) {
// {{SQL CARBON EDIT}}
// don't serialize unmodified unitited files
if (e instanceof UntitledEditorInput && !e.isDirty()
&& !this.configurationService.getValue<boolean>('sql.promptToSaveGeneratedFiles')) {
return;
}
// {{SQL CARBON EDIT}} - End
let value = factory.serialize(e);
if (typeof value === 'string') {

View File

@@ -2,11 +2,10 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorInput, ITextEditorModel } from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IReference } from 'vs/base/common/lifecycle';
import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
@@ -82,7 +81,7 @@ export class ResourceEditorInput extends EditorInput {
return descriptor;
}
resolve(): TPromise<ITextEditorModel> {
resolve(): Thenable<ITextEditorModel> {
if (!this.modelReference) {
this.modelReference = this.textModelResolverService.createModelReference(this.resource);
}
@@ -94,7 +93,7 @@ export class ResourceEditorInput extends EditorInput {
ref.dispose();
this.modelReference = null;
return TPromise.wrapError<ITextEditorModel>(new Error(`Unexpected model for ResourceInput: ${this.resource}`));
return Promise.reject(new Error(`Unexpected model for ResourceInput: ${this.resource}`));
}
return model;
@@ -118,7 +117,7 @@ export class ResourceEditorInput extends EditorInput {
dispose(): void {
if (this.modelReference) {
this.modelReference.done(ref => ref.dispose());
this.modelReference.then(ref => ref.dispose());
this.modelReference = null;
}

View File

@@ -2,10 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';

View File

@@ -2,9 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDiffEditorModel } from 'vs/editor/common/editorCommon';
import { EditorModel } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
@@ -31,7 +29,7 @@ export class TextDiffEditorModel extends DiffEditorModel {
return this._modifiedModel as BaseTextEditorModel;
}
load(): TPromise<EditorModel> {
load(): Thenable<EditorModel> {
return super.load().then(() => {
this.updateTextDiffEditorModel();

View File

@@ -2,15 +2,13 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITextModel, ITextBufferFactory } from 'vs/editor/common/model';
import { IMode } from 'vs/editor/common/modes';
import { EditorModel } from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ITextSnapshot } from 'vs/platform/files/common/files';
@@ -73,21 +71,22 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
*/
protected createTextEditorModel(value: ITextBufferFactory, resource?: URI, modeId?: string): TPromise<EditorModel> {
const firstLineText = this.getFirstLineText(value);
const mode = this.getOrCreateMode(this.modeService, modeId, firstLineText);
return TPromise.as(this.doCreateTextEditorModel(value, mode, resource));
const languageSelection = this.getOrCreateMode(this.modeService, modeId, firstLineText);
return TPromise.as(this.doCreateTextEditorModel(value, languageSelection, resource));
}
private doCreateTextEditorModel(value: ITextBufferFactory, mode: TPromise<IMode>, resource: URI): EditorModel {
private doCreateTextEditorModel(value: ITextBufferFactory, languageSelection: ILanguageSelection, resource: URI): EditorModel {
let model = resource && this.modelService.getModel(resource);
if (!model) {
model = this.modelService.createModel(value, mode, resource);
model = this.modelService.createModel(value, languageSelection, resource);
this.createdEditorModel = true;
// Make sure we clean up when this model gets disposed
this.registerModelDisposeListener(model);
} else {
this.modelService.updateModel(model, value);
this.modelService.setMode(model, mode);
this.modelService.setMode(model, languageSelection);
}
this.textEditorModelHandle = model.uri;
@@ -113,8 +112,8 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
*
* @param firstLineText optional first line of the text buffer to set the mode on. This can be used to guess a mode from content.
*/
protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): TPromise<IMode> {
return modeService.getOrCreateMode(modeId);
protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection {
return modeService.create(modeId);
}
/**

View File

@@ -2,10 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. 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 { URI } from 'vs/base/common/uri';
import { suggestFilename } from 'vs/base/common/mime';
import { memoize } from 'vs/base/common/decorators';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
@@ -18,7 +17,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils';
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { ILabelService } from 'vs/platform/label/common/label';
/**
* An editor input to be used for untitled text buffers.
@@ -46,7 +45,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
@IInstantiationService private instantiationService: IInstantiationService,
@ITextFileService private textFileService: ITextFileService,
@IHashService private hashService: IHashService,
@IUriDisplayService private uriDisplayService: IUriDisplayService
@ILabelService private labelService: ILabelService
) {
super();
@@ -79,17 +78,17 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
@memoize
private get shortDescription(): string {
return paths.basename(this.uriDisplayService.getLabel(resources.dirname(this.resource)));
return paths.basename(this.labelService.getUriLabel(resources.dirname(this.resource)));
}
@memoize
private get mediumDescription(): string {
return this.uriDisplayService.getLabel(resources.dirname(this.resource), true);
return this.labelService.getUriLabel(resources.dirname(this.resource), { relative: true });
}
@memoize
private get longDescription(): string {
return this.uriDisplayService.getLabel(resources.dirname(this.resource));
return this.labelService.getUriLabel(resources.dirname(this.resource));
}
getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string {
@@ -121,12 +120,12 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
@memoize
private get mediumTitle(): string {
return this.uriDisplayService.getLabel(this.resource, true);
return this.labelService.getUriLabel(this.resource, { relative: true });
}
@memoize
private get longTitle(): string {
return this.uriDisplayService.getLabel(this.resource);
return this.labelService.getUriLabel(this.resource);
}
getTitle(verbosity: Verbosity): string {
@@ -216,7 +215,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
}
}
resolve(): TPromise<UntitledEditorModel> {
resolve(): Thenable<UntitledEditorModel> {
// Join a model resolve if we have had one before
if (this.modelResolve) {

View File

@@ -2,17 +2,14 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IEncodingSupport } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IMode } from 'vs/editor/common/modes';
import { Event, Emitter } from 'vs/base/common/event';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
@@ -59,9 +56,9 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
this.registerListeners();
}
protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): TPromise<IMode> {
protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection {
if (!modeId || modeId === PLAINTEXT_MODE_ID) {
return modeService.getOrCreateModeByFilenameOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific
return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific
}
return super.getOrCreateMode(modeService, modeId, firstLineText);
@@ -137,7 +134,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
this.contentChangeEventScheduler.schedule();
}
load(): TPromise<UntitledEditorModel> {
load(): Thenable<UntitledEditorModel> {
// Check for backups first
return this.backupFileService.loadBackupResource(this.resource).then(backupResource => {
@@ -160,6 +157,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
}
return this.doLoad(untitledContents).then(model => {
// Encoding
this.configuredEncoding = this.configurationService.getValue<string>(this.resource, 'files.encoding');
@@ -174,7 +172,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
});
}
private doLoad(content: ITextBufferFactory): TPromise<UntitledEditorModel> {
private doLoad(content: ITextBufferFactory): Thenable<UntitledEditorModel> {
// Create text editor model if not yet done
if (!this.textEditorModel) {
@@ -186,7 +184,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
this.updateTextEditorModel(content);
}
return TPromise.as<UntitledEditorModel>(this);
return Promise.resolve<UntitledEditorModel>(this);
}
private onModelContentChanged(): void {

View File

@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const enum MessageType {
Initialized,
Ready,
Terminate
}
export function createMessageOfType(type: MessageType): Buffer {
const result = Buffer.allocUnsafe(1);
switch (type) {
case MessageType.Initialized: result.writeUInt8(1, 0); break;
case MessageType.Ready: result.writeUInt8(2, 0); break;
case MessageType.Terminate: result.writeUInt8(3, 0); break;
}
return result;
}
export function isMessageOfType(message: Buffer, type: MessageType): boolean {
if (message.length !== 1) {
return false;
}
switch (message.readUInt8(0)) {
case 1: return type === MessageType.Initialized;
case 2: return type === MessageType.Ready;
case 3: return type === MessageType.Terminate;
default: return false;
}
}

View File

@@ -2,111 +2,75 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as types from 'vs/base/common/types';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { isEmptyObject } from 'vs/base/common/types';
/**
* Supported memento scopes.
*/
export enum Scope {
/**
* The memento will be scoped to all workspaces of this domain.
*/
GLOBAL,
/**
* The memento will be scoped to the current workspace.
*/
WORKSPACE
}
/**
* A memento provides access to a datastructure that is persisted and restored as part of the workbench lifecycle.
*/
export class Memento {
// Mementos are static to ensure that for a given component with an id only ever one memento gets loaded
private static globalMementos: { [id: string]: ScopedMemento } = {};
private static workspaceMementos: { [id: string]: ScopedMemento } = {};
private static globalMementos: { [id: string]: ScopedMemento } = Object.create(null);
private static workspaceMementos: { [id: string]: ScopedMemento } = Object.create(null);
private static readonly COMMON_PREFIX = 'memento/';
private id: string;
constructor(id: string) {
this.id = Memento.COMMON_PREFIX + id.toLowerCase();
constructor(id: string, private storageService: IStorageService) {
this.id = Memento.COMMON_PREFIX + id;
}
/**
* Returns a JSON Object that represents the data of this memento. The optional
* parameter scope allows to specify the scope of the memento to load. If not
* provided, the scope will be global, Memento.Scope.WORKSPACE can be used to
* scope the memento to the workspace.
*/
getMemento(storageService: IStorageService, scope: Scope = Scope.GLOBAL): object {
getMemento(scope: StorageScope): object {
// Scope by Workspace
if (scope === Scope.WORKSPACE) {
if (scope === StorageScope.WORKSPACE) {
let workspaceMemento = Memento.workspaceMementos[this.id];
if (!workspaceMemento) {
workspaceMemento = new ScopedMemento(this.id, scope, storageService);
workspaceMemento = new ScopedMemento(this.id, scope, this.storageService);
Memento.workspaceMementos[this.id] = workspaceMemento;
}
return workspaceMemento.getMemento();
}
// Use global scope
// Scope Global
let globalMemento = Memento.globalMementos[this.id];
if (!globalMemento) {
globalMemento = new ScopedMemento(this.id, scope, storageService);
globalMemento = new ScopedMemento(this.id, scope, this.storageService);
Memento.globalMementos[this.id] = globalMemento;
}
return globalMemento.getMemento();
}
/**
* Saves all data of the mementos that have been loaded to the local storage. This includes
* global and workspace scope.
*/
saveMemento(): void {
// Global
const globalMemento = Memento.globalMementos[this.id];
if (globalMemento) {
globalMemento.save();
}
// Workspace
const workspaceMemento = Memento.workspaceMementos[this.id];
if (workspaceMemento) {
workspaceMemento.save();
}
// Global
const globalMemento = Memento.globalMementos[this.id];
if (globalMemento) {
globalMemento.save();
}
}
}
class ScopedMemento {
private id: string;
private mementoObj: object;
private scope: Scope;
constructor(id: string, scope: Scope, private storageService: IStorageService) {
this.id = id;
this.scope = scope;
this.mementoObj = this.loadMemento();
constructor(private id: string, private scope: StorageScope, private storageService: IStorageService) {
this.mementoObj = this.load();
}
getMemento(): object {
return this.mementoObj;
}
private loadMemento(): object {
let storageScope = this.scope === Scope.GLOBAL ? StorageScope.GLOBAL : StorageScope.WORKSPACE;
let memento = this.storageService.get(this.id, storageScope);
private load(): object {
const memento = this.storageService.get(this.id, this.scope);
if (memento) {
return JSON.parse(memento);
}
@@ -115,12 +79,10 @@ class ScopedMemento {
}
save(): void {
let storageScope = this.scope === Scope.GLOBAL ? StorageScope.GLOBAL : StorageScope.WORKSPACE;
if (!types.isEmptyObject(this.mementoObj)) {
this.storageService.store(this.id, JSON.stringify(this.mementoObj), storageScope);
if (!isEmptyObject(this.mementoObj)) {
this.storageService.store(this.id, JSON.stringify(this.mementoObj), this.scope);
} else {
this.storageService.remove(this.id, storageScope);
this.storageService.remove(this.id, this.scope);
}
}
}

View File

@@ -3,13 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage } from 'vs/platform/notification/common/notification';
import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice } from 'vs/platform/notification/common/notification';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Event, Emitter, once } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { isPromiseCanceledError, isErrorWithActions } from 'vs/base/common/errors';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { Action } from 'vs/base/common/actions';
import { isErrorWithActions } from 'vs/base/common/errorsWithActions';
export interface INotificationsModel {
@@ -19,7 +19,7 @@ export interface INotificationsModel {
notify(notification: INotification): INotificationHandle;
}
export enum NotificationChangeType {
export const enum NotificationChangeType {
ADD,
CHANGE,
REMOVE
@@ -125,7 +125,7 @@ export class NotificationsModel extends Disposable implements INotificationsMode
}
}
private findNotification(item: INotificationViewItem): INotificationViewItem {
private findNotification(item: INotificationViewItem): INotificationViewItem | undefined {
for (let i = 0; i < this._notifications.length; i++) {
const notification = this._notifications[i];
if (notification.equals(item)) {
@@ -136,7 +136,7 @@ export class NotificationsModel extends Disposable implements INotificationsMode
return void 0;
}
private createViewItem(notification: INotification): INotificationViewItem {
private createViewItem(notification: INotification): INotificationViewItem | null {
const item = NotificationViewItem.create(notification);
if (!item) {
return null;
@@ -177,8 +177,10 @@ export class NotificationsModel extends Disposable implements INotificationsMode
export interface INotificationViewItem {
readonly severity: Severity;
readonly sticky: boolean;
readonly silent: boolean;
readonly message: INotificationMessage;
readonly source: string;
readonly source: string | undefined;
readonly actions: INotificationActions;
readonly progress: INotificationViewItemProgress;
@@ -194,6 +196,7 @@ export interface INotificationViewItem {
toggle(): void;
hasProgress(): boolean;
hasPrompt(): boolean;
updateSeverity(severity: Severity): void;
updateMessage(message: NotificationMessage): void;
@@ -201,14 +204,14 @@ export interface INotificationViewItem {
close(): void;
equals(item: INotificationViewItem);
equals(item: INotificationViewItem): boolean;
}
export function isNotificationViewItem(obj: any): obj is INotificationViewItem {
return obj instanceof NotificationViewItem;
}
export enum NotificationViewItemLabelKind {
export const enum NotificationViewItemLabelKind {
SEVERITY,
MESSAGE,
ACTIONS,
@@ -339,7 +342,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
private readonly _onDidLabelChange: Emitter<INotificationViewItemLabelChangeEvent> = this._register(new Emitter<INotificationViewItemLabelChangeEvent>());
get onDidLabelChange(): Event<INotificationViewItemLabelChangeEvent> { return this._onDidLabelChange.event; }
static create(notification: INotification): INotificationViewItem {
static create(notification: INotification): INotificationViewItem | null {
if (!notification || !notification.message || isPromiseCanceledError(notification.message)) {
return null; // we need a message to show
}
@@ -356,19 +359,18 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return null; // we need a message to show
}
let actions: INotificationActions;
let actions: INotificationActions | undefined;
if (notification.actions) {
actions = notification.actions;
} else if (isErrorWithActions(notification.message)) {
actions = { primary: notification.message.actions };
}
return new NotificationViewItem(severity, message, notification.source, actions);
return new NotificationViewItem(severity, notification.sticky, notification.silent, message, notification.source, actions);
}
private static parseNotificationMessage(input: NotificationMessage): INotificationMessage {
let message: string;
private static parseNotificationMessage(input: NotificationMessage): INotificationMessage | undefined {
let message: string | undefined;
if (input instanceof Error) {
message = toErrorMessage(input, false);
} else if (typeof input === 'string') {
@@ -376,7 +378,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
}
if (!message) {
return null; // we need a message to show
return void 0; // we need a message to show
}
const raw = message;
@@ -397,21 +399,23 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return matchString;
});
return { raw, value: message, links, original: input };
}
private constructor(private _severity: Severity, private _message: INotificationMessage, private _source: string, actions?: INotificationActions) {
private constructor(
private _severity: Severity,
private _sticky: boolean | undefined,
private _silent: boolean | undefined,
private _message: INotificationMessage,
private _source: string | undefined,
actions?: INotificationActions
) {
super();
this.setActions(actions);
}
private setActions(actions: INotificationActions): void {
if (!actions) {
actions = { primary: [], secondary: [] };
}
private setActions(actions: INotificationActions = { primary: [], secondary: [] }): void {
if (!Array.isArray(actions.primary)) {
actions.primary = [];
}
@@ -425,7 +429,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
}
get canCollapse(): boolean {
return this._actions.primary.length === 0;
return !this.hasPrompt();
}
get expanded(): boolean {
@@ -436,6 +440,35 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return this._severity;
}
get sticky(): boolean {
if (this._sticky) {
return true; // explicitly sticky
}
const hasPrompt = this.hasPrompt();
if (
(hasPrompt && this._severity === Severity.Error) || // notification errors with actions are sticky
(!hasPrompt && this._expanded) || // notifications that got expanded are sticky
(this._progress && !this._progress.state.done) // notifications with running progress are sticky
) {
return true;
}
return false; // not sticky
}
get silent(): boolean {
return !!this._silent;
}
hasPrompt(): boolean {
if (!this._actions.primary) {
return false;
}
return this._actions.primary.length > 0;
}
hasProgress(): boolean {
return !!this._progress;
}
@@ -453,7 +486,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return this._message;
}
get source(): string {
get source(): string | undefined {
return this._source;
}
@@ -526,13 +559,13 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return false;
}
const primaryActions = this._actions.primary;
const otherPrimaryActions = other.actions.primary;
if (primaryActions.length !== otherPrimaryActions.length) {
if (this._message.value !== other.message.value) {
return false;
}
if (this._message.value !== other.message.value) {
const primaryActions = this._actions.primary || [];
const otherPrimaryActions = other.actions.primary || [];
if (primaryActions.length !== otherPrimaryActions.length) {
return false;
}
@@ -544,4 +577,37 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return true;
}
}
export class ChoiceAction extends Action {
private _onDidRun = new Emitter<void>();
get onDidRun(): Event<void> { return this._onDidRun.event; }
private _keepOpen: boolean;
constructor(id: string, choice: IPromptChoice) {
super(id, choice.label, void 0, true, () => {
// Pass to runner
choice.run();
// Emit Event
this._onDidRun.fire();
return Promise.resolve(void 0);
});
this._keepOpen = !!choice.keepOpen;
}
get keepOpen(): boolean {
return this._keepOpen;
}
dispose(): void {
super.dispose();
this._onDidRun.dispose();
}
}

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IComposite } from 'vs/workbench/common/composite';

View File

@@ -3,14 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
export class ResourceContextKey implements IContextKey<URI> {
export class ResourceContextKey extends Disposable implements IContextKey<URI> {
static Scheme = new RawContextKey<string>('resourceScheme', undefined);
static Filename = new RawContextKey<string>('resourceFilename', undefined);
@@ -18,33 +19,52 @@ export class ResourceContextKey implements IContextKey<URI> {
static Resource = new RawContextKey<URI>('resource', undefined);
static Extension = new RawContextKey<string>('resourceExtname', undefined);
static HasResource = new RawContextKey<boolean>('resourceSet', false);
static IsFileSystemResource = new RawContextKey<boolean>('isFileSystemResource', false);
static IsFileSystemResourceOrUntitled = new RawContextKey<boolean>('isFileSystemResourceOrUntitled', false);
private _resourceKey: IContextKey<URI>;
private _schemeKey: IContextKey<string>;
private _filenameKey: IContextKey<string>;
private _langIdKey: IContextKey<string>;
private _extensionKey: IContextKey<string>;
private _hasResource: IContextKey<boolean>;
private readonly _resourceKey: IContextKey<URI>;
private readonly _schemeKey: IContextKey<string>;
private readonly _filenameKey: IContextKey<string>;
private readonly _langIdKey: IContextKey<string | null>;
private readonly _extensionKey: IContextKey<string>;
private readonly _hasResource: IContextKey<boolean>;
private readonly _isFileSystemResource: IContextKey<boolean>;
private readonly _isFileSystemResourceOrUntitled: IContextKey<boolean>;
constructor(
@IContextKeyService contextKeyService: IContextKeyService,
@IFileService private readonly _fileService: IFileService,
@IModeService private readonly _modeService: IModeService
) {
super();
this._schemeKey = ResourceContextKey.Scheme.bindTo(contextKeyService);
this._filenameKey = ResourceContextKey.Filename.bindTo(contextKeyService);
this._langIdKey = ResourceContextKey.LangId.bindTo(contextKeyService);
this._resourceKey = ResourceContextKey.Resource.bindTo(contextKeyService);
this._extensionKey = ResourceContextKey.Extension.bindTo(contextKeyService);
this._hasResource = ResourceContextKey.HasResource.bindTo(contextKeyService);
this._isFileSystemResource = ResourceContextKey.IsFileSystemResource.bindTo(contextKeyService);
this._isFileSystemResourceOrUntitled = ResourceContextKey.IsFileSystemResourceOrUntitled.bindTo(contextKeyService);
this._register(_fileService.onDidChangeFileSystemProviderRegistrations(() => {
const resource = this._resourceKey.get();
this._isFileSystemResource.set(Boolean(resource && _fileService.canHandleResource(resource)));
this._isFileSystemResourceOrUntitled.set(this._isFileSystemResource.get() || this._schemeKey.get() === Schemas.untitled);
}));
}
set(value: URI) {
this._resourceKey.set(value);
this._schemeKey.set(value && value.scheme);
this._filenameKey.set(value && paths.basename(value.fsPath));
this._langIdKey.set(value && this._modeService.getModeIdByFilenameOrFirstLine(value.fsPath));
this._extensionKey.set(value && paths.extname(value.fsPath));
this._hasResource.set(!!value);
if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) {
this._resourceKey.set(value);
this._schemeKey.set(value && value.scheme);
this._filenameKey.set(value && paths.basename(value.fsPath));
this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value.fsPath) : null);
this._extensionKey.set(value && paths.extname(value.fsPath));
this._hasResource.set(!!value);
this._isFileSystemResource.set(value && this._fileService.canHandleResource(value));
this._isFileSystemResourceOrUntitled.set(this._isFileSystemResource.get() || this._schemeKey.get() === Schemas.untitled);
}
}
reset(): void {
@@ -54,43 +74,26 @@ export class ResourceContextKey implements IContextKey<URI> {
this._langIdKey.reset();
this._extensionKey.reset();
this._hasResource.reset();
this._isFileSystemResource.reset();
this._isFileSystemResourceOrUntitled.reset();
}
get(): URI {
get(): URI | undefined {
return this._resourceKey.get();
}
}
/**
* Data URI related helpers.
*/
export namespace DataUri {
export const META_DATA_LABEL = 'label';
export const META_DATA_DESCRIPTION = 'description';
export const META_DATA_SIZE = 'size';
export const META_DATA_MIME = 'mime';
export function parseMetaData(dataUri: URI): Map<string, string> {
const metadata = new Map<string, string>();
// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...
// the metadata is: size:2313;label:SomeLabel;description:SomeDescription
const meta = dataUri.path.substring(dataUri.path.indexOf(';') + 1, dataUri.path.lastIndexOf(';'));
meta.split(';').forEach(property => {
const [key, value] = property.split(':');
if (key && value) {
metadata.set(key, value);
}
});
// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...
// the mime is: image/png
const mime = dataUri.path.substring(0, dataUri.path.indexOf(';'));
if (mime) {
metadata.set(META_DATA_MIME, mime);
private static _uriEquals(a: URI | undefined | null, b: URI | undefined | null): boolean {
if (a === b) {
return true;
}
return metadata;
if (!a || !b) {
return false;
}
return a.scheme === b.scheme // checks for not equals (fail fast)
&& a.authority === b.authority
&& a.path === b.path
&& a.query === b.query
&& a.fragment === b.fragment
&& a.toString() === b.toString(); // for equal we use the normalized toString-form
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, listActiveSelectionForeground, listActiveSelectionBackground } from 'vs/platform/theme/common/colorRegistry';
import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { Disposable } from 'vs/base/common/lifecycle';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { Color } from 'vs/base/common/color';
@@ -60,24 +60,48 @@ export const TAB_ACTIVE_BORDER = registerColor('tab.activeBorder', {
hc: null
}, nls.localize('tabActiveBorder', "Border on the bottom of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_ACTIVE_BORDER_TOP = registerColor('tab.activeBorderTop', {
dark: null,
light: null,
hc: null
}, nls.localize('tabActiveBorderTop', "Border to the top of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_UNFOCUSED_ACTIVE_BORDER = registerColor('tab.unfocusedActiveBorder', {
dark: transparent(TAB_ACTIVE_BORDER, 0.5),
light: transparent(TAB_ACTIVE_BORDER, 0.7),
hc: null
}, nls.localize('tabActiveUnfocusedBorder', "Border on the bottom of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_ACTIVE_BORDER_TOP = registerColor('tab.activeBorderTop', {
dark: null,
light: null,
hc: null
}, nls.localize('tabActiveBorderTop', "Border to the top of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_UNFOCUSED_ACTIVE_BORDER_TOP = registerColor('tab.unfocusedActiveBorderTop', {
dark: transparent(TAB_ACTIVE_BORDER_TOP, 0.5),
light: transparent(TAB_ACTIVE_BORDER_TOP, 0.7),
hc: null
}, nls.localize('tabActiveUnfocusedBorderTop', "Border to the top of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_ACTIVE_MODIFIED_BORDER = registerColor('tab.activeModifiedBorder', {
dark: '#3399CC',
light: '#33AAEE',
hc: null
}, nls.localize('tabActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_INACTIVE_MODIFIED_BORDER = registerColor('tab.inactiveModifiedBorder', {
dark: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5),
light: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5),
hc: Color.white
}, nls.localize('tabInactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_UNFOCUSED_ACTIVE_MODIFIED_BORDER = registerColor('tab.unfocusedActiveModifiedBorder', {
dark: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5),
light: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.7),
hc: Color.white
}, nls.localize('unfocusedActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_UNFOCUSED_INACTIVE_MODIFIED_BORDER = registerColor('tab.unfocusedInactiveModifiedBorder', {
dark: transparent(TAB_INACTIVE_MODIFIED_BORDER, 0.5),
light: transparent(TAB_INACTIVE_MODIFIED_BORDER, 0.5),
hc: Color.white
}, nls.localize('unfocusedINactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
export const TAB_HOVER_BORDER = registerColor('tab.hoverBorder', {
dark: null,
light: null,
@@ -98,7 +122,7 @@ export const TAB_ACTIVE_FOREGROUND = registerColor('tab.activeForeground', {
export const TAB_INACTIVE_FOREGROUND = registerColor('tab.inactiveForeground', {
dark: transparent(TAB_ACTIVE_FOREGROUND, 0.5),
light: transparent(TAB_ACTIVE_FOREGROUND, 0.5),
light: transparent(TAB_ACTIVE_FOREGROUND, 0.7),
hc: Color.white
}, nls.localize('tabInactiveForeground', "Inactive tab foreground color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups."));
@@ -117,6 +141,12 @@ export const TAB_UNFOCUSED_INACTIVE_FOREGROUND = registerColor('tab.unfocusedIna
// < --- Editors --- >
export const EDITOR_PANE_BACKGROUND = registerColor('editorPane.background', {
dark: editorBackground,
light: editorBackground,
hc: editorBackground
}, nls.localize('editorPaneBackground', "Background color of the editor pane visible on the left and right side of the centered editor layout."));
registerColor('editorGroup.background', {
dark: null,
light: null,
@@ -282,7 +312,13 @@ export const ACTIVITY_BAR_FOREGROUND = registerColor('activityBar.foreground', {
dark: Color.white,
light: Color.white,
hc: Color.white
}, nls.localize('activityBarForeground', "Activity bar foreground color (e.g. used for the icons). The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
}, nls.localize('activityBarForeground', "Activity bar item foreground color when it is active. The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
export const ACTIVITY_BAR_INACTIVE_FOREGROUND = registerColor('activityBar.inactiveForeground', {
dark: transparent(ACTIVITY_BAR_FOREGROUND, 0.6),
light: transparent(ACTIVITY_BAR_FOREGROUND, 0.6),
hc: Color.white
}, nls.localize('activityBarInActiveForeground', "Activity bar item foreground color when it is inactive. The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
export const ACTIVITY_BAR_BORDER = registerColor('activityBar.border', {
dark: null,
@@ -290,7 +326,6 @@ export const ACTIVITY_BAR_BORDER = registerColor('activityBar.border', {
hc: contrastBorder
}, nls.localize('activityBarBorder', "Activity bar border color separating to the side bar. The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
export const ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND = registerColor('activityBar.dropBackground', {
dark: Color.white.transparent(0.12),
light: Color.white.transparent(0.12),
@@ -354,6 +389,11 @@ export const SIDE_BAR_SECTION_HEADER_FOREGROUND = registerColor('sideBarSectionH
hc: SIDE_BAR_FOREGROUND
}, nls.localize('sideBarSectionHeaderForeground', "Side bar section header foreground color. The side bar is the container for views like explorer and search."));
export const SIDE_BAR_SECTION_HEADER_BORDER = registerColor('sideBarSectionHeader.border', {
dark: contrastBorder,
light: contrastBorder,
hc: contrastBorder
}, nls.localize('sideBarSectionHeaderBorder', "Side bar section header border color. The side bar is the container for views like explorer and search."));
// < --- Title Bar --- >
@@ -408,36 +448,6 @@ export const MENUBAR_SELECTION_BORDER = registerColor('menubar.selectionBorder',
hc: activeContrastBorder
}, nls.localize('menubarSelectionBorder', "Border color of the selected menu item in the menubar."));
export const MENU_FOREGROUND = registerColor('menu.foreground', {
dark: SIDE_BAR_FOREGROUND,
light: SIDE_BAR_FOREGROUND,
hc: SIDE_BAR_FOREGROUND
}, nls.localize('menuForeground', "Foreground color of menu items."));
export const MENU_BACKGROUND = registerColor('menu.background', {
dark: SIDE_BAR_BACKGROUND,
light: SIDE_BAR_BACKGROUND,
hc: SIDE_BAR_BACKGROUND
}, nls.localize('menuBackground', "Background color of menu items."));
export const MENU_SELECTION_FOREGROUND = registerColor('menu.selectionForeground', {
dark: listActiveSelectionForeground,
light: listActiveSelectionForeground,
hc: listActiveSelectionForeground
}, nls.localize('menuSelectionForeground', "Foreground color of the selected menu item in menus."));
export const MENU_SELECTION_BACKGROUND = registerColor('menu.selectionBackground', {
dark: listActiveSelectionBackground,
light: listActiveSelectionBackground,
hc: listActiveSelectionBackground
}, nls.localize('menuSelectionBackground', "Background color of the selected menu item in menus."));
export const MENU_SELECTION_BORDER = registerColor('menu.selectionBorder', {
dark: null,
light: null,
hc: null
}, nls.localize('menuSelectionBorder', "Border color of the selected menu item in menus."));
// < --- Notifications --- >
export const NOTIFICATIONS_CENTER_BORDER = registerColor('notificationCenter.border', {
@@ -515,7 +525,7 @@ export class Themable extends Disposable {
// Subclasses to override
}
protected getColor(id: string, modify?: (color: Color, theme: ITheme) => Color): string {
protected getColor(id: string, modify?: (color: Color, theme: ITheme) => Color): string | null {
let color = this.theme.getColor(id);
if (color && modify) {

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IComposite } from 'vs/workbench/common/composite';

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { Command } from 'vs/editor/common/modes';
import { UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
@@ -16,6 +15,9 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { values } from 'vs/base/common/map';
import { Registry } from 'vs/platform/registry/common/platform';
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IAction } from 'vs/base/common/actions';
import { IMarkdownString } from 'vs/base/common/htmlContent';
export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test';
@@ -42,7 +44,7 @@ export interface IViewContainersRegistry {
*
* @returns the registered ViewContainer.
*/
registerViewContainer(id: string): ViewContainer;
registerViewContainer(id: string, extensionId?: string): ViewContainer;
/**
* Returns the view container with given id.
@@ -54,7 +56,7 @@ export interface IViewContainersRegistry {
}
export class ViewContainer {
protected constructor(readonly id: string) { }
protected constructor(readonly id: string, readonly extensionId: string) { }
}
class ViewContainersRegistryImpl implements IViewContainersRegistry {
@@ -68,11 +70,11 @@ class ViewContainersRegistryImpl implements IViewContainersRegistry {
return values(this.viewContainers);
}
registerViewContainer(id: string): ViewContainer {
registerViewContainer(id: string, extensionId: string): ViewContainer {
if (!this.viewContainers.has(id)) {
const viewContainer = new class extends ViewContainer {
constructor() {
super(id);
super(id, extensionId);
}
};
this.viewContainers.set(id, viewContainer);
@@ -111,6 +113,14 @@ export interface IViewDescriptor {
// Applies only to newly created views
readonly hideByDefault?: boolean;
readonly focusCommand?: { id: string, keybindings?: IKeybindings };
}
export interface IViewDescriptorCollection {
readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>;
readonly activeViewDescriptors: IViewDescriptor[];
readonly allViewDescriptors: IViewDescriptor[];
}
export interface IViewsRegistry {
@@ -125,8 +135,9 @@ export interface IViewsRegistry {
getViews(loc: ViewContainer): IViewDescriptor[];
getView(id: string): IViewDescriptor;
getView(id: string): IViewDescriptor | null;
getAllViews(): IViewDescriptor[];
}
export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry {
@@ -184,7 +195,7 @@ export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry
return this._views.get(loc) || [];
}
getView(id: string): IViewDescriptor {
getView(id: string): IViewDescriptor | null {
for (const viewContainer of this._viewContainer) {
const viewDescriptor = (this._views.get(viewContainer) || []).filter(v => v.id === id)[0];
if (viewDescriptor) {
@@ -193,6 +204,12 @@ export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry
}
return null;
}
getAllViews(): IViewDescriptor[] {
const allViews: IViewDescriptor[] = [];
this._views.forEach(views => allViews.push(...views));
return allViews;
}
};
export interface IView {
@@ -203,7 +220,7 @@ export interface IView {
export interface IViewsViewlet extends IViewlet {
openView(id: string, focus?: boolean): TPromise<IView>;
openView(id: string, focus?: boolean): IView;
}
@@ -212,15 +229,23 @@ export const IViewsService = createDecorator<IViewsService>('viewsService');
export interface IViewsService {
_serviceBrand: any;
openView(id: string, focus?: boolean): TPromise<IView>;
openView(id: string, focus?: boolean): Thenable<IView>;
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection;
}
// Custom views
export interface ITreeViewer extends IDisposable {
export interface ITreeView extends IDisposable {
dataProvider: ITreeViewDataProvider;
showCollapseAllAction: boolean;
message: string | IMarkdownString;
readonly visible: boolean;
readonly onDidExpandItem: Event<ITreeItem>;
readonly onDidCollapseItem: Event<ITreeItem>;
@@ -229,9 +254,9 @@ export interface ITreeViewer extends IDisposable {
readonly onDidChangeVisibility: Event<boolean>;
readonly visible: boolean;
readonly onDidChangeActions: Event<void>;
refresh(treeItems?: ITreeItem[]): TPromise<void>;
refresh(treeItems?: ITreeItem[]): Promise<void>;
setVisibility(visible: boolean): void;
@@ -243,12 +268,32 @@ export interface ITreeViewer extends IDisposable {
getOptimalWidth(): number;
reveal(item: ITreeItem, parentChain: ITreeItem[], options: { select?: boolean }): TPromise<void>;
reveal(item: ITreeItem): Thenable<void>;
expand(itemOrItems: ITreeItem | ITreeItem[]): Thenable<void>;
setSelection(items: ITreeItem[]): void;
setFocus(item: ITreeItem): void;
getPrimaryActions(): IAction[];
getSecondaryActions(): IAction[];
}
export interface IRevealOptions {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
}
export interface ICustomViewDescriptor extends IViewDescriptor {
readonly treeViewer: ITreeViewer;
readonly treeView: ITreeView;
}
@@ -263,6 +308,14 @@ export enum TreeItemCollapsibleState {
Expanded = 2
}
export interface ITreeItemLabel {
label: string;
highlights?: [number, number][];
}
export interface ITreeItem {
handle: string;
@@ -271,11 +324,13 @@ export interface ITreeItem {
collapsibleState: TreeItemCollapsibleState;
label?: string;
label?: ITreeItemLabel;
icon?: string;
description?: string | boolean;
iconDark?: string;
icon?: UriComponents;
iconDark?: UriComponents;
themeIcon?: ThemeIcon;
@@ -292,6 +347,6 @@ export interface ITreeItem {
export interface ITreeViewDataProvider {
getChildren(element?: ITreeItem): TPromise<ITreeItem[]>;
getChildren(element?: ITreeItem): Promise<ITreeItem[]>;
}
}