88namespace ast_visual_studio_extension . CxExtension . CxAssist . Realtime . Utils
99{
1010 /// <summary>
11- /// Shows Visual Studio status bar progress with animated progress bar.
12- /// Displays: "Checkmarx is Scanning File : filename.ext" with animated bar underneath
11+ /// Shows Visual Studio status bar progress message during realtime scans.
12+ /// Displays: "Checkmarx is Scanning File : filename.ext" with single-run progress bar.
13+ /// Progress bar fills from 0-100% once per scan, then clears.
1314 /// </summary>
1415 internal static class RealtimeScanProgressIndicator
1516 {
1617 private static readonly object ProgressLock = new object ( ) ;
1718 private static int _depth ;
1819 private static uint _progressCookie ;
1920 private static string _currentFileName = string . Empty ;
21+ private static System . Timers . Timer _progressTimer ;
22+ private static uint _currentProgress = 0 ;
2023
2124 internal static async Task PushScanAsync ( string scannerName , string sourceFilePath )
2225 {
@@ -38,10 +41,11 @@ internal static async Task PushScanAsync(string scannerName, string sourceFilePa
3841
3942 try
4043 {
41- // Show animated progress bar with label in same call
42- // This prevents the gap between text and bar
44+ // Show progress bar that fills from 0-100% once during the scan.
45+ // Progress fills at ~200ms per 10%, completing in ~2 seconds.
4346 string label = $ "Checkmarx is Scanning File : { fileName } ";
44- statusBar . Progress ( ref _progressCookie , 1 , label , 1 , 1 ) ;
47+ _currentProgress = 0 ;
48+ StartProgressBar ( label ) ;
4549 }
4650 catch
4751 {
@@ -59,40 +63,33 @@ internal static async Task PopScanAsync()
5963 if ( _depth > 0 )
6064 _depth -- ;
6165
62- var statusBar = Package . GetGlobalService ( typeof ( SVsStatusbar ) ) as IVsStatusbar ;
63- if ( statusBar == null )
64- {
65- if ( _depth == 0 )
66- {
67- TrySetTextFallback ( string . Empty ) ;
68- ResetProgress ( ) ;
69- }
70- else
71- {
72- TrySetTextFallback ( $ "Checkmarx is Scanning File : { _currentFileName } ") ;
73- }
74- return ;
75- }
76-
7766 try
7867 {
7968 if ( _depth == 0 )
8069 {
81- // Clear the progress bar when all scans complete
82- statusBar . Progress ( ref _progressCookie , 0 , string . Empty , 0 , 0 ) ;
70+ // Stop progress bar and clear status bar
71+ StopProgressBar ( ) ;
72+
73+ var statusBar = Package . GetGlobalService ( typeof ( SVsStatusbar ) ) as IVsStatusbar ;
74+ if ( statusBar != null )
75+ {
76+ statusBar . Progress ( ref _progressCookie , 0 , string . Empty , 0 , 0 ) ;
77+ }
78+ TrySetTextFallback ( string . Empty ) ;
8379 ResetProgress ( ) ;
8480 }
8581 else
8682 {
87- // Show progress for next scan
83+ // More scans pending - show current file
8884 string label = $ "Checkmarx is Scanning File : { _currentFileName } ";
89- statusBar . Progress ( ref _progressCookie , 1 , label , 1 , 1 ) ;
85+ TrySetTextFallback ( label ) ;
9086 }
9187 }
9288 catch
9389 {
9490 if ( _depth == 0 )
9591 {
92+ StopProgressBar ( ) ;
9693 TrySetTextFallback ( string . Empty ) ;
9794 ResetProgress ( ) ;
9895 }
@@ -102,12 +99,70 @@ internal static async Task PopScanAsync()
10299
103100 /// <summary>
104101 /// Resets progress state when all scans complete.
102+ /// _progressCookie must be reset to 0 so VS allocates a fresh one on the next PushScan.
103+ /// Reusing a cookie that VS has already closed causes the bar to silently disappear.
105104 /// </summary>
106105 private static void ResetProgress ( )
107106 {
107+ _progressCookie = 0 ;
108108 _currentFileName = string . Empty ;
109109 }
110110
111+ /// <summary>
112+ /// Starts progress bar that fills 0-100% once during scan.
113+ /// Updates every 200ms with +10% increment = ~2 second fill time.
114+ /// </summary>
115+ private static void StartProgressBar ( string label )
116+ {
117+ StopProgressBar ( ) ;
118+
119+ _currentProgress = 0 ;
120+ _progressTimer = new System . Timers . Timer ( 200 ) ;
121+ _progressTimer . Elapsed += ( sender , e ) =>
122+ {
123+ try
124+ {
125+ lock ( ProgressLock )
126+ {
127+ _currentProgress += 10 ;
128+ if ( _currentProgress > 100 )
129+ _currentProgress = 100 ;
130+
131+ var statusBar = Package . GetGlobalService ( typeof ( SVsStatusbar ) ) as IVsStatusbar ;
132+ if ( statusBar != null )
133+ {
134+ statusBar . Progress ( ref _progressCookie , 1 , label , _currentProgress , 100 ) ;
135+ }
136+
137+ // Stop timer once progress reaches 100%
138+ if ( _currentProgress >= 100 )
139+ {
140+ StopProgressBar ( ) ;
141+ }
142+ }
143+ }
144+ catch
145+ {
146+ // Ignore timer errors
147+ }
148+ } ;
149+ _progressTimer . AutoReset = true ;
150+ _progressTimer . Start ( ) ;
151+ }
152+
153+ /// <summary>
154+ /// Stops the progress bar timer.
155+ /// </summary>
156+ private static void StopProgressBar ( )
157+ {
158+ if ( _progressTimer != null )
159+ {
160+ _progressTimer . Stop ( ) ;
161+ _progressTimer . Dispose ( ) ;
162+ _progressTimer = null ;
163+ }
164+ }
165+
111166 private static void TrySetTextFallback ( string message )
112167 {
113168 try
0 commit comments