@@ -55,24 +55,43 @@ export function activate(context: vscode.ExtensionContext) {
5555
5656 // Step 4: Create a decorator to render per-line metrics at line start
5757 if ( currentLineProfiler ) {
58- try { currentLineProfiler . dispose ( ) ; } catch { /* ignore */ }
58+ try { currentLineProfiler . dispose ( ) ; currentLineProfiler . clearReadOnlyConfig ( ) } catch { /* ignore */ }
5959 }
60+
61+
6062 currentLineProfiler = new LineProfilerDecorator ( context , records , sourceRoot , clocksPerSec ) ;
6163 context . subscriptions . push ( currentLineProfiler ) ;
6264 const refresh = ( ) => currentLineProfiler ?. refreshVisibleEditors ( ) ;
6365 context . subscriptions . push ( vscode . window . onDidChangeActiveTextEditor ( refresh ) ) ;
6466 context . subscriptions . push ( vscode . window . onDidChangeVisibleTextEditors ( refresh ) ) ;
6567 currentLineProfiler . refreshVisibleEditors ( ) ;
68+ vscode . commands . executeCommand ( 'setContext' , 'pocketpy.isInProfilerReportMode' , true ) ;
6669 } catch ( err : any ) {
6770 vscode . window . showErrorMessage ( `Failed to load line profiler: ${ err . message ?? err } ` ) ;
6871 }
6972 } ) ;
7073 context . subscriptions . push ( loadProfilerCmd ) ;
74+
75+ const quitProfilerReportMode = vscode . commands . registerCommand ( "pocketpy.quitProfilerReportMode" , async ( ) => {
76+ if ( ! currentLineProfiler ) {
77+ vscode . window . showErrorMessage ( "You are not in profiler mode, cannot quit." )
78+ return
79+ }
80+ await vscode . commands . executeCommand ( 'setContext' , 'pocketpy.isInProfilerReportMode' , false ) ;
81+ currentLineProfiler . dispose ( ) ;
82+ currentLineProfiler . clearReadOnlyConfig ( ) ;
83+ currentLineProfiler = undefined ;
84+ } ) ;
85+ context . subscriptions . push ( quitProfilerReportMode ) ;
86+
87+ vscode . workspace . getConfiguration ( "files" ) . update ( "readonlyInclude" , { } , vscode . ConfigurationTarget . Workspace ) ;
88+
7189}
7290
7391export function deactivate ( ) { }
7492
7593
94+
7695async function pingserver ( host : string , port : number ) {
7796 const msg = 'Content-Length: 44\r\n\r\n{"type":"request","seq":0,"command":"ready"}' ;
7897 const start = Date . now ( ) ;
@@ -167,6 +186,7 @@ class PathMappingTrackerFactory implements vscode.DebugAdapterTrackerFactory {
167186 }
168187}
169188
189+
170190let currentLineProfiler : LineProfilerDecorator | undefined ;
171191type LineInfo = { color : string , blockID : number } ;
172192
@@ -175,6 +195,7 @@ class LineProfilerDecorator implements vscode.Disposable {
175195 private readonly prefixDecorationType : vscode . TextEditorDecorationType ;
176196 private editorToDecorationTypes : Map < string , vscode . TextEditorDecorationType [ ] > = new Map ( ) ;
177197 private editorToColors : Map < string , Map < number , LineInfo > > = new Map ( ) ;
198+ private analysisFilesSet : Set < string > = new Set ( ) ;
178199
179200 constructor (
180201 context : vscode . ExtensionContext ,
@@ -185,10 +206,17 @@ class LineProfilerDecorator implements vscode.Disposable {
185206 // this.context = context;
186207 // Prefix percentage before the code; fixed styling (not theme-driven)
187208 this . prefixDecorationType = vscode . window . createTextEditorDecorationType ( { } ) ;
209+ const currentInclude : { [ key : string ] : boolean } = vscode . workspace . getConfiguration ( "files" ) . get ( "readonlyInclude" , { } ) ;
210+ const workspacePath = vscode . workspace . workspaceFolders ?. [ 0 ] . uri . fsPath ?? sourceRoot
211+ for ( const filepath of Object . keys ( this . data ) ) {
212+ const pathPrefix = path . relative ( workspacePath , sourceRoot ) ;
213+ const analysisFilesPath = path . join ( pathPrefix , filepath ) . replace ( / \\ / g, '/' ) ;
214+ currentInclude [ analysisFilesPath ] = true ;
215+ this . analysisFilesSet . add ( analysisFilesPath ) ;
216+ }
217+ vscode . workspace . getConfiguration ( "files" ) . update ( "readonlyInclude" , currentInclude , vscode . ConfigurationTarget . Workspace ) ;
188218 }
189219
190- // No preparation needed for data URIs
191- async prepare ( ) : Promise < void > { return ; }
192220
193221 dispose ( ) : void {
194222 this . prefixDecorationType . dispose ( ) ;
@@ -199,8 +227,12 @@ class LineProfilerDecorator implements vscode.Disposable {
199227 }
200228
201229 refreshVisibleEditors ( ) : void {
230+ if ( ! currentLineProfiler ) {
231+ return
232+ }
202233 const editors = vscode . window . visibleTextEditors ;
203234 for ( const editor of editors ) {
235+
204236 if ( editor . document . languageId === 'python' ) {
205237 this . applyToEditor ( editor ) ;
206238 }
@@ -256,8 +288,7 @@ class LineProfilerDecorator implements vscode.Disposable {
256288 }
257289
258290 private generateBackgroundColor ( ratio : number ) : string {
259- const intensity = Math . pow ( ratio , 2.2 ) ;
260- const alpha = + ( intensity * 0.6 ) . toFixed ( 2 ) ;
291+ const alpha = + ( ratio * 0.8 ) . toFixed ( 2 ) ;
261292 const hue = 210 ;
262293 const saturation = 60 ;
263294 const lightness = 65 ;
@@ -279,8 +310,9 @@ class LineProfilerDecorator implements vscode.Disposable {
279310 }
280311
281312 private createPrefixDecoration ( line : number , percent : number , blockColor : string ) : vscode . DecorationOptions {
282- const label = `${ String ( percent ) . padStart ( 3 , ' ' ) } %` ;
283- const textColor = '#f0f0f0' ;
313+ // zero width spcae to void fold
314+ const label = `${ String ( percent ) . padStart ( 3 , ' ' ) } %`
315+ const textColor = percent == 0 ? '#888888' : '#f0f0f0' ;
284316 return {
285317 range : new vscode . Range ( line - 1 , 0 , line - 1 , 0 ) ,
286318 renderOptions : {
@@ -363,7 +395,7 @@ class LineProfilerDecorator implements vscode.Disposable {
363395 for ( const [ line , hits , time ] of records ) {
364396 const blockInfo = blockLevels . get ( line ) ?? { color : this . getBlockColors ( ) [ 0 ] , blockID : 0 } ;
365397 const totalTime = blockTimes . get ( blockInfo . blockID ) ! ;
366- const ratio = time / totalTime ;
398+ const ratio = time / totalTime || 0 ;
367399 const percent = Math . round ( ratio * 100 ) ;
368400
369401 const color = this . generateBackgroundColor ( ratio ) ;
@@ -376,7 +408,6 @@ class LineProfilerDecorator implements vscode.Disposable {
376408 prefixOptions . push ( this . createPrefixDecoration ( line , percent , blockInfo . color ) ) ;
377409 coveredLines . add ( line - 1 ) ;
378410 }
379-
380411 const totalLines = editor . document . lineCount ;
381412 for ( let i = 0 ; i < totalLines ; i ++ ) {
382413 if ( ! coveredLines . has ( i ) ) prefixOptions . push ( this . createPaddingDecoration ( i ) ) ;
@@ -394,6 +425,14 @@ class LineProfilerDecorator implements vscode.Disposable {
394425 }
395426 }
396427
428+ public async clearReadOnlyConfig ( ) : Promise < void > {
429+ const currentInclude : { [ key : string ] : boolean } = vscode . workspace . getConfiguration ( "files" ) . get ( "readonlyInclude" , { } ) ;
430+ for ( const path of this . analysisFilesSet ) {
431+ currentInclude [ path ] = false ;
432+ }
433+ await vscode . workspace . getConfiguration ( "files" ) . update ( "readonlyInclude" , currentInclude , vscode . ConfigurationTarget . Workspace ) ;
434+ }
435+
397436 private formatDuration ( clockTicks : number ) : string {
398437 // Convert from clock ticks to seconds using CLOCKS_PER_SEC
399438 const seconds = clockTicks / ( this . clocksPerSec || 1 ) ;
0 commit comments