Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5 (#9161)

* Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5

* small spacing fix
This commit is contained in:
Anthony Dresser
2020-02-15 00:43:09 -06:00
committed by GitHub
parent 74b89a0a85
commit 873c6a39fe
78 changed files with 1474 additions and 1011 deletions

View File

@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHostLabelService, new ExtHostLabelService(rpcProtocol));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
// Check that no named customers are missing
// {{SQL CARBON EDIT}} filter out the services we don't expose
@@ -348,6 +348,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
return extHostLanguageFeatures.registerHoverProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerEvaluatableExpressionProvider(selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerEvaluatableExpressionProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
},
@@ -928,6 +931,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
DocumentLink: extHostTypes.DocumentLink,
DocumentSymbol: extHostTypes.DocumentSymbol,
EndOfLine: extHostTypes.EndOfLine,
EvaluatableExpression: extHostTypes.EvaluatableExpression,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,
CustomExecution: extHostTypes.CustomExecution,

View File

@@ -49,7 +49,7 @@ import { SaveReason } from 'vs/workbench/common/editor';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { TimelineItem, TimelineProviderDescriptor, TimelineChangeEvent, TimelineItemWithSource } from 'vs/workbench/contrib/timeline/common/timeline';
import { Timeline, TimelineChangeEvent, TimelineCursor, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
// {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -357,6 +357,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto): void;
@@ -806,8 +807,6 @@ export interface MainThreadTimelineShape extends IDisposable {
$registerTimelineProvider(provider: TimelineProviderDescriptor): void;
$unregisterTimelineProvider(source: string): void;
$emitTimelineChangeEvent(e: TimelineChangeEvent): void;
$getTimeline(uri: UriComponents, token: CancellationToken): Promise<TimelineItem[]>;
}
// -- extension host
@@ -1213,6 +1212,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
@@ -1461,7 +1461,7 @@ export interface ExtHostTunnelServiceShape {
}
export interface ExtHostTimelineShape {
$getTimeline(source: string, uri: UriComponents, token: CancellationToken): Promise<TimelineItemWithSource[]>;
$getTimeline(source: string, uri: UriComponents, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
}
// --- proxy identifiers

View File

@@ -276,6 +276,27 @@ class HoverAdapter {
}
}
class EvaluatableExpressionAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.EvaluatableExpressionProvider,
) { }
public provideEvaluatableExpression(resource: URI, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
return asPromise(() => this._provider.provideEvaluatableExpression(doc, pos, token)).then(value => {
if (value) {
return typeConvert.EvaluatableExpression.from(value);
}
return undefined;
});
}
}
class DocumentHighlightAdapter {
constructor(
@@ -1329,7 +1350,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter;
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter;
class AdapterData {
constructor(
@@ -1549,6 +1570,18 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, token), undefined);
}
// --- debug hover
registerEvaluatableExpressionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
const handle = this._addNewAdapter(new EvaluatableExpressionAdapter(this._documents, provider), extension);
this._proxy.$registerEvaluatableExpressionProvider(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined> {
return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined);
}
// --- occurrences
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {

View File

@@ -7,61 +7,91 @@ import * as vscode from 'vscode';
import { UriComponents, URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ExtHostTimelineShape, MainThreadTimelineShape, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { TimelineItemWithSource, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline';
import { Timeline, TimelineCursor, TimelineItem, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline';
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { CancellationToken } from 'vs/base/common/cancellation';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ThemeIcon } from 'vs/workbench/api/common/extHostTypes';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export interface IExtHostTimeline extends ExtHostTimelineShape {
readonly _serviceBrand: undefined;
$getTimeline(id: string, uri: UriComponents, token: vscode.CancellationToken): Promise<TimelineItemWithSource[]>;
$getTimeline(id: string, uri: UriComponents, cursor: vscode.TimelineCursor, token: vscode.CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
}
export const IExtHostTimeline = createDecorator<IExtHostTimeline>('IExtHostTimeline');
export class ExtHostTimeline implements IExtHostTimeline {
private static handlePool = 0;
_serviceBrand: undefined;
private _proxy: MainThreadTimelineShape;
private _providers = new Map<string, TimelineProvider>();
private _itemsBySourceByUriMap = new Map<string | undefined, Map<string, Map<string, vscode.TimelineItem>>>();
constructor(
mainContext: IMainContext,
commands: ExtHostCommands,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadTimeline);
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$mid === 11) {
const uri = arg.uri === undefined ? undefined : URI.revive(arg.uri);
return this._itemsBySourceByUriMap.get(getUriKey(uri))?.get(arg.source)?.get(arg.handle);
}
return arg;
}
});
}
async $getTimeline(id: string, uri: UriComponents, token: vscode.CancellationToken): Promise<TimelineItemWithSource[]> {
async $getTimeline(id: string, uri: UriComponents, cursor: vscode.TimelineCursor, token: vscode.CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined> {
const provider = this._providers.get(id);
return provider?.provideTimeline(URI.revive(uri), token) ?? [];
return provider?.provideTimeline(URI.revive(uri), cursor, token, options);
}
registerTimelineProvider(scheme: string | string[], provider: vscode.TimelineProvider, extensionId: ExtensionIdentifier, commandConverter: CommandsConverter): IDisposable {
registerTimelineProvider(scheme: string | string[], provider: vscode.TimelineProvider, _extensionId: ExtensionIdentifier, commandConverter: CommandsConverter): IDisposable {
const timelineDisposables = new DisposableStore();
const convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables);
const convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables).bind(this);
let disposable: IDisposable | undefined;
if (provider.onDidChange) {
disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this);
}
const itemsBySourceByUriMap = this._itemsBySourceByUriMap;
return this.registerTimelineProviderCore({
...provider,
scheme: scheme,
onDidChange: undefined,
async provideTimeline(uri: URI, token: CancellationToken) {
async provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }) {
timelineDisposables.clear();
const results = await provider.provideTimeline(uri, token);
// For now, only allow the caching of a single Uri
if (options?.cacheResults && !itemsBySourceByUriMap.has(getUriKey(uri))) {
itemsBySourceByUriMap.clear();
}
const result = await provider.provideTimeline(uri, cursor, token);
// Intentional == we don't know how a provider will respond
// eslint-disable-next-line eqeqeq
return results != null
? results.map(item => convertTimelineItem(item))
: [];
if (result == null) {
return undefined;
}
// TODO: Determine if we should cache dependent on who calls us (internal vs external)
const convertItem = convertTimelineItem(uri, options?.cacheResults ?? false);
return {
...result,
source: provider.id,
items: result.items.map(convertItem)
};
},
dispose() {
disposable?.dispose();
@@ -70,39 +100,72 @@ export class ExtHostTimeline implements IExtHostTimeline {
});
}
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore): (item: vscode.TimelineItem) => TimelineItemWithSource {
return (item: vscode.TimelineItem) => {
const { iconPath, ...props } = item;
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore) {
return (uri: URI, cacheResults: boolean) => {
let itemsMap: Map<string, vscode.TimelineItem> | undefined;
if (cacheResults) {
const uriKey = getUriKey(uri);
let icon;
let iconDark;
let themeIcon;
if (item.iconPath) {
if (iconPath instanceof ThemeIcon) {
themeIcon = { id: iconPath.id };
let sourceMap = this._itemsBySourceByUriMap.get(uriKey);
if (sourceMap === undefined) {
sourceMap = new Map();
this._itemsBySourceByUriMap.set(uriKey, sourceMap);
}
else if (URI.isUri(iconPath)) {
icon = iconPath;
iconDark = iconPath;
}
else {
({ light: icon, dark: iconDark } = iconPath as { light: URI; dark: URI });
itemsMap = sourceMap.get(source);
if (itemsMap === undefined) {
itemsMap = new Map();
sourceMap.set(source, itemsMap);
}
}
return {
...props,
source: source,
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined,
icon: icon,
iconDark: iconDark,
themeIcon: themeIcon
return (item: vscode.TimelineItem): TimelineItem => {
const { iconPath, ...props } = item;
const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`;
itemsMap?.set(handle, item);
let icon;
let iconDark;
let themeIcon;
if (item.iconPath) {
if (iconPath instanceof ThemeIcon) {
themeIcon = { id: iconPath.id };
}
else if (URI.isUri(iconPath)) {
icon = iconPath;
iconDark = iconPath;
}
else {
({ light: icon, dark: iconDark } = iconPath as { light: URI; dark: URI });
}
}
return {
...props,
handle: handle,
source: source,
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined,
icon: icon,
iconDark: iconDark,
themeIcon: themeIcon
};
};
};
}
private emitTimelineChangeEvent(id: string) {
return (e: vscode.TimelineChangeEvent) => {
// Clear caches
if (e?.uri === undefined) {
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
sourceMap.get(id)?.clear();
}
}
else {
this._itemsBySourceByUriMap.get(getUriKey(e.uri))?.clear();
}
this._proxy.$emitTimelineChangeEvent({ ...e, id: id });
};
}
@@ -123,9 +186,18 @@ export class ExtHostTimeline implements IExtHostTimeline {
this._providers.set(provider.id, provider);
return toDisposable(() => {
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
sourceMap.get(provider.id)?.clear();
}
this._providers.delete(provider.id);
this._proxy.$unregisterTimelineProvider(provider.id);
provider.dispose();
});
}
}
function getUriKey(uri: URI | undefined): string | undefined {
return uri?.toString();
}

View File

@@ -257,7 +257,7 @@ export namespace MarkdownString {
} else if (htmlContent.isMarkdownString(markup)) {
res = markup;
} else if (typeof markup === 'string') {
res = { value: <string>markup };
res = { value: markup };
} else {
res = { value: '' };
}
@@ -737,6 +737,20 @@ export namespace Hover {
return new types.Hover(info.contents.map(MarkdownString.to), Range.to(info.range));
}
}
export namespace EvaluatableExpression {
export function from(expression: vscode.EvaluatableExpression): modes.EvaluatableExpression {
return <modes.EvaluatableExpression>{
range: Range.from(expression.range),
expression: expression.expression
};
}
export function to(info: modes.EvaluatableExpression): types.EvaluatableExpression {
return new types.EvaluatableExpression(Range.to(info.range), info.expression);
}
}
export namespace DocumentHighlight {
export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
return {

View File

@@ -2283,6 +2283,17 @@ export class DebugAdapterInlineImplementation implements vscode.DebugAdapterInli
}
}
@es5ClassCompat
export class EvaluatableExpression implements vscode.EvaluatableExpression {
readonly range: vscode.Range;
readonly expression?: string;
constructor(range: vscode.Range, expression?: string) {
this.range = range;
this.expression = expression;
}
}
export enum LogLevel {
Trace = 1,
Debug = 2,

View File

@@ -57,6 +57,8 @@ namespace schema {
case 'comments/comment/title': return MenuId.CommentTitle;
case 'comments/comment/context': return MenuId.CommentActions;
case 'extension/context': return MenuId.ExtensionContext;
case 'timeline/title': return MenuId.TimelineTitle;
case 'timeline/item/context': return MenuId.TimelineItemContext;
}
return undefined;
@@ -220,6 +222,16 @@ namespace schema {
type: 'array',
items: menuItem
},
'timeline/title': {
description: localize('view.timelineTitle', "The Timeline view title menu"),
type: 'array',
items: menuItem
},
'timeline/item/context': {
description: localize('view.timelineContext', "The Timeline view item context menu"),
type: 'array',
items: menuItem
},
}
};