const { LoggingDebugSession, InitializedEvent, TerminatedEvent, OutputEvent, StoppedEvent, Thread } = require('vscode-debugadapter'); const { spawn } = require('child_process'); class MyLuaDebugSession extends LoggingDebugSession { constructor() { super("myLuaDebug.txt"); console.log("ADAPTER INICIADO"); this._stackFrames = []; this.setDebuggerLinesStartAt1(true); this.setDebuggerColumnsStartAt1(true); } initializeRequest(response, args) { this.sendEvent(new InitializedEvent()); response.body = { supportsConfigurationDoneRequest: true }; this.sendResponse(response); } pendingStackTrace(frames) { this._stackFrames = frames; } handleLine(line) { if (line.startsWith("@@DEBUG@@")) { const json = JSON.parse(line.substring(9)); if (json.type === "luaError") { const e = new OutputEvent(json.message + "\n", "stderr"); e.body.source = { path: json.file }; e.body.line = json.line; this.sendEvent(e); return; } if (json.type === "break") { this.currentFile = json.file; this.currentLine = json.line; this.sendEvent(new StoppedEvent("breakpoint", 1)); return; } if (json.type === "stackTrace") { this.pendingStackTrace(json.payload.frames); return; } return; } // salida normal this.sendEvent(new OutputEvent(line + "\n", "stdout")); } launchRequest(response, args) { const program = args.program; const cwd = args.cwd || process.cwd(); this.process = spawn(program, [], { cwd: cwd, stdio: ['pipe', 'pipe', 'pipe'] }); this.stdoutBuffer = ""; this.process.stdout.on('data', data => { this.stdoutBuffer += data.toString(); let idx; while ((idx = this.stdoutBuffer.indexOf("\n")) >= 0) { const line = this.stdoutBuffer.slice(0, idx).trim(); this.stdoutBuffer = this.stdoutBuffer.slice(idx + 1); this.handleLine(line); } }); this.process.stderr.on('data', data => { this.sendEvent(new OutputEvent(data.toString(), "stderr")); }); this.process.on('exit', () => { this.sendEvent(new TerminatedEvent()); }); this.sendResponse(response); } sendDebugCommand(obj) { if (!this.process || !this.process.stdin) return; console.log("ENVIANDO CMD:", obj); const msg = "@@DEBUGCMD@@" + JSON.stringify(obj) + "\n"; this.process.stdin.write(msg); } nextRequest(response, args) { this.sendDebugCommand({ cmd: "stepOver" }); this.sendResponse(response); } stepInRequest(response, args) { this.sendDebugCommand({ cmd: "stepInto" }); this.sendResponse(response); } stepOutRequest(response, args) { this.sendDebugCommand({ cmd: "stepOut" }); this.sendResponse(response); } setBreakPointsRequest(response, args) { const path = args.source.path; // archivo donde se han puesto breakpoints const clientBreakpoints = args.breakpoints || []; // Extraemos solo las líneas const lines = clientBreakpoints.map(bp => bp.line); // Guardamos internamente los breakpoints if (!this.breakpoints) this.breakpoints = {}; this.breakpoints[path] = lines; // Enviamos los breakpoints a tu aplicación por stdin const msg = { cmd: "setBreakpoints", file: path, lines: lines }; this.sendDebugCommand(msg); //this.process.stdin.write( // "@@DEBUGCMD@@" + JSON.stringify(msg) + "\n" //); // VSCode necesita una respuesta con los breakpoints "verificados" response.body = { breakpoints: lines.map(line => ({ verified: true, line: line })) }; this.sendResponse(response); } continueRequest(response, args) { const msg = { cmd: "continue" }; this.sendDebugCommand(msg); //this.process.stdin.write( // "@@DEBUGCMD@@" + JSON.stringify(msg) + "\n" //); this.sendResponse(response); } pauseRequest(response, args) { this.sendDebugCommand({ cmd: "pause" }); this.sendResponse(response); } stackTraceRequest(response, args) { // Pedimos al motor el stack trace this.sendDebugCommand({ cmd: "stackTrace" }); // IMPORTANTE: el motor responde async, así que esperamos // a que llegue el mensaje @@DEBUG@@ con type=stackTrace const check = () => { if (this._stackFrames.length > 0) { const frames = this._stackFrames; this._stackFrames = []; response.body = { stackFrames: frames.map((f, i) => ({ id: i + 1, name: f.name, source: { path: f.file }, line: f.line, column: 1 })), totalFrames: frames.length }; this.sendResponse(response); } else { setTimeout(check, 5); } }; check(); } disconnectRequest(response, args) { const msg = { cmd: "continue" }; // por si estaba pausado this.sendDebugCommand(msg); //this.process.stdin.write("@@DEBUGCMD@@" + JSON.stringify(msg) + "\n"); this.process.kill(); this.sendResponse(response); } threadsRequest(response) { // VSCode exige al menos un thread response.body = { threads: [ new Thread(1, "Main Thread") ] }; this.sendResponse(response); } stackTraceRequest(response, args) { response.body = { stackFrames: [ { id: 1, name: "Lua", source: { path: this.currentFile }, line: this.currentLine, column: 1 } ], totalFrames: 1 }; this.sendResponse(response); } configurationDoneRequest(response, args) { this.sendResponse(response); } } new MyLuaDebugSession().start(process.stdin, process.stdout);