Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 (#7206)

* Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463

* fix config changes

* fix strictnull checks
This commit is contained in:
Anthony Dresser
2019-09-15 22:38:26 -07:00
committed by GitHub
parent fa6c52699e
commit ea0f9e6ce9
1226 changed files with 21541 additions and 17633 deletions

View File

@@ -92,9 +92,9 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
enableFindWidget: false,
extension: { id: extensionId, location: URI.revive(extensionLocation) }
}, {
allowScripts: options.enableScripts,
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
});
allowScripts: options.enableScripts,
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
});
const webviewZone = new EditorWebviewZone(editor, line, height, webview);

View File

@@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { revive } from 'vs/base/common/marshalling';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadCommands)
export class MainThreadCommands implements MainThreadCommandsShape {
@@ -19,6 +20,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
constructor(
extHostContext: IExtHostContext,
@ICommandService private readonly _commandService: ICommandService,
@IExtensionService private readonly _extensionService: IExtensionService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands);
@@ -70,10 +72,14 @@ export class MainThreadCommands implements MainThreadCommandsShape {
}
}
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined> {
async $executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined> {
for (let i = 0; i < args.length; i++) {
args[i] = revive(args[i], 0);
}
if (retry && args.length > 0 && !CommandsRegistry.getCommand(id)) {
await this._extensionService.activateByEvent(`onCommand:${id}`);
throw new Error('$executeCommand:retry');
}
return this._commandService.executeCommand<T>(id, ...args);
}

View File

@@ -21,7 +21,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
private readonly _proxy: ExtHostDebugServiceShape;
private readonly _toDispose = new DisposableStore();
private _breakpointEventsActive: boolean;
private _breakpointEventsActive: boolean | undefined;
private readonly _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
private _debugAdaptersHandleCounter = 1;
private readonly _debugConfigurationProviders: Map<number, IDebugConfigurationProvider>;
@@ -35,6 +35,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
this._toDispose.add(debugService.onDidNewSession(session => {
this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session));
this._toDispose.add(session.onDidChangeName(name => {
this._proxy.$acceptDebugSessionNameChanged(this.getSessionDto(session), name);
}));
}));
// Need to start listening early to new session events because a custom event can come while a session is initialising
this._toDispose.add(debugService.onWillNewSession(session => {
@@ -225,6 +228,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
});
}
public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void {
const session = this.debugService.getModel().getSession(sessionId);
if (session) {
session.setName(name);
}
}
public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Promise<any> {
const session = this.debugService.getModel().getSession(sessionId, true);
if (session) {
@@ -351,23 +361,24 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
super();
}
public fireError(handle: number, err: Error) {
fireError(handle: number, err: Error) {
this._onError.fire(err);
}
public fireExit(handle: number, code: number, signal: string) {
fireExit(handle: number, code: number, signal: string) {
this._onExit.fire(code);
}
public startSession(): Promise<void> {
startSession(): Promise<void> {
return Promise.resolve(this._proxy.$startDASession(this._handle, this._ds.getSessionDto(this._session)));
}
public sendMessage(message: DebugProtocol.ProtocolMessage): void {
sendMessage(message: DebugProtocol.ProtocolMessage): void {
this._proxy.$sendDAMessage(this._handle, convertToDAPaths(message, true));
}
public stopSession(): Promise<void> {
async stopSession(): Promise<void> {
await this.cancelPendingRequests();
return Promise.resolve(this._proxy.$stopDASession(this._handle));
}
}

View File

@@ -93,14 +93,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
if (!data) {
return undefined;
}
const [weight, bubble, tooltip, letter, themeColor, source] = data;
const [weight, bubble, tooltip, letter, themeColor] = data;
return <IDecorationData>{
weight: weight || 0,
bubble: bubble || false,
color: themeColor && themeColor.id,
tooltip,
letter,
source,
letter
};
});
}

View File

@@ -6,7 +6,7 @@
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString, EditorOption } from 'vs/editor/common/config/editorOptions';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
@@ -58,9 +58,10 @@ export class MainThreadTextEditorProperties {
let cursorStyle: TextEditorCursorStyle;
let lineNumbers: RenderLineNumbersType;
if (codeEditor) {
const codeEditorOpts = codeEditor.getConfiguration();
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
lineNumbers = codeEditorOpts.viewInfo.renderLineNumbers;
const options = codeEditor.getOptions();
const lineNumbersOpts = options.get(EditorOption.lineNumbers);
cursorStyle = options.get(EditorOption.cursorStyle);
lineNumbers = lineNumbersOpts.renderType;
} else if (previousProperties) {
cursorStyle = previousProperties.options.cursorStyle;
lineNumbers = previousProperties.options.lineNumbers;

View File

@@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorOptions, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor';
import { IEditorOptions, ITextEditorOptions, IResourceInput, EditorActivation } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
@@ -118,7 +118,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
const editorOptions: ITextEditorOptions = {
preserveFocus: options.preserveFocus,
pinned: options.pinned,
selection: options.selection
selection: options.selection,
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined
};
const input: IResourceInput = {

View File

@@ -31,6 +31,10 @@ export class MainThreadKeytar implements MainThreadKeytarShape {
return this._credentialsService.findPassword(service);
}
async $findCredentials(service: string): Promise<Array<{ account: string, password: string }>> {
return this._credentialsService.findCredentials(service);
}
dispose(): void {
//
}

View File

@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IModeService } from 'vs/editor/common/services/modeService';
@@ -19,7 +19,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import * as callh from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
import { mixin } from 'vs/base/common/objects';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
@@ -111,7 +111,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return <modes.ILink>data;
}
private static _reviveCallHierarchyItemDto(data: ICallHierarchyDto | undefined): callh.CallHierarchyItem {
private static _reviveCallHierarchyItemDto(data: ICallHierarchyItemDto | undefined): callh.CallHierarchyItem {
if (data) {
data.uri = URI.revive(data.uri);
}
@@ -495,21 +495,28 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
provideCallHierarchyItem: (document, position, token) => {
return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
provideOutgoingCalls: async (model, position, token) => {
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token);
if (!outgoing) {
return undefined; // {{SQL CARBON EDIT}} strict-null-check
}
return outgoing.map(([item, sourceRanges]): callh.OutgoingCall => {
return {
target: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
sourceRanges
};
});
},
resolveCallHierarchyItem: (item, direction, token) => {
return this._proxy.$resolveCallHierarchyItem(handle, item, direction, token).then(data => {
if (data) {
for (let i = 0; i < data.length; i++) {
const [item, locations] = data[i];
data[i] = [
MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
MainThreadLanguageFeatures._reviveLocationDto(locations)
];
}
}
return data as [callh.CallHierarchyItem, modes.Location[]][];
provideIncomingCalls: async (model, position, token) => {
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token);
if (!incoming) {
return undefined; // {{SQL CARBON EDIT}} strict-null-check
}
return incoming.map(([item, sourceRanges]): callh.IncomingCall => {
return {
source: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
sourceRanges
};
});
}
}));

View File

@@ -97,7 +97,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
});
}
private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
private async _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
let cancelId: number | undefined = undefined;
const buttons = commands.map((command, index) => {
@@ -118,7 +118,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
cancelId = buttons.length - 1;
}
return this._dialogService.show(severity, message, buttons, { cancelId })
.then(result => result === commands.length ? undefined : commands[result].handle);
const { choice } = await this._dialogService.show(severity, message, buttons, { cancelId });
return choice === commands.length ? undefined : commands[choice].handle;
}
}

View File

@@ -198,7 +198,7 @@ class MainThreadSCMProvider implements ISCMProvider {
for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] = rawResource;
const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
@@ -206,10 +206,7 @@ class MainThreadSCMProvider implements ISCMProvider {
iconDark: iconDark ? URI.parse(iconDark) : undefined,
tooltip,
strikeThrough,
faded,
source,
letter,
color: color ? color.id : undefined
faded
};
return new MainThreadSCMResource(

View File

@@ -10,7 +10,6 @@ import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
@@ -31,13 +30,13 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
// {{SQL CARBON EDIT}}
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; // {{SQL CARBON EDIT}}
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
export interface ICodeActionsOnSaveOptions {
[kind: string]: boolean;
}
/*
* An update participant that ensures any un-tracked changes are synced to the JSON file contents for a
@@ -45,7 +44,7 @@ import { INotebookService } from 'sql/workbench/services/notebook/browser/notebo
* updates the backing model in-place, this is a backup mechanism to hard-update the file before save in case
* some are missed.
*/
class NotebookUpdateParticipant implements ISaveParticipantParticipant {
class NotebookUpdateParticipant implements ISaveParticipantParticipant { // {{SQL CARBON EDIT}} add notebook participant
constructor(
@INotebookService private notebookService: INotebookService
@@ -153,16 +152,12 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant {
return;
}
let prevSelection: Selection[] = [];
const edits = [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())];
const editor = findEditor(model, this.codeEditorService);
if (editor) {
prevSelection = editor.getSelections();
}
model.pushEditOperations(prevSelection, [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())], edits => prevSelection);
if (editor) {
editor.setSelections(prevSelection);
editor.executeEdits('insertFinalNewLine', edits, editor.getSelections());
} else {
model.pushEditOperations([], edits, () => null);
}
}
}
@@ -276,7 +271,8 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
constructor(
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@ICommandService private readonly _commandService: ICommandService,
@IConfigurationService private readonly _configurationService: IConfigurationService
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) { }
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
@@ -342,7 +338,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
private async applyCodeActions(actionsToRun: readonly CodeAction[]) {
for (const action of actionsToRun) {
await applyCodeAction(action, this._bulkEditService, this._commandService);
await this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService);
}
}

View File

@@ -626,6 +626,9 @@ export class MainThreadTask implements MainThreadTaskShape {
});
});
});
},
getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => {
return Promise.resolve(this._proxy.$getDefaultShellAndArgs());
}
});
}

View File

@@ -3,13 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, IShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -21,7 +21,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
private readonly _toDispose = new DisposableStore();
private readonly _terminalProcesses = new Map<number, Promise<ITerminalProcessExtHostProxy>>();
private readonly _terminalProcessesReady = new Map<number, (proxy: ITerminalProcessExtHostProxy) => void>();
private readonly _terminalOnDidWriteDataListeners = new Map<number, IDisposable>();
private _dataEventTracker: TerminalDataEventTracker | undefined;
constructor(
@@ -131,30 +130,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
}
/** @deprecated */
public $registerOnDataListener(terminalId: number): void {
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
if (!terminalInstance) {
return;
}
// Listener already registered
if (this._terminalOnDidWriteDataListeners.has(terminalId)) {
return;
}
// Register
const listener = terminalInstance.onData(data => {
this._onTerminalData(terminalId, data);
});
this._terminalOnDidWriteDataListeners.set(terminalId, listener);
terminalInstance.addDisposable(listener);
}
public $startSendingDataEvents(): void {
if (!this._dataEventTracker) {
this._dataEventTracker = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => {
this._onTerminalData2(id, data);
this._onTerminalData(id, data);
});
}
}
@@ -170,15 +149,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptActiveTerminalChanged(terminalId);
}
/** @deprecated */
private _onTerminalData(terminalId: number, data: string): void {
this._proxy.$acceptTerminalProcessData(terminalId, data);
}
private _onTerminalData2(terminalId: number, data: string): void {
this._proxy.$acceptTerminalProcessData2(terminalId, data);
}
private _onTitleChanged(terminalId: number, name: string): void {
this._proxy.$acceptTerminalTitleChange(terminalId, name);
}

View File

