Merge remote-tracking branch 'origin/master' into 46192_terminal_renderer

This commit is contained in:
Daniel Imms
2018-06-13 18:51:23 +02:00
1189 changed files with 30024 additions and 15226 deletions

View File

@@ -17,12 +17,11 @@ import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IExtensionService, IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ViewLocation } from 'vs/workbench/common/views';
import { PersistentViewsViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, TEST_VIEW_CONTAINER_ID } from 'vs/workbench/common/views';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { forEach } from 'vs/base/common/collections';
@@ -84,7 +83,7 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
const cssClass = `extensionViewlet-test`;
const icon = require.toUrl('./media/test.svg');
this.registerCustomViewlet({ id: ViewLocation.TEST.id, title, icon }, TEST_VIEW_CONTAINER_ORDER, cssClass);
this.registerCustomViewlet({ id: TEST_VIEW_CONTAINER_ID, title, icon }, TEST_VIEW_CONTAINER_ORDER, cssClass);
}
private handleAndRegisterCustomViewContainers() {
@@ -143,15 +142,16 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
}
private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor, order: number, cssClass: string): void {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);
const id = descriptor.id;
if (!viewletRegistry.getViewlet(id)) {
const location: ViewLocation = ViewLocation.register(id);
viewContainersRegistry.registerViewContainer(id);
// Register as viewlet
class CustomViewlet extends PersistentViewsViewlet {
class CustomViewlet extends ViewContainerViewlet {
constructor(
@IPartService partService: IPartService,
@ITelemetryService telemetryService: ITelemetryService,
@@ -159,12 +159,11 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
@IStorageService storageService: IStorageService,
@IEditorService editorService: IEditorService,
@IInstantiationService instantiationService: IInstantiationService,
@IContextKeyService contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService,
@IContextMenuService contextMenuService: IContextMenuService,
@IExtensionService extensionService: IExtensionService
) {
super(id, location, `${id}.state`, true, partService, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
super(id, `${id}.state`, true, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
}
}
const viewletDescriptor = new ViewletDescriptor(

View File

@@ -7,22 +7,144 @@
import { localize } from 'vs/nls';
import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewLocation, ViewsRegistry, ICustomViewDescriptor } from 'vs/workbench/common/views';
import { CustomTreeViewPanel } from 'vs/workbench/browser/parts/views/customViewPanel';
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewContainer, ViewsRegistry, ICustomViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views';
import { CustomTreeViewPanel, CustomTreeViewer } from 'vs/workbench/browser/parts/views/customView';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { coalesce, } from 'vs/base/common/arrays';
import { viewsContainersExtensionPoint } from 'vs/workbench/api/browser/viewsContainersExtensionPoint';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/parts/files/common/files';
import { VIEWLET_ID as SCM } from 'vs/workbench/parts/scm/common/scm';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/parts/debug/common/debug';
namespace schema {
interface IUserFriendlyViewDescriptor {
id: string;
name: string;
when?: string;
}
export interface IUserFriendlyViewDescriptor {
id: string;
name: string;
when?: string;
const viewDescriptor: IJSONSchema = {
type: 'object',
properties: {
id: {
description: localize('vscode.extension.contributes.view.id', 'Identifier of the view. Use this to register a data provider through `vscode.window.registerTreeDataProviderForView` API. Also to trigger activating your extension by registering `onView:${id}` event to `activationEvents`.'),
type: 'string'
},
name: {
description: localize('vscode.extension.contributes.view.name', 'The human-readable name of the view. Will be shown'),
type: 'string'
},
when: {
description: localize('vscode.extension.contributes.view.when', 'Condition which must be true to show this view'),
type: 'string'
},
}
};
const viewsContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.views', "Contributes views to the editor"),
type: 'object',
properties: {
'explorer': {
description: localize('views.explorer', "Contributes views to Explorer container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'debug': {
description: localize('views.debug', "Contributes views to Debug container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'scm': {
description: localize('views.scm', "Contributes views to SCM container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'test': {
description: localize('views.test', "Contributes views to Test container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
}
},
additionalProperties: {
description: localize('views.contributed', "Contributes views to contributed views container"),
type: 'array',
items: viewDescriptor,
default: []
}
};
const viewsExtensionPoint: IExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }> = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }>('views', [viewsContainersExtensionPoint], viewsContribution);
class ViewsContainersExtensionHandler implements IWorkbenchContribution {
private viewContainersRegistry: IViewContainersRegistry;
constructor(
@IInstantiationService private instantiationService: IInstantiationService
) {
this.viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
this.handleAndRegisterCustomViews();
}
export function isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
private handleAndRegisterCustomViews() {
viewsExtensionPoint.setHandler(extensions => {
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!this.isValidViewDescriptors(entry.value, collector)) {
return;
}
let container = this.getViewContainer(entry.key);
if (!container) {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
container = this.viewContainersRegistry.get(EXPLORER);
}
const registeredViews = ViewsRegistry.getViews(container);
const viewIds = [];
const viewDescriptors = coalesce(entry.value.map(item => {
// validate
if (viewIds.indexOf(item.id) !== -1) {
collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the view container `{1}`", item.id, container.id));
return null;
}
if (registeredViews.some(v => v.id === item.id)) {
collector.error(localize('duplicateView2', "A view with id `{0}` is already registered in the view container `{1}`", item.id, container.id));
return null;
}
const viewDescriptor = <ICustomViewDescriptor>{
id: item.id,
name: item.name,
ctor: CustomTreeViewPanel,
container,
when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true,
collapsed: this.showCollapsed(container),
treeViewer: this.instantiationService.createInstance(CustomTreeViewer, item.id, container)
};
viewIds.push(viewDescriptor.id);
return viewDescriptor;
}));
ViewsRegistry.registerViews(viewDescriptors);
});
}
});
}
private isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(viewDescriptors)) {
collector.error(localize('requirearray', "views must be an array"));
return false;
@@ -46,124 +168,26 @@ namespace schema {
return true;
}
const viewDescriptor: IJSONSchema = {
type: 'object',
properties: {
id: {
description: localize('vscode.extension.contributes.view.id', 'Identifier of the view. Use this to register a data provider through `vscode.window.registerTreeDataProviderForView` API. Also to trigger activating your extension by registering `onView:${id}` event to `activationEvents`.'),
type: 'string'
},
name: {
description: localize('vscode.extension.contributes.view.name', 'The human-readable name of the view. Will be shown'),
type: 'string'
},
when: {
description: localize('vscode.extension.contributes.view.when', 'Condition which must be true to show this view'),
type: 'string'
},
}
};
export const viewsContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.views', "Contributes views to the editor"),
type: 'object',
properties: {
'explorer': {
description: localize('views.explorer', "Contributes views to Explorer container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'debug': {
description: localize('views.debug', "Contributes views to Debug container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'scm': {
description: localize('views.scm', "Contributes views to SCM container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
},
'test': {
description: localize('views.test', "Contributes views to Test container in the Activity bar"),
type: 'array',
items: viewDescriptor,
default: []
}
},
additionalProperties: {
description: localize('views.contributed', "Contributes views to contributed views container"),
type: 'array',
items: viewDescriptor,
default: []
private getViewContainer(value: string): ViewContainer {
switch (value) {
case 'explorer': return this.viewContainersRegistry.get(EXPLORER);
case 'debug': return this.viewContainersRegistry.get(DEBUG);
case 'scm': return this.viewContainersRegistry.get(SCM);
default: return this.viewContainersRegistry.get(`workbench.view.extension.${value}`);
}
};
}
}
function getViewLocation(value: string): ViewLocation {
switch (value) {
case 'explorer': return ViewLocation.Explorer;
case 'debug': return ViewLocation.Debug;
case 'scm': return ViewLocation.SCM;
default: return ViewLocation.get(`workbench.view.extension.${value}`);
private showCollapsed(container: ViewContainer): boolean {
switch (container.id) {
case EXPLORER:
case SCM:
case DEBUG:
return true;
}
return false;
}
}
function showCollapsed(location: ViewLocation): boolean {
switch (location) {
case ViewLocation.Explorer:
case ViewLocation.SCM:
case ViewLocation.Debug:
return true;
}
return false;
}
ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyViewDescriptor[] }>('views', [viewsContainersExtensionPoint], schema.viewsContribution)
.setHandler((extensions) => {
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!schema.isValidViewDescriptors(entry.value, collector)) {
return;
}
let location = getViewLocation(entry.key);
if (!location) {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
location = ViewLocation.Explorer;
}
const registeredViews = ViewsRegistry.getViews(location);
const viewIds = [];
const viewDescriptors = coalesce(entry.value.map(item => {
const viewDescriptor = <ICustomViewDescriptor>{
id: item.id,
name: item.name,
ctor: CustomTreeViewPanel,
location,
when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true,
collapsed: showCollapsed(location),
treeView: true
};
// validate
if (viewIds.indexOf(viewDescriptor.id) !== -1) {
collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the location `{1}`", viewDescriptor.id, viewDescriptor.location.id));
return null;
}
if (registeredViews.some(v => v.id === viewDescriptor.id)) {
collector.error(localize('duplicateView2', "A view with id `{0}` is already registered in the location `{1}`", viewDescriptor.id, viewDescriptor.location.id));
return null;
}
viewIds.push(viewDescriptor.id);
return viewDescriptor;
}));
ViewsRegistry.registerViews(viewDescriptors);
});
}
});
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ViewsContainersExtensionHandler, LifecyclePhase.Starting);

View File

@@ -50,6 +50,7 @@ import './mainThreadTerminalService';
import './mainThreadTreeViews';
import './mainThreadLogService';
import './mainThreadWebview';
import './mainThreadComments';
import './mainThreadUrls';
import './mainThreadWindow';
import './mainThreadWorkspace';

View File

@@ -0,0 +1,137 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditor, getCodeEditor } 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 '../../../base/common/map';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } 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';
@extHostNamedCustomer(MainContext.MainThreadComments)
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
private _disposables: IDisposable[];
private _proxy: ExtHostCommentsShape;
private _documentProviders = new Map<number, IDisposable>();
private _workspaceProviders = new Map<number, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@IEditorService private _editorService: IEditorService,
@ICommentService private _commentService: ICommentService,
@IPanelService private _panelService: IPanelService,
@ICodeEditorService private _codeEditorService: ICodeEditorService
) {
super();
this._disposables = [];
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
this._disposables.push(this._editorService.onDidActiveEditorChange(e => {
const outerEditor = this.getFocusedEditor();
if (!outerEditor) {
return;
}
const controller = ReviewController.get(outerEditor);
if (!controller) {
return;
}
if (!outerEditor.getModel()) {
return;
}
const outerEditorURI = outerEditor.getModel().uri;
this.provideDocumentComments(outerEditorURI).then(commentInfos => {
this._commentService.setDocumentComments(outerEditorURI, commentInfos.filter(info => info !== null));
});
}));
}
$registerDocumentCommentProvider(handle: number): void {
this._documentProviders.set(handle, undefined);
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);
}
}
);
}
$registerWorkspaceCommentProvider(handle: number): void {
this._workspaceProviders.set(handle, undefined);
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, true);
this._panelService.openPanel(COMMENTS_PANEL_ID);
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
if (commentThreads) {
this._commentService.setWorkspaceComments(handle, commentThreads);
}
});
}
$unregisterDocumentCommentProvider(handle: number): void {
this._documentProviders.delete(handle);
this._commentService.unregisterDataProvider(handle);
}
$unregisterWorkspaceCommentProvider(handle: number): void {
this._workspaceProviders.delete(handle);
if (this._workspaceProviders.size === 0) {
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, false);
}
this._commentService.removeWorkspaceComments(handle);
}
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) {
// notify comment service
this._commentService.updateComments(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();
}
getFocusedEditor(): ICodeEditor {
return this._codeEditorService.getFocusedCodeEditor() || getCodeEditor(this._editorService.activeControl);
}
async provideWorkspaceComments(): Promise<modes.CommentThread[]> {
const result: modes.CommentThread[] = [];
for (const handle of keys(this._workspaceProviders)) {
result.push(...await this._proxy.$provideWorkspaceComments(handle));
}
return result;
}
async provideDocumentComments(resource: URI): Promise<modes.CommentInfo[]> {
const result: modes.CommentInfo[] = [];
for (const handle of keys(this._documentProviders)) {
result.push(await this._proxy.$provideDocumentComments(handle, resource));
}
return result;
}
}

