1、实现将程序输入输出默认绑定在ide终端中
This commit is contained in:
parent
a18e33c0a1
commit
47047adc06
|
@ -106,8 +106,8 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
resolve(undefined);
|
||||
}, reject);
|
||||
} else {
|
||||
if (separateConsole !== undefined) {
|
||||
linuxTerm.spawnTerminalEmulator(separateConsole).then(tty => {
|
||||
if (separateConsole === 'external') {
|
||||
linuxTerm.spawnTerminalEmulator('').then(tty => {
|
||||
promises.push(this.sendCommand("inferior-tty-set " + tty));
|
||||
Promise.all(promises).then(() => {
|
||||
this.emit("debug-ready");
|
||||
|
@ -116,7 +116,9 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
});
|
||||
} else {
|
||||
Promise.all(promises).then(() => {
|
||||
this.emit("debug-ready");
|
||||
if(!this.application.includes('gdb')){
|
||||
this.emit("debug-ready");
|
||||
}
|
||||
resolve(undefined);
|
||||
}, reject);
|
||||
}
|
||||
|
|
15
src/gdb.ts
15
src/gdb.ts
|
@ -44,6 +44,7 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
|
|||
export class GDBDebugSession extends MI2DebugSession {
|
||||
public args:LaunchRequestArguments | AttachRequestArguments;
|
||||
protected disassember: GdbDisassembler;
|
||||
protected supportsRunInTerminalRequest = false;
|
||||
|
||||
protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
|
||||
response.body.supportsGotoTargetsRequest = true;
|
||||
|
@ -63,9 +64,10 @@ export class GDBDebugSession extends MI2DebugSession {
|
|||
response.body.supportsDisassembleRequest = true;
|
||||
response.body.supportsReadMemoryRequest = true;
|
||||
response.body.supportsInstructionBreakpoints = true;
|
||||
|
||||
args.supportsRunInTerminalRequest = true;
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: max-line-length
|
||||
public sendErrorResponsePub(response: DebugProtocol.Response, codeOrMessage: number | DebugProtocol.Message, format?: string, variables?: any, dest?: any): void {
|
||||
this.sendErrorResponse(response, codeOrMessage, format, variables, dest);
|
||||
|
@ -125,6 +127,17 @@ export class GDBDebugSession extends MI2DebugSession {
|
|||
args.autorun.forEach(command => {
|
||||
this.miDebugger.sendUserInput(command);
|
||||
});
|
||||
if(this.miDebugger.application === 'gdb'){
|
||||
if(args.terminal === 'integrated' || args.terminal === '' || args.terminal === undefined){
|
||||
let terminalRequestArgs:DebugProtocol.RunInTerminalRequestArguments = {
|
||||
kind: "integrated",
|
||||
title: this.miDebugger.application,
|
||||
cwd: args.cwd || '',
|
||||
args: [],
|
||||
};
|
||||
this.createIntegratedTerminalLinux(terminalRequestArgs);
|
||||
}
|
||||
}
|
||||
this.sendResponse(response);
|
||||
}, err => {
|
||||
this.sendErrorResponse(response, 103, `Failed to load MI Debugger: ${err.toString()}`);
|
||||
|
|
|
@ -11,17 +11,19 @@ import * as net from "net";
|
|||
import * as os from "os";
|
||||
import * as fs from "fs";
|
||||
import { hexFormat } from './backend/common';
|
||||
export type InferiorTerminal = 'integrated' | 'external' | '';
|
||||
|
||||
class ExtendedVariable {
|
||||
constructor(public name, public options) {
|
||||
}
|
||||
}
|
||||
|
||||
export enum RunCommand { CONTINUE, RUN, NONE }
|
||||
|
||||
const STACK_HANDLES_START = 1000;
|
||||
const VAR_HANDLES_START = 512 * 256 + 1000;
|
||||
const VARIABLES_TAG_REGISTER = 0xab;
|
||||
|
||||
|
||||
export class MI2DebugSession extends DebugSession {
|
||||
protected variableHandles = new Handles<string | VariableObject | ExtendedVariable>(VAR_HANDLES_START);
|
||||
protected variableHandlesReverse: { [id: string]: number } = {};
|
||||
|
@ -853,6 +855,78 @@ export class MI2DebugSession extends DebugSession {
|
|||
}
|
||||
}
|
||||
|
||||
public async createIntegratedTerminalLinux(args:DebugProtocol.RunInTerminalRequestArguments) {
|
||||
const mkdirAsync = fs.promises.mkdir;
|
||||
const mkdtempAsync = async (tempDir: string, prefix: string): Promise<string> => {
|
||||
const name = `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
|
||||
const newDirPath = `${tempDir}/${name}`;
|
||||
|
||||
try {
|
||||
await mkdirAsync(newDirPath, { recursive: true });
|
||||
return newDirPath;
|
||||
} catch (err) {
|
||||
throw new Error(`Error creating temp directory: ${err.message}`);
|
||||
}
|
||||
};
|
||||
const ttyTmpDir = await mkdtempAsync(os.tmpdir(), 'debug');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
`${ttyTmpDir}/get-tty`,
|
||||
`#!/usr/bin/env sh
|
||||
clear
|
||||
echo "The input and output of program will be here."
|
||||
echo "Warning of set controlling terminal fail can be ignored."
|
||||
tty > ${ttyTmpDir}/ttynameTmp
|
||||
mv ${ttyTmpDir}/ttynameTmp ${ttyTmpDir}/ttyname
|
||||
# wait for debug to finish
|
||||
# prefer using tail to detect PID exit, but that requires GNU tail
|
||||
tail -f --pid=${process.pid} /dev/null 2>/dev/null || while kill -s 0 ${process.pid} 2>/dev/null; do sleep 1s; done
|
||||
# cleanup
|
||||
rm ${ttyTmpDir}/ttyname
|
||||
rm ${ttyTmpDir}/get-tty
|
||||
rmdir ${ttyTmpDir}
|
||||
`
|
||||
);
|
||||
|
||||
let watcher: fs.FSWatcher | undefined;
|
||||
const ttyNamePromise = new Promise<string>((resolve) => {
|
||||
watcher = fs.watch(ttyTmpDir, (_eventType, filename) => {
|
||||
if (filename === 'ttyname') {
|
||||
watcher?.close();
|
||||
resolve(
|
||||
fs.readFileSync(`${ttyTmpDir}/ttyname`).toString().trim()
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
args.args = ['/bin/sh', `${ttyTmpDir}/get-tty`];
|
||||
const response = await new Promise<DebugProtocol.Response>(
|
||||
(resolve) =>
|
||||
this.sendRequest(
|
||||
'runInTerminal',
|
||||
args,
|
||||
3000,
|
||||
resolve
|
||||
)
|
||||
);
|
||||
if (response.success) {
|
||||
const tty = await ttyNamePromise;
|
||||
this.miDebugger.emit("debug-ready");
|
||||
await this.miDebugger.sendCommand(`inferior-tty-set ${tty}`);
|
||||
return;
|
||||
} else {
|
||||
watcher?.close();
|
||||
const message = `could not start the terminal on the client: ${response.message}`;
|
||||
throw new Error(message);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function prettyStringArray(strings) {
|
||||
|
|
Loading…
Reference in New Issue