From 30731c2ba167d9dd402a109acfb411f68ada9ce6 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Tue, 23 Feb 2016 17:26:12 +0100 Subject: [PATCH] Added support to run process in a separate console (fix #28) --- README.md | 5 +++++ package.json | 6 +++++- src/backend/backend.ts | 4 ++-- src/backend/linux/console.ts | 21 +++++++++++++++++++++ src/backend/mi2/mi2.ts | 34 ++++++++++++++++++++++++++++------ src/gdb.ts | 6 +++--- 6 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/backend/linux/console.ts diff --git a/README.md b/README.md index 7a2c088..75248a3 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,11 @@ path for GDB to find the debug symbols. This will attach to PID 4285 which should already run. GDB will pause the program on entering. +Additionally you can set `terminal` if you want to run the program in a separate terminal with +support for input. On Windows set it to an empty string (`""`) to enable this feature. On linux +set it to an empty string (`""`) to use the default terminal emulator specified with `x-terminal-emulator` +or specify a custom one. Note that it must support the `-e` argument. + ### Using `gdbserver` for remote debugging You can also connect to a gdbserver instance and debug using that. For that modify the diff --git a/package.json b/package.json index 2944f44..9e9a3ff 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,10 @@ "type": "string", "description": "Arguments to append after the executable. You can also use pipes." }, + "terminal": { + "type": "string", + "description": "Leave this field undefined to keep program output in the vscode console at the bottom. If this is set to empty string the program will spawn in a new console using x-terminal-emulator on linux, otherwise with the specified terminal. On windows setting this to an empty string spawns the program in a console, but no other console is supported." + }, "cwd": { "type": "string", "description": "Path of project" @@ -187,4 +191,4 @@ "typescript": "^1.7.5", "vscode": "0.11.x" } -} +} \ No newline at end of file diff --git a/src/backend/backend.ts b/src/backend/backend.ts index c75dde0..4112a43 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -28,8 +28,8 @@ export interface SSHArguments { } export interface IBackend { - load(cwd: string, target: string, procArgs: string): Thenable; - ssh(args: SSHArguments, cwd: string, target: string, procArgs: string): Thenable; + load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable; + ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string): Thenable; attach(cwd: string, executable: string, target: string): Thenable; connect(cwd: string, executable: string, target: string): Thenable; start(): Thenable; diff --git a/src/backend/linux/console.ts b/src/backend/linux/console.ts new file mode 100644 index 0000000..6ab593c --- /dev/null +++ b/src/backend/linux/console.ts @@ -0,0 +1,21 @@ +import * as ChildProcess from "child_process" +import * as fs from "fs" + +export function spawnTerminalEmulator(preferedEmulator: string): Thenable { + return new Promise((resolve, reject) => { + let ttyFileOutput = "/tmp/vscode-gdb-tty-0" + Math.floor(Math.random() * 100000000).toString(36); + ChildProcess.spawn(preferedEmulator || "x-terminal-emulator", ["-e", "sh -c \"tty > " + ttyFileOutput + " && sleep 4294967294\""]); + let it = 0; + let interval = setInterval(() => { + if (fs.existsSync(ttyFileOutput)) { + clearInterval(interval); + let tty = fs.readFileSync(ttyFileOutput).toString("utf8"); + fs.unlink(ttyFileOutput); + return resolve(tty); + } + it++; + if (it > 500) + reject(); + }, 10); + }); +} \ No newline at end of file diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 33aa523..4a96358 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -2,6 +2,7 @@ import { Breakpoint, IBackend, Stack, SSHArguments } from "../backend.ts" import * as ChildProcess from "child_process" import { EventEmitter } from "events" import { parseMI, MINode } from '../mi_parse'; +import * as linuxTerm from '../linux/console'; import * as net from "net" import * as fs from "fs" import { posix } from "path" @@ -26,7 +27,7 @@ export class MI2 extends EventEmitter implements IBackend { super(); } - load(cwd: string, target: string, procArgs: string): Thenable { + load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { if (!nativePath.isAbsolute(target)) target = nativePath.join(cwd, target); return new Promise((resolve, reject) => { @@ -41,14 +42,35 @@ export class MI2 extends EventEmitter implements IBackend { ]; if (procArgs && procArgs.length) promises.push(this.sendCommand("exec-arguments " + procArgs)); - Promise.all(promises).then(() => { - this.emit("debug-ready") - resolve(); - }, reject); + if (process.platform == "win32") { + if (separateConsole !== undefined) + promises.push(this.sendCommand("gdb-set new-console on")) + Promise.all(promises).then(() => { + this.emit("debug-ready") + resolve(); + }, reject); + } + else { + if (separateConsole !== undefined) { + linuxTerm.spawnTerminalEmulator(separateConsole).then(tty => { + promises.push(this.sendCommand("inferior-tty-set " + tty)); + Promise.all(promises).then(() => { + this.emit("debug-ready") + resolve(); + }, reject); + }); + } + else { + Promise.all(promises).then(() => { + this.emit("debug-ready") + resolve(); + }, reject); + } + } }); } - ssh(args: SSHArguments, cwd: string, target: string, procArgs: string): Thenable { + ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { return new Promise((resolve, reject) => { this.isSSH = true; this.sshReady = false; diff --git a/src/gdb.ts b/src/gdb.ts index 5fdc827..ccc41b6 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -14,6 +14,7 @@ export interface LaunchRequestArguments { cwd: string; target: string; arguments: string; + terminal: string; autorun: string[]; ssh: SSHArguments; printCalls: boolean; @@ -110,7 +111,7 @@ class MI2DebugSession extends DebugSession { this.isSSH = true; this.trimCWD = args.cwd.replace(/\\/g, "/"); this.switchCWD = args.ssh.cwd; - this.gdbDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments).then(() => { + this.gdbDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, args.terminal).then(() => { if (args.autorun) args.autorun.forEach(command => { this.gdbDebugger.sendUserInput(command); @@ -121,7 +122,7 @@ class MI2DebugSession extends DebugSession { }); } else { - this.gdbDebugger.load(args.cwd, args.target, args.arguments).then(() => { + this.gdbDebugger.load(args.cwd, args.target, args.arguments, args.terminal).then(() => { if (args.autorun) args.autorun.forEach(command => { this.gdbDebugger.sendUserInput(command); @@ -357,7 +358,6 @@ class MI2DebugSession extends DebugSession { } protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { - this.handleMsg("console", "Evaluate (" + args.context + "): " + args.expression + "\n") if (args.context == "watch" || args.context == "hover") this.gdbDebugger.evalExpression(args.expression).then((res) => { response.body = {