Skip to content

Commit

Permalink
Hides timeline view if no providers registered
Browse files Browse the repository at this point in the history
Helps first-run experience, see here:
microsoft#98614 (comment)
  • Loading branch information
Eric Amodio authored and annkamsk committed Aug 3, 2020
1 parent aa96881 commit fdbf373
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
25 changes: 19 additions & 6 deletions extensions/git/src/timelineProvider.ts
Expand Up @@ -65,27 +65,32 @@ export class GitTimelineProvider implements TimelineProvider {
readonly id = 'git-history';
readonly label = localize('git.timeline.source', 'Git History');

private disposable: Disposable;
private readonly disposable: Disposable;
private providerDisposable: Disposable | undefined;

private repo: Repository | undefined;
private repoDisposable: Disposable | undefined;
private repoStatusDate: Date | undefined;

constructor(private readonly _model: Model) {
constructor(private readonly model: Model) {
this.disposable = Disposable.from(
_model.onDidOpenRepository(this.onRepositoriesChanged, this),
workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this),
model.onDidOpenRepository(this.onRepositoriesChanged, this),
);

if (model.repositories.length) {
this.ensureProviderRegistration();
}
}

dispose() {
this.providerDisposable?.dispose();
this.disposable.dispose();
}

async provideTimeline(uri: Uri, options: TimelineOptions, _token: CancellationToken): Promise<Timeline> {
// console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`);

const repo = this._model.getRepository(uri);
const repo = this.model.getRepository(uri);
if (!repo) {
this.repoDisposable?.dispose();
this.repoStatusDate = undefined;
Expand All @@ -110,7 +115,7 @@ export class GitTimelineProvider implements TimelineProvider {
let limit: number | undefined;
if (options.limit !== undefined && typeof options.limit !== 'number') {
try {
const result = await this._model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]);
const result = await this.model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]);
if (!result.exitCode) {
// Ask for 2 more (1 for the limit commit and 1 for the next commit) than so we can determine if there are more commits
limit = Number(result.stdout) + 2;
Expand Down Expand Up @@ -203,9 +208,17 @@ export class GitTimelineProvider implements TimelineProvider {
};
}

private ensureProviderRegistration() {
if (this.providerDisposable === undefined) {
this.providerDisposable = workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this);
}
}

private onRepositoriesChanged(_repo: Repository) {
// console.log(`GitTimelineProvider.onRepositoriesChanged`);

this.ensureProviderRegistration();

// TODO@eamodio: Being naive for now and just always refreshing each time there is a new repository
this.fireChanged();
}
Expand Down
Expand Up @@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IViewsRegistry, IViewDescriptor, Extensions as ViewExtensions } from 'vs/workbench/common/views';
import { VIEW_CONTAINER } from 'vs/workbench/contrib/files/browser/explorerViewlet';
import { ITimelineService, TimelinePaneId } from 'vs/workbench/contrib/timeline/common/timeline';
import { TimelineService } from 'vs/workbench/contrib/timeline/common/timelineService';
import { TimelineHasProviderContext, TimelineService } from 'vs/workbench/contrib/timeline/common/timelineService';
import { TimelinePane } from './timelinePane';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
Expand All @@ -30,6 +30,7 @@ export class TimelinePaneDescriptor implements IViewDescriptor {
readonly canToggleVisibility = true;
readonly hideByDefault = false;
readonly canMoveView = true;
readonly when = TimelineHasProviderContext;

focusCommand = { id: 'timeline.focus' };
}
Expand Down
37 changes: 37 additions & 0 deletions src/vs/workbench/contrib/timeline/common/timelineService.ts
Expand Up @@ -11,6 +11,10 @@ import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { ITimelineService, TimelineChangeEvent, TimelineOptions, TimelineProvidersChangeEvent, TimelineProvider, InternalTimelineOptions, TimelinePaneId } from './timeline';
import { IViewsService } from 'vs/workbench/common/views';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';

export const TimelineHasProviderContext = new RawContextKey<boolean>('timelineHasProvider', false);

export class TimelineService implements ITimelineService {
declare readonly _serviceBrand: undefined;
Expand All @@ -23,13 +27,30 @@ export class TimelineService implements ITimelineService {
private readonly _onDidChangeUri = new Emitter<URI>();
readonly onDidChangeUri: Event<URI> = this._onDidChangeUri.event;

private excludedSources: Set<string>;
private readonly hasProviderContext: IContextKey<boolean>;
private readonly providers = new Map<string, TimelineProvider>();
private readonly providerSubscriptions = new Map<string, IDisposable>();

constructor(
@ILogService private readonly logService: ILogService,
@IViewsService protected viewsService: IViewsService,
@IConfigurationService protected configurationService: IConfigurationService,
@IContextKeyService protected contextKeyService: IContextKeyService,
) {
this.hasProviderContext = TimelineHasProviderContext.bindTo(this.contextKeyService);

this.excludedSources = new Set(configurationService.getValue('timeline.excludeSources'));
configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('timeline.excludeSources')) {
this.excludedSources = new Set(this.configurationService.getValue('timeline.excludeSources'));

this.updateHasProviderContext();
}
}, this);

this.updateHasProviderContext();

// let source = 'fast-source';
// this.registerTimelineProvider({
// scheme: '*',
Expand Down Expand Up @@ -213,6 +234,9 @@ export class TimelineService implements ITimelineService {
}

this.providers.set(id, provider);

this.updateHasProviderContext();

if (provider.onDidChange) {
this.providerSubscriptions.set(id, provider.onDidChange(e => this._onDidChangeTimeline.fire(e)));
}
Expand All @@ -235,11 +259,24 @@ export class TimelineService implements ITimelineService {

this.providers.delete(id);
this.providerSubscriptions.delete(id);

this.updateHasProviderContext();

this._onDidChangeProviders.fire({ removed: [id] });
}

setUri(uri: URI) {
this.viewsService.openView(TimelinePaneId, true);
this._onDidChangeUri.fire(uri);
}

private updateHasProviderContext() {
if (this.providers.size === 0) {
this.hasProviderContext.set(false);
return;
}

const hasProviders = [...this.providers.keys()].some(id => !this.excludedSources.has(id));
this.hasProviderContext.set(hasProviders);
}
}

0 comments on commit fdbf373

Please sign in to comment.