Skip to content

Commit 0adf20d

Browse files
committed
better code separation and Disposable usage
1 parent e4da8dc commit 0adf20d

File tree

1 file changed

+105
-103
lines changed

1 file changed

+105
-103
lines changed

extension/src/goDebugCommands.ts

Lines changed: 105 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -4,136 +4,138 @@
44
*--------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { TextDecoder } from 'util';
8-
9-
// Track sessions since vscode doesn't provide a list of them.
10-
const sessions = new Map<string, vscode.DebugSession>();
11-
vscode.debug.onDidStartDebugSession((s) => sessions.set(s.id, s));
12-
vscode.debug.onDidTerminateDebugSession((s) => sessions.delete(s.id));
137

148
/**
159
* Registers commands to improve the debugging experience for Go.
1610
*
1711
* Currently, it adds a command to open a variable in a new text document.
1812
*/
1913
export function registerGoDebugCommands(ctx: vscode.ExtensionContext) {
20-
class VariableContentProvider implements vscode.TextDocumentContentProvider {
21-
static uriForRef(ref: VariableRef) {
22-
return vscode.Uri.from({
23-
scheme: 'go-debug-variable',
24-
authority: `${ref.container.variablesReference}@${ref.sessionId}`,
25-
path: `/${ref.variable.name}`
26-
});
27-
}
14+
// Track sessions since vscode doesn't provide a list of them.
15+
const sessions = new Map<string, vscode.DebugSession>();
16+
17+
ctx.subscriptions.push(
18+
vscode.debug.onDidStartDebugSession((s) => sessions.set(s.id, s)),
19+
vscode.debug.onDidTerminateDebugSession((s) => sessions.delete(s.id)),
20+
vscode.workspace.registerTextDocumentContentProvider('go-debug-variable', new VariableContentProvider(sessions)),
21+
vscode.commands.registerCommand('go.debug.openVariableAsDoc', async (ref: VariableRef) => {
22+
const uri = VariableContentProvider.uriForRef(ref);
23+
const doc = await vscode.workspace.openTextDocument(uri);
24+
await vscode.window.showTextDocument(doc);
25+
})
26+
);
27+
}
2828

29-
async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
30-
const name = uri.path.replace(/^\//, '');
31-
const [container, sessionId] = uri.authority.split('@', 2);
32-
if (!container || !sessionId) {
33-
throw new Error('Invalid URI');
34-
}
29+
class VariableContentProvider implements vscode.TextDocumentContentProvider {
30+
sessions: Map<string, vscode.DebugSession>
3531

36-
const session = sessions.get(sessionId);
37-
if (!session) return 'Debug session has been terminated';
32+
constructor(sessionsSet: Map<string, vscode.DebugSession>) {
33+
this.sessions = sessionsSet;
34+
}
35+
36+
static uriForRef(ref: VariableRef) {
37+
return vscode.Uri.from({
38+
scheme: 'go-debug-variable',
39+
authority: `${ref.container.variablesReference}@${ref.sessionId}`,
40+
path: `/${ref.variable.name}`
41+
});
42+
}
3843

39-
const { variables } = await session.customRequest('variables', {
40-
variablesReference: parseInt(container, 10)
41-
}) as { variables: Variable[] };
44+
async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
45+
const name = uri.path.replace(/^\//, '');
46+
const [container, sessionId] = uri.authority.split('@', 2);
47+
if (!container || !sessionId) {
48+
throw new Error('Invalid URI');
49+
}
4250

43-
const v = variables.find(v => v.name === name);
44-
if (!v) return `Cannot resolve variable ${name}`;
51+
const session = this.sessions.get(sessionId);
52+
if (!session) return 'Debug session has been terminated';
4553

46-
if (!v.memoryReference) {
47-
const { result } = await session.customRequest('evaluate', {
48-
expression: v.evaluateName,
49-
context: 'clipboard'
50-
}) as { result: string };
54+
const { variables } = await session.customRequest('variables', {
55+
variablesReference: parseInt(container, 10)
56+
}) as { variables: Variable[] };
5157

52-
v.value = result ?? v.value;
58+
const v = variables.find(v => v.name === name);
59+
if (!v) return `Cannot resolve variable ${name}`;
5360

54-
return parseVariable(v);
55-
}
61+
if (!v.memoryReference) {
62+
const { result } = await session.customRequest('evaluate', {
63+
expression: v.evaluateName,
64+
context: 'clipboard'
65+
}) as { result: string };
5666

57-
const chunk = 1 << 14;
58-
let offset = 0;
59-
let full: Uint8Array[] = [];
67+
v.value = result ?? v.value;
6068

61-
while (true) {
62-
const resp = await session.customRequest('readMemory', {
63-
memoryReference: v.memoryReference,
64-
offset,
65-
count: chunk
66-
}) as { address: string; data: string; unreadableBytes: number };
69+
return parseVariable(v);
70+
}
6771

68-
if (!resp.data) break;
69-
full.push(Buffer.from(resp.data, 'base64'));
72+
const chunk = 1 << 14;
73+
let offset = 0;
74+
let full: Uint8Array[] = [];
7075

71-
if (resp.unreadableBytes === 0) break;
72-
offset += chunk;
73-
}
76+
while (true) {
77+
const resp = await session.customRequest('readMemory', {
78+
memoryReference: v.memoryReference,
79+
offset,
80+
count: chunk
81+
}) as { address: string; data: string; unreadableBytes: number };
7482

75-
const allBytes = Buffer.concat(full);
83+
if (!resp.data) break;
84+
full.push(Buffer.from(resp.data, 'base64'));
7685

77-
return new TextDecoder('utf-8').decode(allBytes);
86+
if (resp.unreadableBytes === 0) break;
87+
offset += chunk;
7888
}
89+
90+
return Buffer.concat(full).toString('utf-8');
7991
}
92+
}
8093

81-
ctx.subscriptions.push(
82-
vscode.workspace.registerTextDocumentContentProvider('go-debug-variable', new VariableContentProvider())
83-
);
94+
/**
95+
* A reference to a variable, used to pass data between commands.
96+
*/
97+
interface VariableRef {
98+
sessionId: string;
99+
container: Container;
100+
variable: Variable;
101+
}
84102

85-
ctx.subscriptions.push(
86-
vscode.commands.registerCommand('go.debug.openVariableAsDoc', async (ref: VariableRef) => {
87-
const uri = VariableContentProvider.uriForRef(ref);
88-
const doc = await vscode.workspace.openTextDocument(uri);
89-
await vscode.window.showTextDocument(doc);
90-
})
91-
);
103+
/**
104+
* A container for variables, used to pass data between commands.
105+
*/
106+
interface Container {
107+
name: string;
108+
variablesReference: number;
109+
expensive: boolean;
110+
}
92111

93-
/**
94-
* A reference to a variable, used to pass data between commands.
95-
*/
96-
interface VariableRef {
97-
sessionId: string;
98-
container: Container;
99-
variable: Variable;
100-
}
112+
/**
113+
* A variable, used to pass data between commands.
114+
*/
115+
interface Variable {
116+
name: string;
117+
value: string;
118+
evaluateName: string;
119+
variablesReference: number;
120+
memoryReference?: string;
121+
}
101122

102-
/**
103-
* A container for variables, used to pass data between commands.
104-
*/
105-
interface Container {
106-
name: string;
107-
variablesReference: number;
108-
expensive: boolean;
109-
}
110123

111-
/**
112-
* A variable, used to pass data between commands.
113-
*/
114-
interface Variable {
115-
name: string;
116-
value: string;
117-
evaluateName: string;
118-
variablesReference: number;
119-
memoryReference?: string;
120-
}
121124

122-
const escapeCodes: Record<string, string> = {
123-
r: '\r',
124-
n: '\n',
125-
t: '\t'
126-
};
127-
128-
/**
129-
* Parses a variable value, unescaping special characters.
130-
*/
131-
function parseVariable(variable: Variable) {
132-
let raw = variable.value.trim();
133-
try {
134-
return JSON.parse(raw);
135-
} catch (_) {
136-
return raw.replace(/\\[nrt\\"'`]/, (_, s) => (s in escapeCodes ? escapeCodes[s] : s));
137-
}
125+
const escapeCodes: Record<string, string> = {
126+
r: '\r',
127+
n: '\n',
128+
t: '\t'
129+
};
130+
131+
/**
132+
* Parses a variable value, unescaping special characters.
133+
*/
134+
function parseVariable(variable: Variable) {
135+
let raw = variable.value.trim();
136+
try {
137+
return JSON.parse(raw);
138+
} catch (_) {
139+
return raw.replace(/\\[nrt\\"'`]/, (_, s) => (s in escapeCodes ? escapeCodes[s] : s));
138140
}
139141
}

0 commit comments

Comments
 (0)