Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Amodio committed Mar 1, 2020
1 parent 77dcee2 commit afacd2b
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 148 deletions.
4 changes: 2 additions & 2 deletions src/vs/workbench/api/browser/mainThreadTimeline.ts
Expand Up @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService } from 'vs/workbench/contrib/timeline/common/timeline';
import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';

@extHostNamedCustomer(MainContext.MainThreadTimeline)
export class MainThreadTimeline implements MainThreadTimelineShape {
Expand Down Expand Up @@ -39,7 +39,7 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
this._timelineService.registerTimelineProvider({
...provider,
onDidChange: onDidChange.event,
provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) {
provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) {
return proxy.$getTimeline(provider.id, uri, options, token, internalOptions);
},
dispose() {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/common/extHost.protocol.ts
Expand Up @@ -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 { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
Expand Down Expand Up @@ -1468,7 +1468,7 @@ export interface ExtHostTunnelServiceShape {
}

export interface ExtHostTimelineShape {
$getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
$getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions): Promise<Timeline | undefined>;
}

// --- proxy identifiers
Expand Down
89 changes: 35 additions & 54 deletions src/vs/workbench/api/common/extHostTimeline.ts
Expand Up @@ -7,7 +7,7 @@ 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 { Timeline, TimelineItem, TimelineOptions, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline';
import { Timeline, TimelineItem, TimelineOptions, TimelineProvider, InternalTimelineOptions } 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, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
Expand All @@ -16,21 +16,19 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

export interface IExtHostTimeline extends ExtHostTimelineShape {
readonly _serviceBrand: undefined;
$getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
$getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): 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>>>();
private _itemsBySourceAndUriMap = new Map<string, Map<string | undefined, Map<string, vscode.TimelineItem>>>();

constructor(
mainContext: IMainContext,
Expand All @@ -42,15 +40,15 @@ export class ExtHostTimeline implements IExtHostTimeline {
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 this._itemsBySourceAndUriMap.get(arg.source)?.get(getUriKey(uri))?.get(arg.handle);
}

return arg;
}
});
}

async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined> {
async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): Promise<Timeline | undefined> {
const provider = this._providers.get(id);
return provider?.provideTimeline(URI.revive(uri), options, token, internalOptions);
}
Expand All @@ -62,26 +60,21 @@ export class ExtHostTimeline implements IExtHostTimeline {

let disposable: IDisposable | undefined;
if (provider.onDidChange) {
disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this);
disposable = provider.onDidChange(e => this._proxy.$emitTimelineChangeEvent({ ...e, id: provider.id }), this);
}

const itemsBySourceByUriMap = this._itemsBySourceByUriMap;
const itemsBySourceAndUriMap = this._itemsBySourceAndUriMap;
return this.registerTimelineProviderCore({
...provider,
scheme: scheme,
onDidChange: undefined,
async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) {
// For now, only allow the caching of a single Uri
if (internalOptions?.cacheResults) {
if (options.cursor === undefined) {
timelineDisposables.clear();
}

if (!itemsBySourceByUriMap.has(getUriKey(uri))) {
itemsBySourceByUriMap.clear();
}
} else {
async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) {
if (internalOptions?.resetCache) {
timelineDisposables.clear();

// For now, only allow the caching of a single Uri
// itemsBySourceAndUriMap.get(provider.id)?.get(getUriKey(uri))?.clear();
itemsBySourceAndUriMap.get(provider.id)?.clear();
}

const result = await provider.provideTimeline(uri, options, token);
Expand All @@ -91,45 +84,49 @@ export class ExtHostTimeline implements IExtHostTimeline {
return undefined;
}

// TODO: Determine if we should cache dependent on who calls us (internal vs external)
const convertItem = convertTimelineItem(uri, internalOptions?.cacheResults ?? false);
// TODO: Should we bother converting all the data if we aren't caching? Meaning it is being requested by an extension?

const convertItem = convertTimelineItem(uri, internalOptions);
return {
...result,
source: provider.id,
items: result.items.map(convertItem)
};
},
dispose() {
for (const sourceMap of itemsBySourceAndUriMap.values()) {
sourceMap.get(provider.id)?.clear();
}

disposable?.dispose();
timelineDisposables.dispose();
}
});
}

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 sourceMap = this._itemsBySourceByUriMap.get(uriKey);
if (sourceMap === undefined) {
sourceMap = new Map();
this._itemsBySourceByUriMap.set(uriKey, sourceMap);
return (uri: URI, options?: InternalTimelineOptions) => {
let items: Map<string, vscode.TimelineItem> | undefined;
if (options?.cacheResults) {
let itemsByUri = this._itemsBySourceAndUriMap.get(source);
if (itemsByUri === undefined) {
itemsByUri = new Map();
this._itemsBySourceAndUriMap.set(source, itemsByUri);
}

itemsMap = sourceMap.get(source);
if (itemsMap === undefined) {
itemsMap = new Map();
sourceMap.set(source, itemsMap);
const uriKey = getUriKey(uri);
items = itemsByUri.get(uriKey);
if (items === undefined) {
items = new Map();
itemsByUri.set(uriKey, items);
}
}

return (item: vscode.TimelineItem): TimelineItem => {
const { iconPath, ...props } = item;

const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`;
itemsMap?.set(handle, item);
const handle = `${source}|${item.id ?? item.timestamp}`;
items?.set(handle, item);

let icon;
let iconDark;
Expand Down Expand Up @@ -161,22 +158,6 @@ export class ExtHostTimeline implements IExtHostTimeline {
};
}

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 });
};
}

private registerTimelineProviderCore(provider: TimelineProvider): IDisposable {
// console.log(`ExtHostTimeline#registerTimelineProvider: id=${provider.id}`);

Expand All @@ -193,7 +174,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
this._providers.set(provider.id, provider);

return toDisposable(() => {
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
for (const sourceMap of this._itemsBySourceAndUriMap.values()) {
sourceMap.get(provider.id)?.clear();
}

Expand Down
18 changes: 17 additions & 1 deletion src/vs/workbench/contrib/timeline/browser/media/timelinePane.css
Expand Up @@ -7,9 +7,25 @@
position: relative;
}

.monaco-workbench .timeline-view.pane-header .description {
margin-left: 10px;
opacity: 0.6;
text-transform: none;
font-weight: normal;
}

.monaco-workbench .timeline-view.pane-header:not(.expanded) .description {
display: none;
}

.monaco-workbench .timeline-view.pane-header .description span.codicon {
font-size: 9px;
margin-left: 2px;
}

.monaco-workbench .timeline-tree-view .message.timeline-subtle {
padding: 10px 22px 0 22px;
opacity: 0.5;
padding: 10px 22px 0 22px;
position: absolute;
pointer-events: none;
z-index: 1;
Expand Down

0 comments on commit afacd2b

Please sign in to comment.