1、实现将程序输入输出默认绑定在ide终端中

This commit is contained in:
xuhong 2024-06-12 16:30:10 +08:00
parent a18e33c0a1
commit 47047adc06
3 changed files with 94 additions and 5 deletions

View File

@ -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);
}

View File

@ -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()}`);

View File

@ -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) {