View File

@@ -6,7 +6,7 @@
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, ITerminalLauncher } from 'vs/workbench/parts/debug/common/debug';
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 {
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
@@ -18,8 +18,6 @@ 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 { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { AbstractTerminalLauncher } from 'vs/workbench/parts/debug/electron-browser/terminalSupport';
@extHostNamedCustomer(MainContext.MainThreadDebugService)
@@ -30,13 +28,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
private _breakpointEventsActive: boolean;
private _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
private _debugAdaptersHandleCounter = 1;
private _terminalLauncher: ITerminalLauncher;
constructor(
extHostContext: IExtHostContext,
@IDebugService private debugService: IDebugService,
@ITerminalService private terminalService: ITerminalService,
@IDebugService private debugService: IDebugService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
this._toDispose = [];
@@ -77,10 +73,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
if (!this._terminalLauncher) {
this._terminalLauncher = new ExtensionTerminalLauncher(this.terminalService, this._proxy);
}
return this._terminalLauncher.runInTerminal(args, config);
return this._proxy.$runInTerminal(args, config);
}
public dispose(): void {
@@ -94,7 +87,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
// set up a handler to send more
this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => {
if (e) {
// Ignore session only breakpoint events since they should only reflect in the UI
if (e && !e.sessionOnly) {
const delta: IBreakpointsDeltaDto = {};
if (e.added) {
delta.added = this.convertToDto(e.added);
@@ -302,25 +296,3 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
return this._proxy.$stopDASession(this._handle);
}
}
export class ExtensionTerminalLauncher extends AbstractTerminalLauncher {
constructor(
@ITerminalService terminalService: ITerminalService,
private _proxy: ExtHostDebugServiceShape
) {
super(terminalService);
}
protected runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
return this._proxy.$runInTerminal(args, config);
}
protected isBusy(processId: number): TPromise<boolean> {
return this._proxy.$isTerminalBusy(processId);
}
protected prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<any> {
return this._proxy.$prepareCommandForTerminal(args, config);
}
}

View File

@@ -26,6 +26,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorG
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';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
@@ -250,12 +251,25 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const [resource, options, position] = args;
return editorService.openEditor({ resource, options }, viewColumnToEditorGroup(editorGroupService, position)).then(() => void 0);
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);
}
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return TPromise.as(void 0);
}
// finally, delegate to opener service
return openerService.open(resource).then(_ => void 0);
});
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -273,4 +287,4 @@ CommandsRegistry.registerCommand('_workbench.diff', function (accessor: Services
}
return editorService.openEditor({ leftResource, rightResource, label, description, options }, viewColumnToEditorGroup(editorGroupService, position)).then(() => void 0);
});
});

View File

@@ -9,12 +9,12 @@ 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 { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
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, SymbolInformationDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter } from '../node/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter } 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';
@@ -72,20 +72,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
private static _reviveSymbolInformationDto(data: SymbolInformationDto): modes.SymbolInformation;
private static _reviveSymbolInformationDto(data: SymbolInformationDto[]): modes.SymbolInformation[];
private static _reviveSymbolInformationDto(data: SymbolInformationDto | SymbolInformationDto[]): modes.SymbolInformation | modes.SymbolInformation[] {
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto): search.IWorkspaceSymbol;
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto[]): search.IWorkspaceSymbol[];
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[]): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] {
if (!data) {
return <modes.SymbolInformation>data;
return <search.IWorkspaceSymbol>data;
} else if (Array.isArray(data)) {
data.forEach(MainThreadLanguageFeatures._reviveSymbolInformationDto);
return <modes.SymbolInformation[]>data;
data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto);
return <search.IWorkspaceSymbol[]>data;
} else {
data.location = MainThreadLanguageFeatures._reviveLocationDto(data.location);
if (data.children) {
data.children.forEach(MainThreadLanguageFeatures._reviveSymbolInformationDto);
}
return <modes.SymbolInformation>data;
return <search.IWorkspaceSymbol>data;
}
}
@@ -103,8 +100,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerOutlineSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: string): void {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
extensionId,
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri)).then(MainThreadLanguageFeatures._reviveSymbolInformationDto);
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.DocumentSymbol[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri));
}
});
}
@@ -238,18 +235,18 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerNavigateTypeSupport(handle: number): void {
let lastResultId: number;
this._registrations[handle] = WorkspaceSymbolProviderRegistry.register(<IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<modes.SymbolInformation[]> => {
this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<search.IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => {
if (lastResultId !== undefined) {
this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);
}
lastResultId = result._id;
return MainThreadLanguageFeatures._reviveSymbolInformationDto(result.symbols);
return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);
});
},
resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise<modes.SymbolInformation> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveSymbolInformationDto(i));
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol): TPromise<search.IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i));
}
});
}

View File

