src/goDebugFactory: redirect stdout/stderr from dlv to Debug Console

Assuming dlv dap keeps using the default debugger Redirect config
debuggee's stdout/stderr is redirected to dlv dap's stdout/stderr
(https://github.com/go-delve/delve/blob/2e80b32c417494ab3fabe929e7051076a7049f7c/pkg/proc/native/proc.go#L333)

Now this CL wires dlv dap's stderr/stdout with
vscode.debug.activeDebugConsole. Currently stdout and stderr
output are not easily distinguishable. We can consider using
different ASCII color codes, but that must be done carefully
because users' color theme may be different.

Change-Id: I66c62a14ab5659e0789f2d9b16274048995640c4
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/296930
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Polina Sokolova <polina@google.com>
diff --git a/src/goDebugFactory.ts b/src/goDebugFactory.ts
index 28d0ff8..c6b8e16 100644
--- a/src/goDebugFactory.ts
+++ b/src/goDebugFactory.ts
@@ -7,7 +7,6 @@
 import { ChildProcess, ChildProcessWithoutNullStreams, spawn } from 'child_process';
 import * as fs from 'fs';
 import { DebugConfiguration } from 'vscode';
-import { logError, logInfo } from './goLogging';
 import { envPath } from './utils/pathUtils';
 import { killProcessTree } from './utils/processUtils';
 import getPort = require('get-port');
@@ -69,18 +68,14 @@
 	} else {
 		configuration.port = await getPort();
 	}
-	const dlvDapServer = spawnDlvDapServerProcess(configuration, logInfo, logError);
+	const dlvDapServer = spawnDlvDapServerProcess(configuration);
 	// Wait to give dlv-dap a chance to start before returning.
 	return await new Promise<{ port: number; host: string; dlvDapServer: ChildProcessWithoutNullStreams }>((resolve) =>
 		setTimeout(() => resolve({ port: configuration.port, host: configuration.host, dlvDapServer }), 500)
 	);
 }
 
-function spawnDlvDapServerProcess(
-	launchArgs: DebugConfiguration,
-	logFn: (...args: any[]) => void,
-	logErrFn: (...args: any[]) => void
-) {
+function spawnDlvDapServerProcess(launchArgs: DebugConfiguration) {
 	const launchArgsEnv = launchArgs.env || {};
 	const env = Object.assign({}, process.env, launchArgsEnv);
 
@@ -92,7 +87,7 @@
 	}
 
 	if (!fs.existsSync(dlvPath)) {
-		logErrFn(
+		appendToDebugConsole(
 			`Couldn't find dlv at the Go tools path, ${process.env['GOPATH']}${
 				env['GOPATH'] ? ', ' + env['GOPATH'] : ''
 			} or ${envPath}`
@@ -116,13 +111,33 @@
 	if (launchArgs.logOutput) {
 		dlvArgs.push('--log-output=' + launchArgs.logOutput);
 	}
-	logFn(`Running: ${dlvPath} ${dlvArgs.join(' ')}`);
+	appendToDebugConsole(`Running: ${dlvPath} ${dlvArgs.join(' ')}`);
 
 	const dir = parseProgramArgSync(launchArgs).dirname;
-	return spawn(dlvPath, dlvArgs, {
+	const p = spawn(dlvPath, dlvArgs, {
 		cwd: dir,
 		env
 	});
+
+	p.stderr.on('data', (chunk) => {
+		appendToDebugConsole(chunk.toString());
+	});
+	p.stdout.on('data', (chunk) => {
+		appendToDebugConsole(chunk.toString());
+	});
+	p.on('close', (code) => {
+		if (code) {
+			appendToDebugConsole(`Process exiting with code: ${code} signal: ${p.killed}`);
+		} else {
+			appendToDebugConsole(`Process exited normally: ${p.killed}`);
+		}
+	});
+	p.on('error', (err) => {
+		if (err) {
+			appendToDebugConsole(`Error: ${err}`);
+		}
+	});
+	return p;
 }
 
 function parseProgramArgSync(
@@ -144,3 +159,8 @@
 	const dirname = programIsDirectory ? program : path.dirname(program);
 	return { program, dirname, programIsDirectory };
 }
+
+function appendToDebugConsole(msg: string) {
+	// TODO(hyangah): use color distinguishable from the color used from print.
+	vscode.debug.activeDebugConsole.append(msg);
+}