Skip to content

Commit 647ae9e

Browse files
lock the file to privent modify unexpectedly
1 parent fb09506 commit 647ae9e

File tree

4 files changed

+76
-13
lines changed

4 files changed

+76
-13
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
"out": true // set this to false to include "out" folder in search results
88
},
99
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10-
"typescript.tsc.autoDetect": "off"
10+
"typescript.tsc.autoDetect": "off",
1111
}

package.json

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"Other"
2222
],
2323
"activationEvents": [
24-
"onDebug"
24+
"onDebug",
25+
"onCommand:commandId"
2526
],
2627
"main": "./out/extension.js",
2728
"contributes": {
@@ -30,8 +31,26 @@
3031
"category": "pocketpy",
3132
"command": "pocketpy.loadProfilerReportJson",
3233
"title": "Load Line Profiler Report"
34+
},
35+
{
36+
"category": "pocketpy",
37+
"command": "pocketpy.quitProfilerReportMode",
38+
"title": "Quit Profiler Report Mode"
3339
}
3440
],
41+
"menus": {
42+
"editor/context": [
43+
{
44+
"command": "pocketpy.quitProfilerReportMode",
45+
"when": "editorFocus && pocketpy.isInProfilerReportMode"
46+
}
47+
]
48+
},
49+
"keybindings": {
50+
"command": "pocketpy.quitProfilerReportMode",
51+
"when": "editorFocus && pocketpy.isInProfilerReportMode",
52+
"key": "escape"
53+
},
3554
"breakpoints": [
3655
{
3756
"language": "python"
@@ -95,7 +114,7 @@
95114
},
96115
"description": "Arguments to pass to the program."
97116
},
98-
"cwd" : {
117+
"cwd": {
99118
"type": "string",
100119
"description": "Current working directory for the program."
101120
}
@@ -119,7 +138,9 @@
119138
"host": "localhost",
120139
"sourceFolder": "${workspaceFolder}",
121140
"program": "${workspaceFolder}/pocketpy/main.exe",
122-
"args": ["--debug"],
141+
"args": [
142+
"--debug"
143+
],
123144
"cwd": "${workspaceFolder}"
124145
}
125146
]

samples/.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"files.readonlyInclude": {}
3+
}

src/extension.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7391
export function deactivate() { }
7492

7593

94+
7695
async 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+
170190
let currentLineProfiler: LineProfilerDecorator | undefined;
171191
type 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

Comments
 (0)