mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 03:58:33 -05:00
Merge from master
This commit is contained in:
@@ -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>];
|
||||
|
||||
|
||||
@@ -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}}
|
||||
|
||||
25
src/vs/workbench/api/electron-browser/mainThreadClipboard.ts
Normal file
25
src/vs/workbench/api/electron-browser/mainThreadClipboard.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 }));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user