1
- import { debugMetaIsComplex , DebugMetaType , DebugVariable } from "abap-adt-api"
1
+ import { ADTClient , debugMetaIsComplex , DebugMetaType , DebugVariable } from "abap-adt-api"
2
2
import { Handles , Scope } from "vscode-debugadapter"
3
3
import { DebugProtocol } from "vscode-debugprotocol"
4
4
import { DebugListener } from "./debugListener"
5
5
import { idThread , STACK_THREAD_MULTIPLIER } from "./debugService"
6
+ import { AbapFsCommands , command } from "../../commands"
7
+ import { env , window } from "vscode"
8
+ import { AbapDebugSession } from "./abapDebugSession"
6
9
7
10
interface Variable {
8
11
id : string ,
@@ -24,6 +27,7 @@ const isDebugVariable = (v: DebugVariable | { id: string; name: string }): v is
24
27
export class VariableManager {
25
28
private handles = new Map < number , Handles < Variable > > ( ) // will be overwritten at first use
26
29
private currentStackId = 0
30
+ private static lastCalled : VariableManager | undefined
27
31
28
32
private variableHandles ( threadId : number ) {
29
33
const handle = this . handles . get ( threadId )
@@ -54,6 +58,7 @@ export class VariableManager {
54
58
const threadId = idThread ( frameId )
55
59
const client = this . client ( threadId )
56
60
if ( ! client ) return [ ]
61
+ VariableManager . lastCalled = this
57
62
const currentStack = this . stackTrace ( threadId ) . find ( s => s . id === frameId )
58
63
if ( currentStack && ! isNaN ( currentStack . stackPosition ) && frameId !== this . currentStackId ) {
59
64
await client . debuggerGoToStack ( currentStack . stackUri || currentStack . stackPosition )
@@ -80,12 +85,77 @@ export class VariableManager {
80
85
}
81
86
return client . debuggerChildVariables ( [ parent . id ] ) . then ( r => r . variables )
82
87
}
88
+ async dumpJson ( client : ADTClient , name : string | DebugVariable ) {
89
+ const v = typeof name !== "string" ? name : await client . debuggerVariables ( [ name ] ) . then ( v => v [ 0 ] )
90
+ if ( ! v ) return
91
+ switch ( v . META_TYPE ) {
92
+ case "simple" :
93
+ if ( v . TECHNICAL_TYPE . match ( / B | S | I | I N T 8 | P | N | D E C F L O A T 1 6 | D E C F L O A T 3 4 | F / ) ) return Number ( v . VALUE )
94
+ return v . VALUE . trimEnd ( )
95
+ case "string" :
96
+ return v . VALUE . trimEnd ( )
97
+ case "structure" :
98
+ const comps = await client . debuggerChildVariables ( [ v . ID ] ) . then ( r => r . variables )
99
+ const str : any = { }
100
+ for ( const comp of comps ) {
101
+ const cv = await this . dumpJson ( client , comp )
102
+ str [ comp . NAME ] = cv
103
+ }
104
+ return str
105
+ case "table" :
106
+ const outlines : any [ ] = [ ]
107
+ const keys = [ ...Array ( v . TABLE_LINES ) . keys ( ) ] . map ( k => `${ v . NAME } [${ k + 1 } ]` )
108
+ const linevars = await client . debuggerVariables ( keys )
109
+ for ( const lv of linevars ) {
110
+ const line = await this . dumpJson ( client , lv )
111
+ outlines . push ( line )
112
+ }
113
+ return outlines
114
+ case "unknown" :
115
+ case "dataref" :
116
+ case "boxedcomp" :
117
+ case "anonymcomp" :
118
+ case "objectref" :
119
+ case "class" :
120
+ case "object" :
121
+ case "boxref" :
122
+ case "anonymcomp" :
123
+ return `Unprocessable:${ v . META_TYPE } `
124
+ }
125
+ }
126
+
127
+ private static currentClient ( variablesReference : number ) : [ VariableManager , ADTClient ] | undefined {
128
+ const vm = VariableManager . lastCalled
129
+ if ( ! vm ) return
130
+ const threadId = idThread ( variablesReference )
131
+ const client = vm . client ( threadId )
132
+ if ( ! client ) return
133
+ return [ vm , client ]
134
+ }
135
+
136
+ @command ( AbapFsCommands . exportToJson )
137
+ private static async exportJson ( arg : { container : { variablesReference : number } , variable : { name : string } } ) {
138
+ const [ vm , client ] = this . currentClient ( arg . container . variablesReference ) || [ ]
139
+ if ( ! vm || ! client ) {
140
+ window . showErrorMessage ( "No active debug session detected" )
141
+ return
142
+ }
143
+ if ( AbapDebugSession . activeSessions > 1 ) window . showWarningMessage ( "Multiple debug session detected. might export from wrong one" )
144
+ const json = await vm . dumpJson ( client , arg . variable . name )
145
+ env . clipboard . writeText ( JSON . stringify ( json , null , 1 ) )
146
+
147
+ }
83
148
async evaluate ( expression : string , frameId ?: number ) : Promise < DebugProtocol . EvaluateResponse [ "body" ] | undefined > {
84
149
try {
85
150
const threadId = frameId && idThread ( frameId )
86
151
if ( ! threadId ) return
87
152
const client = this . client ( threadId )
88
153
if ( ! client ) return
154
+ const jse = expression . match ( / ^ j s o n \( ( .* ) \) \s * $ / )
155
+ if ( jse ?. [ 1 ] ) {
156
+ const json = await this . dumpJson ( client , jse [ 1 ] )
157
+ return { result : JSON . stringify ( json , null , 1 ) , variablesReference : 0 }
158
+ }
89
159
const v = await client . debuggerVariables ( [ expression ] )
90
160
if ( ! v [ 0 ] ) return
91
161
return { result : variableValue ( v [ 0 ] ) , variablesReference : this . variableReference ( v [ 0 ] , threadId ) }
@@ -107,7 +177,8 @@ export class VariableManager {
107
177
name : `${ v . NAME } ` ,
108
178
value : variableValue ( v ) ,
109
179
variablesReference : this . variableReference ( v , vari . threadId ) ,
110
- memoryReference : `${ v . ID } `
180
+ memoryReference : `${ v . ID } ` ,
181
+ evaluateName : `${ v . ID } `
111
182
} ) )
112
183
return variables
113
184
}
0 commit comments