11import * as vscode from 'vscode' ;
22
3+ // Track sessions since vscode doesn't provide a list of them.
4+ const sessions = new Map < string , vscode . DebugSession > ( ) ;
5+ vscode . debug . onDidStartDebugSession ( ( s ) => sessions . set ( s . id , s ) ) ;
6+ vscode . debug . onDidTerminateDebugSession ( ( s ) => sessions . delete ( s . id ) ) ;
7+
38export function registerGoDebugCommands ( ctx : vscode . ExtensionContext ) {
4- ctx . subscriptions . push (
5- vscode . commands . registerCommand (
6- 'go.debug.openVariableAsDoc' ,
7- async ( args : any ) => {
8- const variable = args . variable ;
9-
10- let raw = variable . value . trim ( ) ;
11- if (
12- ( raw . startsWith ( '"' ) && raw . endsWith ( '"' ) ) ||
13- ( raw . startsWith ( '`' ) && raw . endsWith ( '`' ) )
14- ) {
15- raw = raw . slice ( 1 , - 1 ) ;
16- }
17-
18- let text : string ;
19- try {
20- text = JSON . parse ( `"${ raw . replace ( / " / g, '\\"' ) } "` ) ;
21- } catch {
22- text = raw
23- . replace ( / \\ r / g, '\r' )
24- . replace ( / \\ n / g, '\n' )
25- . replace ( / \\ t / g, '\t' )
26- . replace ( / \\ " / g, '"' )
27- . replace ( / \\ \\ / g, '\\' ) ;
28- }
29-
30- const doc = await vscode . workspace . openTextDocument ( {
31- language : 'plaintext' ,
32- content : text
33- } ) ;
34-
35- const editor = await vscode . window . showTextDocument ( doc ) ;
36-
37- await vscode . commands . executeCommand ( 'workbench.action.editor.changeLanguageMode' ) ;
9+ class VariableContentProvider implements vscode . TextDocumentContentProvider {
10+ static uriForRef ( ref : VariableRef ) {
11+ return vscode . Uri . from ( {
12+ scheme : 'go-debug-variable' ,
13+ authority : `${ ref . container . variablesReference } @${ ref . sessionId } ` ,
14+ path : `/${ ref . variable . name } `
15+ } ) ;
16+ }
17+
18+ async provideTextDocumentContent ( uri : vscode . Uri ) : Promise < string > {
19+ const name = uri . path . replace ( / ^ \/ / , '' ) ;
20+ const [ container , sessionId ] = uri . authority . split ( '@' , 2 ) ;
21+ if ( ! container || ! sessionId ) {
22+ throw new Error ( 'Invalid URI' ) ;
3823 }
39- )
40- )
41- }
24+
25+ const session = sessions . get ( sessionId ) ;
26+ if ( ! session ) return 'Debug session has been terminated' ;
27+
28+ const r : { variables : Variable [ ] } = await session . customRequest ( 'variables' , {
29+ variablesReference : parseInt ( container , 10 )
30+ } ) ;
31+
32+ const v = r . variables . find ( ( v ) => v . name === name ) ;
33+ if ( ! v ) return `Cannot resolve variable ${ name } ` ;
34+
35+ const { result } = await session . customRequest ( 'evaluate' , {
36+ expression : v . evaluateName ,
37+ context : 'clipboard'
38+ } ) ;
39+
40+ v . value = result ?? v . value ;
41+
42+ return parseVariable ( v ) ;
43+ }
44+ }
45+
46+ ctx . subscriptions . push (
47+ vscode . workspace . registerTextDocumentContentProvider ( 'go-debug-variable' , new VariableContentProvider ( ) )
48+ ) ;
49+
50+ ctx . subscriptions . push (
51+ vscode . commands . registerCommand ( 'go.debug.openVariableAsDoc' , async ( ref : VariableRef ) => {
52+ const uri = VariableContentProvider . uriForRef ( ref ) ;
53+ const doc = await vscode . workspace . openTextDocument ( uri ) ;
54+ await vscode . window . showTextDocument ( doc ) ;
55+ } )
56+ ) ;
57+
58+ interface VariableRef {
59+ sessionId : string ;
60+ container : Container ;
61+ variable : Variable ;
62+ }
63+
64+ interface Container {
65+ name : string ;
66+ variablesReference : number ;
67+ expensive : boolean ;
68+ }
69+
70+ interface Variable {
71+ name : string ;
72+ value : string ;
73+ evaluateName : string ;
74+ variablesReference : number ;
75+ }
76+
77+ const escapeCodes : Record < string , string > = {
78+ r : '\r' ,
79+ n : '\n' ,
80+ t : '\t'
81+ } ;
82+
83+ function parseVariable ( variable : Variable ) {
84+ let raw = variable . value . trim ( ) ;
85+ try {
86+ // Attempt to parse as JSON
87+ return JSON . parse ( raw ) ;
88+ } catch ( _ ) {
89+ // Fall back to manual unescaping
90+ raw = raw . slice ( 1 , - 1 ) ;
91+ }
92+
93+ // Manually unescape
94+ return raw . replace ( / \\ [ n r t \\ " ' ` ] / , ( _ , s ) => ( s in escapeCodes ? escapeCodes [ s ] : s ) ) ;
95+ }
96+ }
0 commit comments