diff --git a/src/eventBus.ts b/src/eventBus.ts index 8d58cd6..419a384 100644 --- a/src/eventBus.ts +++ b/src/eventBus.ts @@ -1,39 +1,59 @@ -import type { Disposable } from 'vscode'; +import type { Disposable, Uri } from 'vscode'; import { EventEmitter } from 'vscode'; +import type { ViewsConfigKeys } from './config'; +import type { GitCommit } from './git/models/commit'; +import type { GitRevisionReference } from './git/models/reference'; +import type { WebviewIds } from './webviews/webviewBase'; +import type { WebviewViewIds } from './webviews/webviewViewBase'; -export type EventBusPackage = { - name: string; - data?: unknown; - source?: string; +export type CommitSelectedEvent = EventBusEvent<'commit:selected'>; +export type FileSelectedEvent = EventBusEvent<'file:selected'>; + +type EventBusEventMap = { + 'commit:selected': CommitSelectedEventArgs; + 'file:selected': FileSelectedEventArgs; }; +interface CommitSelectedEventArgs { + readonly commit: GitRevisionReference | GitCommit; + readonly pin?: boolean; + readonly preserveFocus?: boolean; + readonly preserveVisibility?: boolean; +} + +interface FileSelectedEventArgs { + readonly uri: Uri; + readonly preserveFocus?: boolean; + readonly preserveVisibility?: boolean; +} + +interface EventBusEvent { + name: T; + data?: EventBusEventMap[T] | undefined; + source?: EventBusSource | undefined; +} + +export type EventBusSource = + | 'gitlens.rebase' + | `gitlens.${WebviewIds}` + | `gitlens.views.${WebviewViewIds}` + | `gitlens.views.${ViewsConfigKeys}`; + export type EventBusOptions = { - source?: string; + source?: EventBusSource; }; export class EventBus implements Disposable { - private _emitter: EventEmitter; - - constructor() { - this._emitter = new EventEmitter(); - } - + private readonly _emitter = new EventEmitter(); private get event() { return this._emitter.event; } - on(eventName: string, handler: (e: EventBusPackage) => void, thisArgs?: any, disposables?: Disposable[]) { - return this.event( - e => { - if (eventName !== e.name) return; - handler.call(thisArgs, e); - }, - thisArgs, - disposables, - ); + dispose() { + this._emitter.dispose(); } - fire(name: string, data?: unknown, options?: EventBusOptions) { + fire(name: T, data?: EventBusEventMap[T], options?: EventBusOptions) { this._emitter.fire({ name: name, data: data, @@ -41,7 +61,20 @@ export class EventBus implements Disposable { }); } - dispose() { - this._emitter?.dispose(); + on( + eventName: T, + handler: (e: EventBusEvent) => void, + thisArgs?: any, + disposables?: Disposable[], + ) { + return this.event( + // eslint-disable-next-line prefer-arrow-callback + function (e) { + if (eventName !== e.name) return; + handler.call(thisArgs, e as EventBusEvent); + }, + thisArgs, + disposables, + ); } } diff --git a/src/plus/webviews/timeline/timelineWebviewView.ts b/src/plus/webviews/timeline/timelineWebviewView.ts index b731796..899e848 100644 --- a/src/plus/webviews/timeline/timelineWebviewView.ts +++ b/src/plus/webviews/timeline/timelineWebviewView.ts @@ -4,7 +4,7 @@ import { commands, Uri, window } from 'vscode'; import { configuration } from '../../../configuration'; import { Commands, ContextKeys } from '../../../constants'; import type { Container } from '../../../container'; -import type { EventBusPackage } from '../../../eventBus'; +import type { FileSelectedEvent } from '../../../eventBus'; import { PlusFeatures } from '../../../features'; import type { RepositoriesChangeEvent } from '../../../git/gitProviderService'; import { GitUri } from '../../../git/gitUri'; @@ -83,7 +83,7 @@ export class TimelineWebviewView extends WebviewViewBase { return [ this.container.subscription.onDidChange(this.onSubscriptionChanged, this), window.onDidChangeActiveTextEditor(debounce(this.onActiveEditorChanged, 250), this), - this.container.events.on('file:selected', this.onFileSelected, this), + this.container.events.on('file:selected', debounce(this.onFileSelected, 250), this), this.container.git.onDidChangeRepository(this.onRepositoryChanged, this), this.container.git.onDidChangeRepositories(this.onRepositoriesChanged, this), ]; @@ -138,6 +138,9 @@ export class TimelineWebviewView extends WebviewViewBase { 'commit:selected', { commit: commit, + pin: false, + preserveFocus: false, + preserveVisibility: false, }, { source: this.id }, ); @@ -172,11 +175,10 @@ export class TimelineWebviewView extends WebviewViewBase { } @debug({ args: false }) - private onFileSelected(event: EventBusPackage) { - if (event.data == null) return; - - let uri: Uri | undefined = event.data as Uri; + private onFileSelected(e: FileSelectedEvent) { + if (e.data == null) return; + let uri: Uri | undefined = e.data.uri; if (uri != null) { if (!this.container.git.isTrackable(uri)) { uri = undefined; diff --git a/src/views/commitsView.ts b/src/views/commitsView.ts index 601d4c8..f53c1fe 100644 --- a/src/views/commitsView.ts +++ b/src/views/commitsView.ts @@ -311,15 +311,28 @@ export class CommitsView extends ViewBase { private notifySelections() { const node = this.selection?.[0]; + if (node == null) return; - if ( - node != null && - (node instanceof CommitNode || node instanceof FileRevisionAsCommitNode || node instanceof CommitFileNode) - ) { + if (node instanceof CommitNode || node instanceof FileRevisionAsCommitNode || node instanceof CommitFileNode) { this.container.events.fire( 'commit:selected', { commit: node.commit, + pin: false, + preserveFocus: true, + preserveVisibility: true, + }, + { source: this.id }, + ); + } + + if (node instanceof FileRevisionAsCommitNode || node instanceof CommitFileNode) { + this.container.events.fire( + 'file:selected', + { + uri: node.uri, + preserveFocus: true, + preserveVisibility: true, }, { source: this.id }, ); diff --git a/src/views/stashesView.ts b/src/views/stashesView.ts index 91b0573..fe7d2f9 100644 --- a/src/views/stashesView.ts +++ b/src/views/stashesView.ts @@ -170,12 +170,28 @@ export class StashesView extends ViewBase { private notifySelections() { const node = this.selection?.[0]; + if (node == null) return; - if (node != null && (node instanceof StashNode || node instanceof StashFileNode)) { + if (node instanceof StashNode || node instanceof StashFileNode) { this.container.events.fire( 'commit:selected', { commit: node.commit, + pin: false, + preserveFocus: true, + preserveVisibility: true, + }, + { source: this.id }, + ); + } + + if (node instanceof StashFileNode) { + this.container.events.fire( + 'file:selected', + { + uri: node.uri, + preserveFocus: true, + preserveVisibility: true, }, { source: this.id }, ); diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts index f66f851..5a5003a 100644 --- a/src/views/viewBase.ts +++ b/src/views/viewBase.ts @@ -111,7 +111,7 @@ export abstract class ViewBase< constructor( public readonly container: Container, - public readonly id: `gitlens.views.${string}`, + public readonly id: `gitlens.views.${ViewsConfigKeys}`, public readonly name: string, private readonly trackingFeature: TrackedUsageFeatures, ) { diff --git a/src/webviews/commitDetails/commitDetailsWebviewView.ts b/src/webviews/commitDetails/commitDetailsWebviewView.ts index 9521129..21b7f76 100644 --- a/src/webviews/commitDetails/commitDetailsWebviewView.ts +++ b/src/webviews/commitDetails/commitDetailsWebviewView.ts @@ -7,7 +7,7 @@ import { configuration } from '../../configuration'; import { Commands, ContextKeys, CoreCommands } from '../../constants'; import type { Container } from '../../container'; import { getContext } from '../../context'; -import type { EventBusPackage } from '../../eventBus'; +import type { CommitSelectedEvent } from '../../eventBus'; import { CommitFormatter } from '../../git/formatters/commitFormatter'; import type { GitCommit } from '../../git/models/commit'; import { isCommit } from '../../git/models/commit'; @@ -112,10 +112,10 @@ export class CommitDetailsWebviewView extends WebviewViewBase({ @@ -824,7 +824,7 @@ export class CommitDetailsWebviewView extends WebviewViewBase