99 fetchDiff ,
1010 isGitRepo ,
1111 getCurrentBranch ,
12+ hasGitChanges ,
1213} from "./git/git-logic" ;
1314import { CstManager } from "./cst-manager" ;
1415
@@ -24,6 +25,7 @@ export function activate(context: vscode.ExtensionContext) {
2425 let repoWatcher : vscode . FileSystemWatcher | undefined ;
2526 let nonRepoWatcher : vscode . FileSystemWatcher | undefined ;
2627 let watchedRepoPath : string | undefined ;
28+ let currentViewedBranch : string | undefined ;
2729 let debounceTimer : NodeJS . Timeout | undefined ;
2830 let nonRepoDebounceTimer : NodeJS . Timeout | undefined ;
2931 let lastState :
@@ -44,15 +46,14 @@ export function activate(context: vscode.ExtensionContext) {
4446 if ( e . exitCode === 0 ) {
4547 activePanel . webview . postMessage ( {
4648 command : "displayOutput" ,
47- data : `Command finished successfully. Refreshing graph... ` ,
49+ data : `Command finished successfully.` ,
4850 } ) ;
4951 } else {
5052 activePanel . webview . postMessage ( {
5153 command : "displayOutput" ,
5254 data : `Command failed with code ${ e . exitCode } ` ,
5355 } ) ;
5456 }
55- activePanel . webview . postMessage ( { command : "refreshGraph" } ) ;
5657 activePanel . webview . postMessage ( { command : "resetExecuting" } ) ;
5758 }
5859 }
@@ -274,11 +275,15 @@ export function activate(context: vscode.ExtensionContext) {
274275 repoPath : string ,
275276 branch ?: string ,
276277 isManual = true ,
278+ reloadReason ?: "git" | "workdir" ,
277279 ) {
278280 if ( ! repoPath ) throw new Error ( "Please specify a directory path." ) ;
279281
282+ const pathChanged = watchedRepoPath !== repoPath ;
283+ currentViewedBranch = branch ;
284+
280285 // Setup file system watchers if path changed
281- if ( watchedRepoPath !== repoPath ) {
286+ if ( pathChanged ) {
282287 if ( repoWatcher ) {
283288 repoWatcher . dispose ( ) ;
284289 repoWatcher = undefined ;
@@ -295,94 +300,6 @@ export function activate(context: vscode.ExtensionContext) {
295300 clearTimeout ( nonRepoDebounceTimer ) ;
296301 nonRepoDebounceTimer = undefined ;
297302 }
298-
299- // Watch for any changes in the .git directory (to trigger an automatic refresh)
300- const gitPattern = new vscode . RelativePattern ( repoPath , ".git/**" ) ;
301- repoWatcher = vscode . workspace . createFileSystemWatcher ( gitPattern ) ;
302-
303- const refresh = ( ) => {
304- if ( debounceTimer ) {
305- clearTimeout ( debounceTimer ) ;
306- }
307- debounceTimer = setTimeout ( ( ) => {
308- if ( activePanel ) {
309- activePanel . webview . postMessage ( { command : "refreshGraph" } ) ;
310- }
311- } , 1000 ) ; // 1 second debounce
312- } ;
313-
314- repoWatcher . onDidChange ( refresh ) ;
315- repoWatcher . onDidCreate ( refresh ) ;
316- repoWatcher . onDidDelete ( refresh ) ;
317-
318- // Watch for changes outside of .git and show a small 'reload' notification
319- // Only setup if not ignored by user
320- const ignoreNotifications = context . globalState . get < boolean > (
321- "codestory.ignoreFileChangeNotifications" ,
322- false ,
323- ) ;
324-
325- if ( ! ignoreNotifications ) {
326- const allPattern = new vscode . RelativePattern ( repoPath , "**" ) ;
327- nonRepoWatcher =
328- vscode . workspace . createFileSystemWatcher ( allPattern ) ;
329-
330- const nonRepoRefresh = ( uri ?: vscode . Uri ) => {
331- const fsPath = uri ?. fsPath || repoPath ;
332- // If the change is inside .git, ignore it here
333- const rel = path . relative ( repoPath , fsPath ) ;
334- if ( rel . split ( path . sep ) [ 0 ] === ".git" ) return ;
335-
336- if ( nonRepoDebounceTimer ) {
337- clearTimeout ( nonRepoDebounceTimer ) ;
338- }
339-
340- nonRepoDebounceTimer = setTimeout ( async ( ) => {
341- // Only show notification when the panel is open
342- if ( ! activePanel ) return ;
343-
344- // Re-check in case it was changed while debouncing
345- if (
346- context . globalState . get < boolean > (
347- "codestory.ignoreFileChangeNotifications" ,
348- false ,
349- )
350- ) {
351- return ;
352- }
353-
354- const selection = await vscode . window . showInformationMessage (
355- "File changes detected outside .git. Reload?" ,
356- "Reload" ,
357- "Don't show again" ,
358- ) ;
359-
360- if ( selection === "Reload" ) {
361- // Trigger a manual reload just like clicking the branch reload button
362- // Use last known branch if available
363- const branchToUse =
364- lastState ?. currentBranch || branch || "HEAD" ;
365- await handleLoadRepo ( panel , repoPath , branchToUse , true ) ;
366- } else if ( selection === "Don't show again" ) {
367- await context . globalState . update (
368- "codestory.ignoreFileChangeNotifications" ,
369- true ,
370- ) ;
371- // Dispose watcher since we won't need it anymore
372- if ( nonRepoWatcher ) {
373- nonRepoWatcher . dispose ( ) ;
374- nonRepoWatcher = undefined ;
375- }
376- }
377- } , 1000 ) ;
378- } ;
379-
380- nonRepoWatcher . onDidChange ( nonRepoRefresh ) ;
381- nonRepoWatcher . onDidCreate ( nonRepoRefresh ) ;
382- nonRepoWatcher . onDidDelete ( nonRepoRefresh ) ;
383- }
384-
385- watchedRepoPath = repoPath ;
386303 lastState = undefined ;
387304 }
388305
@@ -420,6 +337,16 @@ export function activate(context: vscode.ExtensionContext) {
420337
421338 lastState = newState ;
422339
340+ if ( reloadReason === "git" ) {
341+ vscode . window . showInformationMessage (
342+ "Repo reloaded because of a .git change" ,
343+ ) ;
344+ } else if ( reloadReason === "workdir" ) {
345+ vscode . window . showInformationMessage (
346+ "Change in working dir, reload." ,
347+ ) ;
348+ }
349+
423350 panel . webview . postMessage ( {
424351 command : "displayOutput" ,
425352 data : `Loading repository: ${ repoPath } (branch: ${ branch || "HEAD" } )` ,
@@ -443,6 +370,85 @@ export function activate(context: vscode.ExtensionContext) {
443370 command : "displayOutput" ,
444371 data : `Successfully loaded ${ commits . length } commits.` ,
445372 } ) ;
373+
374+ if ( pathChanged ) {
375+ // Watch for any changes in the .git directory (to trigger an automatic refresh)
376+ const gitPattern = new vscode . RelativePattern ( repoPath , ".git/**" ) ;
377+ repoWatcher = vscode . workspace . createFileSystemWatcher ( gitPattern ) ;
378+
379+ const handleFileChange = async ( isGitChange = false ) => {
380+ if ( ! activePanel ) return ;
381+
382+ if ( isGitChange ) {
383+ // if git changes, always reload
384+ vscode . window . setStatusBarMessage (
385+ "Repo State Changed, Reloading..." ,
386+ 3000 ,
387+ ) ;
388+ const branchToUse =
389+ currentViewedBranch || lastState ?. currentBranch || "HEAD" ;
390+ await handleLoadRepo ( panel , repoPath , branchToUse , false , "git" ) ;
391+ } else {
392+ const currentHasChanges = await hasGitChanges ( repoPath ) ;
393+ const previousHasChanges =
394+ lastState ?. commits . some ( ( c ) => c . id === "WORKING_DIR" ) || false ;
395+ if ( currentHasChanges !== previousHasChanges ) {
396+ // Status-bar and an informational popup for working-directory changes
397+ vscode . window . setStatusBarMessage (
398+ "Working Directory State Changed, Reloading..." ,
399+ 3000 ,
400+ ) ;
401+
402+ const branchToUse =
403+ currentViewedBranch || lastState ?. currentBranch || "HEAD" ;
404+ await handleLoadRepo (
405+ panel ,
406+ repoPath ,
407+ branchToUse ,
408+ false ,
409+ "workdir" ,
410+ ) ;
411+ }
412+ }
413+ } ;
414+
415+ const refresh = ( ) => {
416+ if ( debounceTimer ) {
417+ clearTimeout ( debounceTimer ) ;
418+ }
419+ debounceTimer = setTimeout ( ( ) => handleFileChange ( true ) , 1000 ) ;
420+ } ;
421+
422+ repoWatcher . onDidChange ( refresh ) ;
423+ repoWatcher . onDidCreate ( refresh ) ;
424+ repoWatcher . onDidDelete ( refresh ) ;
425+
426+ // Watch for changes outside of .git
427+ const allPattern = new vscode . RelativePattern ( repoPath , "**" ) ;
428+ nonRepoWatcher = vscode . workspace . createFileSystemWatcher ( allPattern ) ;
429+
430+ const nonRepoRefresh = ( uri ?: vscode . Uri ) => {
431+ const fsPath = uri ?. fsPath || repoPath ;
432+ // If the change is inside .git, ignore it here
433+ const rel = path . relative ( repoPath , fsPath ) ;
434+ if ( rel . split ( path . sep ) [ 0 ] === ".git" ) return ;
435+
436+ if ( nonRepoDebounceTimer ) {
437+ clearTimeout ( nonRepoDebounceTimer ) ;
438+ }
439+
440+ nonRepoDebounceTimer = setTimeout (
441+ ( ) => handleFileChange ( false ) ,
442+ 1000 ,
443+ ) ;
444+ } ;
445+
446+ nonRepoWatcher . onDidChange ( nonRepoRefresh ) ;
447+ nonRepoWatcher . onDidCreate ( nonRepoRefresh ) ;
448+ nonRepoWatcher . onDidDelete ( nonRepoRefresh ) ;
449+
450+ watchedRepoPath = repoPath ;
451+ }
446452 }
447453
448454 panel . webview . onDidReceiveMessage (
@@ -563,22 +569,24 @@ export function activate(context: vscode.ExtensionContext) {
563569 console . error ( "Failed to parse global config" , e ) ;
564570 }
565571 }
566- const ignoreBranchPrompt = context . globalState . get < boolean > (
567- "codestory.ignoreBranchPrompt" ,
568- false ,
569- ) ;
572+ const branchUpdateStrategy = vscode . workspace
573+ . getConfiguration ( "codestoryView" )
574+ . get < string > ( "branchUpdateStrategy" , "prompt" ) ;
570575 panel . webview . postMessage ( {
571576 command : "globalConfig" ,
572577 config,
573- ignoreBranchPrompt ,
578+ branchUpdateStrategy ,
574579 } ) ;
575580 return ;
576581
577- case "setIgnoreBranchPrompt" :
578- await context . globalState . update (
579- "codestory.ignoreBranchPrompt" ,
580- message . value ,
581- ) ;
582+ case "setBranchUpdateStrategy" :
583+ await vscode . workspace
584+ . getConfiguration ( "codestoryView" )
585+ . update (
586+ "branchUpdateStrategy" ,
587+ message . value ,
588+ vscode . ConfigurationTarget . Global ,
589+ ) ;
582590 return ;
583591
584592 case "setGlobalConfig" :
@@ -671,19 +679,9 @@ async function runCstTool(
671679 ( err as any ) . code === "ENOENT" ||
672680 stderr . includes ( "not recognized" )
673681 ) {
674- vscode . window
675- . showErrorMessage (
676- `Could not find 'cst' executable. Is it installed?` ,
677- "Open Settings" ,
678- )
679- . then ( ( selection ) => {
680- if ( selection === "Open Settings" ) {
681- vscode . commands . executeCommand (
682- "workbench.action.openSettings" ,
683- "codestoryView.executablePath" ,
684- ) ;
685- }
686- } ) ;
682+ vscode . window . showErrorMessage (
683+ `Could not find 'cst' executable. Is it installed?` ,
684+ ) ;
687685 reject ( new Error ( "Codestory not found" ) ) ;
688686 return ;
689687 }
0 commit comments