terminal support

This commit is contained in:
Vadim Lopatin 2016-06-06 15:43:13 +03:00
parent fd0f10bfc5
commit 8dd29d78a0
7 changed files with 78 additions and 25 deletions

View File

@ -303,6 +303,11 @@ class DebuggerProxy : Debugger, DebuggerCallback {
_debugger.setTerminalExecutable(terminalExecutable);
}
/// set terminal device name before execution
void setTerminalTty(string terminalTty) {
_debugger.setTerminalTty(terminalTty);
}
/// set debugger executable
void setDebuggerExecutable(string debuggerExecutable) {
_debugger.setDebuggerExecutable(debuggerExecutable);
@ -413,7 +418,7 @@ abstract class DebuggerBase : Thread, Debugger {
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
mixin ExecutableParams;
/// provides _terminalExecutable and setTerminalExecutable setter
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
mixin TerminalParams;
protected DebuggerCallback _callback;

View File

@ -23,6 +23,8 @@ interface ProgramExecution {
void setExecutableParams(string executableFile, string[] args, string workingDir, string[string] envVars);
/// set external terminal parameters before execution
void setTerminalExecutable(string terminalExecutable);
/// set external terminal tty before execution
void setTerminalTty(string terminalTty);
/// returns true if it's debugger
@property bool isDebugger();
@ -53,15 +55,20 @@ mixin template ExecutableParams() {
}
/// provides _terminalExecutable and setTerminalExecutable setter
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
mixin template TerminalParams() {
/// executable file name for external console/terminal
protected string _terminalExecutable;
protected string _terminalTty;
/// set external terminal parameters before execution
void setTerminalExecutable(string terminalExecutable) {
_terminalExecutable = terminalExecutable;
}
void setTerminalTty(string terminalTty) {
_terminalTty = terminalTty;
}
}

View File

@ -11,7 +11,7 @@ class ProgramExecutionNoDebug : Thread, ProgramExecution {
// parameters
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
mixin ExecutableParams;
/// provides _terminalExecutable and setTerminalExecutable setter
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
mixin TerminalParams;
protected ProgramExecutionStatusListener _listener;

View File

@ -115,9 +115,11 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
}
Pid terminalPid;
string terminalTty;
string externalTerminalTty;
string startTerminal() {
if (!_terminalTty.empty)
return _terminalTty;
Log.d("Starting terminal ", _terminalExecutable);
import std.random;
import std.file;
@ -125,7 +127,7 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
import std.string;
import core.thread;
uint n = uniform(0, 0x10000000, rndGen());
terminalTty = null;
externalTerminalTty = null;
string termfile = buildPath(tempDir, format("dlangide-term-name-%07x.tmp", n));
Log.d("temp file for tty name: ", termfile);
try {
@ -151,27 +153,29 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
}
// read TTY from file
if (exists(termfile)) {
terminalTty = readText(termfile);
if (terminalTty.endsWith("\n"))
terminalTty = terminalTty[0 .. $-1];
externalTerminalTty = readText(termfile);
if (externalTerminalTty.endsWith("\n"))
externalTerminalTty = externalTerminalTty[0 .. $-1];
// delete file
remove(termfile);
Log.d("Terminal tty: ", terminalTty);
Log.d("Terminal tty: ", externalTerminalTty);
}
} catch (Exception e) {
Log.e("Failed to start terminal ", e);
killTerminal();
}
if (terminalTty.length == 0) {
if (externalTerminalTty.length == 0) {
Log.i("Cannot start terminal");
killTerminal();
} else {
Log.i("Terminal: ", terminalTty);
Log.i("Terminal: ", externalTerminalTty);
}
return terminalTty;
return externalTerminalTty;
}
bool isTerminalActive() {
if (!_terminalTty.empty)
return true;
if (_terminalExecutable.empty)
return true;
if (terminalPid is null)
@ -188,6 +192,8 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
}
void killTerminal() {
if (!_terminalTty.empty)
return;
if (_terminalExecutable.empty)
return;
if (terminalPid is null)
@ -208,16 +214,18 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
override void startDebugging() {
Log.d("GDBInterface.startDebugging()");
string[] debuggerArgs;
if (!_terminalExecutable.empty) {
terminalTty = startTerminal();
if (terminalTty.length == 0) {
if (!_terminalExecutable.empty || !_terminalTty.empty) {
externalTerminalTty = startTerminal();
if (externalTerminalTty.length == 0) {
//_callback.onResponse(ResponseCode.CannotRunDebugger, "Cannot start terminal");
_status = ExecutionStatus.Error;
_stopRequested = true;
return;
}
debuggerArgs ~= "-tty";
debuggerArgs ~= terminalTty;
if (!USE_INIT_SEQUENCE) {
debuggerArgs ~= "-tty";
debuggerArgs ~= externalTerminalTty;
}
}
debuggerArgs ~= "--interpreter=mi";
debuggerArgs ~= "--silent";
@ -677,8 +685,8 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
initRequestsWarnings = 0;
finishedInitRequests = 0;
submitRequest(new GDBInitRequest("-environment-cd " ~ quotePathIfNeeded(_executableWorkingDir), true));
if (terminalTty)
submitRequest(new GDBInitRequest("-inferior-tty-set " ~ terminalTty, true));
if (externalTerminalTty)
submitRequest(new GDBInitRequest("-inferior-tty-set " ~ quotePathIfNeeded(externalTerminalTty), true));
submitRequest(new GDBInitRequest("-gdb-set breakpoint pending on", false));
submitRequest(new GDBInitRequest("-enable-pretty-printing", false));

View File

@ -179,6 +179,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
switch(status) {
case ExecutionStatus.Error:
_logPanel.logLine("Cannot run program " ~ process.executableFile);
_logPanel.activateLogTab();
break;
case ExecutionStatus.Finished:
_logPanel.logLine("Program " ~ process.executableFile ~ " finished with exit code " ~ to!string(exitCode));
@ -274,8 +275,14 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_logPanel.logLine("Starting debugger for " ~ executableFileName);
_statusLine.setBackgroundOperationStatus("debug-run", program.isDebugger ? "debugging..."d : "running..."d);
string[string] env;
string tty = _logPanel.terminalDeviceName;
program.setExecutableParams(executableFileName, args, workingDirectory, env);
program.setTerminalExecutable(externalConsoleExecutable);
if (!tty.empty) {
Log.d("Terminal window device name: ", tty);
program.setTerminalTty(tty);
_logPanel.activateTerminalTab(true);
} else
program.setTerminalExecutable(externalConsoleExecutable);
return true;
}
@ -1375,6 +1382,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
_logPanel.logLine("No project is opened");
return;
}
_logPanel.activateLogTab();
if (!listener) {
if (buildOp == BuildOperation.Upgrade || buildOp == BuildOperation.Build || buildOp == BuildOperation.Rebuild) {
listener = delegate(int result) {

View File

@ -132,12 +132,29 @@ class OutputPanel : DockWindow {
@property TabWidget getTabs() { return _tabs;}
void activateLogTab() {
_tabs.selectTab("logwidget");
}
void activateTerminalTab(bool clear = false) {
_tabs.selectTab("TERMINAL");
if (clear)
_terminalWidget.resetTerminal();
}
this(string id) {
_showCloseButton = false;
dockAlignment = DockAlignment.Bottom;
super(id);
}
/// terminal device for Console tab
@property string terminalDeviceName() {
if (_terminalWidget)
return _terminalWidget.deviceName;
return null;
}
override protected Widget createBodyWidget() {
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
_tabs = new TabWidget("OutputPanelTabs", Align.Bottom);

View File

@ -671,6 +671,10 @@ class TerminalWidget : WidgetGroup, OnScrollHandler {
_device.write(chars.toUTF8);
}
void resetTerminal() {
_content.resetTerminal();
}
private dchar[] outputChars;
// write utf32
void write(dstring chars) {
@ -874,7 +878,9 @@ class TerminalDevice : Thread {
break;
DWORD bytesRead = 0;
// read data from client
if (ReadFile(hpipe, &buf, buf.length, &bytesRead, null)) {
Log.d("TerminalDevice reading from pipe");
if (ReadFile(hpipe, &buf, 1, &bytesRead, null)) { //buf.length
Log.d("TerminalDevice bytes read: ", bytesRead);
if (closed)
break;
if (bytesRead && onBytesRead.assigned) {
@ -887,6 +893,7 @@ class TerminalDevice : Thread {
Log.d("TerminalDevice client disconnecting");
connected = false;
// disconnect client
FlushFileBuffers(hpipe);
DisconnectNamedPipe(hpipe);
}
}
@ -983,11 +990,12 @@ class TerminalDevice : Thread {
import std.uuid;
_name = "\\\\.\\pipe\\dlangide-terminal-" ~ randomUUID().toString;
hpipe = CreateNamedPipeA(cast(const(char)*)_name.toStringz,
PIPE_ACCESS_DUPLEX,
cast(uint)PIPE_TYPE_BYTE,
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, // dwOpenMode
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, // | PIPE_REJECT_REMOTE_CLIENTS,
//PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // | PIPE_REJECT_REMOTE_CLIENTS,
1,
16384,
16384,
1, //16384,
1, //16384,
50,
null);
if (hpipe == INVALID_HANDLE_VALUE) {