mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-22 09:38:38 +01:00
Merge branch 'master' into sandy081/userDataProvider
This commit is contained in:
@@ -15,7 +15,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { ExtHostContext, MainContext, ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
@@ -252,6 +252,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
get remoteName() {
|
||||
return getRemoteName(initData.remote.authority);
|
||||
},
|
||||
get uiKind() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return initData.uiKind;
|
||||
}
|
||||
};
|
||||
if (!initData.environment.extensionTestsLocationURI) {
|
||||
@@ -899,10 +903,13 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
// proposed
|
||||
CallHierarchyDirection: extHostTypes.CallHierarchyDirection,
|
||||
CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall,
|
||||
CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall,
|
||||
CallHierarchyItem: extHostTypes.CallHierarchyItem,
|
||||
Decoration: extHostTypes.Decoration,
|
||||
UserDataError: extHostTypes.UserDataError
|
||||
UserDataError: extHostTypes.UserDataError,
|
||||
WebviewEditorState: extHostTypes.WebviewEditorState,
|
||||
UIKind: UIKind
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -89,6 +88,7 @@ export interface IInitData {
|
||||
logsLocation: URI;
|
||||
autoStart: boolean;
|
||||
remote: { isRemote: boolean; authority: string | undefined; };
|
||||
uiKind: UIKind;
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
@@ -107,6 +107,11 @@ export interface IExtHostContext extends IRPCProtocol {
|
||||
export interface IMainContext extends IRPCProtocol {
|
||||
}
|
||||
|
||||
export enum UIKind {
|
||||
Desktop = 1,
|
||||
Web = 2
|
||||
}
|
||||
|
||||
// --- main thread
|
||||
|
||||
export interface MainThreadClipboardShape extends IDisposable {
|
||||
@@ -117,7 +122,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[]>;
|
||||
}
|
||||
|
||||
@@ -405,8 +410,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;
|
||||
|
||||
@@ -547,6 +550,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;
|
||||
@@ -575,6 +579,7 @@ export interface ExtHostWebviewsShape {
|
||||
$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>;
|
||||
$save(handle: WebviewPanelHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
@@ -1079,8 +1084,7 @@ export interface ICodeLensDto {
|
||||
command?: ICommandDto;
|
||||
}
|
||||
|
||||
export interface ICallHierarchyDto {
|
||||
_id: number;
|
||||
export interface ICallHierarchyItemDto {
|
||||
kind: modes.SymbolKind;
|
||||
name: string;
|
||||
detail?: string;
|
||||
@@ -1123,8 +1127,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 {
|
||||
@@ -1166,9 +1170,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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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 } : e));
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1147,12 +1147,6 @@ export class SelectionRange {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export enum CallHierarchyDirection {
|
||||
CallsFrom = 1,
|
||||
CallsTo = 2,
|
||||
}
|
||||
|
||||
export class CallHierarchyItem {
|
||||
kind: SymbolKind;
|
||||
name: string;
|
||||
@@ -1171,6 +1165,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 {
|
||||
|
||||
@@ -2390,3 +2405,9 @@ export class UserDataError extends Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export enum WebviewEditorState {
|
||||
Readonly = 1,
|
||||
Unchanged = 2,
|
||||
Dirty = 3,
|
||||
}
|
||||
|
||||
@@ -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,27 @@ 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));
|
||||
}
|
||||
|
||||
private readonly _onWillSave = new Emitter<{ waitUntil: (thenable: Thenable<boolean>) => void }>();
|
||||
public readonly onWillSave = this._onWillSave.event;
|
||||
|
||||
async _save(): Promise<boolean> {
|
||||
const waitingOn: Thenable<boolean>[] = [];
|
||||
this._onWillSave.fire({
|
||||
waitUntil: (thenable: Thenable<boolean>): void => { waitingOn.push(thenable); },
|
||||
});
|
||||
const result = await Promise.all(waitingOn);
|
||||
return result.every(x => x);
|
||||
}
|
||||
|
||||
public postMessage(message: any): Promise<boolean> {
|
||||
this.assertNotDisposed();
|
||||
return this._proxy.$postMessage(this._handle, message);
|
||||
@@ -239,7 +263,7 @@ 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>();
|
||||
|
||||
@@ -267,7 +291,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;
|
||||
}
|
||||
@@ -381,12 +405,12 @@ 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);
|
||||
}
|
||||
|
||||
@@ -405,11 +429,18 @@ 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(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel));
|
||||
}
|
||||
|
||||
async $save(handle: WebviewPanelHandle): Promise<boolean> {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (panel) {
|
||||
return panel._save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function convertWebviewOptions(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user