@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IProgressService2, IProgress, IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import { IProgress } from 'vs/platform/progress/common/progress';
import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IProgressService2, IProgressStep, IProgressOptions } from 'vs/workbench/services/progress/common/progress';
@extHostNamedCustomer(MainContext.MainThreadProgress)
export class MainThreadProgress implements MainThreadProgressShape {

View File

@@ -7,26 +7,20 @@
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, CancellationToken } from 'vscode';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, MainContext, IExtHostContext } from '../node/extHost.protocol';
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';
interface MultiStepSession {
handle: number;
input: IQuickInput;
token: CancellationToken;
}
import URI from 'vs/base/common/uri';
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private _proxy: ExtHostQuickOpenShape;
private _quickInputService: IQuickInputService;
private _doSetItems: (items: MyQuickPickItems[]) => any;
private _doSetItems: (items: TransferQuickPickItems[]) => any;
private _doSetError: (error: Error) => any;
private _contents: TPromise<MyQuickPickItems[]>;
private _contents: TPromise<TransferQuickPickItems[]>;
private _token: number = 0;
private _multiStep: MultiStepSession;
constructor(
extHostContext: IExtHostContext,
@@ -39,17 +33,10 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
public dispose(): void {
}
$show(multiStepHandle: number | undefined, options: IPickOptions): TPromise<number | number[]> {
const multiStep = typeof multiStepHandle === 'number';
if (multiStep && !(this._multiStep && multiStepHandle === this._multiStep.handle && !this._multiStep.token.isCancellationRequested)) {
return TPromise.as(undefined);
}
const input: IQuickInput = multiStep ? this._multiStep.input : this._quickInputService;
$show(options: IPickOptions): TPromise<number | number[]> {
const myToken = ++this._token;
this._contents = new TPromise<MyQuickPickItems[]>((c, e) => {
this._contents = new TPromise<TransferQuickPickItems[]>((c, e) => {
this._doSetItems = (items) => {
if (myToken === this._token) {
c(items);
@@ -64,31 +51,31 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
});
if (options.canPickMany) {
return asWinJsPromise(token => input.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
if (items) {
return items.map(item => item.handle);
}
return undefined;
}, undefined, progress => {
if (progress) {
this._proxy.$onItemSelected((<MyQuickPickItems>progress).handle);
this._proxy.$onItemSelected((<TransferQuickPickItems>progress).handle);
}
});
} else {
return asWinJsPromise(token => input.pick(this._contents, options, token)).then(item => {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options, token)).then(item => {
if (item) {
return item.handle;
}
return undefined;
}, undefined, progress => {
if (progress) {
this._proxy.$onItemSelected((<MyQuickPickItems>progress).handle);
this._proxy.$onItemSelected((<TransferQuickPickItems>progress).handle);
}
});
}
}
$setItems(items: MyQuickPickItems[]): TPromise<any> {
$setItems(items: TransferQuickPickItems[]): TPromise<any> {
if (this._doSetItems) {
this._doSetItems(items);
}
@@ -104,14 +91,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
// ---- input
$input(multiStepHandle: number | undefined, options: InputBoxOptions, validateInput: boolean): TPromise<string> {
const multiStep = typeof multiStepHandle === 'number';
if (multiStep && !(this._multiStep && multiStepHandle === this._multiStep.handle && !this._multiStep.token.isCancellationRequested)) {
return TPromise.as(undefined);
}
const input: IQuickInput = multiStep ? this._multiStep.input : this._quickInputService;
$input(options: InputBoxOptions, validateInput: boolean): TPromise<string> {
const inputOptions: IInputOptions = Object.create(null);
if (options) {
@@ -129,27 +109,73 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
}
return asWinJsPromise(token => input.input(inputOptions, token));
return asWinJsPromise(token => this._quickInputService.input(inputOptions, token));
}
// ---- Multi-step input
// ---- QuickInput
$multiStep(handle: number): TPromise<never> {
let outerReject: (err: any) => void;
let innerResolve: (value: void) => void;
const promise = new TPromise<never>((_, rej) => outerReject = rej, () => innerResolve(undefined));
this._quickInputService.multiStepInput((input, token) => {
this._multiStep = { handle, input, token };
const promise = new TPromise<void>(res => innerResolve = res);
token.onCancellationRequested(() => innerResolve(undefined));
return promise;
})
.then(() => promise.cancel(), err => outerReject(err))
.then(() => {
if (this._multiStep && this._multiStep.handle === handle) {
this._multiStep = null;
private sessions = new Map<number, IQuickInput>();
$createOrUpdate(params: TransferQuickInput): TPromise<void> {
const sessionId = params.id;
let session = this.sessions.get(sessionId);
if (!session) {
if (params.type === 'quickPick') {
const input = this._quickInputService.createQuickPick();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidChangeActive(items => {
this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidChangeSelection(items => {
this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
});
session = input;
} else {
const input = this._quickInputService.createInputBox();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
session = input;
}
this.sessions.set(sessionId, session);
}
for (const param in params) {
if (param === 'id' || param === 'type') {
continue;
}
if (param === 'visible') {
if (params.visible) {
session.show();
} else {
session.hide();
}
});
return promise;
} else if (param === 'buttons') {
params.buttons.forEach(button => {
const iconPath = button.iconPath;
iconPath.dark = URI.revive(iconPath.dark);
if (iconPath.light) {
iconPath.light = URI.revive(iconPath.light);
}
});
session[param] = params[param];
} else {
session[param] = params[param];
}
}
return TPromise.as(undefined);
}
$dispose(sessionId: number): TPromise<void> {
const session = this.sessions.get(sessionId);
if (session) {
session.dispose();
this.sessions.delete(sessionId);
}
return TPromise.as(undefined);
}
}

View File

@@ -24,7 +24,7 @@ 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/platform/progress/common/progress';
import { IProgressService2, ProgressLocation } from 'vs/workbench/services/progress/common/progress';
import { localize } from 'vs/nls';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';

View File

@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as crypto from 'crypto';
import * as nls from 'vs/nls';
import URI from 'vs/base/common/uri';
@@ -17,9 +15,12 @@ import * as Platform from 'vs/base/common/platform';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import {
ContributedTask, ExtensionTaskSourceTransfer, TaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
ContributedTask, ExtensionTaskSourceTransfer, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, TaskSourceKind, ExtensionTaskSource, RevealKind, PanelKind
} 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 { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@@ -29,8 +30,6 @@ import {
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO
} from 'vs/workbench/api/shared/tasks';
export { TaskDTO, TaskHandleDTO, TaskExecutionDTO, TaskFilterDTO };
namespace TaskExecutionDTO {
export function from(value: TaskExecution): TaskExecutionDTO {
return {
@@ -65,17 +64,13 @@ namespace TaskProcessEndedDTO {
}
namespace TaskDefinitionDTO {
export function from(value: TaskIdentifier): TaskDefinitionDTO {
export function from(value: KeyedTaskIdentifier): TaskDefinitionDTO {
let result = Objects.assign(Object.create(null), value);
delete result._key;
return result;
}
export function to(value: TaskDefinitionDTO): TaskIdentifier {
const hash = crypto.createHash('md5');
hash.update(JSON.stringify(value));
let result = Objects.assign(Object.create(null), value);
result._key = hash.digest('hex');
return result;
export function to(value: TaskDefinitionDTO): KeyedTaskIdentifier {
return TaskDefinition.createTaskIdentifier(value, console);
}
}
@@ -393,15 +388,24 @@ export class MainThreadTask implements MainThreadTaskShape {
this._taskService.registerTaskProvider(handle, {
provideTasks: () => {
return this._proxy.$provideTasks(handle).then((value) => {
let tasks: Task[] = [];
for (let task of value.tasks) {
if (ContributedTask.is(task)) {
let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
if (uri) {
delete (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(uri));
let taskTransfer = task._source as any as ExtensionTaskSourceTransfer;
if (taskTransfer.__workspaceFolder !== void 0 && taskTransfer.__definition !== void 0) {
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(taskTransfer.__workspaceFolder));
delete taskTransfer.__workspaceFolder;
let taskIdentifier = TaskDefinition.createTaskIdentifier(taskTransfer.__definition, console);
delete taskTransfer.__definition;
if (taskIdentifier !== void 0) {
(task as ContributedTask).defines = taskIdentifier;
task._id = `${task._id}.${taskIdentifier._key}`;
tasks.push(task);
}
} else {
console.warn(`Dropping task ${task.name}. Missing workspace folder and task definition`);
}
}
value.tasks = tasks;
return value;
});
}

View File

@@ -7,7 +7,7 @@
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 } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer, ViewsRegistry, ICustomViewDescriptor } 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';
@@ -30,10 +30,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
$registerTreeViewDataProvider(treeViewId: string): void {
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
this._dataProviders.set(treeViewId, dataProvider);
const treeViewer = this.viewsService.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = dataProvider;
this.registerListeners(treeViewId, treeViewer);
const viewer = this.getTreeViewer(treeViewId);
if (viewer) {
viewer.dataProvider = dataProvider;
this.registerListeners(treeViewId, viewer);
} else {
this.notificationService.error('No view is registered with id: ' + treeViewId);
}
@@ -42,13 +42,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise<void> {
return this.viewsService.openView(treeViewId)
.then(() => {
const viewer = this.viewsService.getTreeViewer(treeViewId);
const viewer = this.getTreeViewer(treeViewId);
return viewer ? viewer.reveal(item, parentChain, options) : null;
});
}
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): TPromise<void> {
const viewer = this.viewsService.getTreeViewer(treeViewId);
const viewer = this.getTreeViewer(treeViewId);
const dataProvider = this._dataProviders.get(treeViewId);
if (viewer && dataProvider) {
const itemsToRefresh = dataProvider.getItemsToRefresh(itemsToRefreshByHandle);
@@ -63,9 +63,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._register(treeViewer.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
}
private getTreeViewer(treeViewId: string): ITreeViewer {
const viewDescriptor: ICustomViewDescriptor = <ICustomViewDescriptor>ViewsRegistry.getView(treeViewId);
return viewDescriptor ? viewDescriptor.treeViewer : null;
}
dispose(): void {
this._dataProviders.forEach((dataProvider, treeViewId) => {
const treeViewer = this.viewsService.getTreeViewer(treeViewId);
const treeViewer = this.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = null;
}

View File

@@ -77,7 +77,10 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
}
const webview = this._webviewService.createWebview(MainThreadWebviews.viewType, title, mainThreadShowOptions, options, URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
const webview = this._webviewService.createWebview(MainThreadWebviews.viewType, title, mainThreadShowOptions, {
...options,
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(URI.revive) : undefined
}, URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
webview.state = {
viewType: viewType,
state: undefined
@@ -273,4 +276,4 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", viewType)}</body>
</html>`;
}
}
}

View File

@@ -46,7 +46,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
import * as vscode from 'vscode';
import * as paths from 'vs/base/common/paths';
import * as files from 'vs/platform/files/common/files';
import { MainContext, ExtHostContext, IInitData, IExtHostContext } from './extHost.protocol';
import { MainContext, ExtHostContext, IInitData, IMainContext } from './extHost.protocol';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
@@ -58,6 +58,7 @@ import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionA
import { OverviewRulerLane } from 'vs/editor/common/model';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';
import { ExtHostComments } from './extHostComments';
import { ExtHostSearch } from './extHostSearch';
import { ExtHostUrls } from './extHostUrls';
@@ -79,7 +80,7 @@ function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
if (extension.enableProposedApi) {
return fn;
} else {
return <any>throwProposedApiError;
return throwProposedApiError.bind(null, extension);
}
}
@@ -88,7 +89,7 @@ function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
*/
export function createApiFactory(
initData: IInitData,
rpcProtocol: IExtHostContext,
rpcProtocol: IMainContext,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
extensionService: ExtHostExtensionService,
@@ -111,7 +112,6 @@ export function createApiFactory(
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostHeapService, extHostLogService));
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands));
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration));
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, schemeTransformer, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
@@ -119,12 +119,14 @@ export function createApiFactory(
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostLogService));
const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer));
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace, extHostDocumentsAndEditors, extHostConfiguration));
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const exthostCommentProviders = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands.converter, extHostDocuments));
// Check that no named customers are missing
const expected: ProxyIdentifier<any>[] = Object.keys(ExtHostContext).map((key) => (<any>ExtHostContext)[key]);
@@ -386,13 +388,13 @@ export function createApiFactory(
return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest);
},
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any {
return extHostQuickOpen.showQuickPick(undefined, items, options, token);
return extHostQuickOpen.showQuickPick(items, options, token);
},
showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) {
return extHostQuickOpen.showWorkspaceFolderPick(options);
},
showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
return extHostQuickOpen.showInput(undefined, options, token);
return extHostQuickOpen.showInput(options, token);
},
showOpenDialog(options) {
return extHostDialogs.showOpenDialog(options);
@@ -446,7 +448,13 @@ export function createApiFactory(
}),
registerProtocolHandler: proposedApiFunction(extension, (handler: vscode.ProtocolHandler) => {
return extHostUrls.registerProtocolHandler(extension.id, handler);
})
}),
createQuickPick: proposedApiFunction(extension, (): vscode.QuickPick => {
return extHostQuickOpen.createQuickPick(extension.id);
}),
createInputBox: proposedApiFunction(extension, (): vscode.InputBox => {
return extHostQuickOpen.createInputBox(extension.id);
}),
};
// namespace: workspace
@@ -545,33 +553,21 @@ export function createApiFactory(
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
return extHostTask.registerTaskProvider(extension, provider);
},
fetchTasks: proposedApiFunction(extension, (filter?: vscode.TaskFilter): Thenable<vscode.Task[]> => {
return extHostTask.fetchTasks(filter);
}),
executeTask: proposedApiFunction(extension, (task: vscode.Task): Thenable<vscode.TaskExecution> => {
return extHostTask.executeTask(extension, task);
}),
get taskExecutions(): vscode.TaskExecution[] {
return extHostTask.taskExecutions;
},
onDidStartTask: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidStartTask(listeners, thisArgs, disposables);
},
onDidEndTask: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidEndTask(listeners, thisArgs, disposables);
},
registerFileSystemProvider(scheme, provider, options) {
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
},
registerDeprecatedFileSystemProvider: proposedApiFunction(extension, (scheme, provider) => {
return extHostFileSystem.registerDeprecatedFileSystemProvider(scheme, provider);
}),
registerSearchProvider: proposedApiFunction(extension, (scheme, provider) => {
return extHostSearch.registerSearchProvider(scheme, provider);
}),
registerDocumentCommentProvider: proposedApiFunction(extension, (provider: vscode.DocumentCommentProvider) => {
return exthostCommentProviders.registerDocumentCommentProvider(provider);
}),
registerWorkspaceCommentProvider: proposedApiFunction(extension, (provider: vscode.WorkspaceCommentProvider) => {
return exthostCommentProviders.registerWorkspaceCommentProvider(provider);
}),
onDidRenameResource: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
return extHostDocuments.onDidRenameResource(listener, thisArg, disposables);
}),
})
};
// namespace: scm
@@ -705,18 +701,7 @@ export function createApiFactory(
SourceBreakpoint: extHostTypes.SourceBreakpoint,
StatusBarAlignment: extHostTypes.StatusBarAlignment,
SymbolInformation: extHostTypes.SymbolInformation,
SymbolInformation2: class extends extHostTypes.SymbolInformation2 {
constructor(name, detail, kind, range, location) {
checkProposedApiEnabled(extension);
super(name, detail, kind, range, location);
}
},
Hierarchy: class <T> extends extHostTypes.Hierarchy<T> {
constructor(parent: T) {
checkProposedApiEnabled(extension);
super(parent);
}
},
DocumentSymbol: extHostTypes.DocumentSymbol,
SymbolKind: extHostTypes.SymbolKind,
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
@@ -746,17 +731,29 @@ export function createApiFactory(
ConfigurationTarget: extHostTypes.ConfigurationTarget,
RelativePattern: extHostTypes.RelativePattern,
DeprecatedFileChangeType: extHostTypes.DeprecatedFileChangeType,
DeprecatedFileType: extHostTypes.DeprecatedFileType,
FileChangeType: extHostTypes.FileChangeType,
FileType: files.FileType,
FileSystemError: extHostTypes.FileSystemError,
FoldingRange: extHostTypes.FoldingRange,
FoldingRangeKind: extHostTypes.FoldingRangeKind
FoldingRangeKind: extHostTypes.FoldingRangeKind,
CommentThreadCollapsibleState: extHostTypes.CommentThreadCollapsibleState
};
};
}
/**
* Returns the original fs path (using the original casing for the drive letter)
*/
export function originalFSPath(uri: URI): string {
const result = uri.fsPath;
if (/^[a-zA-Z]:/.test(result) && uri.path.charAt(1).toLowerCase() === result.charAt(0)) {
// Restore original drive letter casing
return uri.path.charAt(1) + result.substr(1);
}
return result;
}
class Extension<T> implements vscode.Extension<T> {
private _extensionService: ExtHostExtensionService;
@@ -768,7 +765,7 @@ class Extension<T> implements vscode.Extension<T> {
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription) {
this._extensionService = extensionService;
this.id = description.id;
this.extensionPath = paths.normalize(description.extensionLocation.fsPath, true);
this.extensionPath = paths.normalize(originalFSPath(description.extensionLocation), true);
this.packageJSON = description;
}

View File

@@ -18,7 +18,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import { IProgressOptions, IProgressStep } from 'vs/workbench/services/progress/common/progress';
import * as editorCommon from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
@@ -26,7 +26,7 @@ import * as modes from 'vs/editor/common/modes';
import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IConfig, IAdapterExecutable, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug';
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { IQuickPickItem, IPickOptions, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
@@ -102,6 +102,14 @@ export interface MainThreadCommandsShape extends IDisposable {
$getCommands(): Thenable<string[]>;
}
export interface MainThreadCommentsShape extends IDisposable {
$registerDocumentCommentProvider(handle: number): void;
$unregisterDocumentCommentProvider(handle: number): void;
$registerWorkspaceCommentProvider(handle: number): void;
$unregisterWorkspaceCommentProvider(handle: number): void;
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent): void;
}
export interface MainThreadConfigurationShape extends IDisposable {
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: UriComponents): TPromise<void>;
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: UriComponents): TPromise<void>;
@@ -330,15 +338,74 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$sendProcessExit(terminalId: number, exitCode: number): void;
}
export interface MyQuickPickItems extends IPickOpenEntry {
export interface TransferQuickPickItems extends IQuickPickItem {
handle: number;
}
export interface TransferQuickInputButton extends IQuickInputButton {
handle: number;
}
export type TransferQuickInput = TransferQuickPick | TransferInputBox;
export interface BaseTransferQuickInput {
id: number;
type?: 'quickPick' | 'inputBox';
enabled?: boolean;
busy?: boolean;
visible?: boolean;
}
export interface TransferQuickPick extends BaseTransferQuickInput {
type?: 'quickPick';
value?: string;
placeholder?: string;
buttons?: TransferQuickInputButton[];
items?: TransferQuickPickItems[];
canSelectMany?: boolean;
ignoreFocusOut?: boolean;
matchOnDescription?: boolean;
matchOnDetail?: boolean;
}
export interface TransferInputBox extends BaseTransferQuickInput {
type?: 'inputBox';
value?: string;
placeholder?: string;
password?: boolean;
buttons?: TransferQuickInputButton[];
prompt?: string;
validationMessage?: string;
}
export interface MainThreadQuickOpenShape extends IDisposable {
$show(multiStepHandle: number | undefined, options: IPickOptions): TPromise<number | number[]>;
$setItems(items: MyQuickPickItems[]): TPromise<any>;
$show(options: IPickOptions): TPromise<number | number[]>;
$setItems(items: TransferQuickPickItems[]): TPromise<any>;
$setError(error: Error): TPromise<any>;
$input(multiStepHandle: number | undefined, options: vscode.InputBoxOptions, validateInput: boolean): TPromise<string>;
$multiStep(handle: number): TPromise<never>;
$input(options: vscode.InputBoxOptions, validateInput: boolean): TPromise<string>;
$createOrUpdate(params: TransferQuickInput): TPromise<void>;
$dispose(id: number): TPromise<void>;
}
export interface MainThreadStatusBarShape extends IDisposable {
@@ -666,17 +733,15 @@ export interface LocationDto {
range: IRange;
}
export interface SymbolInformationDto extends IdObject {
export interface WorkspaceSymbolDto extends IdObject {
name: string;
containerName?: string;
kind: modes.SymbolKind;
location: LocationDto;
definingRange: IRange;
children?: SymbolInformationDto[];
}
export interface WorkspaceSymbolsDto extends IdObject {
symbols: SymbolInformationDto[];
symbols: WorkspaceSymbolDto[];
}
export interface ResourceFileEditDto {
@@ -720,7 +785,7 @@ export interface CodeActionDto {
}
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<SymbolInformationDto[]>;
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<modes.DocumentSymbol[]>;
$provideCodeLenses(handle: number, resource: UriComponents): TPromise<modes.ICodeLensSymbol[]>;
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol>;
$provideDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<LocationDto | LocationDto[]>;
@@ -734,7 +799,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
$provideWorkspaceSymbols(handle: number, search: string): TPromise<WorkspaceSymbolsDto>;
$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto>;
$resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto>;
$releaseWorkspaceSymbols(handle: number, id: number): void;
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<WorkspaceEditDto>;
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.RenameLocation>;
@@ -752,6 +817,10 @@ export interface ExtHostLanguageFeaturesShape {
export interface ExtHostQuickOpenShape {
$onItemSelected(handle: number): void;
$validateInput(input: string): TPromise<string>;
$onDidChangeActive(sessionId: number, handles: number[]): void;
$onDidChangeSelection(sessionId: number, handles: number[]): void;
$onDidAccept(sessionId: number): void;
$onDidTriggerButton(sessionId: number, handle: number): void;
}
export interface ShellLaunchConfigDto {
@@ -833,8 +902,6 @@ export interface ISourceMultiBreakpointDto {
export interface ExtHostDebugServiceShape {
$substituteVariables(folder: UriComponents | undefined, config: IConfig): TPromise<IConfig>;
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void>;
$isTerminalBusy(processId: number): TPromise<boolean>;
$prepareCommandForTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<any>;
$startDASession(handle: number, debugType: string, adapterExecutableInfo: IAdapterExecutable | null, debugPort: number): TPromise<void>;
$stopDASession(handle: number): TPromise<void>;
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise<void>;
@@ -874,10 +941,18 @@ export interface ExtHostProgressShape {
$acceptProgressCanceled(handle: number): void;
}
export interface ExtHostCommentsShape {
$provideDocumentComments(handle: number, document: UriComponents): TPromise<modes.CommentInfo>;
$createNewCommentThread?(handle: number, document: UriComponents, range: IRange, text: string): TPromise<modes.CommentThread>;
$replyToCommentThread?(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): TPromise<modes.CommentThread>;
$provideWorkspaceComments(handle: number): TPromise<modes.CommentThread[]>;
}
// --- proxy identifiers
export const MainContext = {
MainThreadCommands: <ProxyIdentifier<MainThreadCommandsShape>>createMainId<MainThreadCommandsShape>('MainThreadCommands'),
MainThreadComments: createMainId<MainThreadCommentsShape>('MainThreadComments'),
MainThreadConfiguration: createMainId<MainThreadConfigurationShape>('MainThreadConfiguration'),
MainThreadDebugService: createMainId<MainThreadDebugServiceShape>('MainThreadDebugService'),
MainThreadDecorations: createMainId<MainThreadDecorationsShape>('MainThreadDecorations'),
@@ -935,6 +1010,7 @@ export const ExtHostContext = {
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls'),
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress')
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'),
ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'),
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls')
};

View File

@@ -11,12 +11,11 @@ import * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { IRawColorInfo } from 'vs/workbench/api/node/extHost.protocol';
import { 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 { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures';
import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand } from './apiCommands';
@@ -266,11 +265,11 @@ export class ExtHostApiCommands {
* @return A promise that resolves to an array of symbol information.
*/
private _executeWorkspaceSymbolProvider(query: string): Thenable<types.SymbolInformation[]> {
return this._commands.executeCommand<[IWorkspaceSymbolProvider, modes.SymbolInformation[]][]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
return this._commands.executeCommand<[search.IWorkspaceSymbolProvider, search.IWorkspaceSymbol[]][]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
const result: types.SymbolInformation[] = [];
if (Array.isArray(value)) {
for (let tuple of value) {
result.push(...tuple[1].map(typeConverters.SymbolInformation.to));
result.push(...tuple[1].map(typeConverters.WorkspaceSymbol.to));
}
}
return result;
@@ -404,13 +403,13 @@ export class ExtHostApiCommands {
});
}
private _executeDocumentSymbolProvider(resource: URI): Thenable<types.SymbolInformation[]> {
private _executeDocumentSymbolProvider(resource: URI): Thenable<vscode.DocumentSymbol[]> {
const args = {
resource
};
return this._commands.executeCommand<modes.IOutline>('_executeDocumentSymbolProvider', args).then(value => {
if (value && Array.isArray(value.entries)) {
return value.entries.map(typeConverters.SymbolInformation.to);
return this._commands.executeCommand<modes.DocumentSymbol[]>('_executeDocumentSymbolProvider', args).then(value => {
if (value && Array.isArray(value)) {
return value.map(typeConverters.DocumentSymbol.to);
}
return undefined;
});

View File

@@ -131,6 +131,8 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T> {
this._logService.trace('ExtHostCommands#$executeContributedCommand', id);
if (!this._commands.has(id)) {
return Promise.reject(new Error(`Contributed command '${id}' does not exist.`));
} else {

View File

@@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { asWinJsPromise } from 'vs/base/common/async';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import * as modes from 'vs/editor/common/modes';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
import * as vscode from 'vscode';
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol';
import { CommandsConverter } from './extHostCommands';
import { IRange } from 'vs/editor/common/core/range';
export class ExtHostComments implements ExtHostCommentsShape {
private static handlePool = 0;
private _proxy: MainThreadCommentsShape;
private _documentProviders = new Map<number, vscode.DocumentCommentProvider>();
private _workspaceProviders = new Map<number, vscode.WorkspaceCommentProvider>();
constructor(
mainContext: IMainContext,
private readonly _commandsConverter: CommandsConverter,
private readonly _documents: ExtHostDocuments,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadComments);
}
registerWorkspaceCommentProvider(
provider: vscode.WorkspaceCommentProvider
): vscode.Disposable {
const handle = ExtHostComments.handlePool++;
this._workspaceProviders.set(handle, provider);
this._proxy.$registerWorkspaceCommentProvider(handle);
this.registerListeners(handle, provider);
return {
dispose: () => {
this._proxy.$unregisterWorkspaceCommentProvider(handle);
this._workspaceProviders.delete(handle);
}
};
}
registerDocumentCommentProvider(
provider: vscode.DocumentCommentProvider
): vscode.Disposable {
const handle = ExtHostComments.handlePool++;
this._documentProviders.set(handle, provider);
this._proxy.$registerDocumentCommentProvider(handle);
this.registerListeners(handle, provider);
return {
dispose: () => {
this._proxy.$unregisterDocumentCommentProvider(handle);
this._documentProviders.delete(handle);
}
};
}
$createNewCommentThread(handle: number, uri: UriComponents, range: IRange, text: string): TPromise<modes.CommentThread> {
const data = this._documents.getDocumentData(URI.revive(uri));
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
if (!data || !data.document) {
return TPromise.as(null);
}
return asWinJsPromise(token => {
let provider = this._documentProviders.get(handle);
return provider.createNewCommentThread(data.document, ran, text, token);
}).then(commentThread => commentThread ? convertToCommentThread(commentThread, this._commandsConverter) : null);
}
$replyToCommentThread(handle: number, uri: UriComponents, range: IRange, thread: modes.CommentThread, text: string): TPromise<modes.CommentThread> {
const data = this._documents.getDocumentData(URI.revive(uri));
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
if (!data || !data.document) {
return TPromise.as(null);
}
return asWinJsPromise(token => {
let provider = this._documentProviders.get(handle);
return provider.replyToCommentThread(data.document, ran, convertFromCommentThread(thread), text, token);
}).then(commentThread => commentThread ? convertToCommentThread(commentThread, this._commandsConverter) : null);
}
$provideDocumentComments(handle: number, uri: UriComponents): TPromise<modes.CommentInfo> {
const data = this._documents.getDocumentData(URI.revive(uri));
if (!data || !data.document) {
return TPromise.as(null);
}
return asWinJsPromise(token => {
let provider = this._documentProviders.get(handle);
return provider.provideDocumentComments(data.document, token);
})
.then(commentInfo => commentInfo ? convertCommentInfo(handle, commentInfo, this._commandsConverter) : null);
}
$provideWorkspaceComments(handle: number): TPromise<modes.CommentThread[]> {
const provider = this._workspaceProviders.get(handle);
if (!provider) {
return TPromise.as(null);
}
return asWinJsPromise(token => {
return provider.provideWorkspaceComments(token);
}).then(comments =>
comments.map(x => convertToCommentThread(x, this._commandsConverter)
));
}
private registerListeners(handle: number, provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider) {
provider.onDidChangeCommentThreads(event => {
this._proxy.$onDidCommentThreadsChange(handle, {
owner: handle,
changed: event.changed.map(x => convertToCommentThread(x, this._commandsConverter)),
added: event.added.map(x => convertToCommentThread(x, this._commandsConverter)),
removed: event.removed.map(x => convertToCommentThread(x, this._commandsConverter))
});
});
}
}
function convertCommentInfo(owner: number, vscodeCommentInfo: vscode.CommentInfo, commandsConverter: CommandsConverter): modes.CommentInfo {
return {
owner: owner,
threads: vscodeCommentInfo.threads.map(x => convertToCommentThread(x, commandsConverter)),
commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : []
};
}
function convertToCommentThread(vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread {
return {
threadId: vscodeCommentThread.threadId,
resource: vscodeCommentThread.resource.toString(),
range: extHostTypeConverter.Range.from(vscodeCommentThread.range),
comments: vscodeCommentThread.comments.map(comment => convertToComment(comment, commandsConverter)),
collapsibleState: vscodeCommentThread.collapsibleState
};
}
function convertFromCommentThread(commentThread: modes.CommentThread): vscode.CommentThread {
return {
threadId: commentThread.threadId,
resource: URI.parse(commentThread.resource),
range: extHostTypeConverter.Range.to(commentThread.range),
comments: commentThread.comments.map(convertFromComment),
collapsibleState: commentThread.collapsibleState
};
}
function convertFromComment(comment: modes.Comment): vscode.Comment {
return {
commentId: comment.commentId,
body: extHostTypeConverter.MarkdownString.to(comment.body),
userName: comment.userName,
gravatar: comment.gravatar
};
}
function convertToComment(vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment {
return {
commentId: vscodeComment.commentId,
body: extHostTypeConverter.MarkdownString.from(vscodeComment.body),
userName: vscodeComment.userName,
gravatar: vscodeComment.gravatar,
command: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command) : null
};
}

View File

@@ -10,6 +10,7 @@ import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Event, Emitter } from 'vs/base/common/event';
import { asWinJsPromise } from 'vs/base/common/async';
import * as nls from 'vs/nls';
import {
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto
@@ -24,10 +25,11 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumen
import { IAdapterExecutable, ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug';
import { getTerminalLauncher, hasChildprocesses, prepareCommand } from 'vs/workbench/parts/debug/node/terminals';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { VariableResolver } from 'vs/workbench/services/configurationResolver/node/variableResolver';
import { IStringDictionary } from 'vs/base/common/collections';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver';
import { ExtHostConfiguration } from './extHostConfiguration';
import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils';
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
@@ -66,12 +68,16 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
private _variableResolver: IConfigurationResolverService;
private _integratedTerminalInstance: vscode.Terminal;
private _terminalDisposedListener: IDisposable;
constructor(mainContext: IMainContext,
private _workspaceService: ExtHostWorkspace,
private _extensionService: ExtHostExtensionService,
private _editorsService: ExtHostDocumentsAndEditors,
private _configurationService: ExtHostConfiguration
private _configurationService: ExtHostConfiguration,
private _terminalService: ExtHostTerminalService
) {
this._handleCounter = 0;
@@ -117,22 +123,45 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
}
}
public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
const terminalLauncher = getTerminalLauncher();
if (terminalLauncher) {
return terminalLauncher.runInTerminal(args, config);
public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
if (args.kind === 'integrated') {
if (!this._terminalDisposedListener) {
// React on terminal disposed and check if that is the debug terminal #12956
this._terminalDisposedListener = this._terminalService.onDidCloseTerminal(terminal => {
if (this._integratedTerminalInstance && this._integratedTerminalInstance === terminal) {
this._integratedTerminalInstance = null;
}
});
}
let t = this._integratedTerminalInstance;
if ((t && hasChildprocesses(await t.processId)) || !t) {
t = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee"));
this._integratedTerminalInstance = t;
}
t.show();
return new TPromise((resolve, error) => {
setTimeout(_ => {
const command = prepareCommand(args, config);
t.sendText(command, true);
resolve(void 0);
}, 500);
});
} else if (args.kind === 'external') {
const terminalLauncher = getTerminalLauncher();
if (terminalLauncher) {
return terminalLauncher.runInTerminal(args, config);
}
}
return void 0;
}
public $isTerminalBusy(processId: number): TPromise<boolean> {
return asWinJsPromise(token => hasChildprocesses(processId));
}
public $prepareCommandForTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<any> {
return asWinJsPromise(token => prepareCommand(args, config));
}
public $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): TPromise<IConfig> {
if (!this._variableResolver) {
this._variableResolver = new ExtHostVariableResolverService(this._workspaceService, this._editorsService, this._configurationService);
@@ -146,7 +175,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
throw new Error('Not implemented');
}
};
return asWinJsPromise(token => DebugAdapter.substituteVariables(ws, config, this._variableResolver));
return asWinJsPromise(token => this._variableResolver.resolveAny(ws, config));
}
public $startDASession(handle: number, debugType: string, adpaterExecutable: IAdapterExecutable | null, debugPort: number): TPromise<void> {
@@ -558,15 +587,12 @@ export class ExtHostDebugConsole implements vscode.DebugConsole {
}
}
export class ExtHostVariableResolverService implements IConfigurationResolverService {
export class ExtHostVariableResolverService extends AbstractVariableResolverService {
_serviceBrand: any;
_variableResolver: VariableResolver;
constructor(workspace: ExtHostWorkspace, editors: ExtHostDocumentsAndEditors, configuration: ExtHostConfiguration) {
this._variableResolver = new VariableResolver({
constructor(workspaceService: ExtHostWorkspace, editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfiguration) {
super({
getFolderUri: (folderName: string): URI => {
const folders = workspace.getWorkspaceFolders();
const folders = workspaceService.getWorkspaceFolders();
const found = folders.filter(f => f.name === folderName);
if (found && found.length > 0) {
return found[0].uri;
@@ -574,16 +600,16 @@ export class ExtHostVariableResolverService implements IConfigurationResolverSer
return undefined;
},
getWorkspaceFolderCount: (): number => {
return workspace.getWorkspaceFolders().length;
return workspaceService.getWorkspaceFolders().length;
},
getConfigurationValue: (folderUri: URI, section: string) => {
return configuration.getConfiguration(undefined, folderUri).get<string>(section);
return configurationService.getConfiguration(undefined, folderUri).get<string>(section);
},
getExecPath: (): string | undefined => {
return undefined; // does not exist in EH
},
getFilePath: (): string | undefined => {
const activeEditor = editors.activeEditor();
const activeEditor = editorService.activeEditor();
if (activeEditor) {
const resource = activeEditor.document.uri;
if (resource.scheme === Schemas.file) {
@@ -593,34 +619,19 @@ export class ExtHostVariableResolverService implements IConfigurationResolverSer
return undefined;
},
getSelectedText: (): string | undefined => {
const activeEditor = editors.activeEditor();
const activeEditor = editorService.activeEditor();
if (activeEditor && !activeEditor.selection.isEmpty) {
return activeEditor.document.getText(activeEditor.selection);
}
return undefined;
},
getLineNumber: (): string => {
const activeEditor = editors.activeEditor();
const activeEditor = editorService.activeEditor();
if (activeEditor) {
return String(activeEditor.selection.end.line + 1);
}
return undefined;
}
}, process.env);
}
public resolve(root: IWorkspaceFolder, value: string): string;
public resolve(root: IWorkspaceFolder, value: string[]): string[];
public resolve(root: IWorkspaceFolder, value: IStringDictionary<string>): IStringDictionary<string>;
public resolve(root: IWorkspaceFolder, value: any): any {
return this._variableResolver.resolveAny(root ? root.uri : undefined, value);
}
public resolveAny<T>(root: IWorkspaceFolder, value: T, commandMapping?: IStringDictionary<string>): T {
return this._variableResolver.resolveAny(root ? root.uri : undefined, value, commandMapping);
}
public executeCommandVariables(configuration: any, variables: IStringDictionary<string>): TPromise<IStringDictionary<string>> {
throw new Error('findAndExecuteCommandVariables not implemented.');
});
}
}

View File

@@ -17,17 +17,17 @@ import { keys } from 'vs/base/common/map';
export class DiagnosticCollection implements vscode.DiagnosticCollection {
private static readonly _maxDiagnosticsPerFile: number = 250;
private readonly _name: string;
private readonly _maxDiagnosticsPerFile: number;
private readonly _onDidChangeDiagnostics: Emitter<(vscode.Uri | string)[]>;
private _proxy: MainThreadDiagnosticsShape;
private _isDisposed = false;
private _data = new Map<string, vscode.Diagnostic[]>();
constructor(name: string, proxy: MainThreadDiagnosticsShape, onDidChangeDiagnostics: Emitter<(vscode.Uri | string)[]>) {
constructor(name: string, maxDiagnosticsPerFile: number, proxy: MainThreadDiagnosticsShape, onDidChangeDiagnostics: Emitter<(vscode.Uri | string)[]>) {
this._name = name;
this._maxDiagnosticsPerFile = maxDiagnosticsPerFile;
this._proxy = proxy;
this._onDidChangeDiagnostics = onDidChangeDiagnostics;
}
@@ -109,15 +109,15 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
let diagnostics = this._data.get(uri.toString());
if (diagnostics) {
// no more than 250 diagnostics per file
if (diagnostics.length > DiagnosticCollection._maxDiagnosticsPerFile) {
// no more than N diagnostics per file
if (diagnostics.length > this._maxDiagnosticsPerFile) {
marker = [];
const order = [DiagnosticSeverity.Error, DiagnosticSeverity.Warning, DiagnosticSeverity.Information, DiagnosticSeverity.Hint];
orderLoop: for (let i = 0; i < 4; i++) {
for (let diagnostic of diagnostics) {
if (diagnostic.severity === order[i]) {
const len = marker.push(converter.Diagnostic.from(diagnostic));
if (len === DiagnosticCollection._maxDiagnosticsPerFile) {
if (len === this._maxDiagnosticsPerFile) {
break orderLoop;
}
}
@@ -126,8 +126,8 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
// add 'signal' marker for showing omitted errors/warnings
marker.push({
severity: MarkerSeverity.Error,
message: localize({ key: 'limitHit', comment: ['amount of errors/warning skipped due to limits'] }, "Not showing {0} further errors and warnings.", diagnostics.length - DiagnosticCollection._maxDiagnosticsPerFile),
severity: MarkerSeverity.Info,
message: localize({ key: 'limitHit', comment: ['amount of errors/warning skipped due to limits'] }, "Not showing {0} further errors and warnings.", diagnostics.length - this._maxDiagnosticsPerFile),
startLineNumber: marker[marker.length - 1].startLineNumber,
startColumn: marker[marker.length - 1].startColumn,
endLineNumber: marker[marker.length - 1].endLineNumber,
@@ -201,6 +201,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
private static _idPool: number = 0;
private static readonly _maxDiagnosticsPerFile: number = 1000;
private readonly _proxy: MainThreadDiagnosticsShape;
private readonly _collections: DiagnosticCollection[] = [];
@@ -248,7 +249,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
const { _collections, _proxy, _onDidChangeDiagnostics } = this;
const result = new class extends DiagnosticCollection {
constructor() {
super(name, _proxy, _onDidChangeDiagnostics);
super(name, ExtHostDiagnostics._maxDiagnosticsPerFile, _proxy, _onDidChangeDiagnostics);
_collections.push(this);
}
dispose() {

View File

@@ -78,32 +78,32 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
return Promise.resolve(false);
}
return this._deliverEventAsync(listener, thisArg, stubEvent).then(() => {
return this._deliverEventAsync(extension, listener, thisArg, stubEvent).then(() => {
// don't send result across the wire
return true;
}, err => {
this._logService.error('[onWillSaveTextDocument]', extension.id);
this._logService.error(`onWillSaveTextDocument-listener from extension '${extension.id}' threw ERROR`);
this._logService.error(err);
if (!(err instanceof Error) || (<Error>err).message !== 'concurrent_edits') {
const errors = this._badListeners.get(listener);
this._badListeners.set(listener, !errors ? 1 : errors + 1);
// todo@joh signal to the listener?
// if (errors === this._thresholds.errors) {
// console.warn('BAD onWillSaveTextDocumentEvent-listener is from now on being ignored');
// }
if (errors > this._thresholds.errors) {
this._logService.info(`onWillSaveTextDocument-listener from extension '${extension.id}' will now be IGNORED because of timeouts and/or errors`);
}
}
return false;
});
}
private _deliverEventAsync(listener: Function, thisArg: any, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> {
private _deliverEventAsync(extension: IExtensionDescription, listener: Function, thisArg: any, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> {
const promises: Promise<vscode.TextEdit[]>[] = [];
const t1 = Date.now();
const { document, reason } = stubEvent;
const { version } = document;
@@ -133,6 +133,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
const handle = setTimeout(() => reject(new Error('timeout')), this._thresholds.timeout);
return Promise.all(promises).then(edits => {
this._logService.debug(`onWillSaveTextDocument-listener from extension '${extension.id}' finished after ${(Date.now() - t1)}ms`);
clearTimeout(handle);
resolve(edits);
}).catch(err => {

View File

@@ -13,7 +13,7 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/n
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
import { createApiFactory, initializeExtensionApi, checkProposedApiEnabled } from 'vs/workbench/api/node/extHost.api.impl';
import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData, ExtHostExtensionServiceShape, MainThreadTelemetryShape, IExtHostContext } from './extHost.protocol';
import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData, ExtHostExtensionServiceShape, MainThreadTelemetryShape, IMainContext } from './extHost.protocol';
import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionAPI, IExtensionContext, EmptyExtension, IExtensionModule, ExtensionActivationTimesBuilder, ExtensionActivationTimes, ExtensionActivationReason, ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
@@ -136,7 +136,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
*/
constructor(initData: IInitData,
extHostContext: IExtHostContext,
extHostContext: IMainContext,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
extHostLogService: ExtHostLogService

View File

@@ -6,15 +6,13 @@
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Event, mapEvent } from 'vs/base/common/event';
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape, IFileChangeDto } from './extHost.protocol';
import * as vscode from 'vscode';
import * as files from 'vs/platform/files/common/files';
import * as path from 'path';
import { IDisposable } from 'vs/base/common/lifecycle';
import { asWinJsPromise } from 'vs/base/common/async';
import { values } from 'vs/base/common/map';
import { Range, DeprecatedFileType, DeprecatedFileChangeType, FileChangeType } from 'vs/workbench/api/node/extHostTypes';
import { Range, FileChangeType } from 'vs/workbench/api/node/extHostTypes';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
import { Schemas } from 'vs/base/common/network';
@@ -34,7 +32,7 @@ class FsLinkProvider implements vscode.DocumentLinkProvider {
}
}
provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.DocumentLink[]> {
provideDocumentLinks(document: vscode.TextDocument): vscode.ProviderResult<vscode.DocumentLink[]> {
if (this._schemes.size === 0) {
return undefined;
}
@@ -60,106 +58,6 @@ class FsLinkProvider implements vscode.DocumentLinkProvider {
}
}
class FileSystemProviderShim implements vscode.FileSystemProvider {
onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]>;
constructor(private readonly _delegate: vscode.DeprecatedFileSystemProvider) {
if (!this._delegate.onDidChange) {
this.onDidChangeFile = Event.None;
} else {
this.onDidChangeFile = mapEvent(this._delegate.onDidChange, old => old.map(FileSystemProviderShim._modernizeFileChange));
}
}
watch(uri: vscode.Uri, options: {}): vscode.Disposable {
// does nothing because in the old API there was no notion of
// watch and provider decide what file events to generate...
return { dispose() { } };
}
stat(resource: vscode.Uri): Thenable<vscode.FileStat> {
return this._delegate.stat(resource).then(stat => FileSystemProviderShim._modernizeFileStat(stat));
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri): Thenable<void> {
return this._delegate.move(oldUri, newUri).then(stat => void 0);
}
readDirectory(resource: vscode.Uri): Thenable<[string, vscode.FileType][]> {
return this._delegate.readdir(resource).then(tuples => {
return tuples.map(tuple => <[string, vscode.FileType]>[path.posix.basename(tuple[0].path), FileSystemProviderShim._modernizeFileStat(tuple[1]).type]);
});
}
private static _modernizeFileStat(stat: vscode.DeprecatedFileStat): vscode.FileStat {
let { mtime, size, type } = stat;
let newType: files.FileType;
// no support for bitmask, effectively no support for symlinks
switch (type) {
case DeprecatedFileType.Dir:
newType = files.FileType.Directory;
break;
case DeprecatedFileType.File:
newType = files.FileType.File;
break;
case DeprecatedFileType.Symlink:
newType = files.FileType.File & files.FileType.SymbolicLink;
break;
}
return { type: newType, ctime: 0, mtime, size };
}
private static _modernizeFileChange(e: vscode.DeprecatedFileChange): vscode.FileChangeEvent {
let { resource, type } = e;
let newType: vscode.FileChangeType;
switch (type) {
case DeprecatedFileChangeType.Updated:
newType = FileChangeType.Changed;
break;
case DeprecatedFileChangeType.Added:
newType = FileChangeType.Created;
break;
case DeprecatedFileChangeType.Deleted:
newType = FileChangeType.Deleted;
break;
}
return { uri: resource, type: newType };
}
// --- delete/create file or folder
delete(resource: vscode.Uri): Thenable<void> {
return this._delegate.stat(resource).then(stat => {
if (stat.type === DeprecatedFileType.Dir) {
return this._delegate.rmdir(resource);
} else {
return this._delegate.unlink(resource);
}
});
}
createDirectory(resource: vscode.Uri): Thenable<void> {
return this._delegate.mkdir(resource).then(stat => void 0);
}
// --- read/write
readFile(resource: vscode.Uri): Thenable<Uint8Array> {
let chunks: Buffer[] = [];
return this._delegate.read(resource, 0, -1, {
report(data) {
chunks.push(Buffer.from(data));
}
}).then(() => {
return Buffer.concat(chunks);
});
}
writeFile(resource: vscode.Uri, content: Uint8Array, options: files.FileWriteOptions): Thenable<void> {
return this._delegate.write(resource, content);
}
}
export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
@@ -185,11 +83,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
extHostLanguageFeatures.registerDocumentLinkProvider('*', this._linkProvider);
}
registerDeprecatedFileSystemProvider(scheme: string, provider: vscode.DeprecatedFileSystemProvider) {
return this.registerFileSystemProvider(scheme, new FileSystemProviderShim(provider), { isCaseSensitive: false });
}
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean }) {
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean } = {}) {
if (this._usedSchemes.has(scheme)) {
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
@@ -252,15 +146,15 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
}
$stat(handle: number, resource: UriComponents): TPromise<files.IStat, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
return asWinJsPromise(() => this._fsProvider.get(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
}
$readdir(handle: number, resource: UriComponents): TPromise<[string, files.FileType][], any> {
return asWinJsPromise(token => this._fsProvider.get(handle).readDirectory(URI.revive(resource)));
return asWinJsPromise(() => this._fsProvider.get(handle).readDirectory(URI.revive(resource)));
}
$readFile(handle: number, resource: UriComponents): TPromise<string> {
return asWinJsPromise(token => {
return asWinJsPromise(() => {
return this._fsProvider.get(handle).readFile(URI.revive(resource));
}).then(data => {
return Buffer.isBuffer(data) ? data.toString('base64') : Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString('base64');
@@ -268,33 +162,33 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
}
$writeFile(handle: number, resource: UriComponents, base64Content: string, opts: files.FileWriteOptions): TPromise<void, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).writeFile(URI.revive(resource), Buffer.from(base64Content, 'base64'), opts));
return asWinJsPromise(() => this._fsProvider.get(handle).writeFile(URI.revive(resource), Buffer.from(base64Content, 'base64'), opts));
}
$delete(handle: number, resource: UriComponents): TPromise<void, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).delete(URI.revive(resource), { recursive: true }));
return asWinJsPromise(() => this._fsProvider.get(handle).delete(URI.revive(resource), { recursive: true }));
}
$rename(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): TPromise<void, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
return asWinJsPromise(() => this._fsProvider.get(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
}
$copy(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): TPromise<void, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).copy(URI.revive(oldUri), URI.revive(newUri), opts));
return asWinJsPromise(() => this._fsProvider.get(handle).copy(URI.revive(oldUri), URI.revive(newUri), opts));
}
$mkdir(handle: number, resource: UriComponents): TPromise<void, any> {
return asWinJsPromise(token => this._fsProvider.get(handle).createDirectory(URI.revive(resource)));
return asWinJsPromise(() => this._fsProvider.get(handle).createDirectory(URI.revive(resource)));
}
$watch(handle: number, session: number, resource: UriComponents, opts: files.IWatchOptions): void {
asWinJsPromise(token => {
asWinJsPromise(() => {
let subscription = this._fsProvider.get(handle).watch(URI.revive(resource), opts);
this._watches.set(session, subscription);
});
}
$unwatch(handle: number, session: number): void {
$unwatch(session: number): void {
let subscription = this._watches.get(session);
if (subscription) {
subscription.dispose();

View File

@@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { mixin } from 'vs/base/common/objects';
import * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/node/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, Hierarchy, SymbolInformation2 } from 'vs/workbench/api/node/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol } from 'vs/workbench/api/node/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
@@ -17,10 +17,10 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, SymbolInformationDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter } from './extHost.protocol';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter } from './extHost.protocol';
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { isObject } from 'vs/base/common/types';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
@@ -37,21 +37,21 @@ class OutlineAdapter {
this._provider = provider;
}
provideDocumentSymbols(resource: URI): TPromise<SymbolInformationDto[]> {
provideDocumentSymbols(resource: URI): TPromise<modes.DocumentSymbol[]> {
let doc = this._documents.getDocumentData(resource).document;
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
if (isFalsyOrEmpty(value)) {
return undefined;
}
let [probe] = value;
if (!(probe instanceof Hierarchy)) {
value = OutlineAdapter._asSymbolHierarchy(<SymbolInformation[]>value);
if (value[0] instanceof DocumentSymbol) {
return (<DocumentSymbol[]>value).map(typeConvert.DocumentSymbol.from);
} else {
return OutlineAdapter._asDocumentSymbolTree(resource, <SymbolInformation[]>value);
}
return (<Hierarchy<SymbolInformation2>[]>value).map(typeConvert.HierarchicalSymbolInformation.from);
});
}
private static _asSymbolHierarchy(info: SymbolInformation[]): vscode.Hierarchy<SymbolInformation2>[] {
private static _asDocumentSymbolTree(resource: URI, info: SymbolInformation[]): modes.DocumentSymbol[] {
// first sort by start (and end) and then loop over all elements
// and build a tree based on containment.
info = info.slice(0).sort((a, b) => {
@@ -61,12 +61,17 @@ class OutlineAdapter {
}
return res;
});
let res: Hierarchy<SymbolInformation2>[] = [];
let parentStack: Hierarchy<SymbolInformation2>[] = [];
let res: modes.DocumentSymbol[] = [];
let parentStack: modes.DocumentSymbol[] = [];
for (let i = 0; i < info.length; i++) {
let element = new Hierarchy(new SymbolInformation2(info[i].name, '', info[i].kind, info[i].location.range, info[i].location));
element.parent.containerName = info[i].containerName;
element.parent.location = info[i].location; // todo@joh make this proper
let element = <modes.DocumentSymbol>{
name: info[i].name,
kind: typeConvert.SymbolKind.from(info[i].kind),
containerName: info[i].containerName,
fullRange: typeConvert.Range.from(info[i].location.range),
identifierRange: typeConvert.Range.from(info[i].location.range),
children: []
};
while (true) {
if (parentStack.length === 0) {
@@ -75,7 +80,7 @@ class OutlineAdapter {
break;
}
let parent = parentStack[parentStack.length - 1];
if (parent.parent.range.contains(element.parent.range) && !parent.parent.range.isEqual(element.parent.range)) {
if (EditorRange.containsRange(parent.fullRange, element.fullRange) && !EditorRange.equalsRange(parent.fullRange, element.fullRange)) {
parent.children.push(element);
parentStack.push(element);
break;
@@ -428,7 +433,7 @@ class NavigateTypeAdapter {
console.warn('INVALID SymbolInformation, lacks name', item);
continue;
}
const symbol = IdObject.mixin(typeConvert.SymbolInformation.from(item));
const symbol = IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
this._symbolCache[symbol._id] = item;
result.symbols.push(symbol);
}
@@ -441,7 +446,7 @@ class NavigateTypeAdapter {
});
}
resolveWorkspaceSymbol(symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
resolveWorkspaceSymbol(symbol: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto> {
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
return TPromise.as(symbol);
@@ -450,7 +455,7 @@ class NavigateTypeAdapter {
const item = this._symbolCache[symbol._id];
if (item) {
return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => {
return value && mixin(symbol, typeConvert.SymbolInformation.from(value), true);
return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true);
});
}
return undefined;
@@ -930,7 +935,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<SymbolInformationDto[]> {
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<modes.DocumentSymbol[]> {
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource)));
}
@@ -1085,7 +1090,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
}
$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
$resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
}

View File

@@ -8,10 +8,11 @@ import { ProgressOptions } from 'vscode';
import { MainThreadProgressShape, ExtHostProgressShape } from './extHost.protocol';
import { ProgressLocation } from './extHostTypeConverters';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { IProgressStep, Progress } from 'vs/platform/progress/common/progress';
import { Progress } from 'vs/platform/progress/common/progress';
import { localize } from 'vs/nls';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { debounce } from 'vs/base/common/decorators';
import { IProgressStep } from 'vs/workbench/services/progress/common/progress';
export class ExtHostProgress implements ExtHostProgressShape {

View File

@@ -4,13 +4,18 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { wireCancellationToken, asWinJsPromise } from 'vs/base/common/async';
import { asWinJsPromise, wireCancellationToken } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode';
import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { Emitter } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
import { ExtHostQuickOpenShape, IMainContext, MainContext, MainThreadQuickOpenShape, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol';
import URI from 'vs/base/common/uri';
import { ThemeIcon } from 'vs/workbench/api/node/extHostTypes';
export type Item = string | QuickPickItem;
@@ -23,23 +28,25 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
private _onDidSelectItem: (handle: number) => void;
private _validateInput: (input: string) => string | Thenable<string>;
private _sessions = new Map<number, ExtHostQuickInput>();
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) {
this._proxy = mainContext.getProxy(MainContext.MainThreadQuickOpen);
this._workspace = workspace;
this._commands = commands;
}
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: Item[] | Thenable<Item[]>, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
showQuickPick(itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
showQuickPick(itemsOrItemsPromise: Item[] | Thenable<Item[]>, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
// clear state from last invocation
this._onDidSelectItem = undefined;
const itemsPromise = <TPromise<Item[]>>TPromise.wrap(itemsOrItemsPromise);
const quickPickWidget = this._proxy.$show(multiStepHandle, {
const quickPickWidget = this._proxy.$show({
placeHolder: options && options.placeHolder,
matchOnDescription: options && options.matchOnDescription,
matchOnDetail: options && options.matchOnDetail,
@@ -54,7 +61,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
return itemsPromise.then(items => {
let pickItems: MyQuickPickItems[] = [];
let pickItems: TransferQuickPickItems[] = [];
for (let handle = 0; handle < items.length; handle++) {
let item = items[handle];
@@ -115,12 +122,12 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
// ---- input
showInput(multiStepHandle: number | undefined, options?: InputBoxOptions, token: CancellationToken = CancellationToken.None): Thenable<string> {
showInput(options?: InputBoxOptions, token: CancellationToken = CancellationToken.None): Thenable<string> {
// global validate fn used in callback below
this._validateInput = options && options.validateInput;
const promise = this._proxy.$input(multiStepHandle, options, typeof this._validateInput === 'function');
const promise = this._proxy.$input(options, typeof this._validateInput === 'function');
return wireCancellationToken(token, promise, true);
}
@@ -142,4 +149,406 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0];
});
}
// ---- QuickInput
createQuickPick(extensionId: string): QuickPick {
const session = new ExtHostQuickPick(this._proxy, extensionId, () => this._sessions.delete(session._id));
this._sessions.set(session._id, session);
return session;
}
createInputBox(extensionId: string): InputBox {
const session = new ExtHostInputBox(this._proxy, extensionId, () => this._sessions.delete(session._id));
this._sessions.set(session._id, session);
return session;
}
$onDidAccept(sessionId: number): void {
const session = this._sessions.get(sessionId);
if (session instanceof ExtHostQuickPick) {
session._fireDidAccept();
}
}
$onDidChangeActive(sessionId: number, handles: number[]): void {
const session = this._sessions.get(sessionId);
if (session instanceof ExtHostQuickPick) {
session._fireDidChangeFocus(handles);
}
}
$onDidChangeSelection(sessionId: number, handles: number[]): void {
const session = this._sessions.get(sessionId);
if (session instanceof ExtHostQuickPick) {
session._fireDidChangeSelection(handles);
}
}
$onDidTriggerButton(sessionId: number, handle: number): void {
const session = this._sessions.get(sessionId);
if (session) {
session._fireDidTriggerButton(handle);
}
}
}
class ExtHostQuickInput implements QuickInput {
private static _nextId = 1;
_id = ExtHostQuickPick._nextId++;
private _visible = false;
private _enabled = true;
private _busy = false;
private _ignoreFocusOut = true;
private _buttons: QuickInputButton[] = [];
private _handlesToButtons = new Map<number, QuickInputButton>();
private _onDidTriggerButtonEmitter = new Emitter<QuickInputButton>();
private _onDidHideEmitter = new Emitter<void>();
private _updateTimeout: number;
private _pendingUpdate: TransferQuickInput = { id: this._id };
private _disposed = false;
protected _disposables: IDisposable[] = [
this._onDidTriggerButtonEmitter,
this._onDidHideEmitter,
];
constructor(protected _proxy: MainThreadQuickOpenShape, protected _extensionId: string, private _onDidDispose: () => void) {
}
get enabled() {
return this._enabled;
}
set enabled(enabled: boolean) {
this._enabled = enabled;
this.update({ enabled });
}
get busy() {
return this._busy;
}
set busy(busy: boolean) {
this._busy = busy;
this.update({ busy });
}
get ignoreFocusOut() {
return this._ignoreFocusOut;
}
set ignoreFocusOut(ignoreFocusOut: boolean) {
this._ignoreFocusOut = ignoreFocusOut;
this.update({ ignoreFocusOut });
}
get buttons() {
return this._buttons;
}
set buttons(buttons: QuickInputButton[]) {
this._buttons = buttons;
this._handlesToButtons.clear();
buttons.forEach((button, i) => {
this._handlesToButtons.set(i, button);
});
this.update({
buttons: buttons.map<TransferQuickInputButton>((button, i) => ({
iconPath: getIconUris(button.iconPath),
toolTip: button.tooltip,
handle: i,
}))
});
}
onDidTriggerButton = this._onDidTriggerButtonEmitter.event;
show(): void {
this._visible = true;
this.update({ visible: true });
}
hide(): void {
this._visible = false;
this.update({ visible: false });
}
onDidHide = this._onDidHideEmitter.event;
_fireDidTriggerButton(handle: number) {
const button = this._handlesToButtons.get(handle);
this._onDidTriggerButtonEmitter.fire(button);
}
public dispose(): void {
if (this._disposed) {
return;
}
this._disposed = true;
this._disposables = dispose(this._disposables);
if (this._updateTimeout) {
clearTimeout(this._updateTimeout);
this._updateTimeout = undefined;
}
this._proxy.$dispose(this._id);
this._onDidDispose();
}
protected update(properties: Record<string, any>): void {
if (this._disposed) {
return;
}
assign(this._pendingUpdate, properties);
if (!this._visible) {
return;
}
if (properties.visible) {
if (this._updateTimeout) {
clearTimeout(this._updateTimeout);
this._updateTimeout = undefined;
}
this.dispatchUpdate();
} else if (!this._updateTimeout) {
// Defer the update so that multiple changes to setters dont cause a redraw each
this._updateTimeout = setTimeout(() => {
this._updateTimeout = undefined;
this.dispatchUpdate();
}, 0);
}
}
private dispatchUpdate() {
this._proxy.$createOrUpdate(this._pendingUpdate);
this._pendingUpdate = { id: this._id };
}
}
function getIconUris(iconPath: QuickInputButton['iconPath']) {
const light = getLightIconUri(iconPath);
return { dark: getDarkIconUri(iconPath) || light, light };
}
function getLightIconUri(iconPath: QuickInputButton['iconPath']) {
if (iconPath && !(iconPath instanceof ThemeIcon)) {
if (typeof iconPath === 'string'
|| iconPath instanceof URI) {
return getIconUri(iconPath);
}
return getIconUri(iconPath['light']);
}
return undefined;
}
function getDarkIconUri(iconPath: QuickInputButton['iconPath']) {
if (iconPath && !(iconPath instanceof ThemeIcon) && iconPath['dark']) {
return getIconUri(iconPath['dark']);
}
return undefined;
}
function getIconUri(iconPath: string | URI) {
if (iconPath instanceof URI) {
return iconPath;
}
return URI.file(iconPath);
}
class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
private _value = '';
private _placeholder: string;
private _onDidChangeValueEmitter = new Emitter<string>();
private _onDidAcceptEmitter = new Emitter<void>();
private _items: QuickPickItem[] = [];
private _handlesToItems = new Map<number, QuickPickItem>();
private _canSelectMany = false;
private _matchOnDescription = true;
private _matchOnDetail = true;
private _focusedItems: QuickPickItem[] = [];
private _onDidChangeActiveEmitter = new Emitter<QuickPickItem[]>();
private _selectedItems: QuickPickItem[] = [];
private _onDidChangeSelectionEmitter = new Emitter<QuickPickItem[]>();
constructor(proxy: MainThreadQuickOpenShape, extensionId: string, onDispose: () => void) {
super(proxy, extensionId, onDispose);
this._disposables.push(
this._onDidChangeValueEmitter,
this._onDidAcceptEmitter,
this._onDidChangeActiveEmitter,
this._onDidChangeSelectionEmitter,
);
this.update({ type: 'quickPick' });
}
get value() {
return this._value;
}
set value(value: string) {
this._value = value;
this.update({ value });
}
get placeholder() {
return this._placeholder;
}
set placeholder(placeholder: string) {
this._placeholder = placeholder;
this.update({ placeholder });
}
onDidChangeValue = this._onDidChangeValueEmitter.event;
onDidAccept = this._onDidAcceptEmitter.event;
get items() {
return this._items;
}
set items(items: QuickPickItem[]) {
this._items = items;
this._handlesToItems.clear();
items.forEach((item, i) => {
this._handlesToItems.set(i, item);
});
this.update({
items: items.map((item, i) => ({
label: item.label,
description: item.description,
handle: i,
detail: item.detail,
picked: item.picked
}))
});
}
get canSelectMany() {
return this._canSelectMany;
}
set canSelectMany(canSelectMany: boolean) {
this._canSelectMany = canSelectMany;
this.update({ canSelectMany });
}
get matchOnDescription() {
return this._matchOnDescription;
}
set matchOnDescription(matchOnDescription: boolean) {
this._matchOnDescription = matchOnDescription;
this.update({ matchOnDescription });
}
get matchOnDetail() {
return this._matchOnDetail;
}
set matchOnDetail(matchOnDetail: boolean) {
this._matchOnDetail = matchOnDetail;
this.update({ matchOnDetail });
}
get activeItems() {
return this._focusedItems;
}
onDidChangeActive = this._onDidChangeActiveEmitter.event;
get selectedItems() {
return this._selectedItems;
}
onDidChangeSelection = this._onDidChangeSelectionEmitter.event;
_fireDidAccept() {
this._onDidAcceptEmitter.fire();
}
_fireDidChangeFocus(handles: number[]) {
const items = handles.map(handle => this._handlesToItems.get(handle));
this._focusedItems = items;
this._onDidChangeActiveEmitter.fire(items);
}
_fireDidChangeSelection(handles: number[]) {
const items = handles.map(handle => this._handlesToItems.get(handle));
this._selectedItems = items;
this._onDidChangeSelectionEmitter.fire(items);
}
}
class ExtHostInputBox extends ExtHostQuickInput implements InputBox {
private _value = '';
private _placeholder: string;
private _password: boolean;
private _prompt: string;
private _validationMessage: string;
private _onDidChangeValueEmitter = new Emitter<string>();
private _onDidAcceptEmitter = new Emitter<string>();
constructor(proxy: MainThreadQuickOpenShape, extensionId: string, onDispose: () => void) {
super(proxy, extensionId, onDispose);
this._disposables.push(
this._onDidChangeValueEmitter,
this._onDidAcceptEmitter,
);
this.update({ type: 'inputBox' });
}
get value() {
return this._value;
}
set value(value: string) {
this._value = value;
this.update({ value });
}
get placeholder() {
return this._placeholder;
}
set placeholder(placeholder: string) {
this._placeholder = placeholder;
this.update({ placeholder });
}
get password() {
return this._password;
}
set password(password: boolean) {
this._password = password;
this.update({ password });
}
get prompt() {
return this._prompt;
}
set prompt(prompt: string) {
this._prompt = prompt;
this.update({ prompt });
}
get validationMessage() {
return this._validationMessage;
}
set validationMessage(validationMessage: string) {
this._validationMessage = validationMessage;
this.update({ validationMessage });
}
onDidChangeValue = this._onDidChangeValueEmitter.event;
onDidAccept = this._onDidAcceptEmitter.event;
}

View File

@@ -454,7 +454,7 @@ class TextSearchEngine {
new TPromise(resolve => process.nextTick(resolve))
.then(() => {
this.activeCancellationTokens.add(cancellation);
return this.provider.provideTextSearchResults(this.pattern, searchOptions, progress, cancellation.token);
return this.provider.provideTextSearchResults(patternInfoToQuery(this.pattern), searchOptions, progress, cancellation.token);
})
.then(() => {
this.activeCancellationTokens.delete(cancellation);
@@ -500,6 +500,15 @@ class TextSearchEngine {
}
}
function patternInfoToQuery(patternInfo: IPatternInfo): vscode.TextSearchQuery {
return <vscode.TextSearchQuery>{
isCaseSensitive: patternInfo.isCaseSensitive || false,
isRegExp: patternInfo.isRegExp || false,
isWordMatch: patternInfo.isWordMatch || false,
pattern: patternInfo.pattern
};
}
class FileSearchEngine {
private filePattern: string;
private normalizedFilePatternLowercase: string;

View File

@@ -28,8 +28,6 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumen
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
export { TaskExecutionDTO };
/*
namespace ProblemPattern {
export function from(value: vscode.ProblemPattern | vscode.MultiLineProblemPattern): Problems.ProblemPattern | Problems.MultiLineProblemPattern {
@@ -234,13 +232,14 @@ namespace TaskPanelKind {
namespace PresentationOptions {
export function from(value: vscode.TaskPresentationOptions): tasks.PresentationOptions {
if (value === void 0 || value === null) {
return { reveal: tasks.RevealKind.Always, echo: true, focus: false, panel: tasks.PanelKind.Shared };
return { reveal: tasks.RevealKind.Always, echo: true, focus: false, panel: tasks.PanelKind.Shared, showReuseMessage: true };
}
return {
reveal: TaskRevealKind.from(value.reveal),
echo: value.echo === void 0 ? true : !!value.echo,
focus: !!value.focus,
panel: TaskPanelKind.from(value.panel)
panel: TaskPanelKind.from(value.panel),
showReuseMessage: value.showReuseMessage === void 0 ? true : !!value.showReuseMessage
};
}
}
@@ -385,21 +384,16 @@ namespace Tasks {
// in shape and we don't have backwards converting function. So transfer the URI and resolve the
// workspace folder on the main side.
(source as any as tasks.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
(source as any as tasks.ExtensionTaskSourceTransfer).__definition = task.definition;
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let key = (task as types.Task).definitionKey;
let kind = (task as types.Task).definition;
let id = `${extension.id}.${key}`;
let taskKind: tasks.TaskIdentifier = {
_key: key,
type: kind.type
};
Objects.assign(taskKind, kind);
// The definition id will be prefix on the main side since we compute it there.
let id = `${extension.id}`;
let result: tasks.ContributedTask = {
_id: id, // uuidMap.getUUID(identifier),
_id: id,
_source: source,
_label: label,
type: kind.type,
defines: taskKind,
type: task.definition.type,
defines: undefined,
name: task.name,
identifier: label,
group: task.group ? (task.group as types.TaskGroup).id : undefined,

View File

@@ -6,13 +6,14 @@
import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import * as search from 'vs/workbench/parts/search/common/search';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
import { EndOfLineSequence } from 'vs/editor/common/model';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
import { ProgressLocation as MainProgressLocation } from 'vs/workbench/services/progress/common/progress';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
@@ -355,16 +356,16 @@ export namespace SymbolKind {
}
}
export namespace SymbolInformation {
export function from(info: vscode.SymbolInformation): modes.SymbolInformation {
return <modes.SymbolInformation>{
export namespace WorkspaceSymbol {
export function from(info: vscode.SymbolInformation): search.IWorkspaceSymbol {
return <search.IWorkspaceSymbol>{
name: info.name,
kind: SymbolKind.from(info.kind),
containerName: info.containerName,
location: location.from(info.location)
};
}
export function to(info: modes.SymbolInformation): types.SymbolInformation {
export function to(info: search.IWorkspaceSymbol): types.SymbolInformation {
return new types.SymbolInformation(
info.name,
SymbolKind.to(info.kind),
@@ -374,31 +375,30 @@ export namespace SymbolInformation {
}
}
export namespace HierarchicalSymbolInformation {
export function from(info: vscode.Hierarchy<vscode.SymbolInformation2>): modes.SymbolInformation {
let result: modes.SymbolInformation = {
name: info.parent.name,
detail: info.parent.detail,
location: location.from(info.parent.location),
definingRange: Range.from(info.parent.range),
kind: SymbolKind.from(info.parent.kind),
containerName: info.parent.containerName
export namespace DocumentSymbol {
export function from(info: vscode.DocumentSymbol): modes.DocumentSymbol {
let result: modes.DocumentSymbol = {
name: info.name,
detail: info.detail,
fullRange: Range.from(info.fullRange),
identifierRange: Range.from(info.gotoRange),
kind: SymbolKind.from(info.kind)
};
if (info.children) {
result.children = info.children.map(from);
}
return result;
}
export function to(info: modes.SymbolInformation): types.Hierarchy<vscode.SymbolInformation2> {
let result = new types.Hierarchy<vscode.SymbolInformation2>(new types.SymbolInformation2(
export function to(info: modes.DocumentSymbol): vscode.DocumentSymbol {
let result = new types.DocumentSymbol(
info.name,
info.detail,
SymbolKind.to(info.kind),
Range.to(info.definingRange),
location.to(info.location),
));
Range.to(info.fullRange),
Range.to(info.identifierRange),
);
if (info.children) {
result.children = info.children.map(to);
result.children = info.children.map(to) as any;
}
return result;
}

View File

@@ -881,28 +881,29 @@ export class SymbolInformation {
}
}
export class SymbolInformation2 extends SymbolInformation {
export class DocumentSymbol {
name: string;
detail: string;
range: Range;
kind: SymbolKind;
fullRange: Range;
gotoRange: Range;
children: DocumentSymbol[];
constructor(name: string, detail: string, kind: SymbolKind, range: Range, location: Location) {
super(name, kind, undefined, location);
constructor(name: string, detail: string, kind: SymbolKind, fullRange: Range, gotoRange: Range) {
this.name = name;
this.detail = detail;
this.range = range;
}
}
export class Hierarchy<T> {
parent: T;
children: Hierarchy<T>[];
constructor(parent: T) {
this.parent = parent;
this.kind = kind;
this.fullRange = fullRange;
this.gotoRange = gotoRange;
this.children = [];
if (!this.fullRange.contains(this.gotoRange)) {
throw new Error('gotoRange must be contained in fullRange');
}
}
}
export enum CodeActionTrigger {
Automatic = 1,
Manual = 2,
@@ -1494,7 +1495,6 @@ export class Task implements vscode.Task {
private __id: string;
private _definition: vscode.TaskDefinition;
private _definitionKey: string;
private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder;
private _name: string;
private _execution: ProcessExecution | ShellExecution;
@@ -1555,7 +1555,6 @@ export class Task implements vscode.Task {
}
this.__id = undefined;
this._scope = undefined;
this._definitionKey = undefined;
this._definition = undefined;
if (this._execution instanceof ProcessExecution) {
this._definition = {
@@ -1579,19 +1578,9 @@ export class Task implements vscode.Task {
throw illegalArgument('Kind can\'t be undefined or null');
}
this.clear();
this._definitionKey = undefined;
this._definition = value;
}
get definitionKey(): string {
if (!this._definitionKey) {
const hash = crypto.createHash('md5');
hash.update(JSON.stringify(this._definition));
this._definitionKey = hash.digest('hex');
}
return this._definitionKey;
}
get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder {
return this._scope;
}
@@ -1845,12 +1834,6 @@ export enum LogLevel {
}
//#region file api
// todo@remote
export enum DeprecatedFileChangeType {
Updated = 0,
Added = 1,
Deleted = 2
}
export enum FileChangeType {
Changed = 1,
@@ -1858,12 +1841,6 @@ export enum FileChangeType {
Deleted = 3,
}
export enum DeprecatedFileType {
File = 0,
Dir = 1,
Symlink = 2
}
export class FileSystemError extends Error {
static FileExists(messageOrUri?: string | URI): FileSystemError {
@@ -1928,3 +1905,15 @@ export enum FoldingRangeKind {
}
//#endregion
export enum CommentThreadCollapsibleState {
/**
* Determines an item is collapsed
*/
Collapsed = 0,
/**
* Determines an item is expanded
*/
Expanded = 1
}

View File

@@ -16,6 +16,7 @@ export interface TaskPresentationOptionsDTO {
echo?: boolean;
focus?: boolean;
panel?: number;
showReuseMessage?: boolean;
}
export interface ExecutionOptionsDTO {