@@ -35,9 +35,11 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._dataProviders.set(treeViewId, dataProvider);
const viewer = this.getTreeView(treeViewId);
if (viewer) {
viewer.dataProvider = dataProvider;
// Order is important here. The internal tree isn't created until the dataProvider is set.
// Set all other properties first!
viewer.showCollapseAllAction = !!options.showCollapseAll;
viewer.canSelectMany = !!options.canSelectMany;
viewer.dataProvider = dataProvider;
this.registerListeners(treeViewId, viewer);
this._proxy.$setVisible(treeViewId, viewer.visible);
} else {
@@ -74,6 +76,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
$setTitle(treeViewId: string, title: string): void {
const viewer = this.getTreeView(treeViewId);
if (viewer) {
viewer.title = title;
}
}
private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, itemIn: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
options = options ? options : { select: false, focus: false };
const select = isUndefinedOrNull(options.select) ? false : options.select;

View File

@@ -8,7 +8,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/extensionUrlHandler';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
class ExtensionUrlHandler implements IURLHandler {
@@ -37,7 +37,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
constructor(
context: IExtHostContext,
@IURLService private readonly urlService: IURLService,
@IExtensionUrlHandler private readonly inactiveExtensionUrlHandler: IExtensionUrlHandler
@IExtensionUrlHandler private readonly extensionUrlHandler: IExtensionUrlHandler
) {
this.proxy = context.getProxy(ExtHostContext.ExtHostUrls);
}
@@ -47,7 +47,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
const disposable = this.urlService.registerHandler(handler);
this.handlers.set(handle, { extensionId, disposable });
this.inactiveExtensionUrlHandler.registerExtensionHandler(extensionId, handler);
this.extensionUrlHandler.registerExtensionHandler(extensionId, handler);
return Promise.resolve(undefined);
}
@@ -61,7 +61,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
const { extensionId, disposable } = tuple;
this.inactiveExtensionUrlHandler.unregisterExtensionHandler(extensionId);
this.extensionUrlHandler.unregisterExtensionHandler(extensionId);
this.handlers.delete(handle);
disposable.dispose();

View File

@@ -16,18 +16,13 @@ import { IProductService } from 'vs/platform/product/common/product';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions, WebviewPanelViewStateData } from 'vs/workbench/api/common/extHost.protocol';
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { extHostNamedCustomer } from '../common/extHostCustomers';
interface OldMainThreadWebviewState {
readonly viewType: string;
state: any;
}
import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
/**
* Bi-directional map between webview handles and inputs.
@@ -78,6 +73,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
private readonly _proxy: ExtHostWebviewsShape;
private readonly _webviewEditorInputs = new WebviewHandleStore();
private readonly _revivers = new Map<string, IDisposable>();
private readonly _editorProviders = new Map<string, IDisposable>();
constructor(
context: IExtHostContext,
@@ -95,11 +91,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
this._register(_editorService.onDidActiveEditorChange(this.updateWebviewViewStates, this));
this._register(_editorService.onDidVisibleEditorsChange(this.updateWebviewViewStates, this));
// This reviver's only job is to activate webview extensions
// This reviver's only job is to activate webview panel extensions
// This should trigger the real reviver to be registered from the extension host side.
this._register(_webviewEditorService.registerReviver({
canRevive: (webview: WebviewEditorInput) => {
if (!webview.webview.state) {
this._register(_webviewEditorService.registerResolver({
canResolve: (webview: WebviewEditorInput) => {
if (!webview.webview.state && webview.getTypeId() === WebviewEditorInput.typeId) { // TODO: The typeid check is a workaround for the CustomFileEditorInput case
return false;
}
@@ -109,7 +105,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
}
return false;
},
reviveWebview: () => { throw new Error('not implemented'); }
resolveWebview: () => { throw new Error('not implemented'); }
}));
}
@@ -154,19 +150,26 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
webview.setName(value);
}
public $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void {
const webview = this.getWebviewEditorInput(handle);
if (webview instanceof CustomFileEditorInput) {
webview.setState(state);
}
}
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
const webview = this.getWebviewEditorInput(handle);
webview.iconPath = reviveWebviewIcon(value);
}
public $setHtml(handle: WebviewPanelHandle, value: string): void {
const webview = this.getWebview(handle);
webview.html = value;
const webview = this.getWebviewEditorInput(handle);
webview.webview.html = value;
}
public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void {
const webview = this.getWebview(handle);
webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
const webview = this.getWebviewEditorInput(handle);
webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
}
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
@@ -182,8 +185,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
}
public async $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
const webview = this.getWebview(handle);
webview.sendMessage(message);
const webview = this.getWebviewEditorInput(handle);
webview.webview.sendMessage(message);
return true;
}
@@ -192,11 +195,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
throw new Error(`Reviver for ${viewType} already registered`);
}
this._revivers.set(viewType, this._webviewEditorService.registerReviver({
canRevive: (webviewEditorInput) => {
this._revivers.set(viewType, this._webviewEditorService.registerResolver({
canResolve: (webviewEditorInput) => {
return !!webviewEditorInput.webview.state && webviewEditorInput.viewType === this.getInternalWebviewViewType(viewType);
},
reviveWebview: async (webviewEditorInput): Promise<void> => {
resolveWebview: async (webviewEditorInput): Promise<void> => {
const viewType = this.fromInternalWebviewViewType(webviewEditorInput.viewType);
if (!viewType) {
webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewEditorInput.viewType);
@@ -210,16 +213,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
let state = undefined;
if (webviewEditorInput.webview.state) {
try {
// Check for old-style webview state first which stored state inside another state object
// TODO: remove this after 1.37 ships.
if (
typeof (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState).viewType === 'string' &&
'state' in (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState)
) {
state = JSON.parse((webviewEditorInput.webview.state as any).state);
} else {
state = JSON.parse(webviewEditorInput.webview.state);
}
state = JSON.parse(webviewEditorInput.webview.state);
} catch {
// noop
}
@@ -245,6 +239,48 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
this._revivers.delete(viewType);
}
public $registerEditorProvider(viewType: string): void {
if (this._editorProviders.has(viewType)) {
throw new Error(`Provider for ${viewType} already registered`);
}
this._editorProviders.set(viewType, this._webviewEditorService.registerResolver({
canResolve: (webviewEditorInput) => {
return webviewEditorInput.getTypeId() !== WebviewEditorInput.typeId && webviewEditorInput.viewType === viewType;
},
resolveWebview: async (webview) => {
const handle = `resolved-${MainThreadWebviews.revivalPool++}`;
this._webviewEditorInputs.add(handle, webview);
this.hookupWebviewEventDelegate(handle, webview);
try {
await this._proxy.$resolveWebviewEditor(
webview.getResource(),
handle,
viewType,
webview.getTitle(),
webview.webview.state,
editorGroupToViewColumn(this._editorGroupService, webview.group || 0),
webview.webview.options
);
} catch (error) {
onUnexpectedError(error);
webview.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
}
}
}));
}
public $unregisterEditorProvider(viewType: string): void {
const provider = this._editorProviders.get(viewType);
if (!provider) {
throw new Error(`No provider for ${viewType} registered`);
}
provider.dispose();
this._editorProviders.delete(viewType);
}
private getInternalWebviewViewType(viewType: string): string {
return `mainThreadWebview-${viewType}`;
}
@@ -271,6 +307,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
}
webview.webview.state = newState;
});
input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value));
}
private updateWebviewViewStates() {
@@ -333,10 +370,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
return this._webviewEditorInputs.getInputForHandle(handle);
}
private getWebview(handle: WebviewPanelHandle): Webview {
return this.getWebviewEditorInput(handle).webview;
}
private static getDeserializationFailedContents(viewType: string) {
return `<!DOCTYPE html>
<html>

View File

@@ -48,7 +48,7 @@ const configurationEntrySchema: IJSONSchema = {
nls.localize('scope.resource.description', "Configuration that can be configured in the user, remote, workspace or folder settings."),
nls.localize('scope.machine-overridable.description', "Machine configuration that can be configured also in workspace or folder settings.")
],
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window` and `resource`.")
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window`, `resource` and `machine-overridable`.")
},
enumDescriptions: {
type: 'array',
@@ -238,6 +238,7 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
allowComments: true,
allowsTrailingCommas: true,
default: {
folders: [
{

View File

@@ -517,7 +517,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
}
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
}
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
@@ -528,6 +528,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
},
registerWebviewEditorProvider: (viewType: string, provider: vscode.WebviewEditorProvider) => {
checkProposedApiEnabled(extension);
return extHostWebviews.registerWebviewEditorProvider(viewType, provider);
},
registerDecorationProvider(provider: vscode.DecorationProvider) {
checkProposedApiEnabled(extension);
return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
@@ -838,7 +842,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
DocumentSymbol: extHostTypes.DocumentSymbol,
EndOfLine: extHostTypes.EndOfLine,
EventEmitter: Emitter,
ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext,
ExtensionKind: extHostTypes.ExtensionKind,
CustomExecution2: extHostTypes.CustomExecution2,
FileChangeType: extHostTypes.FileChangeType,
@@ -897,8 +900,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// proposed
CallHierarchyDirection: extHostTypes.CallHierarchyDirection,
CallHierarchyItem: extHostTypes.CallHierarchyItem
CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall,
CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall,
CallHierarchyItem: extHostTypes.CallHierarchyItem,
Decoration: extHostTypes.Decoration,
WebviewEditorState: extHostTypes.WebviewEditorState,
};
};
}

View File

@@ -39,7 +39,6 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import * as tasks from 'vs/workbench/api/common/shared/tasks';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
@@ -120,7 +119,7 @@ export interface MainThreadClipboardShape extends IDisposable {
export interface MainThreadCommandsShape extends IDisposable {
$registerCommand(id: string): void;
$unregisterCommand(id: string): void;
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined>;
$executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined>;
$getCommands(): Promise<string[]>;
}
@@ -248,6 +247,7 @@ export interface MainThreadTreeViewsShape extends IDisposable {
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
$setTitle(treeViewId: string, title: string): void;
}
export interface MainThreadDownloadServiceShape extends IDisposable {
@@ -267,6 +267,7 @@ export interface MainThreadKeytarShape extends IDisposable {
$setPassword(service: string, account: string, password: string): Promise<void>;
$deletePassword(service: string, account: string): Promise<boolean>;
$findPassword(service: string): Promise<string | null>;
$findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
}
export interface IRegExpDto {
@@ -401,8 +402,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$hide(terminalId: number): void;
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
$show(terminalId: number, preserveFocus: boolean): void;
/** @deprecated */
$registerOnDataListener(terminalId: number): void;
$startSendingDataEvents(): void;
$stopSendingDataEvents(): void;
@@ -543,6 +542,7 @@ export interface MainThreadWebviewsShape extends IDisposable {
$disposeWebview(handle: WebviewPanelHandle): void;
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
$setTitle(handle: WebviewPanelHandle, value: string): void;
$setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void;
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void;
$setHtml(handle: WebviewPanelHandle, value: string): void;
@@ -551,6 +551,9 @@ export interface MainThreadWebviewsShape extends IDisposable {
$registerSerializer(viewType: string): void;
$unregisterSerializer(viewType: string): void;
$registerEditorProvider(viewType: string): void;
$unregisterEditorProvider(viewType: string): void;
}
export interface WebviewPanelViewStateData {
@@ -563,9 +566,11 @@ export interface WebviewPanelViewStateData {
export interface ExtHostWebviewsShape {
$onMessage(handle: WebviewPanelHandle, message: any): void;
$onMissingCsp(handle: WebviewPanelHandle, extensionId: string): void;
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -663,11 +668,7 @@ export type SCMRawResource = [
string[] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/,
string | undefined /*source*/,
string | undefined /*letter*/,
ThemeColor | null /*color*/
boolean /*faded*/
];
export type SCMRawResourceSplice = [
@@ -719,6 +720,7 @@ export interface MainThreadDebugServiceShape extends IDisposable {
$unregisterDebugConfigurationProvider(handle: number): void;
$unregisterDebugAdapterDescriptorFactory(handle: number): void;
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, parentSessionID: string | undefined): Promise<boolean>;
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
$appendDebugConsole(value: string): void;
$startBreakpointEvents(): void;
@@ -1069,8 +1071,7 @@ export interface ICodeLensDto {
command?: ICommandDto;
}
export interface ICallHierarchyDto {
_id: number;
export interface ICallHierarchyItemDto {
kind: modes.SymbolKind;
name: string;
detail?: string;
@@ -1113,8 +1114,8 @@ export interface ExtHostLanguageFeaturesShape {
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<modes.SelectionRange[][]>;
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyDto | undefined>;
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[ICallHierarchyDto, modes.Location[]][]>;
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
}
export interface ExtHostQuickOpenShape {
@@ -1156,9 +1157,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalOpened(id: number, name: string): void;
$acceptActiveTerminalChanged(id: number | null): void;
$acceptTerminalProcessId(id: number, processId: number): void;
/** @deprecated */
$acceptTerminalProcessData(id: number, data: string): void;
$acceptTerminalProcessData2(id: number, data: string): void;
$acceptTerminalTitleChange(id: number, name: string): void;
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
@@ -1191,6 +1190,7 @@ export interface ExtHostTaskShape {
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
$OnDidEndTask(execution: tasks.TaskExecutionDTO): void;
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>;
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined }>;
}
export interface IBreakpointDto {
@@ -1266,6 +1266,7 @@ export interface ExtHostDebugServiceShape {
$acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void;
$acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void;
$acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void;
$acceptDebugSessionNameChanged(session: IDebugSessionDto, name: string): void;
}
export interface DecorationRequest {
@@ -1274,7 +1275,7 @@ export interface DecorationRequest {
readonly uri: UriComponents;
}
export type DecorationData = [number, boolean, string, string, ThemeColor, string];
export type DecorationData = [number, boolean, string, string, ThemeColor];
export type DecorationReply = { [id: number]: DecorationData };
export interface ExtHostDecorationsShape {

View File

@@ -8,7 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/contrib/search/common/search';
@@ -182,6 +182,22 @@ export class ExtHostApiCommands {
],
returns: 'A promise that resolves to an array of DocumentLink-instances.'
});
this._register('vscode.executeCallHierarchyProviderIncomingCalls', this._executeCallHierarchyIncomingCallsProvider, {
description: 'Execute call hierarchy provider for incoming calls',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
],
returns: 'A promise that resolves to an array of CallHierarchyIncomingCall-instances.'
});
this._register('vscode.executeCallHierarchyProviderOutgoingCalls', this._executeCallHierarchyOutgoingCallsProvider, {
description: 'Execute call hierarchy provider for outgoing calls',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
],
returns: 'A promise that resolves to an array of CallHierarchyOutgoingCall-instances.'
});
this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, {
description: 'Execute document color provider.',
args: [
@@ -557,6 +573,36 @@ export class ExtHostApiCommands {
return this._commands.executeCommand<modes.ILink[]>('_executeLinkProvider', resource)
.then(tryMapWith(typeConverters.DocumentLink.to));
}
private async _executeCallHierarchyIncomingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyIncomingCall[]> {
type IncomingCallDto = {
source: ICallHierarchyItemDto;
sourceRanges: IRange[];
};
const args = { resource, position: typeConverters.Position.from(position) };
const calls = await this._commands.executeCommand<IncomingCallDto[]>('_executeCallHierarchyIncomingCalls', args);
const result: vscode.CallHierarchyIncomingCall[] = [];
for (const call of calls) {
result.push(new types.CallHierarchyIncomingCall(typeConverters.CallHierarchyItem.to(call.source), <vscode.Range[]>call.sourceRanges.map(typeConverters.Range.to)));
}
return result;
}
private async _executeCallHierarchyOutgoingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyOutgoingCall[]> {
type OutgoingCallDto = {
sourceRanges: IRange[];
target: ICallHierarchyItemDto;
};
const args = { resource, position: typeConverters.Position.from(position) };
const calls = await this._commands.executeCommand<OutgoingCallDto[]>('_executeCallHierarchyOutgoingCalls', args);
const result: vscode.CallHierarchyOutgoingCall[] = [];
for (const call of calls) {
result.push(new types.CallHierarchyOutgoingCall(typeConverters.CallHierarchyItem.to(call.target), <vscode.Range[]>call.sourceRanges.map(typeConverters.Range.to)));
}
return result;
}
}
function tryMapWith<T, R>(f: (x: T) => R) {

View File

@@ -33,7 +33,7 @@ export interface ArgumentProcessor {
export class ExtHostCommands implements ExtHostCommandsShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private readonly _commands = new Map<string, CommandHandler>();
private readonly _proxy: MainThreadCommandsShape;
@@ -112,6 +112,10 @@ export class ExtHostCommands implements ExtHostCommandsShape {
executeCommand<T>(id: string, ...args: any[]): Promise<T> {
this._logService.trace('ExtHostCommands#executeCommand', id);
return this._doExecuteCommand(id, args, true);
}
private async _doExecuteCommand<T>(id: string, args: any[], retry: boolean): Promise<T> {
if (this._commands.has(id)) {
// we stay inside the extension host and support
@@ -120,8 +124,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
} else {
// automagically convert some argument types
args = cloneAndChange(args, function (value) {
const toArgs = cloneAndChange(args, function (value) {
if (value instanceof extHostTypes.Position) {
return extHostTypeConverter.Position.from(value);
}
@@ -136,7 +139,19 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
});
return this._proxy.$executeCommand<T>(id, args).then(result => revive(result, 0));
try {
const result = await this._proxy.$executeCommand<T>(id, toArgs, retry);
return revive(result, 0);
} catch (e) {
// Rerun the command when it wasn't known, had arguments, and when retry
// is enabled. We do this because the command might be registered inside
// the extension host now and can therfore accept the arguments as-is.
if (e instanceof Error && e.message === '$executeCommand:retry') {
return this._doExecuteCommand(id, args, false);
} else {
throw e;
}
}
}
}

View File

@@ -42,7 +42,7 @@ type ConfigurationInspect<T> = {
export class ExtHostConfiguration implements ExtHostConfigurationShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private readonly _proxy: MainThreadConfigurationShape;
private readonly _extHostWorkspace: ExtHostWorkspace;

View File

@@ -13,7 +13,7 @@ export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtH
export interface IExtHostDebugService extends ExtHostDebugServiceShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
onDidStartDebugSession: Event<vscode.DebugSession>;
onDidTerminateDebugSession: Event<vscode.DebugSession>;

View File

@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import { URI } from 'vs/base/common/uri';
import { MainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol';
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
import { Disposable, Decoration } from 'vs/workbench/api/common/extHostTypes';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { asArray } from 'vs/base/common/arrays';
@@ -59,12 +59,14 @@ export class ExtHostDecorations implements IExtHostDecorations {
}
const { provider, extensionId } = entry;
return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => {
if (data && data.letter && data.letter.length !== 1) {
console.warn(`INVALID decoration from extension '${extensionId.value}'. The 'letter' must be set and be one character, not '${data.letter}'.`);
if (!data) {
return;
}
if (data) {
result[id] = <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color, data.source];
try {
Decoration.validate(data);
result[id] = <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color];
} catch (e) {
console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`);
}
}, err => {
console.error(err);

View File

@@ -17,7 +17,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private _disposables: Disposable[] = [];

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as vscode from 'vscode';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@@ -11,29 +12,11 @@ import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/s
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
export interface IExtensionMemento {
get<T>(key: string): T | undefined;
get<T>(key: string, defaultValue: T): T;
update(key: string, value: any): Promise<void>;
}
export interface IExtensionContext {
subscriptions: IDisposable[];
workspaceState: IExtensionMemento;
globalState: IExtensionMemento;
extensionPath: string;
storagePath: string;
globalStoragePath: string;
asAbsolutePath(relativePath: string): string;
readonly logPath: string;
executionContext: number;
}
/**
* Represents the source code (module) of an extension.
*/
export interface IExtensionModule {
activate?(ctx: IExtensionContext): Promise<IExtensionAPI>;
activate?(ctx: vscode.ExtensionContext): Promise<IExtensionAPI>;
deactivate?(): void;
}

View File

@@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
@@ -25,7 +25,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { Schemas } from 'vs/base/common/network';
import { VSBuffer } from 'vs/base/common/buffer';
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes';
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -64,7 +64,7 @@ type TelemetryActivationEventFragment = {
export abstract class AbstractExtHostExtensionService implements ExtHostExtensionServiceShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
@@ -331,11 +331,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
return Promise.all<any>([
this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
return Promise.all([
this._loadCommonJSModule<IExtensionModule>(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
this._loadExtensionContext(extensionDescription)
]).then(values => {
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder);
});
}
@@ -353,7 +353,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
this._storagePath.whenReady
]).then(() => {
const that = this;
return Object.freeze(<IExtensionContext>{
return Object.freeze<vscode.ExtensionContext>({
globalState,
workspaceState,
subscriptions: [],
@@ -361,13 +361,12 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); }
});
});
}
private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
// Make sure the extension's surface is not undefined
extensionModule = extensionModule || {
activate: undefined,
@@ -379,7 +378,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
});
}
private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
if (typeof extensionModule.activate === 'function') {
try {
activationTimesBuilder.activateCallStart();
@@ -767,7 +766,7 @@ function getTelemetryActivationEvent(extensionDescription: IExtensionDescription
export const IExtHostExtensionService = createDecorator<IExtHostExtensionService>('IExtHostExtensionService');
export interface IExtHostExtensionService extends AbstractExtHostExtensionService {
_serviceBrand: any;
_serviceBrand: undefined;
initialize(): Promise<void>;
isActivated(extensionId: ExtensionIdentifier): boolean;
activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;

View File

@@ -14,7 +14,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
import { asPromise } from 'vs/base/common/async';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorInfo, IMainContext, IdObject, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILanguageConfigurationDto, IWorkspaceSymbolDto, ISuggestResultDto, IWorkspaceSymbolsDto, ICodeActionDto, IDocumentFilterDto, IWorkspaceEditDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICodeLensDto, ISuggestDataDto, ILinksListDto, ChainedCacheId, ICodeLensListDto, ICodeActionListDto, ISignatureHelpDto, ISignatureHelpContextDto } from './extHost.protocol';
import * as extHostProtocol from './extHost.protocol';
import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
@@ -24,8 +24,6 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { LRUCache } from 'vs/base/common/map';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
@@ -67,10 +65,10 @@ class DocumentSymbolAdapter {
const res: modes.DocumentSymbol[] = [];
const parentStack: modes.DocumentSymbol[] = [];
for (const info of infos) {
const element = <modes.DocumentSymbol>{
const element: modes.DocumentSymbol = {
name: info.name || '!!MISSING: name!!',
kind: typeConvert.SymbolKind.from(info.kind),
tags: info.tags && info.tags.map(typeConvert.SymbolTag.from),
tags: info.tags ? info.tags.map(typeConvert.SymbolTag.from) : [],
detail: '',
containerName: info.containerName,
range: typeConvert.Range.from(info.location.range),
@@ -112,7 +110,7 @@ class CodeLensAdapter {
private readonly _provider: vscode.CodeLensProvider
) { }
provideCodeLenses(resource: URI, token: CancellationToken): Promise<ICodeLensListDto | undefined> {
provideCodeLenses(resource: URI, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => {
@@ -125,7 +123,7 @@ class CodeLensAdapter {
const disposables = new DisposableStore();
this._disposables.set(cacheId, disposables);
const result: ICodeLensListDto = {
const result: extHostProtocol.ICodeLensListDto = {
cacheId,
lenses: [],
};
@@ -142,7 +140,7 @@ class CodeLensAdapter {
});
}
resolveCodeLens(symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined> {
resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
const lens = symbol.cacheId && this._cache.get(...symbol.cacheId);
if (!lens) {
@@ -309,7 +307,7 @@ class ReferenceAdapter {
}
}
export interface CustomCodeAction extends ICodeActionDto {
export interface CustomCodeAction extends extHostProtocol.ICodeActionDto {
_isSynthetic?: boolean;
}
@@ -328,7 +326,7 @@ class CodeActionAdapter {
private readonly _extensionId: ExtensionIdentifier
) { }
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined> {
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
const doc = this._documents.getDocument(resource);
const ran = Selection.isISelection(rangeOrSelection)
@@ -392,7 +390,7 @@ class CodeActionAdapter {
}
}
return <ICodeActionListDto>{ cacheId, actions };
return <extHostProtocol.ICodeActionListDto>{ cacheId, actions };
});
}
@@ -481,8 +479,8 @@ class NavigateTypeAdapter {
this._provider = provider;
}
provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto> {
const result: IWorkspaceSymbolsDto = IdObject.mixin({ symbols: [] });
provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
const result: extHostProtocol.IWorkspaceSymbolsDto = extHostProtocol.IdObject.mixin({ symbols: [] });
return asPromise(() => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (isNonEmptyArray(value)) {
for (const item of value) {
@@ -494,7 +492,7 @@ class NavigateTypeAdapter {
console.warn('INVALID SymbolInformation, lacks name', item);
continue;
}
const symbol = IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
this._symbolCache[symbol._id!] = item;
result.symbols.push(symbol);
}
@@ -507,7 +505,7 @@ class NavigateTypeAdapter {
});
}
resolveWorkspaceSymbol(symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined> {
resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
return Promise.resolve(symbol);
@@ -544,7 +542,7 @@ class RenameAdapter {
private readonly _provider: vscode.RenameProvider
) { }
provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
@@ -557,10 +555,10 @@ class RenameAdapter {
}, err => {
const rejectReason = RenameAdapter._asMessage(err);
if (rejectReason) {
return <IWorkspaceEditDto>{ rejectReason, edits: undefined! };
return <extHostProtocol.IWorkspaceEditDto>{ rejectReason, edits: undefined! };
} else {
// generic error
return Promise.reject<IWorkspaceEditDto>(err);
return Promise.reject<extHostProtocol.IWorkspaceEditDto>(err);
}
});
}
@@ -634,7 +632,7 @@ class SuggestAdapter {
this._provider = provider;
}
provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined> {
provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
@@ -663,7 +661,7 @@ class SuggestAdapter {
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos))
.with({ end: pos });
const result: ISuggestResultDto = {
const result: extHostProtocol.ISuggestResultDto = {
x: pid,
b: [],
a: typeConvert.Range.from(wordRangeBeforePos),
@@ -683,7 +681,7 @@ class SuggestAdapter {
});
}
resolveCompletionItem(_resource: URI, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined> {
resolveCompletionItem(_resource: URI, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
if (typeof this._provider.resolveCompletionItem !== 'function') {
return Promise.resolve(undefined);
@@ -711,7 +709,7 @@ class SuggestAdapter {
this._cache.delete(id);
}
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId): ISuggestDataDto | undefined {
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined {
if (typeof item.label !== 'string' || item.label.length === 0) {
console.warn('INVALID text edit -> must have at least a label');
return undefined;
@@ -722,7 +720,7 @@ class SuggestAdapter {
throw Error('DisposableStore is missing...');
}
const result: ISuggestDataDto = {
const result: extHostProtocol.ISuggestDataDto = {
//
x: id,
//
@@ -779,7 +777,7 @@ class SignatureHelpAdapter {
private readonly _provider: vscode.SignatureHelpProvider,
) { }
provideSignatureHelp(resource: URI, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise<ISignatureHelpDto | undefined> {
provideSignatureHelp(resource: URI, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
const vscodeContext = this.reviveContext(context);
@@ -793,7 +791,7 @@ class SignatureHelpAdapter {
});
}
private reviveContext(context: ISignatureHelpContextDto): vscode.SignatureHelpContext {
private reviveContext(context: extHostProtocol.ISignatureHelpContextDto): vscode.SignatureHelpContext {
let activeSignatureHelp: vscode.SignatureHelp | undefined = undefined;
if (context.activeSignatureHelp) {
const revivedSignatureHelp = typeConvert.SignatureHelp.to(context.activeSignatureHelp);
@@ -857,7 +855,7 @@ class LinkProviderAdapter {
private readonly _provider: vscode.DocumentLinkProvider
) { }
provideLinks(resource: URI, token: CancellationToken): Promise<ILinksListDto | undefined> {
provideLinks(resource: URI, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => {
@@ -879,9 +877,9 @@ class LinkProviderAdapter {
} else {
// cache links for future resolving
const pid = this._cache.add(links);
const result: ILinksListDto = { links: [], id: pid };
const result: extHostProtocol.ILinksListDto = { links: [], id: pid };
for (let i = 0; i < links.length; i++) {
const dto: ILinkDto = typeConvert.DocumentLink.from(links[i]);
const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]);
dto.cacheId = [pid, i];
result.links.push(dto);
}
@@ -890,7 +888,7 @@ class LinkProviderAdapter {
});
}
resolveLink(id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined> {
resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
if (typeof this._provider.resolveDocumentLink !== 'function') {
return Promise.resolve(undefined);
}
@@ -915,14 +913,14 @@ class ColorProviderAdapter {
private _provider: vscode.DocumentColorProvider
) { }
provideColors(resource: URI, token: CancellationToken): Promise<IRawColorInfo[]> {
provideColors(resource: URI, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => {
if (!Array.isArray<vscode.ColorInformation>(colors)) {
return [];
}
const colorInfos: IRawColorInfo[] = colors.map(ci => {
const colorInfos: extHostProtocol.IRawColorInfo[] = colors.map(ci => {
return {
color: typeConvert.Color.from(ci.color),
range: typeConvert.Range.from(ci.range)
@@ -933,7 +931,7 @@ class ColorProviderAdapter {
});
}
provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
provideColorPresentations(resource: URI, raw: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
const document = this._documents.getDocument(resource);
const range = typeConvert.Range.to(raw.range);
const color = typeConvert.Color.to(raw.color);
@@ -1011,56 +1009,29 @@ class SelectionRangeAdapter {
class CallHierarchyAdapter {
// todo@joh keep object (heap service, lifecycle)
private readonly _cache = new LRUCache<number, vscode.CallHierarchyItem>(1000, 0.8);
private _idPool = 0;
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.CallHierarchyItemProvider
) { }
provideCallHierarchyItem(resource: URI, pos: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
const document = this._documents.getDocument(resource);
const position = typeConvert.Position.to(pos);
return asPromise(() => this._provider.provideCallHierarchyItem(document, position, token)).then(item => {
if (!item) {
return undefined;
}
return this._fromItem(item);
});
async provideCallsTo(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const calls = await this._provider.provideCallHierarchyIncomingCalls(doc, pos, token);
if (!calls) {
return undefined;
}
return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.source), call.sourceRanges.map(typeConvert.Range.from)]));
}
resolveCallHierarchyItem(item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
return asPromise(() => this._provider.resolveCallHierarchyItem(
this._cache.get(item._id)!,
direction as number, token) // todo@joh proper convert
).then(data => {
if (!data) {
return [];
}
return data.map(tuple => {
return <[callHierarchy.CallHierarchyItem, modes.Location[]]>[
this._fromItem(tuple[0]),
tuple[1].map(typeConvert.location.from)
];
});
});
}
private _fromItem(item: vscode.CallHierarchyItem, _id: number = this._idPool++): callHierarchy.CallHierarchyItem {
const res = <callHierarchy.CallHierarchyItem>{
_id,
name: item.name,
detail: item.detail,
kind: typeConvert.SymbolKind.from(item.kind),
uri: item.uri,
range: typeConvert.Range.from(item.range),
selectionRange: typeConvert.Range.from(item.selectionRange),
};
this._cache.set(_id, item);
return res;
async provideCallsFrom(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const calls = await this._provider.provideCallHierarchyOutgoingCalls(doc, pos, token);
if (!calls) {
return undefined;
}
return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.target), call.sourceRanges.map(typeConvert.Range.from)]));
}
}
@@ -1077,12 +1048,12 @@ class AdapterData {
) { }
}
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageFeaturesShape {
private static _handlePool: number = 0;
private readonly _uriTransformer: IURITransformer | null;
private _proxy: MainThreadLanguageFeaturesShape;
private _proxy: extHostProtocol.MainThreadLanguageFeaturesShape;
private _documents: ExtHostDocuments;
private _commands: ExtHostCommands;
private _diagnostics: ExtHostDiagnostics;
@@ -1090,7 +1061,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
private readonly _logService: ILogService;
constructor(
mainContext: IMainContext,
mainContext: extHostProtocol.IMainContext,
uriTransformer: IURITransformer | null,
documents: ExtHostDocuments,
commands: ExtHostCommands,
@@ -1098,18 +1069,18 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
logService: ILogService
) {
this._uriTransformer = uriTransformer;
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures);
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadLanguageFeatures);
this._documents = documents;
this._commands = commands;
this._diagnostics = diagnostics;
this._logService = logService;
}
private _transformDocumentSelector(selector: vscode.DocumentSelector): Array<IDocumentFilterDto> {
private _transformDocumentSelector(selector: vscode.DocumentSelector): Array<extHostProtocol.IDocumentFilterDto> {
return coalesce(asArray(selector).map(sel => this._doTransformDocumentSelector(sel)));
}
private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): IDocumentFilterDto | undefined {
private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): extHostProtocol.IDocumentFilterDto | undefined {
if (typeof selector === 'string') {
return {
$serialized: true,
@@ -1217,11 +1188,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return result;
}
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined> {
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined);
}
$resolveCodeLens(handle: number, symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined> {
$resolveCodeLens(handle: number, symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined);
}
@@ -1316,7 +1287,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
}
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined> {
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined);
}
@@ -1364,11 +1335,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto> {
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token), { symbols: [] });
}
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined> {
$resolveWorkspaceSymbol(handle: number, symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token), undefined);
}
@@ -1384,7 +1355,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | undefined> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token), undefined);
}
@@ -1400,11 +1371,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined> {
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined);
}
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined> {
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, token), undefined);
}
@@ -1415,7 +1386,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
// --- parameter hints
registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable {
const metadata: ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars)
const metadata: extHostProtocol.ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars)
? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] }
: metadataOrTriggerChars;
@@ -1424,7 +1395,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise<ISignatureHelpDto | undefined> {
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token), undefined);
}
@@ -1440,11 +1411,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<ILinksListDto | undefined> {
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token), undefined);
}
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined> {
$resolveDocumentLink(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(id, token), undefined);
}
@@ -1458,11 +1429,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<IRawColorInfo[]> {
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource), token), []);
}
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined);
}
@@ -1496,24 +1467,24 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallHierarchyItem(URI.revive(resource), position, token), undefined);
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(URI.revive(resource), position, token), undefined);
}
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.resolveCallHierarchyItem(item, direction, token), []);
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(URI.revive(resource), position, token), undefined);
}
// --- configuration
private static _serializeRegExp(regExp: RegExp): IRegExpDto {
private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto {
return {
pattern: regExp.source,
flags: regExpFlags(regExp),
};
}
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): IIndentationRuleDto {
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): extHostProtocol.IIndentationRuleDto {
return {
decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern),
increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern),
@@ -1522,7 +1493,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
};
}
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): IOnEnterRuleDto {
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): extHostProtocol.IOnEnterRuleDto {
return {
beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
afterText: onEnterRule.afterText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText) : undefined,
@@ -1531,7 +1502,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
};
}
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): IOnEnterRuleDto[] {
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): extHostProtocol.IOnEnterRuleDto[] {
return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule);
}
@@ -1551,7 +1522,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
}
const handle = this._nextHandle();
const serializedConfiguration: ILanguageConfigurationDto = {
const serializedConfiguration: extHostProtocol.ILanguageConfigurationDto = {
comments: configuration.comments,
brackets: configuration.brackets,
wordPattern: configuration.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern) : undefined,

View File

@@ -3,11 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionMemento } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
export class ExtensionMemento implements IExtensionMemento {
export class ExtensionMemento implements vscode.Memento {
private readonly _id: string;
private readonly _shared: boolean;

View File

@@ -7,7 +7,7 @@ import { MainContext, MainThreadOutputServiceShape, ExtHostOutputServiceShape }
import * as vscode from 'vscode';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { VSBuffer } from 'vs/base/common/buffer';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -137,23 +137,15 @@ export class LazyOutputChannel implements vscode.OutputChannel {
export class ExtHostOutputService implements ExtHostOutputServiceShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
protected readonly _proxy: MainThreadOutputServiceShape;
protected readonly _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
protected readonly _visibleChannelDisposable = new MutableDisposable();
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadOutputService);
}
$setVisibleChannel(channelId: string): void {
if (channelId) {
const channel = this._channels.get(channelId);
if (channel) {
this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update());
}
}
}
createOutputChannel(name: string): vscode.OutputChannel {

View File

@@ -134,6 +134,7 @@ interface IKeytarModule {
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
findPassword(service: string): Promise<string | null>;
findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
}
class KeytarNodeModuleFactory implements INodeModuleFactory {
@@ -174,6 +175,9 @@ class KeytarNodeModuleFactory implements INodeModuleFactory {
},
findPassword: (service: string): Promise<string | null> => {
return mainThreadKeytar.$findPassword(service);
},
findCredentials(service: string): Promise<Array<{ account: string, password: string }>> {
return mainThreadKeytar.$findCredentials(service);
}
};
}

View File

@@ -9,11 +9,11 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
export const IExtHostRpcService = createDecorator<IExtHostRpcService>('IExtHostRpcService');
export interface IExtHostRpcService extends IRPCProtocol {
_serviceBrand: any;
_serviceBrand: undefined;
}
export class ExtHostRpcService implements IExtHostRpcService {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
readonly getProxy: <T>(identifier: ProxyIdentifier<T>) => T;
readonly set: <T, R extends T> (identifier: ProxyIdentifier<T>, instance: R) => R;

View File

@@ -319,11 +319,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
const source = r.decorations && r.decorations.source || undefined;
const letter = r.decorations && r.decorations.letter || undefined;
const color = r.decorations && r.decorations.color || undefined;
const rawResource = [handle, <UriComponents>sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource;
const rawResource = [handle, <UriComponents>sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource;
return { rawResource, handle };
});

View File

@@ -16,7 +16,7 @@ export interface IStorageChangeEvent {
export class ExtHostStorage implements ExtHostStorageShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private _proxy: MainThreadStorageShape;

View File

@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
export interface IExtensionStoragePaths {
_serviceBrand: any;
_serviceBrand: undefined;
whenReady: Promise<any>;
workspaceValue(extension: IExtensionDescription): string | undefined;
globalValue(extension: IExtensionDescription): string;

View File

@@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
export interface IExtHostTask extends ExtHostTaskShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
taskExecutions: vscode.TaskExecution[];
onDidStartTask: Event<vscode.TaskStartEvent>;

View File

@@ -4,14 +4,18 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { Event } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI, UriComponents } from 'vs/base/common/uri';
import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
import { timeout } from 'vs/base/common/async';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
_serviceBrand: any;
_serviceBrand: undefined;
activeTerminal: vscode.Terminal | undefined;
terminals: vscode.Terminal[];
@@ -30,3 +34,562 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
}
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
export class BaseExtHostTerminal {
public _id: number | undefined;
protected _idPromise: Promise<number>;
private _idPromiseComplete: ((value: number) => any) | undefined;
private _disposed: boolean = false;
private _queuedRequests: ApiRequest[] = [];
constructor(
protected _proxy: MainThreadTerminalServiceShape,
id?: number
) {
this._idPromise = new Promise<number>(c => {
if (id !== undefined) {
this._id = id;
c(id);
} else {
this._idPromiseComplete = c;
}
});
}
public dispose(): void {
if (!this._disposed) {
this._disposed = true;
this._queueApiRequest(this._proxy.$dispose, []);
}
}
protected _checkDisposed() {
if (this._disposed) {
throw new Error('Terminal has already been disposed');
}
}
protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void {
const request: ApiRequest = new ApiRequest(callback, args);
if (!this._id) {
this._queuedRequests.push(request);
return;
}
request.run(this._proxy, this._id);
}
public _runQueuedRequests(id: number): void {
this._id = id;
if (this._idPromiseComplete) {
this._idPromiseComplete(id);
this._idPromiseComplete = undefined;
}
this._queuedRequests.forEach((r) => {
r.run(this._proxy, id);
});
this._queuedRequests.length = 0;
}
}
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
private _pidPromise: Promise<number | undefined>;
private _cols: number | undefined;
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
private _rows: number | undefined;
public isOpen: boolean = false;
constructor(
proxy: MainThreadTerminalServiceShape,
private _name?: string,
id?: number
) {
super(proxy, id);
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
}
public async create(
shellPath?: string,
shellArgs?: string[] | string,
cwd?: string | URI,
env?: { [key: string]: string | null },
waitOnExit?: boolean,
strictEnv?: boolean,
hideFromUser?: boolean
): Promise<void> {
const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser });
this._name = terminal.name;
this._runQueuedRequests(terminal.id);
}
public async createExtensionTerminal(): Promise<number> {
const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true });
this._name = terminal.name;
this._runQueuedRequests(terminal.id);
return terminal.id;
}
public get name(): string {
return this._name || '';
}
public set name(name: string) {
this._name = name;
}
public get dimensions(): vscode.TerminalDimensions | undefined {
if (this._cols === undefined || this._rows === undefined) {
return undefined;
}
return {
columns: this._cols,
rows: this._rows
};
}
public setDimensions(cols: number, rows: number): boolean {
if (cols === this._cols && rows === this._rows) {
// Nothing changed
return false;
}
this._cols = cols;
this._rows = rows;
return true;
}
public get processId(): Promise<number | undefined> {
return this._pidPromise;
}
public sendText(text: string, addNewLine: boolean = true): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
}
public show(preserveFocus: boolean): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$show, [preserveFocus]);
}
public hide(): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$hide, []);
}
public _setProcessId(processId: number | undefined): void {
// The event may fire 2 times when the panel is restored
if (this._pidPromiseComplete) {
this._pidPromiseComplete(processId);
this._pidPromiseComplete = undefined;
} else {
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
this._pidPromise.then(pid => {
if (pid !== processId) {
this._pidPromise = Promise.resolve(processId);
}
});
}
}
}
class ApiRequest {
private _callback: (...args: any[]) => void;
private _args: any[];
constructor(callback: (...args: any[]) => void, args: any[]) {
this._callback = callback;
this._args = args;
}
public run(proxy: MainThreadTerminalServiceShape, id: number) {
this._callback.apply(proxy, [id].concat(this._args));
}
}
export class ExtHostPseudoterminal implements ITerminalChildProcess {
private readonly _onProcessData = new Emitter<string>();
public readonly onProcessData: Event<string> = this._onProcessData.event;
private readonly _onProcessExit = new Emitter<number>();
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
private readonly _onProcessTitleChanged = new Emitter<string>();
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
constructor(private readonly _pty: vscode.Pseudoterminal) { }
shutdown(): void {
this._pty.close();
}
input(data: string): void {
if (this._pty.handleInput) {
this._pty.handleInput(data);
}
}
resize(cols: number, rows: number): void {
if (this._pty.setDimensions) {
this._pty.setDimensions({ columns: cols, rows });
}
}
getInitialCwd(): Promise<string> {
return Promise.resolve('');
}
getCwd(): Promise<string> {
return Promise.resolve('');
}
getLatency(): Promise<number> {
return Promise.resolve(0);
}
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
// Attach the listeners
this._pty.onDidWrite(e => this._onProcessData.fire(e));
if (this._pty.onDidClose) {
this._pty.onDidClose(e => this._onProcessExit.fire(e || 0));
}
if (this._pty.onDidOverrideDimensions) {
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBONEDIT}} strict-null-checks
}
this._pty.open(initialDimensions ? initialDimensions : undefined);
}
}
export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
readonly _serviceBrand: undefined;
protected _proxy: MainThreadTerminalServiceShape;
protected _activeTerminal: ExtHostTerminal | undefined;
protected _terminals: ExtHostTerminal[] = [];
protected _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
public get terminals(): ExtHostTerminal[] { return this._terminals; }
protected readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
protected readonly _onDidOpenTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
protected readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
protected readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
protected readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
});
}
public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal;
public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void>;
public abstract $requestAvailableShells(): Promise<IShellDefinitionDto[]>;
public abstract $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options.name);
const p = new ExtHostPseudoterminal(options.pty);
terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p));
this._terminals.push(terminal);
return terminal;
}
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
const terminal = this._getTerminalByIdEventually(id);
if (!terminal) {
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
}
const p = new ExtHostPseudoterminal(pty);
this._setupExtHostProcessListeners(id, p);
}
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
const original = this._activeTerminal;
if (id === null) {
this._activeTerminal = undefined;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
return;
}
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._activeTerminal = terminal;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
}
}
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._onDidWriteTerminalData.fire({ terminal, data });
}
}
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions as vscode.TerminalDimensions
});
}
}
}
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
await this._getTerminalByIdEventually(id);
if (this._terminalProcesses[id]) {
// Extension pty terminal only - when virtual process resize fires it means that the
// terminal's maximum dimensions changed
this._terminalProcesses[id].resize(cols, rows);
}
}
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
await this._getTerminalByIdEventually(id);
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
if (extHostTerminal) {
extHostTerminal.name = name;
}
}
public async $acceptTerminalClosed(id: number): Promise<void> {
await this._getTerminalByIdEventually(id);
const index = this._getTerminalObjectIndexById(this.terminals, id);
if (index !== null) {
const terminal = this._terminals.splice(index, 1)[0];
this._onDidCloseTerminal.fire(terminal);
}
}
public $acceptTerminalOpened(id: number, name: string): void {
const index = this._getTerminalObjectIndexById(this._terminals, id);
if (index !== null) {
// The terminal has already been created (via createTerminal*), only fire the event
this._onDidOpenTerminal.fire(this.terminals[index]);
this.terminals[index].isOpen = true;
return;
}
const terminal = new ExtHostTerminal(this._proxy, name, id);
this._terminals.push(terminal);
this._onDidOpenTerminal.fire(terminal);
terminal.isOpen = true;
}
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
terminal._setProcessId(processId);
}
}
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
// TODO: Use await this._getTerminalByIdEventually(id);
let terminal = this._getTerminalById(id);
if (terminal) {
callback(terminal);
} else {
// Retry one more time in case the terminal has not yet been initialized.
setTimeout(() => {
terminal = this._getTerminalById(id);
if (terminal) {
callback(terminal);
}
}, EXT_HOST_CREATION_DELAY * 2);
}
}
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
// Pseudoterminal.start
const terminal = await this._getTerminalByIdEventually(id);
if (!terminal) {
return;
}
// Wait for onDidOpenTerminal to fire
let openPromise: Promise<void>;
if (terminal.isOpen) {
openPromise = Promise.resolve();
} else {
openPromise = new Promise<void>(r => {
// Ensure open is called after onDidOpenTerminal
const listener = this.onDidOpenTerminal(async e => {
if (e === terminal) {
listener.dispose();
r();
}
});
});
}
await openPromise;
// Processes should be initialized here for normal virtual process terminals, however for
// tasks they are responsible for attaching the virtual process to a terminal so this
// function may be called before tasks is able to attach to the terminal.
let retries = 5;
while (retries-- > 0) {
if (this._terminalProcesses[id]) {
(this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions);
return;
}
await timeout(50);
}
}
protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
if (p.onProcessOverrideDimensions) {
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
}
this._terminalProcesses[id] = p;
}
public $acceptProcessInput(id: number, data: string): void {
this._terminalProcesses[id].input(data);
}
public $acceptProcessResize(id: number, cols: number, rows: number): void {
try {
this._terminalProcesses[id].resize(cols, rows);
} catch (error) {
// We tried to write to a closed pipe / channel.
if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') {
throw (error);
}
}
}
public $acceptProcessShutdown(id: number, immediate: boolean): void {
this._terminalProcesses[id].shutdown(immediate);
}
public $acceptProcessRequestInitialCwd(id: number): void {
this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd));
}
public $acceptProcessRequestCwd(id: number): void {
this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd));
}
public $acceptProcessRequestLatency(id: number): number {
return id;
}
private _onProcessExit(id: number, exitCode: number): void {
// Remove process reference
delete this._terminalProcesses[id];
// Send exit event to main side
this._proxy.$sendProcessExit(id, exitCode);
}
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
if (!this._getTerminalPromises[id]) {
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
} else {
this._getTerminalPromises[id].then(c => {
return this._createGetTerminalPromise(id, retries);
});
}
return this._getTerminalPromises[id];
}
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
return new Promise(c => {
if (retries === 0) {
c(undefined);
return;
}
const terminal = this._getTerminalById(id);
if (terminal) {
c(terminal);
} else {
// This should only be needed immediately after createTerminalRenderer is called as
// the ExtHostTerminal has not yet been iniitalized
timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1)));
}
});
}
private _getTerminalById(id: number): ExtHostTerminal | null {
return this._getTerminalObjectById(this._terminals, id);
}
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
const index = this._getTerminalObjectIndexById(array, id);
return index !== null ? array[index] : null;
}
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
let index: number | null = null;
array.some((item, i) => {
const thisId = item._id;
if (thisId === id) {
index = i;
return true;
}
return false;
});
return index;
}
}
export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
throw new Error('Not implemented');
}
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
throw new Error('Not implemented');
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
throw new Error('Not implemented');
}
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
throw new Error('Not implemented');
}
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
throw new Error('Not implemented');
}
public async $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
throw new Error('Not implemented');
}
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
// No-op for web worker ext host as workspace permissions aren't used
}
}

View File

@@ -99,6 +99,11 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
checkProposedApiEnabled(extension);
treeView.message = message;
},
get title() { return treeView.title; },
set title(title: string) {
checkProposedApiEnabled(extension);
treeView.title = title;
},
reveal: (element: T, options?: IRevealOptions): Promise<void> => {
return treeView.reveal(element, options);
},
@@ -200,6 +205,15 @@ export class ExtHostTreeView<T> extends Disposable {
constructor(private viewId: string, options: vscode.TreeViewOptions<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
super();
if (extension.contributes && extension.contributes.views) {
for (const location in extension.contributes.views) {
for (const view of extension.contributes.views[location]) {
if (view.id === viewId) {
this._title = view.name;
}
}
}
}
this.dataProvider = options.treeDataProvider;
// {{SQL CARBON EDIT}}
if (this.proxy) {
@@ -282,6 +296,16 @@ export class ExtHostTreeView<T> extends Disposable {
this._onDidChangeData.fire({ message: true, element: false });
}
private _title: string = '';
get title(): string {
return this._title;
}
set title(title: string) {
this._title = title;
this.proxy.$setTitle(this.viewId, title);
}
setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void {
const element = this.getExtensionElement(treeItemHandle);
if (element) {

View File

@@ -19,7 +19,7 @@ import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import * as htmlContent from 'vs/base/common/htmlContent';
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
import { IWorkspaceEditDto, IResourceTextEditDto, IResourceFileEditDto } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
@@ -31,6 +31,7 @@ import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
export interface PositionLike {
line: number;
character: number;
@@ -473,8 +474,8 @@ export namespace TextEdit {
}
export namespace WorkspaceEdit {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): IWorkspaceEditDto {
const result: IWorkspaceEditDto = {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): extHostProtocol.IWorkspaceEditDto {
const result: extHostProtocol.IWorkspaceEditDto = {
edits: []
};
for (const entry of (value as types.WorkspaceEdit)._allEntries()) {
@@ -482,28 +483,28 @@ export namespace WorkspaceEdit {
if (Array.isArray(uriOrEdits)) {
// text edits
const doc = documents && uri ? documents.getDocument(uri) : undefined;
result.edits.push(<IResourceTextEditDto>{ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) });
result.edits.push(<extHostProtocol.IResourceTextEditDto>{ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) });
} else {
// resource edits
result.edits.push(<IResourceFileEditDto>{ oldUri: uri, newUri: uriOrEdits, options: entry[2] });
result.edits.push(<extHostProtocol.IResourceFileEditDto>{ oldUri: uri, newUri: uriOrEdits, options: entry[2] });
}
}
return result;
}
export function to(value: IWorkspaceEditDto) {
export function to(value: extHostProtocol.IWorkspaceEditDto) {
const result = new types.WorkspaceEdit();
for (const edit of value.edits) {
if (Array.isArray((<IResourceTextEditDto>edit).edits)) {
if (Array.isArray((<extHostProtocol.IResourceTextEditDto>edit).edits)) {
result.set(
URI.revive((<IResourceTextEditDto>edit).resource),
<types.TextEdit[]>(<IResourceTextEditDto>edit).edits.map(TextEdit.to)
URI.revive((<extHostProtocol.IResourceTextEditDto>edit).resource),
<types.TextEdit[]>(<extHostProtocol.IResourceTextEditDto>edit).edits.map(TextEdit.to)
);
} else {
result.renameFile(
URI.revive((<IResourceFileEditDto>edit).oldUri!),
URI.revive((<IResourceFileEditDto>edit).newUri!),
(<IResourceFileEditDto>edit).options
URI.revive((<extHostProtocol.IResourceFileEditDto>edit).oldUri!),
URI.revive((<extHostProtocol.IResourceFileEditDto>edit).newUri!),
(<extHostProtocol.IResourceFileEditDto>edit).options
);
}
}
@@ -626,6 +627,32 @@ export namespace DocumentSymbol {
}
}
export namespace CallHierarchyItem {
export function from(item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
return {
name: item.name,
detail: item.detail,
kind: SymbolKind.from(item.kind),
uri: item.uri,
range: Range.from(item.range),
selectionRange: Range.from(item.selectionRange),
};
}
export function to(item: extHostProtocol.ICallHierarchyItemDto): vscode.CallHierarchyItem {
return new types.CallHierarchyItem(
SymbolKind.to(item.kind),
item.name,
item.detail || '',
URI.revive(item.uri),
Range.to(item.range),
Range.to(item.selectionRange)
);
}
}
export namespace location {
export function from(value: vscode.Location): modes.Location {
return {
@@ -1136,3 +1163,13 @@ export namespace LogLevel {
return types.LogLevel.Info;
}
}
export namespace WebviewEditorState {
export function from(state: vscode.WebviewEditorState): modes.WebviewEditorState {
switch (state) {
case types.WebviewEditorState.Readonly: return modes.WebviewEditorState.Readonly;
case types.WebviewEditorState.Unchanged: return modes.WebviewEditorState.Unchanged;
case types.WebviewEditorState.Dirty: return modes.WebviewEditorState.Dirty;
default: throw new Error('Unknown vscode.WebviewEditorState');
}
}
}

View File

@@ -1146,12 +1146,6 @@ export class SelectionRange {
}
}
export enum CallHierarchyDirection {
CallsFrom = 1,
CallsTo = 2,
}
export class CallHierarchyItem {
kind: SymbolKind;
name: string;
@@ -1170,6 +1164,27 @@ export class CallHierarchyItem {
}
}
export class CallHierarchyIncomingCall {
source: vscode.CallHierarchyItem;
sourceRanges: vscode.Range[];
constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) {
this.sourceRanges = sourceRanges;
this.source = item;
}
}
export class CallHierarchyOutgoingCall {
target: vscode.CallHierarchyItem;
sourceRanges: vscode.Range[];
constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) {
this.sourceRanges = sourceRanges;
this.target = item;
}
}
@es5ClassCompat
export class CodeLens {
@@ -2345,12 +2360,31 @@ export class QuickInputButtons {
private constructor() { }
}
export enum ExtensionExecutionContext {
Local = 1,
Remote = 2
}
export enum ExtensionKind {
UI = 1,
Workspace = 2
}
export class Decoration {
static validate(d: Decoration): void {
if (d.letter && d.letter.length !== 1) {
throw new Error(`The 'letter'-property must be undefined or a single character`);
}
if (!d.bubble && !d.color && !d.letter && !d.priority && !d.title) {
throw new Error(`The decoration is empty`);
}
}
letter?: string;
title?: string;
color?: vscode.ThemeColor;
priority?: number;
bubble?: boolean;
}
export enum WebviewEditorState {
Readonly = 1,
Unchanged = 2,
Dirty = 3,
}

View File

@@ -8,13 +8,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { URI, UriComponents } from 'vs/base/common/uri';
export interface IURITransformerService extends IURITransformer {
_serviceBrand: any;
_serviceBrand: undefined;
}
export const IURITransformerService = createDecorator<IURITransformerService>('IURITransformerService');
export class URITransformerService implements IURITransformerService {
_serviceBrand: any;
_serviceBrand: undefined;
transformIncoming: (uri: UriComponents) => UriComponents;
transformOutgoing: (uri: UriComponents) => UriComponents;

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -13,7 +13,7 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import * as vscode from 'vscode';
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol';
import { Disposable } from './extHostTypes';
import { Disposable, WebviewEditorState } from './extHostTypes';
type IconPath = URI | { light: URI, dark: URI };
@@ -40,7 +40,9 @@ export class ExtHostWebview implements vscode.Webview {
}
public get cspSource(): string {
return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
return this._initData.webviewCspSource
.replace('{{uuid}}', this._handle)
.replace('{{commit}}', this._initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44');
}
public get html(): string {
@@ -79,7 +81,7 @@ export class ExtHostWebview implements vscode.Webview {
}
}
export class ExtHostWebviewPanel implements vscode.WebviewPanel {
export class ExtHostWebviewEditor implements vscode.WebviewEditor {
private readonly _handle: WebviewPanelHandle;
private readonly _proxy: MainThreadWebviewsShape;
@@ -92,6 +94,7 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel {
private _viewColumn: vscode.ViewColumn | undefined;
private _visible: boolean = true;
private _active: boolean = true;
private _state = WebviewEditorState.Readonly;
_isDisposed: boolean = false;
@@ -212,6 +215,15 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel {
this._visible = value;
}
public get state(): vscode.WebviewEditorState {
return this._state;
}
public set state(newState: vscode.WebviewEditorState) {
this._state = newState;
this._proxy.$setState(this._handle, typeConverters.WebviewEditorState.from(newState));
}
public postMessage(message: any): Promise<boolean> {
this.assertNotDisposed();
return this._proxy.$postMessage(this._handle, message);
@@ -239,8 +251,9 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
private readonly _proxy: MainThreadWebviewsShape;
private readonly _webviewPanels = new Map<WebviewPanelHandle, ExtHostWebviewPanel>();
private readonly _webviewPanels = new Map<WebviewPanelHandle, ExtHostWebviewEditor>();
private readonly _serializers = new Map<string, vscode.WebviewPanelSerializer>();
private readonly _editorProviders = new Map<string, vscode.WebviewEditorProvider>();
constructor(
mainContext: IMainContext,
@@ -266,7 +279,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation);
const webview = new ExtHostWebview(handle, this._proxy, options, this.initData);
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview);
this._webviewPanels.set(handle, panel);
return panel;
}
@@ -288,6 +301,23 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
});
}
public registerWebviewEditorProvider(
viewType: string,
provider: vscode.WebviewEditorProvider
): vscode.Disposable {
if (this._editorProviders.has(viewType)) {
throw new Error(`Editor provider for '${viewType}' already registered`);
}
this._editorProviders.set(viewType, provider);
this._proxy.$registerEditorProvider(viewType);
return new Disposable(() => {
this._editorProviders.delete(viewType);
this._proxy.$unregisterEditorProvider(viewType);
});
}
public $onMessage(
handle: WebviewPanelHandle,
message: any
@@ -298,6 +328,13 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
}
public $onMissingCsp(
_handle: WebviewPanelHandle,
extensionId: string
): void {
console.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
}
public $onDidChangeWebviewPanelViewStates(newStates: WebviewPanelViewStateData): void {
const handles = Object.keys(newStates);
// Notify webviews of state changes in the following order:
@@ -356,14 +393,35 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData);
const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
this._webviewPanels.set(webviewHandle, revivedPanel);
return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state));
}
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewPanel | undefined {
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined {
return this._webviewPanels.get(handle);
}
async $resolveWebviewEditor(
resource: UriComponents,
webviewHandle: WebviewPanelHandle,
viewType: string,
title: string,
state: any,
position: EditorViewColumn,
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
): Promise<void> {
const provider = this._editorProviders.get(viewType);
if (!provider) {
return Promise.reject(new Error(`No provider found for '${viewType}'`));
}
const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData);
const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
this._webviewPanels.set(webviewHandle, revivedPanel);
return Promise.resolve(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel));
}
}
function convertWebviewOptions(

View File

@@ -156,7 +156,7 @@ class ExtHostWorkspaceImpl extends Workspace {
export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;

View File

@@ -7,6 +7,7 @@ import { URI } from 'vs/base/common/uri';
import * as vscode from 'vscode';
export interface WebviewInitData {
readonly commit?: string;
readonly webviewResourceRoot: string;
readonly webviewCspSource: string;
}
@@ -14,11 +15,11 @@ export interface WebviewInitData {
export function asWebviewUri(
initData: WebviewInitData,
uuid: string,
resource: vscode.Uri
resource: vscode.Uri,
): vscode.Uri {
const uri = initData.webviewResourceRoot
.replace('{{commit}}', initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44')
.replace('{{resource}}', resource.toString().replace(/^\S+?:/, ''))
.replace('{{uuid}}', uuid);
return URI.parse(uri);
}

View File

@@ -41,7 +41,7 @@ import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugServic
export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugServiceShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private _configProviderHandleCounter: number;
private _configProviders: ConfigProviderTuple[];
@@ -687,6 +687,13 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe
this._onDidChangeActiveDebugSession.fire(this._activeDebugSession);
}
public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise<void> {
const session = await this.getSession(sessionDto);
if (session) {
session._acceptNameChanged(name);
}
}
public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise<void> {
const session = await this.getSession(sessionDto);
const ee: vscode.DebugSessionCustomEvent = {
@@ -917,6 +924,15 @@ export class ExtHostDebugSession implements vscode.DebugSession {
return this._name;
}
public set name(name: string) {
this._name = name;
this._debugServiceProxy.$setDebugSessionName(this._id, name);
}
_acceptNameChanged(name: string) {
this._name = name;
}
public get workspaceFolder(): vscode.WorkspaceFolder | undefined {
return this._workspaceFolder;
}

View File

@@ -13,6 +13,7 @@ import { dirExists, mkdirp } from 'vs/base/node/pfs';
import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { MutableDisposable } from 'vs/base/common/lifecycle';
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
@@ -49,6 +50,8 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
private _logsLocation: URI;
private _namePool: number = 1;
private readonly _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
private readonly _visibleChannelDisposable = new MutableDisposable();
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@@ -58,12 +61,23 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
this._logsLocation = initData.logsLocation;
}
$setVisibleChannel(channelId: string): void {
if (channelId) {
const channel = this._channels.get(channelId);
if (channel) {
this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update());
}
}
}
createOutputChannel(name: string): vscode.OutputChannel {
name = name.trim();
if (!name) {
throw new Error('illegal argument `name`. must not be falsy');
}
return new LazyOutputChannel(name, this._doCreateOutChannel(name));
const extHostOutputChannel = this._doCreateOutChannel(name);
extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel)));
return new LazyOutputChannel(name, extHostOutputChannel);
}
private async _doCreateOutChannel(name: string): Promise<AbstractExtHostOutputChannel> {

View File

@@ -29,8 +29,8 @@ export class ExtHostSearch implements ExtHostSearchShape {
private readonly _fileSearchUsedSchemes = new Set<string>();
private _handlePool: number = 0;
private _internalFileSearchHandle: number;
private _internalFileSearchProvider: SearchService | null;
private _internalFileSearchHandle: number = -1;
private _internalFileSearchProvider: SearchService | null = null;
private _fileSearchManager: FileSearchManager;

View File

@@ -357,7 +357,7 @@ interface HandlerData {
export class ExtHostTask implements ExtHostTaskShape {
readonly _serviceBrand: any;
readonly _serviceBrand: undefined;
private readonly _proxy: MainThreadTaskShape;
private readonly _workspaceProvider: IExtHostWorkspaceProvider;
@@ -662,6 +662,10 @@ export class ExtHostTask implements ExtHostTaskShape {
return undefined;
}
public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
return this._terminalService.$requestDefaultShellAndArgs(true);
}
private nextHandle(): number {
return this._handleCounter++;
}

View File

@@ -9,223 +9,28 @@ import * as os from 'os';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as platform from 'vs/base/common/platform';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ILogService } from 'vs/platform/log/common/log';
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
import { timeout } from 'vs/base/common/async';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export class BaseExtHostTerminal {
public _id: number | undefined;
protected _idPromise: Promise<number>;
private _idPromiseComplete: ((value: number) => any) | undefined;
private _disposed: boolean = false;
private _queuedRequests: ApiRequest[] = [];
export class ExtHostTerminalService extends BaseExtHostTerminalService {
constructor(
protected _proxy: MainThreadTerminalServiceShape,
id?: number
) {
this._idPromise = new Promise<number>(c => {
if (id !== undefined) {
this._id = id;
c(id);
} else {
this._idPromiseComplete = c;
}
});
}
public dispose(): void {
if (!this._disposed) {
this._disposed = true;
this._queueApiRequest(this._proxy.$dispose, []);
}
}
protected _checkDisposed() {
if (this._disposed) {
throw new Error('Terminal has already been disposed');
}
}
protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void {
const request: ApiRequest = new ApiRequest(callback, args);
if (!this._id) {
this._queuedRequests.push(request);
return;
}
request.run(this._proxy, this._id);
}
public _runQueuedRequests(id: number): void {
this._id = id;
if (this._idPromiseComplete) {
this._idPromiseComplete(id);
this._idPromiseComplete = undefined;
}
this._queuedRequests.forEach((r) => {
r.run(this._proxy, id);
});
this._queuedRequests.length = 0;
}
}
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
private _pidPromise: Promise<number | undefined>;
private _cols: number | undefined;
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
private _rows: number | undefined;
/** @deprecated */
private readonly _onData = new Emitter<string>();
/** @deprecated */
public get onDidWriteData(): Event<string> {
// Tell the main side to start sending data if it's not already
this._idPromise.then(id => {
this._proxy.$registerOnDataListener(id);
});
return this._onData.event;
}
public isOpen: boolean = false;
constructor(
proxy: MainThreadTerminalServiceShape,
private _name?: string,
id?: number
) {
super(proxy, id);
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
}
public async create(
shellPath?: string,
shellArgs?: string[] | string,
cwd?: string | URI,
env?: { [key: string]: string | null },
waitOnExit?: boolean,
strictEnv?: boolean,
hideFromUser?: boolean
): Promise<void> {
const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser });
this._name = terminal.name;
this._runQueuedRequests(terminal.id);
}
public async createExtensionTerminal(): Promise<number> {
const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true });
this._name = terminal.name;
this._runQueuedRequests(terminal.id);
return terminal.id;
}
public get name(): string {
return this._name || '';
}
public set name(name: string) {
this._name = name;
}
public get dimensions(): vscode.TerminalDimensions | undefined {
if (this._cols === undefined || this._rows === undefined) {
return undefined;
}
return {
columns: this._cols,
rows: this._rows
};
}
public setDimensions(cols: number, rows: number): boolean {
if (cols === this._cols && rows === this._rows) {
// Nothing changed
return false;
}
this._cols = cols;
this._rows = rows;
return true;
}
public get processId(): Promise<number | undefined> {
return this._pidPromise;
}
public sendText(text: string, addNewLine: boolean = true): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
}
public show(preserveFocus: boolean): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$show, [preserveFocus]);
}
public hide(): void {
this._checkDisposed();
this._queueApiRequest(this._proxy.$hide, []);
}
public _setProcessId(processId: number | undefined): void {
// The event may fire 2 times when the panel is restored
if (this._pidPromiseComplete) {
this._pidPromiseComplete(processId);
this._pidPromiseComplete = undefined;
} else {
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
this._pidPromise.then(pid => {
if (pid !== processId) {
this._pidPromise = Promise.resolve(processId);
}
});
}
}
public _fireOnData(data: string): void {
this._onData.fire(data);
}
}
export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
readonly _serviceBrand: any;
private _proxy: MainThreadTerminalServiceShape;
private _activeTerminal: ExtHostTerminal | undefined;
private _terminals: ExtHostTerminal[] = [];
private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
private _variableResolver: ExtHostVariableResolverService | undefined;
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
// TODO: Pull this from main side
private _isWorkspaceShellAllowed: boolean = false;
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
public get terminals(): ExtHostTerminal[] { return this._terminals; }
private readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
private readonly _onDidOpenTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
private readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
private readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
private readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration,
@@ -233,11 +38,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
@ILogService private _logService: ILogService
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
});
super(extHostRpc);
this._updateLastActiveWorkspace();
this._updateVariableResolver();
this._registerListeners();
@@ -257,23 +58,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
return terminal;
}
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options.name);
const p = new ExtHostPseudoterminal(options.pty);
terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p));
this._terminals.push(terminal);
return terminal;
}
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
const terminal = this._getTerminalByIdEventually(id);
if (!terminal) {
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
}
const p = new ExtHostPseudoterminal(pty);
this._setupExtHostProcessListeners(id, p);
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
const fetchSetting = (key: string) => {
const setting = configProvider
@@ -305,116 +89,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, useAutomationShell, this._lastActiveWorkspace, this._variableResolver, this._logService);
}
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
const original = this._activeTerminal;
if (id === null) {
this._activeTerminal = undefined;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
return;
}
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._activeTerminal = terminal;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
}
}
/** @deprecated */
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
terminal._fireOnData(data);
}
}
public async $acceptTerminalProcessData2(id: number, data: string): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._onDidWriteTerminalData.fire({ terminal, data });
}
}
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions as vscode.TerminalDimensions
});
}
}
}
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
await this._getTerminalByIdEventually(id);
if (this._terminalProcesses[id]) {
// Extension pty terminal only - when virtual process resize fires it means that the
// terminal's maximum dimensions changed
this._terminalProcesses[id].resize(cols, rows);
}
}
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
await this._getTerminalByIdEventually(id);
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
if (extHostTerminal) {
extHostTerminal.name = name;
}
}
public async $acceptTerminalClosed(id: number): Promise<void> {
await this._getTerminalByIdEventually(id);
const index = this._getTerminalObjectIndexById(this.terminals, id);
if (index !== null) {
const terminal = this._terminals.splice(index, 1)[0];
this._onDidCloseTerminal.fire(terminal);
}
}
public $acceptTerminalOpened(id: number, name: string): void {
const index = this._getTerminalObjectIndexById(this._terminals, id);
if (index !== null) {
// The terminal has already been created (via createTerminal*), only fire the event
this._onDidOpenTerminal.fire(this.terminals[index]);
this.terminals[index].isOpen = true;
return;
}
const terminal = new ExtHostTerminal(this._proxy, name, id);
this._terminals.push(terminal);
this._onDidOpenTerminal.fire(terminal);
terminal.isOpen = true;
}
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
terminal._setProcessId(processId);
}
}
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
// TODO: Use await this._getTerminalByIdEventually(id);
let terminal = this._getTerminalById(id);
if (terminal) {
callback(terminal);
} else {
// Retry one more time in case the terminal has not yet been initialized.
setTimeout(() => {
terminal = this._getTerminalById(id);
if (terminal) {
callback(terminal);
}
}, EXT_HOST_CREATION_DELAY * 2);
}
}
private _apiInspectConfigToPlain<T>(
config: { key: string; defaultValue?: T; globalValue?: T; workspaceValue?: T, workspaceFolderValue?: T } | undefined
): { user: T | undefined, value: T | undefined, default: T | undefined } {
@@ -508,7 +182,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
this._variableResolver,
isWorkspaceShellAllowed,
pkg.version,
terminalConfig.get<boolean>('setLocaleVariables', false),
terminalConfig.get<'auto' | 'off' | 'on'>('detectLocale', 'auto'),
baseEnv
);
@@ -521,86 +195,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
}
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
// Pseudoterminal.start
const terminal = await this._getTerminalByIdEventually(id);
if (!terminal) {
return;
}
// Wait for onDidOpenTerminal to fire
let openPromise: Promise<void>;
if (terminal.isOpen) {
openPromise = Promise.resolve();
} else {
openPromise = new Promise<void>(r => {
// Ensure open is called after onDidOpenTerminal
const listener = this.onDidOpenTerminal(async e => {
if (e === terminal) {
listener.dispose();
r();
}
});
});
}
await openPromise;
// Processes should be initialized here for normal virtual process terminals, however for
// tasks they are responsible for attaching the virtual process to a terminal so this
// function may be called before tasks is able to attach to the terminal.
let retries = 5;
while (retries-- > 0) {
if (this._terminalProcesses[id]) {
(this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions);
return;
}
await timeout(50);
}
}
private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
if (p.onProcessOverrideDimensions) {
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
}
this._terminalProcesses[id] = p;
}
public $acceptProcessInput(id: number, data: string): void {
this._terminalProcesses[id].input(data);
}
public $acceptProcessResize(id: number, cols: number, rows: number): void {
try {
this._terminalProcesses[id].resize(cols, rows);
} catch (error) {
// We tried to write to a closed pipe / channel.
if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') {
throw (error);
}
}
}
public $acceptProcessShutdown(id: number, immediate: boolean): void {
this._terminalProcesses[id].shutdown(immediate);
}
public $acceptProcessRequestInitialCwd(id: number): void {
this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd));
}
public $acceptProcessRequestCwd(id: number): void {
this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd));
}
public $acceptProcessRequestLatency(id: number): number {
return id;
}
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
return detectAvailableShells();
}
@@ -613,138 +207,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
});
}
private _onProcessExit(id: number, exitCode: number): void {
// Remove process reference
delete this._terminalProcesses[id];
// Send exit event to main side
this._proxy.$sendProcessExit(id, exitCode);
}
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
if (!this._getTerminalPromises[id]) {
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
} else {
this._getTerminalPromises[id].then(c => {
return this._createGetTerminalPromise(id, retries);
});
}
return this._getTerminalPromises[id];
}
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
return new Promise(c => {
if (retries === 0) {
c(undefined);
return;
}
const terminal = this._getTerminalById(id);
if (terminal) {
c(terminal);
} else {
// This should only be needed immediately after createTerminalRenderer is called as
// the ExtHostTerminal has not yet been iniitalized
timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1)));
}
});
}
private _getTerminalById(id: number): ExtHostTerminal | null {
return this._getTerminalObjectById(this._terminals, id);
}
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
const index = this._getTerminalObjectIndexById(array, id);
return index !== null ? array[index] : null;
}
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
let index: number | null = null;
array.some((item, i) => {
const thisId = item._id;
if (thisId === id) {
index = i;
return true;
}
return false;
});
return index;
}
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
this._isWorkspaceShellAllowed = isAllowed;
}
}
class ApiRequest {
private _callback: (...args: any[]) => void;
private _args: any[];
constructor(callback: (...args: any[]) => void, args: any[]) {
this._callback = callback;
this._args = args;
}
public run(proxy: MainThreadTerminalServiceShape, id: number) {
this._callback.apply(proxy, [id].concat(this._args));
}
}
class ExtHostPseudoterminal implements ITerminalChildProcess {
private readonly _onProcessData = new Emitter<string>();
public readonly onProcessData: Event<string> = this._onProcessData.event;
private readonly _onProcessExit = new Emitter<number>();
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
private readonly _onProcessTitleChanged = new Emitter<string>();
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
constructor(private readonly _pty: vscode.Pseudoterminal) { }
shutdown(): void {
this._pty.close();
}
input(data: string): void {
if (this._pty.handleInput) {
this._pty.handleInput(data);
}
}
resize(cols: number, rows: number): void {
if (this._pty.setDimensions) {
this._pty.setDimensions({ columns: cols, rows });
}
}
getInitialCwd(): Promise<string> {
return Promise.resolve('');
}
getCwd(): Promise<string> {
return Promise.resolve('');
}
getLatency(): Promise<number> {
return Promise.resolve(0);
}
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
// Attach the listeners
this._pty.onDidWrite(e => this._onProcessData.fire(e));
if (this._pty.onDidClose) {
this._pty.onDidClose(e => this._onProcessExit.fire(e || 0));
}
if (this._pty.onDidOverrideDimensions) {
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks
}
this._pty.open(initialDimensions ? initialDimensions : undefined);
}
}

View File

@@ -6,74 +6,10 @@
import { createApiFactoryAndRegisterActors } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} replace with ours
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { endsWith, startsWith } from 'vs/base/common/strings';
import { endsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
class ExportsTrap {
static readonly Instance = new ExportsTrap();
private readonly _names: string[] = [];
private readonly _exports = new Map<string, any>();
private constructor() {
const exportsProxy = new Proxy({}, {
set: (target: any, p: PropertyKey, value: any) => {
// store in target
target[p] = value;
// store in named-bucket
const name = this._names[this._names.length - 1];
this._exports.get(name)![p] = value;
return true;
}
});
const moduleProxy = new Proxy({}, {
get: (target: any, p: PropertyKey) => {
if (p === 'exports') {
return exportsProxy;
}
return target[p];
},
set: (target: any, p: PropertyKey, value: any) => {
// store in target
target[p] = value;
// override bucket
if (p === 'exports') {
const name = this._names[this._names.length - 1];
this._exports.set(name, value);
}
return true;
}
});
(<any>self).exports = exportsProxy;
(<any>self).module = moduleProxy;
}
add(name: string) {
this._exports.set(name, Object.create(null));
this._names.push(name);
return {
claim: () => {
const result = this._exports.get(name);
this._exports.delete(name);
this._names.pop();
return result;
}
};
}
}
class WorkerRequireInterceptor extends RequireInterceptor {
_installInterceptor() { }
@@ -105,43 +41,33 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
await this._fakeModules.install();
}
protected _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
protected async _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
(<any>self).window = self; // <- that's improper but might help extensions that aren't authored correctly
module = module.with({ path: ensureSuffix(module.path, '.js') });
const response = await fetch(module.toString(true));
// FAKE require function that only works for the vscode-module
const moduleStack: URI[] = [];
(<any>self).require = (mod: string) => {
if (response.status !== 200) {
throw new Error(response.statusText);
}
const parent = moduleStack[moduleStack.length - 1];
const result = this._fakeModules.getModule(mod, parent);
// fetch JS sources as text and create a new function around it
const initFn = new Function('module', 'exports', 'require', 'window', await response.text());
if (result !== undefined) {
return result;
// define commonjs globals: `module`, `exports`, and `require`
const _exports = {};
const _module = { exports: _exports };
const _require = (request: string) => {
const result = this._fakeModules.getModule(request, module);
if (result === undefined) {
throw new Error(`Cannot load module '${request}'`);
}
if (!startsWith(mod, '.')) {
throw new Error(`Cannot load module '${mod}'`);
}
const next = joinPath(parent, '..', ensureSuffix(mod, '.js'));
moduleStack.push(next);
const trap = ExportsTrap.Instance.add(next.toString());
importScripts(next.toString(true));
moduleStack.pop();
return trap.claim();
return result;
};
try {
activationTimesBuilder.codeLoadingStart();
module = module.with({ path: ensureSuffix(module.path, '.js') });
moduleStack.push(module);
const trap = ExportsTrap.Instance.add(module.toString());
importScripts(module.toString(true));
moduleStack.pop();
return Promise.resolve<T>(trap.claim());
initFn(_module, _exports, _require, self);
return <T>(_module.exports !== _exports ? _module.exports : _exports);
} finally {
activationTimesBuilder.codeLoadingStop();
}

View File

@@ -15,7 +15,7 @@ import { localize } from 'vs/nls';
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
_serviceBrand: any;
_serviceBrand: undefined;
private readonly _proxy: MainThreadLogShape;
private readonly _logFile: UriComponents;