@@ -18,13 +18,13 @@ import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/vie
1818import { TreeResourceNavigator , WorkbenchObjectTree } from 'vs/platform/list/browser/listService' ;
1919import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding' ;
2020import { IContextMenuService } from 'vs/platform/contextview/browser/contextView' ;
21- import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey' ;
21+ import { IContextKeyService , IContextKey , RawContextKey } from 'vs/platform/contextkey/common/contextkey' ;
2222import { IConfigurationService , IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration' ;
2323import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
24- import { ITimelineService , TimelineChangeEvent , TimelineItem , TimelineOptions , TimelineProvidersChangeEvent , TimelineRequest , Timeline } from 'vs/workbench/contrib/timeline/common/timeline' ;
24+ import { ITimelineService , TimelineChangeEvent , TimelineItem , TimelineOptions , TimelineProvidersChangeEvent , TimelineRequest , Timeline , TimelinePaneId } from 'vs/workbench/contrib/timeline/common/timeline' ;
2525import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
2626import { SideBySideEditor , toResource } from 'vs/workbench/common/editor' ;
27- import { ICommandService } from 'vs/platform/commands/common/commands' ;
27+ import { ICommandService , CommandsRegistry , ICommandHandler } from 'vs/platform/commands/common/commands' ;
2828import { IThemeService , LIGHT , ThemeIcon } from 'vs/platform/theme/common/themeService' ;
2929import { IViewDescriptorService } from 'vs/workbench/common/views' ;
3030import { basename } from 'vs/base/common/path' ;
@@ -34,7 +34,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
3434import { IActionViewItemProvider , ActionBar , ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar' ;
3535import { IAction , ActionRunner } from 'vs/base/common/actions' ;
3636import { ContextAwareMenuEntryActionViewItem , createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem' ;
37- import { MenuItemAction , IMenuService , MenuId } from 'vs/platform/actions/common/actions' ;
37+ import { MenuItemAction , IMenuService , MenuId , MenuRegistry } from 'vs/platform/actions/common/actions' ;
3838import { fromNow } from 'vs/base/common/date' ;
3939import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
4040
@@ -85,8 +85,9 @@ interface TimelineCursors {
8585 more : boolean ;
8686}
8787
88+ export const TimelineFollowActiveEditorContext = new RawContextKey < boolean > ( 'timelineFollowActiveEditor' , true ) ;
89+
8890export class TimelinePane extends ViewPane {
89- static readonly ID = 'timeline' ;
9091 static readonly TITLE = localize ( 'timeline' , 'Timeline' ) ;
9192
9293 private _$container ! : HTMLElement ;
@@ -95,9 +96,11 @@ export class TimelinePane extends ViewPane {
9596 private _$tree ! : HTMLDivElement ;
9697 private _tree ! : WorkbenchObjectTree < TreeElement , FuzzyScore > ;
9798 private _treeRenderer : TimelineTreeRenderer | undefined ;
98- private _menus : TimelineMenus ;
99+ private _menus : TimelinePaneMenus ;
99100 private _visibilityDisposables : DisposableStore | undefined ;
100101
102+ private _followActiveEditorContext : IContextKey < boolean > ;
103+
101104 private _excludedSources : Set < string > ;
102105 private _cursorsByProvider : Map < string , TimelineCursors > = new Map ( ) ;
103106 private _items : { element : TreeElement } [ ] = [ ] ;
@@ -122,13 +125,53 @@ export class TimelinePane extends ViewPane {
122125 ) {
123126 super ( { ...options , titleMenuId : MenuId . TimelineTitle } , keybindingService , contextMenuService , configurationService , contextKeyService , viewDescriptorService , instantiationService , openerService , themeService , telemetryService ) ;
124127
125- this . _menus = this . _register ( this . instantiationService . createInstance ( TimelineMenus , this . id ) ) ;
128+ this . _menus = this . _register ( this . instantiationService . createInstance ( TimelinePaneMenus , this . id ) ) ;
129+ this . _register ( this . instantiationService . createInstance ( TimelinePaneCommands , this ) ) ;
126130
127131 const scopedContextKeyService = this . _register ( this . contextKeyService . createScoped ( ) ) ;
128- scopedContextKeyService . createKey ( 'view' , TimelinePane . ID ) ;
132+ scopedContextKeyService . createKey ( 'view' , TimelinePaneId ) ;
133+
134+ this . _followActiveEditorContext = TimelineFollowActiveEditorContext . bindTo ( this . contextKeyService ) ;
129135
130136 this . _excludedSources = new Set ( configurationService . getValue ( 'timeline.excludeSources' ) ) ;
131137 configurationService . onDidChangeConfiguration ( this . onConfigurationChanged , this ) ;
138+
139+ this . _register ( timelineService . onDidChangeUri ( uri => this . setUri ( uri ) , this ) ) ;
140+ }
141+
142+ private _followActiveEditor : boolean = true ;
143+ get followActiveEditor ( ) : boolean {
144+ return this . _followActiveEditor ;
145+ }
146+ set followActiveEditor ( value : boolean ) {
147+ if ( this . _followActiveEditor === value ) {
148+ return ;
149+ }
150+
151+ this . _followActiveEditor = value ;
152+ this . _followActiveEditorContext . set ( value ) ;
153+
154+ if ( value ) {
155+ this . onActiveEditorChanged ( ) ;
156+ }
157+ }
158+
159+ reset ( ) {
160+ this . loadTimeline ( true ) ;
161+ }
162+
163+ setUri ( uri : URI ) {
164+ this . setUriCore ( uri , true ) ;
165+ }
166+
167+ private setUriCore ( uri : URI | undefined , disableFollowing : boolean ) {
168+ if ( disableFollowing ) {
169+ this . followActiveEditor = false ;
170+ }
171+
172+ this . _uri = uri ;
173+ this . _treeRenderer ?. setUri ( uri ) ;
174+ this . loadTimeline ( true ) ;
132175 }
133176
134177 private onConfigurationChanged ( e : IConfigurationChangeEvent ) {
@@ -141,6 +184,10 @@ export class TimelinePane extends ViewPane {
141184 }
142185
143186 private onActiveEditorChanged ( ) {
187+ if ( ! this . followActiveEditor ) {
188+ return ;
189+ }
190+
144191 let uri ;
145192
146193 const editor = this . editorService . activeEditor ;
@@ -154,9 +201,7 @@ export class TimelinePane extends ViewPane {
154201 return ;
155202 }
156203
157- this . _uri = uri ;
158- this . _treeRenderer ?. setUri ( uri ) ;
159- this . loadTimeline ( true ) ;
204+ this . setUriCore ( uri , false ) ;
160205 }
161206
162207 private onProvidersChanged ( e : TimelineProvidersChangeEvent ) {
@@ -177,11 +222,6 @@ export class TimelinePane extends ViewPane {
177222 }
178223 }
179224
180- private onReset ( ) {
181- this . loadTimeline ( true ) ;
182- }
183-
184-
185225 private _titleDescription : string | undefined ;
186226 get titleDescription ( ) : string | undefined {
187227 return this . _titleDescription ;
@@ -574,13 +614,14 @@ export class TimelinePane extends ViewPane {
574614
575615 this . timelineService . onDidChangeProviders ( this . onProvidersChanged , this , this . _visibilityDisposables ) ;
576616 this . timelineService . onDidChangeTimeline ( this . onTimelineChanged , this , this . _visibilityDisposables ) ;
577- this . timelineService . onDidReset ( this . onReset , this , this . _visibilityDisposables ) ;
578617 this . editorService . onDidActiveEditorChange ( this . onActiveEditorChanged , this , this . _visibilityDisposables ) ;
579618
580619 this . onActiveEditorChanged ( ) ;
581620 } else {
582621 this . _visibilityDisposables ?. dispose ( ) ;
583622 }
623+
624+ super . setVisible ( visible ) ;
584625 }
585626
586627 protected layoutBody ( height : number , width : number ) : void {
@@ -671,7 +712,7 @@ export class TimelinePane extends ViewPane {
671712 this . message = file ? localize ( 'timeline.loading' , 'Loading timeline for {0}...' , file ) : '' ;
672713 }
673714
674- private onContextMenu ( menus : TimelineMenus , treeEvent : ITreeContextMenuEvent < TreeElement | null > ) : void {
715+ private onContextMenu ( menus : TimelinePaneMenus , treeEvent : ITreeContextMenuEvent < TreeElement | null > ) : void {
675716 const item = treeEvent . element ;
676717 if ( item === null ) {
677718 return ;
@@ -795,7 +836,7 @@ class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, Tim
795836 private _actionViewItemProvider : IActionViewItemProvider ;
796837
797838 constructor (
798- private readonly _menus : TimelineMenus ,
839+ private readonly _menus : TimelinePaneMenus ,
799840 @IInstantiationService protected readonly instantiationService : IInstantiationService ,
800841 @IThemeService private _themeService : IThemeService
801842 ) {
@@ -854,7 +895,58 @@ class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, Tim
854895 }
855896}
856897
857- class TimelineMenus extends Disposable {
898+ class TimelinePaneCommands extends Disposable {
899+
900+ static RefreshCommand = 'timeline.refresh' ;
901+ static ToggleFollowActiveEditorCommand = 'timeline.toggleFollowActiveEditor' ;
902+
903+ constructor ( private _pane : TimelinePane ) {
904+ super ( ) ;
905+
906+ this . _register ( CommandsRegistry . registerCommand ( TimelinePaneCommands . RefreshCommand , this . refreshCommand ( ) ) ) ;
907+ this . _register ( MenuRegistry . appendMenuItem ( MenuId . TimelineTitle , ( {
908+ group : 'navigation' ,
909+ order : 99 ,
910+ command : {
911+ id : TimelinePaneCommands . RefreshCommand ,
912+ title : localize ( TimelinePaneCommands . RefreshCommand , "Refresh" ) ,
913+ icon : { id : 'codicon/refresh' }
914+ }
915+ } ) ) ) ;
916+
917+ this . _register ( CommandsRegistry . registerCommand ( TimelinePaneCommands . ToggleFollowActiveEditorCommand , this . toggleFollowActiveEditorCommand ( ) ) ) ;
918+ this . _register ( MenuRegistry . appendMenuItem ( MenuId . TimelineTitle , ( {
919+ group : 'navigation' ,
920+ order : 2 ,
921+ command : {
922+ id : TimelinePaneCommands . ToggleFollowActiveEditorCommand ,
923+ title : localize ( `${ TimelinePaneCommands . ToggleFollowActiveEditorCommand } .stop` , "Stop following the Active Editor" ) ,
924+ icon : { id : 'codicon/eye' }
925+ } ,
926+ when : TimelineFollowActiveEditorContext
927+ } ) ) ) ;
928+ this . _register ( MenuRegistry . appendMenuItem ( MenuId . TimelineTitle , ( {
929+ group : 'navigation' ,
930+ order : 2 ,
931+ command : {
932+ id : TimelinePaneCommands . ToggleFollowActiveEditorCommand ,
933+ title : localize ( `${ TimelinePaneCommands . ToggleFollowActiveEditorCommand } .follow` , "Follow the Active Editor" ) ,
934+ icon : { id : 'codicon/eye-closed' }
935+ } ,
936+ when : TimelineFollowActiveEditorContext . toNegated ( )
937+ } ) ) ) ;
938+ }
939+
940+ refreshCommand ( ) : ICommandHandler {
941+ return ( accessor , arg ) => this . _pane . reset ( ) ;
942+ }
943+
944+ toggleFollowActiveEditorCommand ( ) : ICommandHandler {
945+ return ( accessor , arg ) => this . _pane . followActiveEditor = ! this . _pane . followActiveEditor ;
946+ }
947+ }
948+
949+ class TimelinePaneMenus extends Disposable {
858950
859951 constructor (
860952 private id : string ,
0 commit comments