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

@@ -3,12 +3,10 @@
* 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 { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
export type IExtHostNamedCustomer<T extends IDisposable> = [ProxyIdentifier<T>, IExtHostCustomerCtor<T>];

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -17,6 +15,7 @@ import { LanguageConfigurationFileHandler } from 'vs/workbench/parts/codeEditor/
// --- mainThread participants
import 'vs/workbench/api/node/apiCommands';
import './mainThreadClipboard';
import './mainThreadCommands';
import './mainThreadConfiguration';
// {{SQL CARBON EDIT}}

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { clipboard } from 'electron';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { MainContext, MainThreadClipboardShape } from '../node/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadClipboard)
export class MainThreadCommands implements MainThreadClipboardShape {
dispose(): void {
// nothing
}
$readText(): Promise<string> {
return Promise.resolve(clipboard.readText());
}
$writeText(value: string): Promise<void> {
clipboard.writeText(value);
return undefined;
}
}

View File

@@ -2,11 +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 { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { IDisposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { revive } from 'vs/base/common/marshalling';
@@ -80,7 +78,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
}
$getCommands(): Thenable<string[]> {
return TPromise.as(Object.keys(CommandsRegistry.getCommands()));
return Promise.resolve(Object.keys(CommandsRegistry.getCommands()));
}
}

View File

@@ -2,22 +2,68 @@
* 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 { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditor, isCodeEditor, isDiffEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import * as modes from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { keys } from 'vs/base/common/map';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../node/extHost.protocol';
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentProviderFeatures } from '../node/extHost.protocol';
import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService';
import { COMMENTS_PANEL_ID } from 'vs/workbench/parts/comments/electron-browser/commentsPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import URI from 'vs/base/common/uri';
import { ReviewController } from 'vs/workbench/parts/comments/electron-browser/commentsEditorContribution';
import { URI } from 'vs/base/common/uri';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { generateUuid } from 'vs/base/common/uuid';
export class MainThreadDocumentCommentProvider implements modes.DocumentCommentProvider {
private _proxy: ExtHostCommentsShape;
private _handle: number;
private _features: CommentProviderFeatures;
get startDraftLabel(): string { return this._features.startDraftLabel; }
get deleteDraftLabel(): string { return this._features.deleteDraftLabel; }
get finishDraftLabel(): string { return this._features.finishDraftLabel; }
constructor(proxy: ExtHostCommentsShape, handle: number, features: CommentProviderFeatures) {
this._proxy = proxy;
this._handle = handle;
this._features = features;
}
async provideDocumentComments(uri, token) {
return this._proxy.$provideDocumentComments(this._handle, uri);
}
async createNewCommentThread(uri, range, text, token) {
return this._proxy.$createNewCommentThread(this._handle, uri, range, text);
}
async replyToCommentThread(uri, range, thread, text, token) {
return this._proxy.$replyToCommentThread(this._handle, uri, range, thread, text);
}
async editComment(uri, comment, text, token) {
return this._proxy.$editComment(this._handle, uri, comment, text);
}
async deleteComment(uri, comment, token) {
return this._proxy.$deleteComment(this._handle, uri, comment);
}
async startDraft(token): Promise<void> {
return this._proxy.$startDraft(this._handle);
}
async deleteDraft(token): Promise<void> {
return this._proxy.$deleteDraft(this._handle);
}
async finishDraft(token): Promise<void> {
return this._proxy.$finishDraft(this._handle);
}
onDidChangeCommentThreads = null;
}
@extHostNamedCustomer(MainContext.MainThreadComments)
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
@@ -25,75 +71,64 @@ export class MainThreadComments extends Disposable implements MainThreadComments
private _proxy: ExtHostCommentsShape;
private _documentProviders = new Map<number, IDisposable>();
private _workspaceProviders = new Map<number, IDisposable>();
private _handlers = new Map<number, string>();
private _firstSessionStart: boolean;
constructor(
extHostContext: IExtHostContext,
@IEditorService private _editorService: IEditorService,
@ICommentService private _commentService: ICommentService,
@IPanelService private _panelService: IPanelService,
@ICodeEditorService private _codeEditorService: ICodeEditorService
@ITelemetryService private _telemetryService: ITelemetryService
) {
super();
this._disposables = [];
this._firstSessionStart = true;
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
this._disposables.push(this._editorService.onDidActiveEditorChange(e => {
const editors = this.getFocusedEditors();
if (!editors || !editors.length) {
return;
}
editors.forEach(editor => {
const controller = ReviewController.get(editor);
if (!controller) {
return;
}
if (!editor.getModel()) {
return;
}
const outerEditorURI = editor.getModel().uri;
this.provideDocumentComments(outerEditorURI).then(commentInfos => {
this._commentService.setDocumentComments(outerEditorURI, commentInfos.filter(info => info !== null));
});
});
}));
}
$registerDocumentCommentProvider(handle: number): void {
$registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void {
this._documentProviders.set(handle, undefined);
const handler = new MainThreadDocumentCommentProvider(this._proxy, handle, features);
this._commentService.registerDataProvider(
handle,
{
provideDocumentComments: async (uri, token) => {
return this._proxy.$provideDocumentComments(handle, uri);
},
onDidChangeCommentThreads: null,
createNewCommentThread: async (uri, range, text, token) => {
return this._proxy.$createNewCommentThread(handle, uri, range, text);
},
replyToCommentThread: async (uri, range, thread, text, token) => {
return this._proxy.$replyToCommentThread(handle, uri, range, thread, text);
}
}
);
const providerId = generateUuid();
this._handlers.set(handle, providerId);
this._commentService.registerDataProvider(providerId, handler);
}
$registerWorkspaceCommentProvider(handle: number): void {
$registerWorkspaceCommentProvider(handle: number, extensionId: string): void {
this._workspaceProviders.set(handle, undefined);
const providerId = generateUuid();
this._handlers.set(handle, providerId);
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, true);
this._panelService.openPanel(COMMENTS_PANEL_ID);
if (this._firstSessionStart) {
this._panelService.openPanel(COMMENTS_PANEL_ID);
this._firstSessionStart = false;
}
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
if (commentThreads) {
this._commentService.setWorkspaceComments(handle, commentThreads);
this._commentService.setWorkspaceComments(providerId, commentThreads);
}
});
/* __GDPR__
"comments:registerWorkspaceCommentProvider" : {
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._telemetryService.publicLog('comments:registerWorkspaceCommentProvider', {
extensionId: extensionId
});
}
$unregisterDocumentCommentProvider(handle: number): void {
this._documentProviders.delete(handle);
this._commentService.unregisterDataProvider(handle);
const handlerId = this._handlers.get(handle);
this._commentService.unregisterDataProvider(handlerId);
this._handlers.delete(handle);
}
$unregisterWorkspaceCommentProvider(handle: number): void {
@@ -101,41 +136,32 @@ export class MainThreadComments extends Disposable implements MainThreadComments
if (this._workspaceProviders.size === 0) {
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, false);
}
this._commentService.removeWorkspaceComments(handle);
const handlerId = this._handlers.get(handle);
this._commentService.removeWorkspaceComments(handlerId);
this._handlers.delete(handle);
}
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) {
// notify comment service
this._commentService.updateComments(event);
const providerId = this._handlers.get(handle);
this._commentService.updateComments(providerId, event);
}
dispose(): void {
this._disposables = dispose(this._disposables);
this._workspaceProviders.forEach(value => dispose(value));
this._workspaceProviders.clear();
this._documentProviders.forEach(value => dispose(value));
this._documentProviders.clear();
}
getVisibleEditors(): ICodeEditor[] {
let ret: ICodeEditor[] = [];
getFocusedEditors(): ICodeEditor[] {
let activeControl = this._editorService.activeControl;
if (activeControl) {
if (isCodeEditor(activeControl.getControl())) {
return [this._editorService.activeControl.getControl() as ICodeEditor];
this._editorService.visibleControls.forEach(control => {
if (isCodeEditor(control.getControl())) {
ret.push(control.getControl() as ICodeEditor);
}
if (isDiffEditor(activeControl.getControl())) {
let diffEditor = activeControl.getControl() as IDiffEditor;
return [diffEditor.getOriginalEditor(), diffEditor.getModifiedEditor()];
if (isDiffEditor(control.getControl())) {
let diffEditor = control.getControl() as IDiffEditor;
ret.push(diffEditor.getOriginalEditor(), diffEditor.getModifiedEditor());
}
}
});
let editor = this._codeEditorService.getFocusedCodeEditor();
if (editor) {
return [editor];
}
return [];
return ret;
}
async provideWorkspaceComments(): Promise<modes.CommentThread[]> {
@@ -153,4 +179,12 @@ export class MainThreadComments extends Disposable implements MainThreadComments
}
return result;
}
dispose(): void {
this._disposables = dispose(this._disposables);
this._workspaceProviders.forEach(value => dispose(value));
this._workspaceProviders.clear();
this._documentProviders.forEach(value => dispose(value));
this._documentProviders.clear();
}
}

View File

@@ -2,10 +2,8 @@
* 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 URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
@@ -36,17 +34,17 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
this._configurationListener.dispose();
}
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resourceUriComponenets: UriComponents): TPromise<void> {
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resourceUriComponenets: UriComponents): Thenable<void> {
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
return this.writeConfiguration(target, key, value, resource);
}
$removeConfigurationOption(target: ConfigurationTarget, key: string, resourceUriComponenets: UriComponents): TPromise<void> {
$removeConfigurationOption(target: ConfigurationTarget, key: string, resourceUriComponenets: UriComponents): Thenable<void> {
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
return this.writeConfiguration(target, key, undefined, resource);
}
private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise<void> {
private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI): Promise<void> {
target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource);
return this.configurationService.updateValue(key, value, { resource }, target, true);
}

View File

@@ -2,36 +2,35 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
// {{SQL CARBON EDIT}}
/*
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import uri from 'vs/base/common/uri';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IAdapterExecutable, ITerminalSettings, IDebugAdapter, IDebugAdapterProvider } from 'vs/workbench/parts/debug/common/debug';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI as uri } from 'vs/base/common/uri';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDebugAdapterTrackerFactory } from 'vs/workbench/parts/debug/common/debug';
import {
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
} from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import severity from 'vs/base/common/severity';
import { AbstractDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
import * as paths from 'vs/base/common/paths';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils';
import { convertToVSCPaths, convertToDAPaths, stringToUri, uriToString } from 'vs/workbench/parts/debug/common/debugUtils';
@extHostNamedCustomer(MainContext.MainThreadDebugService)
export class MainThreadDebugService implements MainThreadDebugServiceShape, IDebugAdapterProvider {
export class MainThreadDebugService implements MainThreadDebugServiceShape, IDebugAdapterFactory {
private _proxy: ExtHostDebugServiceShape;
private _toDispose: IDisposable[];
private _breakpointEventsActive: boolean;
private _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
private _debugAdaptersHandleCounter = 1;
private _debugConfigurationProviders: Map<number, IDebugConfigurationProvider>;
private _debugAdapterDescriptorFactories: Map<number, IDebugAdapterDescriptorFactory>;
private _debugAdapterTrackerFactories: Map<number, IDebugAdapterTrackerFactory>;
private _sessions: Set<DebugSessionUUID>;
constructor(
extHostContext: IExtHostContext,
@@ -39,51 +38,56 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
this._toDispose = [];
this._toDispose.push(debugService.onDidNewSession(proc => this._proxy.$acceptDebugSessionStarted(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.onDidEndSession(proc => this._proxy.$acceptDebugSessionTerminated(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.getViewModel().onDidFocusSession(proc => {
if (proc) {
this._proxy.$acceptDebugSessionActiveChanged(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false));
} else {
this._proxy.$acceptDebugSessionActiveChanged(undefined);
}
this._toDispose.push(debugService.onDidNewSession(session => {
this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session));
}));
// Need to start listening early to new session events because a custom event can come while a session is initialising
this._toDispose.push(debugService.onWillNewSession(session => {
this._toDispose.push(session.onDidCustomEvent(event => this._proxy.$acceptDebugSessionCustomEvent(this.getSessionDto(session), event)));
}));
this._toDispose.push(debugService.onDidEndSession(session => {
this._proxy.$acceptDebugSessionTerminated(this.getSessionDto(session));
this._sessions.delete(session.getId());
}));
this._toDispose.push(debugService.getViewModel().onDidFocusSession(session => {
this._proxy.$acceptDebugSessionActiveChanged(this.getSessionDto(session));
}));
this._toDispose.push(debugService.onDidCustomEvent(event => {
if (event && event.sessionId) {
const process = this.debugService.getModel().getSessions().filter(p => p.getId() === event.sessionId).pop();
if (process) {
this._proxy.$acceptDebugSessionCustomEvent(event.sessionId, process.configuration.type, process.configuration.name, event);
}
}
}));
this._debugAdapters = new Map<number, ExtensionHostDebugAdapter>();
}
public $registerDebugTypes(debugTypes: string[]) {
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this));
}
createDebugAdapter(debugType: string, adapterInfo, debugPort: number): IDebugAdapter {
const handle = this._debugAdaptersHandleCounter++;
const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo, debugPort);
this._debugAdapters.set(handle, da);
return da;
}
substituteVariables(folder: IWorkspaceFolder, config: IConfig): TPromise<IConfig> {
return this._proxy.$substituteVariables(folder ? folder.uri : undefined, config);
}
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
return this._proxy.$runInTerminal(args, config);
this._debugAdapters = new Map();
this._debugConfigurationProviders = new Map();
this._debugAdapterDescriptorFactories = new Map();
this._debugAdapterTrackerFactories = new Map();
this._sessions = new Set();
}
public dispose(): void {
this._toDispose = dispose(this._toDispose);
}
public $startBreakpointEvents(): TPromise<any> {
// interface IDebugAdapterProvider
createDebugAdapter(session: IDebugSession): IDebugAdapter {
const handle = this._debugAdaptersHandleCounter++;
const da = new ExtensionHostDebugAdapter(this, handle, this._proxy, session);
this._debugAdapters.set(handle, da);
return da;
}
substituteVariables(folder: IWorkspaceFolder, config: IConfig): Promise<IConfig> {
return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config));
}
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise<number | undefined> {
return Promise.resolve(this._proxy.$runInTerminal(args, config));
}
// RPC methods (MainThreadDebugServiceShape)
public $registerDebugTypes(debugTypes: string[]) {
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterFactory(debugTypes, this));
}
public $startBreakpointEvents(): void {
if (!this._breakpointEventsActive) {
this._breakpointEventsActive = true;
@@ -118,11 +122,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
});
}
}
return TPromise.wrap<void>(undefined);
}
public $registerBreakpoints(DTOs: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise<void> {
public $registerBreakpoints(DTOs: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): Thenable<void> {
for (let dto of DTOs) {
if (dto.type === 'sourceMulti') {
@@ -137,7 +139,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
logMessage: l.logMessage
}
);
this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps);
this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps, 'extension');
} else if (dto.type === 'function') {
this.debugService.addFunctionBreakpoint(dto.functionName, dto.id);
}
@@ -145,12 +147,154 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return void 0;
}
public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise<void> {
public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Thenable<void> {
breakpointIds.forEach(id => this.debugService.removeBreakpoints(id));
functionBreakpointIds.forEach(id => this.debugService.removeFunctionBreakpoints(id));
return void 0;
}
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasProvideDebugAdapter: boolean, hasTracker: boolean, handle: number): Thenable<void> {
const provider = <IDebugConfigurationProvider>{
type: debugType,
hasTracker: hasTracker
};
if (hasProvide) {
provider.provideDebugConfigurations = (folder) => {
return Promise.resolve(this._proxy.$provideDebugConfigurations(handle, folder));
};
}
if (hasResolve) {
provider.resolveDebugConfiguration = (folder, config) => {
return Promise.resolve(this._proxy.$resolveDebugConfiguration(handle, folder, config));
};
}
if (hasProvideDebugAdapter) {
provider.debugAdapterExecutable = (folder) => {
return Promise.resolve(this._proxy.$legacyDebugAdapterExecutable(handle, folder));
};
}
this._debugConfigurationProviders.set(handle, provider);
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugConfigurationProvider(provider));
return Promise.resolve(undefined);
}
public $unregisterDebugConfigurationProvider(handle: number): void {
const provider = this._debugConfigurationProviders.get(handle);
if (provider) {
this._debugConfigurationProviders.delete(handle);
this.debugService.getConfigurationManager().unregisterDebugConfigurationProvider(provider);
}
}
public $registerDebugAdapterDescriptorFactory(debugType: string, handle: number): Thenable<void> {
const provider = <IDebugAdapterDescriptorFactory>{
type: debugType,
createDebugAdapterDescriptor: session => {
return Promise.resolve(this._proxy.$provideDebugAdapter(handle, this.getSessionDto(session)));
}
};
this._debugAdapterDescriptorFactories.set(handle, provider);
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterDescriptorFactory(provider));
return Promise.resolve(undefined);
}
public $unregisterDebugAdapterDescriptorFactory(handle: number): void {
const provider = this._debugAdapterDescriptorFactories.get(handle);
if (provider) {
this._debugAdapterDescriptorFactories.delete(handle);
this.debugService.getConfigurationManager().unregisterDebugAdapterDescriptorFactory(provider);
}
}
public $registerDebugAdapterTrackerFactory(debugType: string, handle: number) {
const factory = <IDebugAdapterTrackerFactory>{
type: debugType,
};
this._debugAdapterTrackerFactories.set(handle, factory);
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterTrackerFactory(factory));
return Promise.resolve(undefined);
}
public $unregisterDebugAdapterTrackerFactory(handle: number) {
const factory = this._debugAdapterTrackerFactories.get(handle);
if (factory) {
this._debugAdapterTrackerFactories.delete(handle);
this.debugService.getConfigurationManager().unregisterDebugAdapterTrackerFactory(factory);
}
}
public $startDebugging(_folderUri: uri | undefined, nameOrConfiguration: string | IConfig): Thenable<boolean> {
const folderUri = _folderUri ? uri.revive(_folderUri) : undefined;
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
return this.debugService.startDebugging(launch, nameOrConfiguration).then(success => {
return success;
}, err => {
return Promise.reject(new Error(err && err.message ? err.message : 'cannot start debugging'));
});
}
public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Thenable<any> {
const session = this.debugService.getModel().getSessions(true).filter(s => s.getId() === sessionId).pop();
if (session) {
return session.customRequest(request, args).then(response => {
if (response && response.success) {
return response.body;
} else {
return Promise.reject(new Error(response ? response.message : 'custom request failed'));
}
});
}
return Promise.reject(new Error('debug session not found'));
}
public $appendDebugConsole(value: string): void {
// Use warning as severity to get the orange color for messages coming from the debug extension
const session = this.debugService.getViewModel().focusedSession;
if (session) {
session.appendToRepl(value, severity.Warning);
}
}
public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) {
this._debugAdapters.get(handle).acceptMessage(convertToVSCPaths(message, source => uriToString(source)));
}
public $acceptDAError(handle: number, name: string, message: string, stack: string) {
this._debugAdapters.get(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`));
}
public $acceptDAExit(handle: number, code: number, signal: string) {
this._debugAdapters.get(handle).fireExit(handle, code, signal);
}
// dto helpers
getSessionDto(session: IDebugSession): IDebugSessionDto {
if (session) {
const sessionID = <DebugSessionUUID>session.getId();
if (this._sessions.has(sessionID)) {
return sessionID;
} else {
this._sessions.add(sessionID);
return {
id: sessionID,
type: session.configuration.type,
name: session.configuration.name,
folderUri: session.root ? session.root.uri : undefined,
configuration: session.configuration
};
}
}
return undefined;
}
private convertToDto(bps: (ReadonlyArray<IBreakpoint | IFunctionBreakpoint>)): (ISourceBreakpointDto | IFunctionBreakpointDto)[] {
return bps.map(bp => {
if ('name' in bp) {
@@ -180,85 +324,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
});
}
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<void> {
const provider = <IDebugConfigurationProvider>{
type: debugType
};
if (hasProvide) {
provider.provideDebugConfigurations = folder => {
return this._proxy.$provideDebugConfigurations(handle, folder);
};
}
if (hasResolve) {
provider.resolveDebugConfiguration = (folder, debugConfiguration) => {
return this._proxy.$resolveDebugConfiguration(handle, folder, debugConfiguration);
};
}
if (hasDebugAdapterExecutable) {
provider.debugAdapterExecutable = (folder) => {
return this._proxy.$debugAdapterExecutable(handle, folder);
};
}
this.debugService.getConfigurationManager().registerDebugConfigurationProvider(handle, provider);
return TPromise.wrap<void>(undefined);
}
public $unregisterDebugConfigurationProvider(handle: number): TPromise<any> {
this.debugService.getConfigurationManager().unregisterDebugConfigurationProvider(handle);
return TPromise.wrap<void>(undefined);
}
public $startDebugging(_folderUri: uri | undefined, nameOrConfiguration: string | IConfig): TPromise<boolean> {
const folderUri = _folderUri ? uri.revive(_folderUri) : undefined;
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
return this.debugService.startDebugging(launch, nameOrConfiguration).then(x => {
return true;
}, err => {
return TPromise.wrapError(err && err.message ? err.message : 'cannot start debugging');
});
}
public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): TPromise<any> {
const process = this.debugService.getModel().getSessions().filter(p => p.getId() === sessionId).pop();
if (process) {
return process.raw.custom(request, args).then(response => {
if (response && response.success) {
return response.body;
} else {
return TPromise.wrapError(new Error(response ? response.message : 'custom request failed'));
}
});
}
return TPromise.wrapError(new Error('debug session not found'));
}
public $appendDebugConsole(value: string): TPromise<any> {
// Use warning as severity to get the orange color for messages coming from the debug extension
this.debugService.logToRepl(value, severity.Warning);
return TPromise.wrap<void>(undefined);
}
public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) {
convertToVSCPaths(message, source => {
if (typeof source.path === 'object') {
source.path = uri.revive(source.path).toString();
}
});
this._debugAdapters.get(handle).acceptMessage(message);
}
public $acceptDAError(handle: number, name: string, message: string, stack: string) {
this._debugAdapters.get(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`));
}
public $acceptDAExit(handle: number, code: number, signal: string) {
this._debugAdapters.get(handle).fireExit(handle, code, signal);
}
}
/**
@@ -269,7 +334,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
/*
class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _debugType: string, private _adapterExecutable: IAdapterExecutable | null, private _debugPort: number) {
constructor(private _ds: MainThreadDebugService, private _handle: number, private _proxy: ExtHostDebugServiceShape, private _session: IDebugSession) {
super();
}
@@ -281,25 +346,17 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
this._onExit.fire(code);
}
public startSession(): TPromise<void> {
return this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable, this._debugPort);
public startSession(): Promise<void> {
return Promise.resolve(this._proxy.$startDASession(this._handle, this._ds.getSessionDto(this._session)));
}
public sendMessage(message: DebugProtocol.ProtocolMessage): void {
convertToDAPaths(message, source => {
if (paths.isAbsolute(source.path)) {
(<any>source).path = uri.file(source.path);
} else {
(<any>source).path = uri.parse(source.path);
}
});
this._proxy.$sendDAMessage(this._handle, message);
this._proxy.$sendDAMessage(this._handle, convertToDAPaths(message, source => stringToUri(source)));
}
public stopSession(): TPromise<void> {
return this._proxy.$stopDASession(this._handle);
public stopSession(): Promise<void> {
return Promise.resolve(this._proxy.$stopDASession(this._handle));
}
}
// {{SQL CARBON EDIT}}

View File

@@ -2,9 +2,8 @@
* 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 URI, { UriComponents } from 'vs/base/common/uri';
import { URI, UriComponents } 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, DecorationData, DecorationRequest } from '../node/extHost.protocol';
@@ -19,7 +18,7 @@ class DecorationRequestsQueue {
private _requests: { [id: number]: DecorationRequest } = Object.create(null);
private _resolver: { [id: number]: (data: DecorationData) => any } = Object.create(null);
private _timer: number;
private _timer: any;
constructor(
private _proxy: ExtHostDecorationsShape
@@ -50,7 +49,7 @@ class DecorationRequestsQueue {
// make request
const requests = this._requests;
const resolver = this._resolver;
this._proxy.$provideDecorations(values(requests)).then(data => {
this._proxy.$provideDecorations(values(requests), CancellationToken.None).then(data => {
for (const id in resolver) {
resolver[id](data[id]);
}

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 { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers';
import URI, { UriComponents } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { MainThreadDiagnosticsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';

View File

@@ -2,21 +2,19 @@
* 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 URI from 'vs/base/common/uri';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { URI } from 'vs/base/common/uri';
import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { forEach } from 'vs/base/common/collections';
import { IFileDialogService, IOpenDialogOptions, ISaveDialogOptions } from 'vs/platform/dialogs/common/dialogs';
@extHostNamedCustomer(MainContext.MainThreadDialogs)
export class MainThreadDialogs implements MainThreadDiaglogsShape {
constructor(
context: IExtHostContext,
@IWindowService private readonly _windowService: IWindowService
@IFileDialogService private readonly _fileDialogService: IFileDialogService,
) {
//
}
@@ -25,54 +23,22 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
//
}
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<string[]> {
// TODO@joh what about remote dev setup?
if (options.defaultUri && options.defaultUri.scheme !== 'file') {
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
return <any>Promise.reject(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.'));
}
return new Promise<string[]>(resolve => {
this._windowService.showOpenDialog(
MainThreadDialogs._convertOpenOptions(options)
).then(filenames => resolve(isFalsyOrEmpty(filenames) ? undefined : filenames));
});
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<URI[]> {
return Promise.resolve(this._fileDialogService.showOpenDialog(MainThreadDialogs._convertOpenOptions(options)));
}
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<string> {
// TODO@joh what about remote dev setup?
if (options.defaultUri && options.defaultUri.scheme !== 'file') {
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
return <any>Promise.reject(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.'));
}
return new Promise<string>(resolve => {
this._windowService.showSaveDialog(
MainThreadDialogs._convertSaveOptions(options)
).then(filename => resolve(!filename ? undefined : filename));
});
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<URI> {
return Promise.resolve(this._fileDialogService.showSaveDialog(MainThreadDialogs._convertSaveOptions(options)));
}
private static _convertOpenOptions(options: MainThreadDialogOpenOptions): Electron.OpenDialogOptions {
const result: Electron.OpenDialogOptions = {
properties: ['createDirectory']
private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions {
const result: IOpenDialogOptions = {
openLabel: options.openLabel,
canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders),
canSelectFolders: options.canSelectFolders,
canSelectMany: options.canSelectMany,
defaultUri: URI.revive(options.defaultUri)
};
if (options.openLabel) {
result.buttonLabel = options.openLabel;
}
if (options.defaultUri) {
result.defaultPath = URI.revive(options.defaultUri).fsPath;
}
if (!options.canSelectFiles && !options.canSelectFolders) {
options.canSelectFiles = true;
}
if (options.canSelectFiles) {
result.properties.push('openFile');
}
if (options.canSelectFolders) {
result.properties.push('openDirectory');
}
if (options.canSelectMany) {
result.properties.push('multiSelections');
}
if (options.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value }));
@@ -80,16 +46,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
return result;
}
private static _convertSaveOptions(options: MainThreadDialogSaveOptions): Electron.SaveDialogOptions {
const result: Electron.SaveDialogOptions = {
private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions {
const result: ISaveDialogOptions = {
defaultUri: URI.revive(options.defaultUri),
saveLabel: options.saveLabel
};
if (options.defaultUri) {
result.defaultPath = URI.revive(options.defaultUri).fsPath;
}
if (options.saveLabel) {
result.buttonLabel = options.saveLabel;
}
if (options.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value }));

View File

@@ -2,13 +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 { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable } from 'vs/base/common/lifecycle';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { URI, UriComponents } from 'vs/base/common/uri';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
@@ -18,11 +15,13 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostDocumentContentProvidersShape, IExtHostContext, MainContext, MainThreadDocumentContentProvidersShape } from '../node/extHost.protocol';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
@extHostNamedCustomer(MainContext.MainThreadDocumentContentProviders)
export class MainThreadDocumentContentProviders implements MainThreadDocumentContentProvidersShape {
private _resourceContentProvider: { [handle: number]: IDisposable } = Object.create(null);
private readonly _resourceContentProvider = new Map<number, IDisposable>();
private readonly _pendingUpdate = new Map<string, CancellationTokenSource>();
private readonly _proxy: ExtHostDocumentContentProvidersShape;
constructor(
@@ -30,38 +29,37 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService,
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
@ICodeEditorService codeEditorService: ICodeEditorService
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentContentProviders);
}
public dispose(): void {
for (let handle in this._resourceContentProvider) {
this._resourceContentProvider[handle].dispose();
}
dispose(): void {
this._resourceContentProvider.forEach(p => p.dispose());
this._pendingUpdate.forEach(source => source.dispose());
}
$registerTextContentProvider(handle: number, scheme: string): void {
this._resourceContentProvider[handle] = this._textModelResolverService.registerTextModelContentProvider(scheme, {
provideTextContent: (uri: URI): TPromise<ITextModel> => {
const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, {
provideTextContent: (uri: URI): Thenable<ITextModel> => {
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
if (typeof value === 'string') {
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
const mode = this._modeService.getOrCreateModeByFilenameOrFirstLine(uri.fsPath, firstLineText);
return this._modelService.createModel(value, mode, uri);
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText);
return this._modelService.createModel(value, languageSelection, uri);
}
return undefined;
});
}
});
this._resourceContentProvider.set(handle, registration);
}
$unregisterTextContentProvider(handle: number): void {
const registration = this._resourceContentProvider[handle];
const registration = this._resourceContentProvider.get(handle);
if (registration) {
registration.dispose();
delete this._resourceContentProvider[handle];
this._resourceContentProvider.delete(handle);
}
}
@@ -71,11 +69,27 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
return;
}
// cancel and dispose an existing update
if (this._pendingUpdate.has(model.id)) {
this._pendingUpdate.get(model.id).cancel();
}
// create and keep update token
const myToken = new CancellationTokenSource();
this._pendingUpdate.set(model.id, myToken);
this._editorWorkerService.computeMoreMinimalEdits(model.uri, [{ text: value, range: model.getFullModelRange() }]).then(edits => {
// remove token
this._pendingUpdate.delete(model.id);
if (myToken.token.isCancellationRequested) {
// ignore this
return;
}
if (edits.length > 0) {
// use the evil-edit as these models show in readonly-editor only
model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
}
}, onUnexpectedError);
}).catch(onUnexpectedError);
}
}

View File

@@ -2,23 +2,21 @@
* 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 URI, { UriComponents } from 'vs/base/common/uri';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { TPromise } from 'vs/base/common/winjs.base';
import { IFileService } from 'vs/platform/files/common/files';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ExtHostContext, MainThreadDocumentsShape, ExtHostDocumentsShape, IExtHostContext } from '../node/extHost.protocol';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { ITextEditorModel } from 'vs/workbench/common/editor';
import { ITextModel } from 'vs/editor/common/model';
import { IDisposable, IReference, dispose } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITextModel } from 'vs/editor/common/model';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
import { ITextEditorModel } from 'vs/workbench/common/editor';
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
export class BoundModelReferenceCollection {
@@ -38,7 +36,7 @@ export class BoundModelReferenceCollection {
add(ref: IReference<ITextEditorModel>): void {
let length = ref.object.textEditorModel.getValueLength();
let handle: number;
let handle: any;
let entry: { length: number, dispose(): void };
const dispose = () => {
let idx = this._data.indexOf(entry);
@@ -169,17 +167,17 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
// --- from extension host process
$trySaveDocument(uri: UriComponents): TPromise<boolean> {
$trySaveDocument(uri: UriComponents): Thenable<boolean> {
return this._textFileService.save(URI.revive(uri));
}
$tryOpenDocument(_uri: UriComponents): TPromise<any> {
$tryOpenDocument(_uri: UriComponents): Thenable<any> {
const uri = URI.revive(_uri);
if (!uri.scheme || !(uri.fsPath || uri.authority)) {
return TPromise.wrapError(new Error(`Invalid uri. Scheme and authority or path must be set.`));
return Promise.reject(new Error(`Invalid uri. Scheme and authority or path must be set.`));
}
let promise: TPromise<boolean>;
let promise: Thenable<boolean>;
switch (uri.scheme) {
case Schemas.untitled:
promise = this._handleUnititledScheme(uri);
@@ -192,22 +190,22 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
return promise.then(success => {
if (!success) {
return TPromise.wrapError(new Error('cannot open ' + uri.toString()));
return Promise.reject(new Error('cannot open ' + uri.toString()));
} else if (!this._modelIsSynced[uri.toString()]) {
return TPromise.wrapError(new Error('cannot open ' + uri.toString() + '. Detail: Files above 50MB cannot be synchronized with extensions.'));
return Promise.reject(new Error('cannot open ' + uri.toString() + '. Detail: Files above 50MB cannot be synchronized with extensions.'));
} else {
return undefined;
}
}, err => {
return TPromise.wrapError(new Error('cannot open ' + uri.toString() + '. Detail: ' + toErrorMessage(err)));
return Promise.reject(new Error('cannot open ' + uri.toString() + '. Detail: ' + toErrorMessage(err)));
});
}
$tryCreateDocument(options?: { language?: string, content?: string }): TPromise<URI> {
$tryCreateDocument(options?: { language?: string, content?: string }): Thenable<URI> {
return this._doCreateUntitled(void 0, options ? options.language : void 0, options ? options.content : void 0);
}
private _handleAsResourceInput(uri: URI): TPromise<boolean> {
private _handleAsResourceInput(uri: URI): Thenable<boolean> {
return this._textModelResolverService.createModelReference(uri).then(ref => {
this._modelReferenceCollection.add(ref);
const result = !!ref.object;
@@ -215,17 +213,17 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
});
}
private _handleUnititledScheme(uri: URI): TPromise<boolean> {
private _handleUnititledScheme(uri: URI): Thenable<boolean> {
let asFileUri = uri.with({ scheme: Schemas.file });
return this._fileService.resolveFile(asFileUri).then(stats => {
// don't create a new file ontop of an existing file
return TPromise.wrapError<boolean>(new Error('file already exists on disk'));
return Promise.reject(new Error('file already exists on disk'));
}, err => {
return this._doCreateUntitled(uri).then(resource => !!resource);
});
}
private _doCreateUntitled(resource?: URI, modeId?: string, initialValue?: string): TPromise<URI> {
private _doCreateUntitled(resource?: URI, modeId?: string, initialValue?: string): Thenable<URI> {
return this._untitledEditorService.loadOrCreate({
resource,
modeId,

View File

@@ -2,47 +2,33 @@
* 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 { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { ITextModel } from 'vs/editor/common/model';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IModelAddedData, ITextEditorAddData, IDocumentsAndEditorsDelta, IExtHostContext, MainContext } from '../node/extHost.protocol';
import { MainThreadTextEditor } from './mainThreadEditor';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/shared/editor';
import { IEditor } from 'vs/workbench/common/editor';
import { IEditor } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { MainThreadDocuments } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/node/extHost.protocol';
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/shared/editor';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { IEditor as IWorkbenchEditor } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isDiffEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import URI from 'vs/base/common/uri';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
namespace mapset {
export function setValues<T>(set: Set<T>): T[] {
// return Array.from(set);
let ret: T[] = [];
set.forEach(v => ret.push(v));
return ret;
}
export function mapValues<T>(map: Map<any, T>): T[] {
// return Array.from(map.values());
let ret: T[] = [];
map.forEach(v => ret.push(v));
return ret;
}
}
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
namespace delta {
@@ -125,8 +111,8 @@ class DocumentAndEditorState {
static compute(before: DocumentAndEditorState, after: DocumentAndEditorState): DocumentAndEditorStateDelta {
if (!before) {
return new DocumentAndEditorStateDelta(
[], mapset.setValues(after.documents),
[], mapset.mapValues(after.textEditors),
[], values(after.documents),
[], values(after.textEditors),
undefined, after.activeEditor
);
}
@@ -151,25 +137,36 @@ class DocumentAndEditorState {
}
}
const enum ActiveEditorOrder {
Editor, Panel
}
class MainThreadDocumentAndEditorStateComputer {
private _toDispose: IDisposable[] = [];
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
private _currentState: DocumentAndEditorState;
private _activeEditorOrder: ActiveEditorOrder = ActiveEditorOrder.Editor;
constructor(
private readonly _onDidChangeState: (delta: DocumentAndEditorStateDelta) => void,
@IModelService private readonly _modelService: IModelService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IEditorService private readonly _editorService: IEditorService
@IEditorService private readonly _editorService: IEditorService,
@IPanelService private readonly _panelService: IPanelService
) {
this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose);
this._modelService.onModelRemoved(this._updateState, this, this._toDispose);
this._modelService.onModelRemoved(_ => this._updateState(), this, this._toDispose);
this._editorService.onDidActiveEditorChange(_ => this._updateState(), this, this._toDispose);
this._codeEditorService.onCodeEditorAdd(this._onDidAddEditor, this, this._toDispose);
this._codeEditorService.onCodeEditorRemove(this._onDidRemoveEditor, this, this._toDispose);
this._codeEditorService.listCodeEditors().forEach(this._onDidAddEditor, this);
this._panelService.onDidPanelOpen(_ => this._activeEditorOrder = ActiveEditorOrder.Panel, undefined, this._toDispose);
this._panelService.onDidPanelClose(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
this._editorService.onDidVisibleEditorsChange(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
this._updateState();
}
@@ -178,9 +175,11 @@ class MainThreadDocumentAndEditorStateComputer {
}
private _onDidAddEditor(e: ICodeEditor): void {
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidChangeModel(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidFocusEditorText(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidBlurEditorText(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable([
e.onDidChangeModel(() => this._updateState()),
e.onDidFocusEditorText(() => this._updateState()),
e.onDidFocusEditorWidget(() => this._updateState(e))
]));
this._updateState();
}
@@ -219,7 +218,7 @@ class MainThreadDocumentAndEditorStateComputer {
));
}
private _updateState(): void {
private _updateState(widgetFocusCandidate?: ICodeEditor): void {
// models: ignore too large models
const models = new Set<ITextModel>();
@@ -229,10 +228,9 @@ class MainThreadDocumentAndEditorStateComputer {
}
}
// editor: only take those that have a not too large model
const editors = new Map<string, TextEditorSnapshot>();
let activeEditor: string = null;
let activeEditor: string | null = null;
for (const editor of this._codeEditorService.listCodeEditors()) {
if (editor.isSimpleWidget) {
@@ -245,20 +243,27 @@ class MainThreadDocumentAndEditorStateComputer {
) {
const apiEditor = new TextEditorSnapshot(editor);
editors.set(apiEditor.id, apiEditor);
if (editor.hasTextFocus()) {
if (editor.hasTextFocus() || (widgetFocusCandidate === editor && editor.hasWidgetFocus())) {
// text focus has priority, widget focus is tricky because multiple
// editors might claim widget focus at the same time. therefore we use a
// candidate (which is the editor that has raised an widget focus event)
// in addition to the widget focus check
activeEditor = apiEditor.id;
}
}
}
// active editor: if none of the previous editors had focus we try
// to match the active workbench editor with one of editor we have
// just computed
// to match output panels or the active workbench editor with
// one of editor we have just computed
if (!activeEditor) {
let candidate = this._editorService.activeTextEditorWidget;
if (isDiffEditor(candidate)) {
candidate = candidate.getModifiedEditor();
let candidate: IEditor;
if (this._activeEditorOrder === ActiveEditorOrder.Editor) {
candidate = this._getActiveEditorFromEditorPart() || this._getActiveEditorFromPanel();
} else {
candidate = this._getActiveEditorFromPanel() || this._getActiveEditorFromEditorPart();
}
if (candidate) {
editors.forEach(snapshot => {
if (candidate === snapshot.editor) {
@@ -276,6 +281,23 @@ class MainThreadDocumentAndEditorStateComputer {
this._onDidChangeState(delta);
}
}
private _getActiveEditorFromPanel(): IEditor {
let panel = this._panelService.getActivePanel();
if (panel instanceof BaseTextEditor && isCodeEditor(panel.getControl())) {
return panel.getControl();
} else {
return undefined;
}
}
private _getActiveEditorFromEditorPart(): IEditor {
let result = this._editorService.activeTextEditorWidget;
if (isDiffEditor(result)) {
result = result.getModifiedEditor();
}
return result;
}
}
@extHostCustomer
@@ -307,7 +329,8 @@ export class MainThreadDocumentsAndEditors {
@ITextModelService textModelResolverService: ITextModelService,
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IBulkEditService bulkEditService: IBulkEditService
@IBulkEditService bulkEditService: IBulkEditService,
@IPanelService panelService: IPanelService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
@@ -319,7 +342,7 @@ export class MainThreadDocumentsAndEditors {
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
// It is expected that the ctor of the state computer calls our `_onDelta`.
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService);
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, panelService);
this._toDispose = [
mainThreadDocuments,
@@ -430,7 +453,7 @@ export class MainThreadDocumentsAndEditors {
return undefined;
}
findTextEditorIdFor(editor: IEditor): string {
findTextEditorIdFor(editor: IWorkbenchEditor): string {
for (let id in this._textEditors) {
if (this._textEditors[id].matches(editor)) {
return id;

View File

@@ -2,21 +2,20 @@
* 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 editorCommon from 'vs/editor/common/editorCommon';
import { Event, Emitter } from 'vs/base/common/event';
import { IEditor } from 'vs/workbench/common/editor';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { TextEditorCursorStyle, cursorStyleToString, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions, IEditorPropertiesChangeData } from 'vs/workbench/api/node/extHost.protocol';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ITextModel, ISingleEditOperation, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextModelUpdateOptions } from 'vs/editor/common/model';
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EndOfLineSequence, IIdentifiedSingleEditOperation, ISingleEditOperation, ITextModel, ITextModelUpdateOptions } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
import { IApplyEditsOptions, IEditorPropertiesChangeData, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType } from 'vs/workbench/api/node/extHost.protocol';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { IEditor } from 'vs/workbench/common/editor';
export interface IFocusTracker {
onGainedFocus(): void;
@@ -33,7 +32,7 @@ export class MainThreadTextEditorProperties {
}
private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Selection[] {
let result: Selection[] = null;
let result: Selection[] | null = null;
if (codeEditor) {
result = codeEditor.getSelections();
}

View File

@@ -2,31 +2,30 @@
* 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 { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { localize } from 'vs/nls';
import { disposed } from 'vs/base/common/errors';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { equals as objectEquals } from 'vs/base/common/objects';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { EditorViewColumn, viewColumnToEditorGroup, editorGroupToViewColumn } from 'vs/workbench/api/shared/editor';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IApplyEditsOptions, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/shared/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { ExtHostContext, ExtHostEditorsShape, IExtHostContext, ITextDocumentShowOptions, ITextEditorPositionData, MainThreadTextEditorsShape } from '../node/extHost.protocol';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from './mainThreadEditor';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IURLService } from 'vs/platform/url/common/url';
import product from 'vs/platform/node/product';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
@@ -115,7 +114,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// --- from extension host process
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string> {
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Thenable<string> {
const uri = URI.revive(resource);
const editorOptions: ITextEditorOptions = {
@@ -137,7 +136,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
});
}
$tryShowEditor(id: string, position?: EditorViewColumn): TPromise<void> {
$tryShowEditor(id: string, position?: EditorViewColumn): Thenable<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let model = mainThreadEditor.getModel();
@@ -149,7 +148,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return undefined;
}
$tryHideEditor(id: string): TPromise<void> {
$tryHideEditor(id: string): Thenable<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let editors = this._editorService.visibleControls;
@@ -162,65 +161,65 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return undefined;
}
$trySetSelections(id: string, selections: ISelection[]): TPromise<void> {
$trySetSelections(id: string, selections: ISelection[]): Thenable<void> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).setSelections(selections);
return TPromise.as(null);
return Promise.resolve(null);
}
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<void> {
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): Thenable<void> {
key = `${this._instanceId}-${key}`;
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).setDecorations(key, ranges);
return TPromise.as(null);
return Promise.resolve(null);
}
$trySetDecorationsFast(id: string, key: string, ranges: number[]): TPromise<void> {
$trySetDecorationsFast(id: string, key: string, ranges: number[]): Thenable<void> {
key = `${this._instanceId}-${key}`;
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).setDecorationsFast(key, ranges);
return TPromise.as(null);
return Promise.resolve(null);
}
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void> {
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Thenable<void> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
return undefined;
}
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<void> {
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Thenable<void> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).setConfiguration(options);
return TPromise.as(null);
return Promise.resolve(null);
}
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> {
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Thenable<boolean> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
return Promise.resolve(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
}
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): TPromise<boolean> {
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): Thenable<boolean> {
const { edits } = reviveWorkspaceEditDto(dto);
return this._bulkEditService.apply({ edits }, undefined).then(() => true, err => false);
}
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): Thenable<boolean> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError<boolean>(disposed(`TextEditor(${id})`));
return Promise.reject(disposed(`TextEditor(${id})`));
}
return TPromise.as(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
return Promise.resolve(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
}
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
@@ -235,11 +234,11 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
this._codeEditorService.removeDecorationType(key);
}
$getDiffInformation(id: string): TPromise<ILineChange[]> {
$getDiffInformation(id: string): Thenable<ILineChange[]> {
const editor = this._documentsAndEditors.getEditor(id);
if (!editor) {
return TPromise.wrapError<ILineChange[]>(new Error('No such TextEditor'));
return Promise.reject(new Error('No such TextEditor'));
}
const codeEditor = editor.getCodeEditor();
@@ -247,31 +246,42 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
const diffEditors = this._codeEditorService.listDiffEditors();
const [diffEditor] = diffEditors.filter(d => d.getOriginalEditor().getId() === codeEditorId || d.getModifiedEditor().getId() === codeEditorId);
if (!diffEditor) {
return TPromise.as([]);
if (diffEditor) {
return Promise.resolve(diffEditor.getLineChanges());
}
return TPromise.as(diffEditor.getLineChanges());
const dirtyDiffContribution = codeEditor.getContribution('editor.contrib.dirtydiff');
if (dirtyDiffContribution) {
return Promise.resolve((dirtyDiffContribution as any).getChanges());
}
return Promise.resolve([]);
}
}
// --- commands
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn]) {
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn, string?]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const urlService = accessor.get(IURLService);
const [resource, options, position] = args;
const [resource, options, position, label] = args;
if (options || typeof position === 'number') {
// use editor options or editor view column as a hint to use the editor service for opening
return editorService.openEditor({ resource, options }, viewColumnToEditorGroup(editorGroupService, position)).then(_ => void 0);
return editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, position)).then(_ => void 0);
}
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return TPromise.as(void 0);
return Promise.resolve(void 0);
}
if (resource && (resource.scheme === product.urlProtocol || /^vscode/.test(resource.scheme))) {
return urlService.open(resource).then(_ => void 0);
}
// finally, delegate to opener service

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 { SerializedError, onUnexpectedError } from 'vs/base/common/errors';
import { MainThreadErrorsShape, MainContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { MainContext, MainThreadErrorsShape } from 'vs/workbench/api/node/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadErrors)
export class MainThreadErrors implements MainThreadErrorsShape {

View File

@@ -2,14 +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 Severity from 'vs/base/common/severity';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MainThreadExtensionServiceShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { SerializedError } from 'vs/base/common/errors';
import Severity from 'vs/base/common/severity';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IExtHostContext, MainContext, MainThreadExtensionServiceShape } from 'vs/workbench/api/node/extHost.protocol';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
@extHostNamedCustomer(MainContext.MainThreadExtensionService)
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {

View File

@@ -2,15 +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 { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI } from 'vs/base/common/uri';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../node/extHost.protocol';
import { LabelRules, ILabelService } from 'vs/platform/label/common/label';
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
export class MainThreadFileSystem implements MainThreadFileSystemShape {
@@ -20,7 +19,8 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
constructor(
extHostContext: IExtHostContext,
@IFileService private readonly _fileService: IFileService
@IFileService private readonly _fileService: IFileService,
@ILabelService private readonly _labelService: ILabelService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
}
@@ -39,6 +39,10 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
this._fileProvider.delete(handle);
}
$setUriFormatter(selector: string, formatter: LabelRules): void {
this._labelService.registerFormatter(selector, formatter);
}
$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
this._fileProvider.get(handle).$onFileSystemChange(changes);
}
@@ -47,10 +51,12 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
class RemoteFileSystemProvider implements IFileSystemProvider {
private readonly _onDidChange = new Emitter<IFileChange[]>();
private readonly _registrations: IDisposable[];
private readonly _registration: IDisposable;
readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
readonly capabilities: FileSystemProviderCapabilities;
readonly onDidChangeCapabilities: Event<void> = Event.None;
constructor(
fileService: IFileService,
@@ -60,11 +66,11 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
private readonly _proxy: ExtHostFileSystemShape
) {
this.capabilities = capabilities;
this._registrations = [fileService.registerProvider(scheme, this)];
this._registration = fileService.registerProvider(scheme, this);
}
dispose(): void {
dispose(this._registrations);
this._registration.dispose();
this._onDidChange.dispose();
}
@@ -86,42 +92,57 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
// --- forwarding calls
stat(resource: URI): TPromise<IStat> {
private static _asBuffer(data: Uint8Array): Buffer {
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
}
stat(resource: URI): Thenable<IStat> {
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
throw err;
});
}
readFile(resource: URI): TPromise<Uint8Array, any> {
return this._proxy.$readFile(this._handle, resource).then(encoded => {
return Buffer.from(encoded, 'base64');
});
readFile(resource: URI): Thenable<Uint8Array> {
return this._proxy.$readFile(this._handle, resource);
}
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): TPromise<void, any> {
let encoded = Buffer.isBuffer(content)
? content.toString('base64')
: Buffer.from(content.buffer, content.byteOffset, content.byteLength).toString('base64');
return this._proxy.$writeFile(this._handle, resource, encoded, opts);
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Thenable<void> {
return this._proxy.$writeFile(this._handle, resource, RemoteFileSystemProvider._asBuffer(content), opts);
}
delete(resource: URI, opts: FileDeleteOptions): TPromise<void, any> {
delete(resource: URI, opts: FileDeleteOptions): Thenable<void> {
return this._proxy.$delete(this._handle, resource, opts);
}
mkdir(resource: URI): TPromise<void, any> {
mkdir(resource: URI): Thenable<void> {
return this._proxy.$mkdir(this._handle, resource);
}
readdir(resource: URI): TPromise<[string, FileType][], any> {
readdir(resource: URI): Thenable<[string, FileType][]> {
return this._proxy.$readdir(this._handle, resource);
}
rename(resource: URI, target: URI, opts: FileOverwriteOptions): TPromise<void, any> {
rename(resource: URI, target: URI, opts: FileOverwriteOptions): Thenable<void> {
return this._proxy.$rename(this._handle, resource, target, opts);
}
copy(resource: URI, target: URI, opts: FileOverwriteOptions): TPromise<void, any> {
copy(resource: URI, target: URI, opts: FileOverwriteOptions): Thenable<void> {
return this._proxy.$copy(this._handle, resource, target, opts);
}
open(resource: URI): Thenable<number> {
return this._proxy.$open(this._handle, resource);
}
close(fd: number): Thenable<void> {
return this._proxy.$close(this._handle, fd);
}
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Thenable<number> {
return this._proxy.$read(this._handle, fd, pos, RemoteFileSystemProvider._asBuffer(data), offset, length);
}
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Thenable<number> {
return this._proxy.$write(this._handle, fd, pos, RemoteFileSystemProvider._asBuffer(data), offset, length);
}
}

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 { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/common/files';

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ExtHostContext, ObjectIdentifier, IExtHostContext } from '../node/extHost.protocol';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -37,7 +35,7 @@ export class HeapService implements IHeapService {
private _activeSignals = new WeakMap<any, object>();
private _activeIds = new Set<number>();
private _consumeHandle: number;
private _consumeHandle: any;
constructor() {
//
@@ -139,4 +137,4 @@ export class MainThreadHeapService {
}
registerSingleton(IHeapService, HeapService);
registerSingleton(IHeapService, HeapService, true);

View File

@@ -2,26 +2,23 @@
* 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 { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/parts/search/common/search';
import { wireCancellationToken } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto } from '../node/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata } from '../node/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
@@ -115,7 +112,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
displayName,
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.DocumentSymbol[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri));
return this._proxy.$provideDocumentSymbols(handle, model.uri, token);
}
});
}
@@ -126,10 +123,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
const provider = <modes.CodeLensProvider>{
provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Thenable<modes.ICodeLensSymbol[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeLenses(handle, model.uri)));
return this._heapService.trackRecursive(this._proxy.$provideCodeLenses(handle, model.uri, token));
},
resolveCodeLens: (model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Thenable<modes.ICodeLensSymbol> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$resolveCodeLens(handle, model.uri, codeLens)));
return this._heapService.trackRecursive(this._proxy.$resolveCodeLens(handle, model.uri, codeLens, token));
}
};
@@ -151,10 +148,18 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- declaration
$registerDeclaractionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DefinitionProvider>{
provideDefinition: (model, position, token): Thenable<modes.DefinitionLink[]> => {
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DeclarationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DeclarationProvider>{
provideDeclaration: (model, position, token) => {
return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
@@ -162,7 +167,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ImplementationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ImplementationProvider>{
provideImplementation: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
@@ -170,7 +175,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.TypeDefinitionProvider>{
provideTypeDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
@@ -180,7 +185,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.HoverProvider>{
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.Hover> => {
return wireCancellationToken(token, this._proxy.$provideHover(handle, model.uri, position));
return this._proxy.$provideHover(handle, model.uri, position, token);
}
});
}
@@ -190,7 +195,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentHighlightProvider>{
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentHighlights(handle, model.uri, position));
return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);
}
});
}
@@ -200,7 +205,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ReferenceProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ReferenceProvider>{
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> => {
return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context)).then(MainThreadLanguageFeatures._reviveLocationDto);
return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);
}
});
}
@@ -210,7 +215,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Thenable<modes.CodeAction[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context))).then(MainThreadLanguageFeatures._reviveCodeActionDto);
return this._heapService.trackRecursive(this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token)).then(MainThreadLanguageFeatures._reviveCodeActionDto);
},
providedCodeActionKinds
});
@@ -221,7 +226,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options));
return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);
}
});
}
@@ -229,7 +234,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options));
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
}
});
}
@@ -240,7 +245,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
autoFormatTriggerCharacters,
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options));
return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token);
}
});
}
@@ -250,8 +255,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerNavigateTypeSupport(handle: number): void {
let lastResultId: number;
this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<search.IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => {
provideWorkspaceSymbols: (search: string, token: CancellationToken): Thenable<search.IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search, token).then(result => {
if (lastResultId !== undefined) {
this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);
}
@@ -259,8 +264,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);
});
},
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol): TPromise<search.IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i));
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol, token: CancellationToken): Thenable<search.IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item, token).then(i => MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i));
}
});
}
@@ -271,10 +276,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
this._registrations[handle] = modes.RenameProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.RenameProvider>{
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)).then(reviveWorkspaceEditDto);
return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto);
},
resolveRenameLocation: supportResolveLocation
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.RenameLocation> => wireCancellationToken(token, this._proxy.$resolveRenameLocation(handle, model.uri, position))
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.RenameLocation> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)
: undefined
});
}
@@ -282,10 +287,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- suggest
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
this._registrations[handle] = modes.SuggestRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ISuggestSupport>{
this._registrations[handle] = modes.CompletionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CompletionItemProvider>{
triggerCharacters,
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable<modes.ISuggestResult> => {
return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position, context)).then(result => {
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Thenable<modes.CompletionList> => {
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
if (!result) {
return result;
}
@@ -297,22 +302,22 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
});
},
resolveCompletionItem: supportsResolveDetails
? (model, position, suggestion, token) => wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion))
? (model, position, suggestion, token) => this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion, token)
: undefined
});
}
// --- parameter hints
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], triggerCharacter: string[]): void {
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void {
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.SignatureHelpProvider>{
signatureHelpTriggerCharacters: triggerCharacter,
signatureHelpTriggerCharacters: metadata.triggerCharacters,
signatureHelpRetriggerCharacters: metadata.retriggerCharacters,
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.SignatureHelp> => {
return wireCancellationToken(token, this._proxy.$provideSignatureHelp(handle, model.uri, position));
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken, context: modes.SignatureHelpContext): Thenable<modes.SignatureHelp> => {
return this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);
}
});
}
@@ -321,10 +326,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.LinkProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.LinkProvider>{
provideLinks: (model, token) => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideDocumentLinks(handle, model.uri)));
return this._heapService.trackRecursive(this._proxy.$provideDocumentLinks(handle, model.uri, token));
},
resolveLink: (link, token) => {
return wireCancellationToken(token, this._proxy.$resolveDocumentLink(handle, link));
return this._proxy.$resolveDocumentLink(handle, link, token);
}
});
}
@@ -335,7 +340,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
const proxy = this._proxy;
this._registrations[handle] = modes.ColorProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentColorProvider>{
provideDocumentColors: (model, token) => {
return wireCancellationToken(token, proxy.$provideDocumentColors(handle, model.uri))
return proxy.$provideDocumentColors(handle, model.uri, token)
.then(documentColors => {
return documentColors.map(documentColor => {
const [red, green, blue, alpha] = documentColor.color;
@@ -355,10 +360,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
},
provideColorPresentations: (model, colorInfo, token) => {
return wireCancellationToken(token, proxy.$provideColorPresentations(handle, model.uri, {
return proxy.$provideColorPresentations(handle, model.uri, {
color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha],
range: colorInfo.range
}));
}, token);
}
});
}
@@ -369,7 +374,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
const proxy = this._proxy;
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.FoldingRangeProvider>{
provideFoldingRanges: (model, context, token) => {
return wireCancellationToken(token, proxy.$provideFoldingRanges(handle, model.uri, context));
return proxy.$provideFoldingRanges(handle, model.uri, context, token);
}
});
}
// -- smart select
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.SelectionRangeRegistry.register(typeConverters.LanguageSelector.from(selector), {
provideSelectionRanges: (model, position, token) => {
return this._proxy.$provideSelectionRanges(handle, model.uri, position, token);
}
});
}
@@ -405,6 +420,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return {
beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText),
afterText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText),
oneLineAboveText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.oneLineAboveText),
action: onEnterRule.action
};
}

View File

@@ -2,29 +2,42 @@
* 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, UriComponents } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { MainThreadLanguagesShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@extHostNamedCustomer(MainContext.MainThreadLanguages)
export class MainThreadLanguages implements MainThreadLanguagesShape {
private _modeService: IModeService;
constructor(
extHostContext: IExtHostContext,
@IModeService modeService: IModeService
_extHostContext: IExtHostContext,
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService
) {
this._modeService = modeService;
}
public dispose(): void {
dispose(): void {
// nothing
}
$getLanguages(): TPromise<string[]> {
return TPromise.as(this._modeService.getRegisteredModes());
$getLanguages(): Thenable<string[]> {
return Promise.resolve(this._modeService.getRegisteredModes());
}
$changeLanguage(resource: UriComponents, languageId: string): Thenable<void> {
const uri = URI.revive(resource);
let model = this._modelService.getModel(uri);
if (!model) {
return Promise.reject(new Error('Invalid uri'));
}
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (!languageIdentifier || languageIdentifier.language !== languageId) {
return Promise.reject(new Error(`Unknown language id: ${languageId}`));
}
this._modelService.setMode(model, this._modeService.create(languageId));
return Promise.resolve(undefined);
}
}

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ILogService } from 'vs/platform/log/common/log';
import { Disposable } from 'vs/base/common/lifecycle';

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 * as nls from 'vs/nls';
import Severity from 'vs/base/common/severity';

View File

@@ -2,19 +2,23 @@
* 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 { IOutputService, IOutputChannel, OUTPUT_PANEL_ID, Extensions, IOutputChannelRegistry } from 'vs/workbench/parts/output/common/output';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { MainThreadOutputServiceShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { MainThreadOutputServiceShape, MainContext, IExtHostContext, ExtHostOutputServiceShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { UriComponents, URI } from 'vs/base/common/uri';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { anyEvent } from 'vs/base/common/event';
@extHostNamedCustomer(MainContext.MainThreadOutputService)
export class MainThreadOutputService implements MainThreadOutputServiceShape {
export class MainThreadOutputService extends Disposable implements MainThreadOutputServiceShape {
private static _idPool = 1;
private _proxy: ExtHostOutputServiceShape;
private readonly _outputService: IOutputService;
private readonly _partService: IPartService;
private readonly _panelService: IPanelService;
@@ -25,50 +29,79 @@ export class MainThreadOutputService implements MainThreadOutputServiceShape {
@IPartService partService: IPartService,
@IPanelService panelService: IPanelService
) {
super();
this._outputService = outputService;
this._partService = partService;
this._panelService = panelService;
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostOutputService);
const setVisibleChannel = () => {
const panel = this._panelService.getActivePanel();
const visibleChannel: IOutputChannel = panel && panel.getId() === OUTPUT_PANEL_ID ? this._outputService.getActiveChannel() : null;
this._proxy.$setVisibleChannel(visibleChannel ? visibleChannel.id : null);
};
this._register(anyEvent<any>(this._outputService.onActiveOutputChannel, this._panelService.onDidPanelOpen, this._panelService.onDidPanelClose)(() => setVisibleChannel()));
setVisibleChannel();
}
public dispose(): void {
// Leave all the existing channels intact (e.g. might help with troubleshooting)
public $register(label: string, log: boolean, file?: UriComponents): Thenable<string> {
const id = 'extension-output-#' + (MainThreadOutputService._idPool++);
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : null, log });
this._register(toDisposable(() => this.$dispose(id)));
return Promise.resolve(id);
}
public $append(channelId: string, label: string, value: string): TPromise<void> {
this._getChannel(channelId, label).append(value);
return undefined;
}
public $clear(channelId: string, label: string): TPromise<void> {
this._getChannel(channelId, label).clear();
return undefined;
}
public $reveal(channelId: string, label: string, preserveFocus: boolean): TPromise<void> {
const channel = this._getChannel(channelId, label);
this._outputService.showChannel(channel.id, preserveFocus);
return undefined;
}
private _getChannel(channelId: string, label: string): IOutputChannel {
if (!Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannel(channelId)) {
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel(channelId, label);
public $append(channelId: string, value: string): Thenable<void> {
const channel = this._getChannel(channelId);
if (channel) {
channel.append(value);
}
return this._outputService.getChannel(channelId);
return undefined;
}
public $close(channelId: string): TPromise<void> {
public $update(channelId: string): Thenable<void> {
const channel = this._getChannel(channelId);
if (channel) {
channel.update();
}
return undefined;
}
public $clear(channelId: string, till: number): Thenable<void> {
const channel = this._getChannel(channelId);
if (channel) {
channel.clear(till);
}
return undefined;
}
public $reveal(channelId: string, preserveFocus: boolean): Thenable<void> {
const channel = this._getChannel(channelId);
if (channel) {
this._outputService.showChannel(channel.id, preserveFocus);
}
return undefined;
}
public $close(channelId: string): Thenable<void> {
const panel = this._panelService.getActivePanel();
if (panel && panel.getId() === OUTPUT_PANEL_ID && channelId === this._outputService.getActiveChannel().id) {
return this._partService.setPanelHidden(true);
this._partService.setPanelHidden(true);
}
return undefined;
}
public $dispose(channelId: string, label: string): TPromise<void> {
this._getChannel(channelId, label).dispose();
public $dispose(channelId: string): Thenable<void> {
const channel = this._getChannel(channelId);
if (channel) {
channel.dispose();
}
return undefined;
}
private _getChannel(channelId: string): IOutputChannel {
return this._outputService.getChannel(channelId);
}
}

View File

@@ -2,12 +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 { IProgress } from 'vs/platform/progress/common/progress';
import { IProgress, IProgressService2, IProgressStep, IProgressOptions } from 'vs/platform/progress/common/progress';
import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IProgressService2, IProgressStep, IProgressOptions } from 'vs/workbench/services/progress/common/progress';
@extHostNamedCustomer(MainContext.MainThreadProgress)
export class MainThreadProgress implements MainThreadProgressShape {

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 { asWinJsPromise } from 'vs/base/common/async';
import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput } from 'vs/platform/quickinput/common/quickInput';
import { InputBoxOptions } from 'vscode';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, TransferQuickPickItems, MainContext, IExtHostContext, TransferQuickInput, TransferQuickInputButton } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation';
interface QuickInputSession {
input: IQuickInput;
@@ -22,10 +20,10 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private _proxy: ExtHostQuickOpenShape;
private _quickInputService: IQuickInputService;
private _doSetItems: (items: TransferQuickPickItems[]) => any;
private _doSetError: (error: Error) => any;
private _contents: TPromise<TransferQuickPickItems[]>;
private _token: number = 0;
private _items: Record<number, {
resolve(items: TransferQuickPickItems[]): void;
reject(error: Error): void;
}> = {};
constructor(
extHostContext: IExtHostContext,
@@ -38,21 +36,9 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
public dispose(): void {
}
$show(options: IPickOptions<TransferQuickPickItems>): TPromise<number | number[]> {
const myToken = ++this._token;
this._contents = new TPromise<TransferQuickPickItems[]>((c, e) => {
this._doSetItems = (items) => {
if (myToken === this._token) {
c(items);
}
};
this._doSetError = (error) => {
if (myToken === this._token) {
e(error);
}
};
$show(instance: number, options: IPickOptions<TransferQuickPickItems>, token: CancellationToken): Thenable<number | number[]> {
const contents = new Promise<TransferQuickPickItems[]>((resolve, reject) => {
this._items[instance] = { resolve, reject };
});
options = {
@@ -65,14 +51,14 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
if (options.canPickMany) {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
return this._quickInputService.pick(contents, options as { canPickMany: true }, token).then(items => {
if (items) {
return items.map(item => item.handle);
}
return undefined;
});
} else {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options, token)).then(item => {
return this._quickInputService.pick(contents, options, token).then(item => {
if (item) {
return item.handle;
}
@@ -81,23 +67,25 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
}
}
$setItems(items: TransferQuickPickItems[]): TPromise<any> {
if (this._doSetItems) {
this._doSetItems(items);
$setItems(instance: number, items: TransferQuickPickItems[]): Thenable<void> {
if (this._items[instance]) {
this._items[instance].resolve(items);
delete this._items[instance];
}
return undefined;
}
$setError(error: Error): TPromise<any> {
if (this._doSetError) {
this._doSetError(error);
$setError(instance: number, error: Error): Thenable<void> {
if (this._items[instance]) {
this._items[instance].reject(error);
delete this._items[instance];
}
return undefined;
}
// ---- input
$input(options: InputBoxOptions, validateInput: boolean): TPromise<string> {
$input(options: InputBoxOptions, validateInput: boolean, token: CancellationToken): Thenable<string> {
const inputOptions: IInputOptions = Object.create(null);
if (options) {
@@ -115,14 +103,14 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
}
return asWinJsPromise(token => this._quickInputService.input(inputOptions, token));
return this._quickInputService.input(inputOptions, token);
}
// ---- QuickInput
private sessions = new Map<number, QuickInputSession>();
$createOrUpdate(params: TransferQuickInput): TPromise<void> {
$createOrUpdate(params: TransferQuickInput): Thenable<void> {
const sessionId = params.id;
let session = this.sessions.get(sessionId);
if (!session) {
@@ -211,15 +199,15 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
input[param] = params[param];
}
}
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
$dispose(sessionId: number): TPromise<void> {
$dispose(sessionId: number): Thenable<void> {
const session = this.sessions.get(sessionId);
if (session) {
session.input.dispose();
this.sessions.delete(sessionId);
}
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
}

View File

@@ -3,11 +3,9 @@
* 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, { UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter, debounceEvent } from 'vs/base/common/event';
import { assign } from 'vs/base/common/objects';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/services/scm/common/scm';
@@ -15,6 +13,7 @@ import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeature
import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ISplice, Sequence } from 'vs/base/common/sequence';
import { CancellationToken } from 'vs/base/common/cancellation';
class MainThreadSCMResourceGroup implements ISCMResourceGroup {
@@ -73,7 +72,7 @@ class MainThreadSCMResource implements ISCMResource {
public decorations: ISCMResourceDecorations
) { }
open(): TPromise<void> {
open(): Thenable<void> {
return this.proxy.$executeResourceCommand(this.sourceControlHandle, this.groupHandle, this.handle);
}
@@ -124,6 +123,9 @@ class MainThreadSCMProvider implements ISCMProvider {
private _onDidChangeCommitTemplate = new Emitter<string>();
get onDidChangeCommitTemplate(): Event<string> { return this._onDidChangeCommitTemplate.event; }
private _onDidChangeStatusBarCommands = new Emitter<Command[]>();
get onDidChangeStatusBarCommands(): Event<Command[]> { return this._onDidChangeStatusBarCommands.event; }
private _onDidChange = new Emitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
@@ -143,6 +145,10 @@ class MainThreadSCMProvider implements ISCMProvider {
if (typeof features.commitTemplate !== 'undefined') {
this._onDidChangeCommitTemplate.fire(this.commitTemplate);
}
if (typeof features.statusBarCommands !== 'undefined') {
this._onDidChangeStatusBarCommands.fire(this.statusBarCommands);
}
}
$registerGroup(handle: number, id: string, label: string): void {
@@ -241,7 +247,7 @@ class MainThreadSCMProvider implements ISCMProvider {
return TPromise.as(null);
}
return this.proxy.$provideOriginalResource(this.handle, uri)
return TPromise.wrap(this.proxy.$provideOriginalResource(this.handle, uri, CancellationToken.None))
.then(result => result && URI.revive(result));
}
@@ -270,6 +276,9 @@ export class MainThreadSCM implements MainThreadSCMShape {
@ISCMService private scmService: ISCMService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSCM);
debounceEvent(scmService.onDidChangeSelectedRepositories, (_, e) => e, 100)
(this.onDidChangeSelectedRepositories, this, this._disposables);
}
dispose(): void {
@@ -393,6 +402,16 @@ export class MainThreadSCM implements MainThreadSCMShape {
repository.input.placeholder = placeholder;
}
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void {
const repository = this._repositories[sourceControlHandle];
if (!repository) {
return;
}
repository.input.visible = visible;
}
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void {
const repository = this._repositories[sourceControlHandle];
@@ -402,7 +421,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
if (enabled) {
repository.input.validateInput = (value, pos): TPromise<IInputValidation | undefined> => {
return this._proxy.$validateInput(sourceControlHandle, value, pos).then(result => {
return TPromise.wrap(this._proxy.$validateInput(sourceControlHandle, value, pos).then(result => {
if (!result) {
return undefined;
}
@@ -411,10 +430,18 @@ export class MainThreadSCM implements MainThreadSCMShape {
message: result[0],
type: result[1]
};
});
}));
};
} else {
repository.input.validateInput = () => TPromise.as(undefined);
}
}
private onDidChangeSelectedRepositories(repositories: ISCMRepository[]): void {
const handles = repositories
.filter(r => r.provider instanceof MainThreadSCMProvider)
.map(r => (r.provider as MainThreadSCMProvider).handle);
this._proxy.$setSelectedSourceControls(handles);
}
}

View File

@@ -3,9 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { sequence } from 'vs/base/common/async';
import { sequence, IdleValue } from 'vs/base/common/async';
import * as strings from 'vs/base/common/strings';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
@@ -24,9 +22,9 @@ import { EditOperation } from 'vs/editor/common/core/editOperation';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IProgressService2, ProgressLocation } from 'vs/workbench/services/progress/common/progress';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { localize } from 'vs/nls';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
@@ -37,6 +35,7 @@ import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
export interface ISaveParticipantParticipant extends ISaveParticipant {
// progressMessage: string;
@@ -59,7 +58,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
private doTrimTrailingWhitespace(model: ITextModel, isAutoSaved: boolean): void {
let prevSelection: Selection[] = [];
const cursors: Position[] = [];
let cursors: Position[] = [];
let editor = findEditor(model, this.codeEditorService);
if (editor) {
@@ -67,7 +66,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
// Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump
prevSelection = editor.getSelections();
if (isAutoSaved) {
cursors.push(...prevSelection.map(s => new Position(s.positionLineNumber, s.positionColumn)));
cursors = prevSelection.map(s => s.getPosition());
const snippetsRange = SnippetController2.get(editor).getSessionEnclosingRange();
if (snippetsRange) {
for (let lineNumber = snippetsRange.startLineNumber; lineNumber <= snippetsRange.endLineNumber; lineNumber++) {
@@ -87,7 +86,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
}
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): ICodeEditor {
let candidate: ICodeEditor = null;
let candidate: ICodeEditor | null = null;
if (model.isAttachedToEditor()) {
for (const editor of codeEditorService.listCodeEditors()) {
@@ -153,11 +152,26 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void {
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
this.doTrimFinalNewLines(model.textEditorModel);
this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO);
}
}
private doTrimFinalNewLines(model: ITextModel): void {
/**
* returns 0 if the entire file is empty or whitespace only
*/
private findLastLineWithContent(model: ITextModel): number {
for (let lineNumber = model.getLineCount(); lineNumber >= 1; lineNumber--) {
const lineContent = model.getLineContent(lineNumber);
if (strings.lastNonWhitespaceIndex(lineContent) !== -1) {
// this line has content
return lineNumber;
}
}
// no line has content
return 0;
}
private doTrimFinalNewLines(model: ITextModel, isAutoSaved: boolean): void {
const lineCount = model.getLineCount();
// Do not insert new line if file does not end with new line
@@ -166,24 +180,29 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant
}
let prevSelection: Selection[] = [];
let cannotTouchLineNumber = 0;
const editor = findEditor(model, this.codeEditorService);
if (editor) {
prevSelection = editor.getSelections();
if (isAutoSaved) {
for (let i = 0, len = prevSelection.length; i < len; i++) {
const positionLineNumber = prevSelection[i].positionLineNumber;
if (positionLineNumber > cannotTouchLineNumber) {
cannotTouchLineNumber = positionLineNumber;
}
}
}
}
let currentLineNumber = model.getLineCount();
let currentLine = model.getLineContent(currentLineNumber);
let currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1;
while (currentLineIsEmptyOrWhitespace) {
currentLineNumber--;
currentLine = model.getLineContent(currentLineNumber);
currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1;
const lastLineNumberWithContent = this.findLastLineWithContent(model);
const deleteFromLineNumber = Math.max(lastLineNumberWithContent + 1, cannotTouchLineNumber + 1);
const deletionRange = model.validateRange(new Range(deleteFromLineNumber, 1, lineCount, model.getLineMaxColumn(lineCount)));
if (deletionRange.isEmpty()) {
return;
}
const deletionRange = model.validateRange(new Range(currentLineNumber + 1, 1, lineCount + 1, 1));
if (!deletionRange.isEmpty()) {
model.pushEditOperations(prevSelection, [EditOperation.delete(deletionRange)], edits => prevSelection);
}
model.pushEditOperations(prevSelection, [EditOperation.delete(deletionRange)], edits => prevSelection);
if (editor) {
editor.setSelections(prevSelection);
@@ -212,14 +231,15 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
const versionNow = model.getVersionId();
const { tabSize, insertSpaces } = model.getOptions();
const timeout = this._configurationService.getValue('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
return new Promise<ISingleEditOperation[]>((resolve, reject) => {
let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces });
let source = new CancellationTokenSource();
let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces }, source.token);
setTimeout(() => {
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
request.cancel();
source.cancel();
}, timeout);
request.then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits)).then(resolve, err => {
@@ -231,7 +251,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
});
}).then(edits => {
if (!isFalsyOrEmpty(edits) && versionNow === model.getVersionId()) {
if (isNonEmptyArray(edits) && versionNow === model.getVersionId()) {
const editor = findEditor(model, this._editorService);
if (editor) {
this._editsWithEditor(editor, edits);
@@ -354,7 +374,7 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant {
@extHostCustomer
export class SaveParticipant implements ISaveParticipant {
private _saveParticipants: ISaveParticipantParticipant[];
private readonly _saveParticipants: IdleValue<ISaveParticipantParticipant[]>;
constructor(
extHostContext: IExtHostContext,
@@ -362,26 +382,27 @@ export class SaveParticipant implements ISaveParticipant {
@IProgressService2 private readonly _progressService: IProgressService2,
@ILogService private readonly _logService: ILogService
) {
this._saveParticipants = [
this._saveParticipants = new IdleValue(() => [
instantiationService.createInstance(TrimWhitespaceParticipant),
instantiationService.createInstance(CodeActionOnParticipant),
instantiationService.createInstance(FormatOnSaveParticipant),
instantiationService.createInstance(FinalNewLineParticipant),
instantiationService.createInstance(TrimFinalNewLinesParticipant),
instantiationService.createInstance(ExtHostSaveParticipant, extHostContext),
];
]);
// Hook into model
TextFileEditorModel.setSaveParticipant(this);
}
dispose(): void {
TextFileEditorModel.setSaveParticipant(undefined);
this._saveParticipants.dispose();
}
participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Thenable<void> {
return this._progressService.withProgress({ location: ProgressLocation.Window }, progress => {
progress.report({ message: localize('saveParticipants', "Running Save Participants...") });
const promiseFactory = this._saveParticipants.map(p => () => {
const promiseFactory = this._saveParticipants.getValue().map(p => () => {
return Promise.resolve(p.participate(model, env));
});
return sequence(promiseFactory).then(() => { }, err => this._logService.warn(err));

View File

@@ -2,17 +2,16 @@
* 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 { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType, SearchProviderType } from 'vs/platform/search/common/search';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, QueryType, SearchProviderType, ITextQuery, IFileQuery } from 'vs/platform/search/common/search';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol';
import { CancellationToken } from 'vs/base/common/cancellation';
@extHostNamedCustomer(MainContext.MainThreadSearch)
export class MainThreadSearch implements MainThreadSearchShape {
@@ -68,7 +67,7 @@ class SearchOperation {
private static _idPool = 0;
constructor(
readonly progress: (match: IFileMatch) => any,
readonly progress?: (match: IFileMatch) => any,
readonly id: number = ++SearchOperation._idPool,
readonly matches = new Map<string, IFileMatch>()
) {
@@ -78,12 +77,14 @@ class SearchOperation {
addMatch(match: IFileMatch): void {
if (this.matches.has(match.resource.toString())) {
// Merge with previous IFileMatches
this.matches.get(match.resource.toString()).lineMatches.push(...match.lineMatches);
this.matches.get(match.resource.toString()).results.push(...match.results);
} else {
this.matches.set(match.resource.toString(), match);
}
this.progress(this.matches.get(match.resource.toString()));
if (this.progress) {
this.progress(match);
}
}
}
@@ -106,39 +107,37 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
dispose(this._registrations);
}
search(query: ISearchQuery, onProgress?: (p: ISearchProgressItem) => void): TPromise<ISearchComplete> {
fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
return this.doSearch(query, null, token);
}
textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
return this.doSearch(query, onProgress, token);
}
doSearch(query: ITextQuery | IFileQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
if (isFalsyOrEmpty(query.folderQueries)) {
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
let outer: TPromise;
const search = new SearchOperation(onProgress);
this._searches.set(search.id, search);
return new TPromise((resolve, reject) => {
const searchP = query.type === QueryType.File
? this._proxy.$provideFileSearchResults(this._handle, search.id, query, token)
: this._proxy.$provideTextSearchResults(this._handle, search.id, query, token);
const search = new SearchOperation(onProgress);
this._searches.set(search.id, search);
outer = query.type === QueryType.File
? this._proxy.$provideFileSearchResults(this._handle, search.id, query)
: this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, query);
outer.then((result: ISearchCompleteStats) => {
this._searches.delete(search.id);
resolve(({ results: values(search.matches), stats: result.stats, limitHit: result.limitHit }));
}, err => {
this._searches.delete(search.id);
reject(err);
});
}, () => {
if (outer) {
outer.cancel();
}
return Promise.resolve(searchP).then((result: ISearchCompleteStats) => {
this._searches.delete(search.id);
return { results: values(search.matches), stats: result.stats, limitHit: result.limitHit };
}, err => {
this._searches.delete(search.id);
return Promise.reject(err);
});
}
clearCache(cacheKey: string): TPromise<void> {
return this._proxy.$clearCache(cacheKey);
clearCache(cacheKey: string): Promise<void> {
return Promise.resolve(this._proxy.$clearCache(cacheKey));
}
handleFindMatch(session: number, dataOrUri: (UriComponents | IRawFileMatch2)[]): void {
@@ -149,10 +148,10 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
const searchOp = this._searches.get(session);
dataOrUri.forEach(result => {
if ((<IRawFileMatch2>result).lineMatches) {
if ((<IRawFileMatch2>result).results) {
searchOp.addMatch({
resource: URI.revive((<IRawFileMatch2>result).resource),
lineMatches: (<IRawFileMatch2>result).lineMatches
results: (<IRawFileMatch2>result).results
});
} else {
searchOp.addMatch({

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 { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IDisposable } from 'vs/base/common/lifecycle';

View File

@@ -2,49 +2,69 @@
* 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 { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { MainThreadStorageShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { MainThreadStorageShape, MainContext, IExtHostContext, ExtHostStorageShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IDisposable } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadStorage)
export class MainThreadStorage implements MainThreadStorageShape {
private _storageService: IStorageService;
private _proxy: ExtHostStorageShape;
private _storageListener: IDisposable;
private _sharedStorageKeysToWatch: Map<string, boolean> = new Map<string, boolean>();
constructor(
extHostContext: IExtHostContext,
@IStorageService storageService: IStorageService
) {
this._storageService = storageService;
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostStorage);
this._storageListener = this._storageService.onDidChangeStorage(e => {
let shared = e.scope === StorageScope.GLOBAL;
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
try {
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
} catch (error) {
// ignore parsing errors that can happen
}
}
});
}
dispose(): void {
this._storageListener.dispose();
}
$getValue<T>(shared: boolean, key: string): TPromise<T> {
$getValue<T>(shared: boolean, key: string): Thenable<T> {
if (shared) {
this._sharedStorageKeysToWatch.set(key, true);
}
try {
return Promise.resolve(this._getValue<T>(shared, key));
} catch (error) {
return Promise.reject(error);
}
}
private _getValue<T>(shared: boolean, key: string): T {
let jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
if (!jsonValue) {
return TPromise.as(undefined);
}
let value: T;
try {
value = JSON.parse(jsonValue);
return TPromise.as(value);
} catch (err) {
return TPromise.wrapError<T>(err);
return undefined;
}
return JSON.parse(jsonValue);
}
$setValue(shared: boolean, key: string, value: any): TPromise<void> {
let jsonValue: any;
$setValue(shared: boolean, key: string, value: object): Thenable<void> {
let jsonValue: string;
try {
jsonValue = JSON.stringify(value);
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
} catch (err) {
return TPromise.wrapError(err);
return Promise.reject(err);
}
return undefined;
}

View File

@@ -2,35 +2,38 @@
* 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 nls from 'vs/nls';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as Objects from 'vs/base/common/objects';
import { TPromise } from 'vs/base/common/winjs.base';
import * as Types from 'vs/base/common/types';
import * as Platform from 'vs/base/common/platform';
import { IStringDictionary } from 'vs/base/common/collections';
import { IStringDictionary, forEach } from 'vs/base/common/collections';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import {
ContributedTask, ExtensionTaskSourceTransfer, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, TaskSourceKind, ExtensionTaskSource, RevealKind, PanelKind
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, TaskSourceKind, ExtensionTaskSource, RevealKind, PanelKind, RunOptions
} from 'vs/workbench/parts/tasks/common/tasks';
import { TaskDefinition } from 'vs/workbench/parts/tasks/node/tasks';
import { ITaskService, TaskFilter } from 'vs/workbench/parts/tasks/common/taskService';
import { ResolveSet, ResolvedVariables } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskService, TaskFilter, ITaskProvider } from 'vs/workbench/parts/tasks/common/taskService';
import { TaskDefinition } from 'vs/workbench/parts/tasks/node/tasks';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import {
TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO,
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO,
RunOptionsDTO
} from 'vs/workbench/api/shared/tasks';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
namespace TaskExecutionDTO {
export function from(value: TaskExecution): TaskExecutionDTO {
@@ -91,6 +94,15 @@ namespace TaskPresentationOptionsDTO {
return Objects.assign(Object.create(null), value);
}
export function to(value: TaskPresentationOptionsDTO): PresentationOptions {
if (value === void 0 || value === null) {
return { reveal: RevealKind.Always, echo: true, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false };
}
return Objects.assign(Object.create(null), value);
}
}
namespace RunOptionsDTO {
export function from(value: RunOptions): RunOptionsDTO {
if (value === void 0 || value === null) {
return undefined;
}
@@ -242,7 +254,7 @@ namespace TaskSourceDTO {
export function to(value: TaskSourceDTO, workspace: IWorkspaceContextService): ExtensionTaskSource {
let scope: TaskScope;
let workspaceFolder: IWorkspaceFolder;
if (value.scope === void 0) {
if ((value.scope === void 0) || ((typeof value.scope === 'number') && (value.scope !== TaskScope.Global))) {
if (workspace.getWorkspace().folders.length === 0) {
scope = TaskScope.Global;
workspaceFolder = undefined;
@@ -288,7 +300,8 @@ namespace TaskDTO {
presentationOptions: task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined,
isBackground: task.isBackground,
problemMatchers: [],
hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false
hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false,
runOptions: RunOptionsDTO.from(task.runOptions),
};
if (task.group) {
result.group = task.group;
@@ -324,7 +337,7 @@ namespace TaskDTO {
return undefined;
}
command.presentation = TaskPresentationOptionsDTO.to(task.presentationOptions);
command.presentation = Objects.assign(command.presentation || {}, { echo: true, reveal: RevealKind.Always, focus: false, panel: PanelKind.Shared });
command.presentation = Objects.assign(command.presentation || ({} as PresentationOptions), { echo: true, reveal: RevealKind.Always, focus: false, panel: PanelKind.Shared });
let source = TaskSourceDTO.to(task.source, workspace);
@@ -343,7 +356,8 @@ namespace TaskDTO {
command: command,
isBackground: !!task.isBackground,
problemMatchers: task.problemMatchers.slice(),
hasDefinedMatchers: task.hasDefinedMatchers
hasDefinedMatchers: task.hasDefinedMatchers,
runOptions: task.runOptions,
};
return result;
}
@@ -363,15 +377,16 @@ export class MainThreadTask implements MainThreadTaskShape {
private _extHostContext: IExtHostContext;
private _proxy: ExtHostTaskShape;
private _activeHandles: { [handle: number]: boolean; };
private _providers: Map<number, { disposable: IDisposable, provider: ITaskProvider }>;
constructor(
extHostContext: IExtHostContext,
@ITaskService private readonly _taskService: ITaskService,
@IWorkspaceContextService private readonly _workspaceContextServer: IWorkspaceContextService
@IWorkspaceContextService private readonly _workspaceContextServer: IWorkspaceContextService,
@IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTask);
this._activeHandles = Object.create(null);
this._providers = new Map();
this._taskService.onDidStateChange((event: TaskEvent) => {
let task = event.__task;
if (event.kind === TaskEventKind.Start) {
@@ -387,16 +402,16 @@ export class MainThreadTask implements MainThreadTaskShape {
}
public dispose(): void {
Object.keys(this._activeHandles).forEach((handle) => {
this._taskService.unregisterTaskProvider(parseInt(handle, 10));
this._providers.forEach((value) => {
value.disposable.dispose();
});
this._activeHandles = Object.create(null);
this._providers.clear();
}
public $registerTaskProvider(handle: number): TPromise<void> {
this._taskService.registerTaskProvider(handle, {
public $registerTaskProvider(handle: number): Thenable<void> {
let provider: ITaskProvider = {
provideTasks: (validTypes: IStringDictionary<boolean>) => {
return this._proxy.$provideTasks(handle, validTypes).then((value) => {
return Promise.resolve(this._proxy.$provideTasks(handle, validTypes)).then((value) => {
let tasks: Task[] = [];
for (let task of value.tasks) {
let taskTransfer = task._source as any as ExtensionTaskSourceTransfer;
@@ -418,18 +433,18 @@ export class MainThreadTask implements MainThreadTaskShape {
return value;
});
}
});
this._activeHandles[handle] = true;
return TPromise.wrap<void>(undefined);
};
let disposable = this._taskService.registerTaskProvider(provider);
this._providers.set(handle, { disposable, provider });
return Promise.resolve(undefined);
}
public $unregisterTaskProvider(handle: number): TPromise<void> {
this._taskService.unregisterTaskProvider(handle);
delete this._activeHandles[handle];
return TPromise.wrap<void>(undefined);
public $unregisterTaskProvider(handle: number): Thenable<void> {
this._providers.delete(handle);
return Promise.resolve(undefined);
}
public $fetchTasks(filter?: TaskFilterDTO): TPromise<TaskDTO[]> {
public $fetchTasks(filter?: TaskFilterDTO): Thenable<TaskDTO[]> {
return this._taskService.tasks(TaskFilterDTO.to(filter)).then((tasks) => {
let result: TaskDTO[] = [];
for (let task of tasks) {
@@ -442,12 +457,14 @@ export class MainThreadTask implements MainThreadTaskShape {
});
}
public $executeTask(value: TaskHandleDTO | TaskDTO): TPromise<TaskExecutionDTO> {
return new TPromise<TaskExecutionDTO>((resolve, reject) => {
public $executeTask(value: TaskHandleDTO | TaskDTO): Thenable<TaskExecutionDTO> {
return new Promise<TaskExecutionDTO>((resolve, reject) => {
if (TaskHandleDTO.is(value)) {
let workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
this._taskService.getTask(workspaceFolder, value.id, true).then((task: Task) => {
this._taskService.run(task);
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
let result: TaskExecutionDTO = {
id: value.id,
task: TaskDTO.from(task)
@@ -458,7 +475,9 @@ export class MainThreadTask implements MainThreadTaskShape {
});
} else {
let task = TaskDTO.to(value, this._workspaceContextServer, true);
this._taskService.run(task);
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
let result: TaskExecutionDTO = {
id: task._id,
task: TaskDTO.from(task)
@@ -468,8 +487,8 @@ export class MainThreadTask implements MainThreadTaskShape {
});
}
public $terminateTask(id: string): TPromise<void> {
return new TPromise<void>((resolve, reject) => {
public $terminateTask(id: string): Thenable<void> {
return new Promise<void>((resolve, reject) => {
this._taskService.getActiveTasks().then((tasks) => {
for (let task of tasks) {
if (id === task._id) {
@@ -504,16 +523,39 @@ export class MainThreadTask implements MainThreadTaskShape {
this._taskService.registerTaskSystem(key, {
platform: platform,
uriProvider: (path: string): URI => {
return URI.parse(`${info.scheme}://${info.host}:${info.port}${path}`);
return URI.parse(`${info.scheme}://${info.authority}${path}`);
},
context: this._extHostContext,
resolveVariables: (workspaceFolder: IWorkspaceFolder, variables: Set<string>): TPromise<Map<string, string>> => {
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise<ResolvedVariables> => {
let vars: string[] = [];
variables.forEach(item => vars.push(item));
return this._proxy.$resolveVariables(workspaceFolder.uri, vars).then(values => {
let result = new Map<string, string>();
Object.keys(values).forEach(key => result.set(key, values[key]));
return result;
toResolve.variables.forEach(item => vars.push(item));
return Promise.resolve(this._proxy.$resolveVariables(workspaceFolder.uri, { process: toResolve.process, variables: vars })).then(values => {
const partiallyResolvedVars = new Array<string>();
forEach(values.variables, (entry) => {
partiallyResolvedVars.push(entry.value);
});
return new Promise((resolve, reject) => {
this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks').then(resolvedVars => {
let result = {
process: undefined as string,
variables: new Map<string, string>()
};
for (let i = 0; i < partiallyResolvedVars.length; i++) {
const variableName = vars[i].substring(2, vars[i].length - 1);
if (values.variables[vars[i]] === vars[i]) {
result.variables.set(variableName, resolvedVars.get(variableName));
} else {
result.variables.set(variableName, partiallyResolvedVars[i]);
}
}
if (Types.isString(values.process)) {
result.process = values.process;
}
resolve(result);
}, reason => {
reject(reason);
});
});
});
}
});

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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadTelemetryShape, MainContext, IExtHostContext } from '../node/extHost.protocol';

View File

@@ -2,11 +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 { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/parts/terminal/common/terminal';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@@ -14,6 +12,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
private _proxy: ExtHostTerminalServiceShape;
private _remoteAuthority: string | null;
private _toDispose: IDisposable[] = [];
private _terminalProcesses: { [id: number]: ITerminalProcessExtHostProxy } = {};
private _terminalOnDidWriteDataListeners: { [id: number]: IDisposable } = {};
@@ -24,6 +23,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
@ITerminalService private terminalService: ITerminalService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._remoteAuthority = extHostContext.remoteAuthority;
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
// Delay this message so the TerminalInstance constructor has a chance to finish and
// return the ID normally to the extension host. The ID that is passed here will be used
@@ -35,6 +35,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : undefined)));
this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
// Set initial ext host state
this.terminalService.terminalInstances.forEach(t => {
@@ -54,7 +55,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// when the extension host process goes down ?
}
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number> {
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): Thenable<number> {
const shellLaunchConfig: IShellLaunchConfig = {
name,
executable: shellPath,
@@ -64,12 +65,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
ignoreConfigurationCwd: true,
env
};
return TPromise.as(this.terminalService.createTerminal(shellLaunchConfig).id);
return Promise.resolve(this.terminalService.createTerminal(shellLaunchConfig).id);
}
public $createTerminalRenderer(name: string): TPromise<number> {
public $createTerminalRenderer(name: string): Thenable<number> {
const instance = this.terminalService.createTerminalRenderer(name);
return TPromise.as(instance.id);
return Promise.resolve(instance.id);
}
public $show(terminalId: number, preserveFocus: boolean): void {
@@ -163,6 +164,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptTerminalProcessData(terminalId, data);
}
private _onTitleChanged(terminalId: number, name: string): void {
this._proxy.$acceptTerminalTitleChange(terminalId, name);
}
private _onTerminalRendererInput(terminalId: number, data: string): void {
this._proxy.$acceptTerminalRendererInput(terminalId, data);
}
@@ -172,7 +177,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
private _onTerminalOpened(terminalInstance: ITerminalInstance): void {
this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title);
if (terminalInstance.title) {
this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title);
} else {
terminalInstance.waitForTitle().then(title => {
this._proxy.$acceptTerminalOpened(terminalInstance.id, title);
});
}
}
private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
@@ -188,6 +199,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
// Only allow processes on remote ext hosts
if (!this._remoteAuthority) {
return;
}
this._terminalProcesses[request.proxy.terminalId] = request.proxy;
const shellLaunchConfigDto: ShellLaunchConfigDto = {
name: request.shellLaunchConfig.name,
@@ -196,10 +212,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
cwd: request.shellLaunchConfig.cwd,
env: request.shellLaunchConfig.env
};
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.cols, request.rows);
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows);
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
request.proxy.onShutdown(() => this._proxy.$acceptProcessShutdown(request.proxy.terminalId));
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
}
public $sendProcessTitle(terminalId: number, title: string): void {

View File

@@ -2,15 +2,22 @@
* 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 { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer, ViewsRegistry, ICustomViewDescriptor } from 'vs/workbench/common/views';
// {{SQL CARBON EDIT}}
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, ViewsRegistry, ICustomViewDescriptor, IRevealOptions, TreeItemCollapsibleState } from 'vs/workbench/common/views';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { isUndefinedOrNull, isNumber } from 'vs/base/common/types';
import { IMarkdownString } from 'vs/base/common/htmlContent';
// {{SQL CARBON EDIT}}
import * as sqlops from 'sqlops';
import { Emitter } from 'vs/base/common/event';
import { generateUuid } from 'vs/base/common/uuid';
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService';
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
@@ -21,18 +28,25 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
constructor(
extHostContext: IExtHostContext,
@IViewsService private viewsService: IViewsService,
@INotificationService private notificationService: INotificationService
@INotificationService private notificationService: INotificationService,
// {{SQL CARBON EDIT}}
@IObjectExplorerService private objectExplorerService: IObjectExplorerService
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
}
$registerTreeViewDataProvider(treeViewId: string): void {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean }): void {
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
this._dataProviders.set(treeViewId, dataProvider);
const viewer = this.getTreeViewer(treeViewId);
// {{SQL CARBON EDIT}}
if (this.checkForDataExplorer(treeViewId)) {
return;
}
const viewer = this.getTreeView(treeViewId);
if (viewer) {
viewer.dataProvider = dataProvider;
viewer.showCollapseAllAction = !!options.showCollapseAll;
this.registerListeners(treeViewId, viewer);
this._proxy.$setVisible(treeViewId, viewer.visible);
} else {
@@ -40,41 +54,103 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): TPromise<void> {
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Thenable<void> {
return this.viewsService.openView(treeViewId, options.focus)
.then(() => {
const viewer = this.getTreeViewer(treeViewId);
return viewer ? viewer.reveal(item, parentChain, options) : null;
const viewer = this.getTreeView(treeViewId);
return this.reveal(viewer, this._dataProviders.get(treeViewId), item, parentChain, options);
});
}
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): TPromise<void> {
const viewer = this.getTreeViewer(treeViewId);
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): Thenable<void> {
const viewer = this.getTreeView(treeViewId);
const dataProvider = this._dataProviders.get(treeViewId);
if (viewer && dataProvider) {
const itemsToRefresh = dataProvider.getItemsToRefresh(itemsToRefreshByHandle);
return viewer.refresh(itemsToRefresh.length ? itemsToRefresh : void 0);
}
return TPromise.as(null);
return null;
}
private registerListeners(treeViewId: string, treeViewer: ITreeViewer): void {
this._register(treeViewer.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
this._register(treeViewer.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
this._register(treeViewer.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
this._register(treeViewer.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)));
$setMessage(treeViewId: string, message: string | IMarkdownString): void {
const viewer = this.getTreeView(treeViewId);
if (viewer) {
viewer.message = message;
}
}
private getTreeViewer(treeViewId: string): ITreeViewer {
private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
options = options ? options : { select: false, focus: false };
const select = isUndefinedOrNull(options.select) ? false : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
let expand = Math.min(isNumber(options.expand) ? options.expand : options.expand === true ? 1 : 0, 3);
if (dataProvider.isEmpty()) {
// Refresh if empty
await treeView.refresh();
}
for (const parent of parentChain) {
await treeView.expand(parent);
}
item = dataProvider.getItem(item.handle);
if (item) {
await treeView.reveal(item);
if (select) {
treeView.setSelection([item]);
}
if (focus) {
treeView.setFocus(item);
}
let itemsToExpand = [item];
for (; itemsToExpand.length > 0 && expand > 0; expand--) {
await treeView.expand(itemsToExpand);
itemsToExpand = itemsToExpand.reduce((result, item) => {
item = dataProvider.getItem(item.handle);
if (item && item.children && item.children.length) {
result.push(...item.children);
}
return result;
}, []);
}
}
}
private registerListeners(treeViewId: string, treeView: ITreeView): void {
this._register(treeView.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
this._register(treeView.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
this._register(treeView.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
this._register(treeView.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)));
}
private getTreeView(treeViewId: string): ITreeView {
const viewDescriptor: ICustomViewDescriptor = <ICustomViewDescriptor>ViewsRegistry.getView(treeViewId);
return viewDescriptor ? viewDescriptor.treeViewer : null;
return viewDescriptor ? viewDescriptor.treeView : null;
}
// {{SQL CARBON EDIT}}
private checkForDataExplorer(treeViewId: string): boolean {
const viewDescriptor: ICustomViewDescriptor = <ICustomViewDescriptor>ViewsRegistry.getView(treeViewId);
if (viewDescriptor.container.id === 'workbench.view.dataExplorer') {
const dataProvider = new OETreeViewDataProvider(treeViewId, this._proxy);
this.objectExplorerService.registerProvider(treeViewId, dataProvider);
dataProvider.registerOnExpandCompleted(e => this.objectExplorerService.onNodeExpanded({
errorMessage: e.errorMessage,
nodePath: e.nodePath,
nodes: e.nodes,
sessionId: e.sessionId,
providerId: treeViewId
}));
dataProvider.registerOnSessionCreated(e => this.objectExplorerService.onSessionCreated(undefined, e));
viewDescriptor.treeView.refresh();
}
return false;
}
dispose(): void {
this._dataProviders.forEach((dataProvider, treeViewId) => {
const treeViewer = this.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = null;
const treeView = this.getTreeView(treeViewId);
if (treeView) {
treeView.dataProvider = null;
}
});
this._dataProviders.clear();
@@ -98,24 +174,21 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
) {
}
getChildren(treeItem?: ITreeItem): TPromise<ITreeItem[]> {
if (treeItem && treeItem.children) {
return TPromise.as(treeItem.children);
}
return this._proxy.$getChildren(this.treeViewId, treeItem ? treeItem.handle : void 0)
.then(children => {
return this.postGetChildren(children);
}, err => {
this.notificationService.error(err);
return [];
});
getChildren(treeItem?: ITreeItem): Promise<ITreeItem[]> {
return Promise.resolve(this._proxy.$getChildren(this.treeViewId, treeItem ? treeItem.handle : void 0)
.then(
children => this.postGetChildren(children),
err => {
this.notificationService.error(err);
return [];
}));
}
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): ITreeItem[] {
const itemsToRefresh: ITreeItem[] = [];
if (itemsToRefreshByHandle) {
for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
const currentTreeItem = this.itemsMap.get(treeItemHandle);
const currentTreeItem = this.getItem(treeItemHandle);
if (currentTreeItem) { // Refresh only if the item exists
const treeItem = itemsToRefreshByHandle[treeItemHandle];
// Update the current item with refreshed item
@@ -137,8 +210,16 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
return itemsToRefresh;
}
getItem(treeItemHandle: string): ITreeItem {
return this.itemsMap.get(treeItemHandle);
}
isEmpty(): boolean {
return this.itemsMap.size === 0;
}
private postGetChildren(elements: ITreeItem[]): ITreeItem[] {
const result = [];
const result: ITreeItem[] = [];
if (elements) {
for (const element of elements) {
this.itemsMap.set(element.handle, element);
@@ -158,3 +239,100 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
}
}
}
// {{SQL CARBON EDIT}}
export class OETreeViewDataProvider implements sqlops.ObjectExplorerProvider {
protected itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
private onExpandComplete = new Emitter<sqlops.ObjectExplorerExpandInfo>();
private onSessionCreated = new Emitter<sqlops.ObjectExplorerSession>();
private sessionId: string;
handle: number;
readonly providerId = this.treeViewId;
constructor(protected treeViewId: string,
protected _proxy: ExtHostTreeViewsShape
) {
}
public createNewSession(connInfo: sqlops.ConnectionInfo): Thenable<sqlops.ObjectExplorerSessionResponse> {
// no op
this.sessionId = generateUuid();
setTimeout(() => {
this.onSessionCreated.fire({
sessionId: this.sessionId,
errorMessage: undefined,
rootNode: {
errorMessage: undefined,
iconType: undefined,
isLeaf: undefined,
label: undefined,
metadata: undefined,
nodePath: undefined,
nodeStatus: undefined,
nodeSubType: undefined,
nodeType: undefined
},
success: true
});
});
return Promise.resolve({ sessionId: this.sessionId });
}
public expandNode(nodeInfo: sqlops.ExpandNodeInfo): Thenable<boolean> {
this._proxy.$getChildren(this.treeViewId, nodeInfo.nodePath).then(e => {
this.onExpandComplete.fire({
errorMessage: undefined,
nodePath: nodeInfo.nodePath,
nodes: e.map(e => {
return <sqlops.NodeInfo>{
nodePath: e.handle,
label: e.label.label,
iconType: e.icon.path,
// this is just needed since we don't have this
nodeSubType: e.iconDark.path,
isLeaf: e.collapsibleState === TreeItemCollapsibleState.None,
childProvider: e.childProvider,
payload: e.payload,
nodeType: e.contextValue
};
}),
sessionId: this.sessionId
});
});
return Promise.resolve(true);
}
public refreshNode(nodeInfo: sqlops.ExpandNodeInfo): Thenable<boolean> {
// no op
return Promise.resolve(true);
}
public closeSession(closeSessionInfo: sqlops.ObjectExplorerCloseSessionInfo): Thenable<sqlops.ObjectExplorerCloseSessionResponse> {
// no op
return Promise.resolve({ sessionId: undefined, success: true });
}
public findNodes(findNodesInfo: sqlops.FindNodesInfo): Thenable<sqlops.ObjectExplorerFindNodesResponse> {
// no op
return Promise.resolve({ nodes: [] });
}
public registerOnSessionCreated(handler: (response: sqlops.ObjectExplorerSession) => any): void {
// no op
this.onSessionCreated.event(handler);
return;
}
public registerOnSessionDisconnected?(handler: (response: sqlops.ObjectExplorerSession) => any): void {
// no op
return;
}
public registerOnExpandCompleted(handler: (response: sqlops.ObjectExplorerExpandInfo) => any): void {
this.onExpandComplete.event(handler);
return;
}
}

View File

@@ -5,11 +5,10 @@
import { ExtHostContext, IExtHostContext, MainContext, MainThreadUrlsShape, ExtHostUrlsShape } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from './extHostCustomers';
import { TPromise } from 'vs/base/common/winjs.base';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionUrlHandler } from 'vs/platform/url/electron-browser/inactiveExtensionUrlHandler';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
class ExtensionUrlHandler implements IURLHandler {
@@ -19,12 +18,12 @@ class ExtensionUrlHandler implements IURLHandler {
readonly extensionId: string
) { }
handleURL(uri: URI): TPromise<boolean> {
handleURL(uri: URI): Promise<boolean> {
if (uri.authority !== this.extensionId) {
return TPromise.as(false);
return Promise.resolve(false);
}
return this.proxy.$handleExternalUri(this.handle, uri).then(() => true);
return Promise.resolve(this.proxy.$handleExternalUri(this.handle, uri)).then(() => true);
}
}
@@ -42,21 +41,21 @@ export class MainThreadUrls implements MainThreadUrlsShape {
this.proxy = context.getProxy(ExtHostContext.ExtHostUrls);
}
$registerUriHandler(handle: number, extensionId: string): TPromise<void> {
$registerUriHandler(handle: number, extensionId: string): Thenable<void> {
const handler = new ExtensionUrlHandler(this.proxy, handle, extensionId);
const disposable = this.urlService.registerHandler(handler);
this.handlers.set(handle, { extensionId, disposable });
this.inactiveExtensionUrlHandler.registerExtensionHandler(extensionId, handler);
return TPromise.as(null);
return Promise.resolve(null);
}
$unregisterUriHandler(handle: number): TPromise<void> {
$unregisterUriHandler(handle: number): Thenable<void> {
const tuple = this.handlers.get(handle);
if (!tuple) {
return TPromise.as(null);
return Promise.resolve(null);
}
const { extensionId, disposable } = tuple;
@@ -65,7 +64,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
this.handlers.delete(handle);
disposable.dispose();
return TPromise.as(null);
return Promise.resolve(null);
}
dispose(): void {

View File

@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import * as map from 'vs/base/common/map';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI, UriComponents } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@@ -19,6 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import * as vscode from 'vscode';
import { extHostNamedCustomer } from './extHostCustomers';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
@@ -45,7 +45,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
@IWebviewEditorService private readonly _webviewService: IWebviewEditorService,
@IOpenerService private readonly _openerService: IOpenerService,
@IExtensionService private readonly _extensionService: IExtensionService,
@ITelemetryService private readonly _telemetryService: ITelemetryService
) {
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose);
@@ -53,8 +53,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._toDispose.push(_webviewService.registerReviver(MainThreadWebviews.viewType, this));
lifecycleService.onWillShutdown(e => {
e.veto(this._onWillShutdown());
lifecycleService.onBeforeShutdown(e => {
e.veto(this._onBeforeShutdown());
}, this, this._toDispose);
}
@@ -68,6 +68,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
title: string,
showOptions: { viewColumn: EditorViewColumn | null, preserveFocus: boolean },
options: WebviewInputOptions,
extensionId: string,
extensionLocation: UriComponents
): void {
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
@@ -84,6 +85,13 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._webviews.set(handle, webview);
this._activeWebview = handle;
/* __GDPR__
"webviews:createWebviewPanel" : {
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId });
}
public $disposeWebview(handle: WebviewPanelHandle): void {
@@ -122,7 +130,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, showOptions.preserveFocus);
}
public $postMessage(handle: WebviewPanelHandle, message: any): TPromise<boolean> {
public $postMessage(handle: WebviewPanelHandle, message: any): Thenable<boolean> {
const webview = this.getWebview(handle);
const editors = this._editorService.visibleControls
.filter(e => e instanceof WebviewEditor)
@@ -133,7 +141,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
editor.sendMessage(message);
}
return TPromise.as(editors.length > 0);
return Promise.resolve(editors.length > 0);
}
public $registerSerializer(viewType: string): void {
@@ -144,9 +152,9 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._revivers.delete(viewType);
}
public reviveWebview(webview: WebviewEditorInput): TPromise<void> {
public reviveWebview(webview: WebviewEditorInput): Promise<void> {
const viewType = webview.state.viewType;
return this._extensionService.activateByEvent(`onWebviewPanel:${viewType}`).then(() => {
return Promise.resolve(this._extensionService.activateByEvent(`onWebviewPanel:${viewType}`).then(() => {
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
this._webviews.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
@@ -164,7 +172,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
.then(undefined, () => {
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
});
});
}));
}
public canRevive(webview: WebviewEditorInput): boolean {
@@ -175,14 +183,13 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
return this._revivers.has(webview.state.viewType) || !!webview.reviver;
}
private _onWillShutdown(): TPromise<boolean> {
private _onBeforeShutdown(): boolean {
this._webviews.forEach((view) => {
if (this.canRevive(view)) {
view.state.state = view.webviewState;
}
});
return TPromise.as(false); // Don't veto shutdown
return false; // Don't veto shutdown
}
private createWebviewEventDelegate(handle: WebviewPanelHandle) {
@@ -317,4 +324,4 @@ function reviveWebviewIcon(
light: URI.revive(value.light),
dark: URI.revive(value.dark)
};
}
}

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 { IWindowService } from 'vs/platform/windows/common/windows';
import { MainThreadWindowShape, ExtHostWindowShape, ExtHostContext, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
@@ -27,7 +25,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
(this.proxy.$onDidChangeWindowFocus, this.proxy, this.disposables);
}
$getWindowVisibility(): TPromise<boolean> {
$getWindowVisibility(): Thenable<boolean> {
return this.windowService.isFocused();
}

View File

@@ -2,33 +2,34 @@
* 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 { isPromiseCanceledError } from 'vs/base/common/errors';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI, UriComponents } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IFileMatch, IFolderQuery, IPatternInfo, IQueryOptions, ISearchConfiguration, ISearchQuery, ISearchService, QueryType, ISearchProgressItem } from 'vs/platform/search/common/search';
import { ILabelService } from 'vs/platform/label/common/label';
import { IFolderQuery, IPatternInfo, ISearchConfiguration, ISearchProgressItem, ISearchService, QueryType, IFileQuery } from 'vs/platform/search/common/search';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { QueryBuilder } from 'vs/workbench/parts/search/common/queryBuilder';
import { QueryBuilder, ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { TextSearchComplete } from 'vscode';
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
private readonly _toDispose: IDisposable[] = [];
private readonly _activeSearches: { [id: number]: TPromise<URI[]> } = Object.create(null);
private readonly _activeCancelTokens: { [id: number]: CancellationTokenSource } = Object.create(null);
private readonly _proxy: ExtHostWorkspaceShape;
constructor(
@@ -39,7 +40,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
@IStatusbarService private readonly _statusbarService: IStatusbarService,
@IWindowService private readonly _windowService: IWindowService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILabelService private readonly _labelService: ILabelService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
@@ -49,9 +52,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
dispose(): void {
dispose(this._toDispose);
for (let requestId in this._activeSearches) {
const search = this._activeSearches[requestId];
search.cancel();
for (let requestId in this._activeCancelTokens) {
const tokenSource = this._activeCancelTokens[requestId];
tokenSource.cancel();
}
}
@@ -99,20 +102,27 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
}
private _onDidChangeWorkspace(): void {
this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace());
const workspace = this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace();
this._proxy.$acceptWorkspaceData(workspace ? {
configuration: workspace.configuration,
folders: workspace.folders,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
} : null);
}
// --- search ---
$startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<URI[]> {
$startFileSearch(includePattern: string, _includeFolder: UriComponents, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Thenable<URI[]> {
const includeFolder = URI.revive(_includeFolder);
const workspace = this._contextService.getWorkspace();
if (!workspace.folders.length) {
return undefined;
}
let folderQueries: IFolderQuery[];
if (typeof includeFolder === 'string') {
folderQueries = [{ folder: URI.file(includeFolder) }]; // if base provided, only search in that folder
if (includeFolder) {
folderQueries = [{ folder: includeFolder }]; // if base provided, only search in that folder
} else {
folderQueries = workspace.folders.map(folder => ({ folder: folder.uri })); // absolute pattern: search across all folders
}
@@ -131,13 +141,18 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
return !folderConfig.search.followSymlinks;
});
const query: ISearchQuery = {
// TODO replace wth QueryBuilder
folderQueries.forEach(fq => {
fq.ignoreSymlinks = ignoreSymlinks;
});
const query: IFileQuery = {
folderQueries,
type: QueryType.File,
maxResults,
disregardExcludeSettings: excludePatternOrDisregardExcludes === false,
useRipgrep,
ignoreSymlinks
_reason: 'startFileSearch'
};
if (typeof includePattern === 'string') {
query.includePattern = { [includePattern]: true };
@@ -149,62 +164,65 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
this._searchService.extendQuery(query);
const search = this._searchService.search(query).then(result => {
return this._searchService.fileSearch(query, token).then(result => {
return result.results.map(m => m.resource);
}, err => {
if (!isPromiseCanceledError(err)) {
return TPromise.wrapError(err);
return Promise.reject(err);
}
return undefined;
});
this._activeSearches[requestId] = search;
const onDone = () => delete this._activeSearches[requestId];
search.done(onDone, onDone);
return search;
}
$startTextSearch(pattern: IPatternInfo, options: IQueryOptions, requestId: number): TPromise<void, IFileMatch> {
$startTextSearch(pattern: IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Thenable<TextSearchComplete> {
const workspace = this._contextService.getWorkspace();
const folders = workspace.folders.map(folder => folder.uri);
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.text(pattern, folders, options);
query._reason = 'startTextSearch';
const onProgress = (p: ISearchProgressItem) => {
if (p.lineMatches) {
if (p.results) {
this._proxy.$handleTextSearchResult(p, requestId);
}
};
const search = this._searchService.search(query, onProgress).then(
() => {
delete this._activeSearches[requestId];
return null;
const search = this._searchService.textSearch(query, token, onProgress).then(
result => {
return { limitHit: result.limitHit };
},
err => {
delete this._activeSearches[requestId];
if (!isPromiseCanceledError(err)) {
return TPromise.wrapError(err);
return Promise.reject(err);
}
return undefined;
});
this._activeSearches[requestId] = search;
return search;
}
$cancelSearch(requestId: number): Thenable<boolean> {
const search = this._activeSearches[requestId];
if (search) {
delete this._activeSearches[requestId];
search.cancel();
return TPromise.as(true);
}
return undefined;
$checkExists(includes: string[], token: CancellationToken): Thenable<boolean> {
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
const folders = this._contextService.getWorkspace().folders.map(folder => folder.uri);
const query = queryBuilder.file(folders, {
_reason: 'checkExists',
includePattern: includes.join(', '),
exists: true
});
return this._searchService.fileSearch(query, token).then(
result => {
return result.limitHit;
},
err => {
if (!isPromiseCanceledError(err)) {
return Promise.reject(err);
}
return undefined;
});
}
// --- save & edit resources ---
@@ -214,6 +232,10 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
return result.results.every(each => each.success === true);
});
}
$resolveProxy(url: string): Thenable<string> {
return this._windowService.resolveProxy(url);
}
}
CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (accessor: ServicesAccessor, workspace: URI, disableExtensions: string[]) {
@@ -230,4 +252,4 @@ CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (ac
}
return workspaceEditingService.enterWorkspace(workspace.fsPath);
});
});