Skip to content

Commit a6f3179

Browse files
copy debug object to JSON
1 parent cf89d47 commit a6f3179

File tree

5 files changed

+94
-3
lines changed

5 files changed

+94
-3
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
## [1.7.6] 2024-04-13
4+
5+
### Added
6+
7+
-export debug object as JSON
8+
39
## [1.7.2] 2023-10-31
410

511
### Added

client/src/adt/debugger/abapDebugSession.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export interface AbapDebugSessionCfg extends DebugSession {
1919
export class AbapDebugSession extends LoggingDebugSession {
2020
private closed?: () => void
2121
private static sessions = new Map<string, AbapDebugSession>()
22+
public static get activeSessions() {
23+
return this.sessions.size
24+
}
2225
private lasttargetId = 0
2326
static byConnection(connId: string) {
2427
return AbapDebugSession.sessions.get(connId)

client/src/adt/debugger/variableManager.ts

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { debugMetaIsComplex, DebugMetaType, DebugVariable } from "abap-adt-api"
1+
import { ADTClient, debugMetaIsComplex, DebugMetaType, DebugVariable } from "abap-adt-api"
22
import { Handles, Scope } from "vscode-debugadapter"
33
import { DebugProtocol } from "vscode-debugprotocol"
44
import { DebugListener } from "./debugListener"
55
import { idThread, STACK_THREAD_MULTIPLIER } from "./debugService"
6+
import { AbapFsCommands, command } from "../../commands"
7+
import { env, window } from "vscode"
8+
import { AbapDebugSession } from "./abapDebugSession"
69

710
interface Variable {
811
id: string,
@@ -24,6 +27,7 @@ const isDebugVariable = (v: DebugVariable | { id: string; name: string }): v is
2427
export class VariableManager {
2528
private handles = new Map<number, Handles<Variable>>()// will be overwritten at first use
2629
private currentStackId = 0
30+
private static lastCalled: VariableManager | undefined
2731

2832
private variableHandles(threadId: number) {
2933
const handle = this.handles.get(threadId)
@@ -54,6 +58,7 @@ export class VariableManager {
5458
const threadId = idThread(frameId)
5559
const client = this.client(threadId)
5660
if (!client) return []
61+
VariableManager.lastCalled = this
5762
const currentStack = this.stackTrace(threadId).find(s => s.id === frameId)
5863
if (currentStack && !isNaN(currentStack.stackPosition) && frameId !== this.currentStackId) {
5964
await client.debuggerGoToStack(currentStack.stackUri || currentStack.stackPosition)
@@ -80,12 +85,77 @@ export class VariableManager {
8085
}
8186
return client.debuggerChildVariables([parent.id]).then(r => r.variables)
8287
}
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|INT8|P|N|DECFLOAT16|DECFLOAT34|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+
}
83148
async evaluate(expression: string, frameId?: number): Promise<DebugProtocol.EvaluateResponse["body"] | undefined> {
84149
try {
85150
const threadId = frameId && idThread(frameId)
86151
if (!threadId) return
87152
const client = this.client(threadId)
88153
if (!client) return
154+
const jse = expression.match(/^json\((.*)\)\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+
}
89159
const v = await client.debuggerVariables([expression])
90160
if (!v[0]) return
91161
return { result: variableValue(v[0]), variablesReference: this.variableReference(v[0], threadId) }
@@ -107,7 +177,8 @@ export class VariableManager {
107177
name: `${v.NAME}`,
108178
value: variableValue(v),
109179
variablesReference: this.variableReference(v, vari.threadId),
110-
memoryReference: `${v.ID}`
180+
memoryReference: `${v.ID}`,
181+
evaluateName: `${v.ID}`
111182
}))
112183
return variables
113184
}

client/src/commands/registry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const AbapFsCommands = {
1919
showDump: "abapfs.showDump",
2020
refreshDumps: "abapfs.refreshDumps",
2121
tableContents: "abapfs.tableContents",
22+
exportToJson: "abapfs.exportToJson",
2223
// atc
2324
atcChecks: "abapfs.atcChecks",
2425
atcIgnore: "abapfs.atcIgnore",

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@
205205
"command": "abapfs.search",
206206
"title": "AbapFs Search for object"
207207
},
208+
{
209+
"command": "abapfs.exportToJson",
210+
"title": "Export to JSON (clipboard)"
211+
},
208212
{
209213
"command": "abapfs.create",
210214
"title": "AbapFs Create object"
@@ -1091,6 +1095,12 @@
10911095
"when": "resourceScheme == adt",
10921096
"group": "4_search@1"
10931097
}
1098+
],
1099+
"debug/variables/context": [
1100+
{
1101+
"command": "abapfs.exportToJson",
1102+
"when": "debugType == abap"
1103+
}
10941104
]
10951105
},
10961106
"configuration": {
@@ -1293,4 +1303,4 @@
12931303
}
12941304
}
12951305
}
1296-
}
1306+
}

0 commit comments

Comments
 (0)