mirror of https://github.com/buggins/dlangide.git
terminal support
This commit is contained in:
parent
fd0f10bfc5
commit
8dd29d78a0
|
@ -303,6 +303,11 @@ class DebuggerProxy : Debugger, DebuggerCallback {
|
||||||
_debugger.setTerminalExecutable(terminalExecutable);
|
_debugger.setTerminalExecutable(terminalExecutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set terminal device name before execution
|
||||||
|
void setTerminalTty(string terminalTty) {
|
||||||
|
_debugger.setTerminalTty(terminalTty);
|
||||||
|
}
|
||||||
|
|
||||||
/// set debugger executable
|
/// set debugger executable
|
||||||
void setDebuggerExecutable(string debuggerExecutable) {
|
void setDebuggerExecutable(string debuggerExecutable) {
|
||||||
_debugger.setDebuggerExecutable(debuggerExecutable);
|
_debugger.setDebuggerExecutable(debuggerExecutable);
|
||||||
|
@ -413,7 +418,7 @@ abstract class DebuggerBase : Thread, Debugger {
|
||||||
|
|
||||||
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
|
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
|
||||||
mixin ExecutableParams;
|
mixin ExecutableParams;
|
||||||
/// provides _terminalExecutable and setTerminalExecutable setter
|
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
|
||||||
mixin TerminalParams;
|
mixin TerminalParams;
|
||||||
|
|
||||||
protected DebuggerCallback _callback;
|
protected DebuggerCallback _callback;
|
||||||
|
|
|
@ -23,6 +23,8 @@ interface ProgramExecution {
|
||||||
void setExecutableParams(string executableFile, string[] args, string workingDir, string[string] envVars);
|
void setExecutableParams(string executableFile, string[] args, string workingDir, string[string] envVars);
|
||||||
/// set external terminal parameters before execution
|
/// set external terminal parameters before execution
|
||||||
void setTerminalExecutable(string terminalExecutable);
|
void setTerminalExecutable(string terminalExecutable);
|
||||||
|
/// set external terminal tty before execution
|
||||||
|
void setTerminalTty(string terminalTty);
|
||||||
|
|
||||||
/// returns true if it's debugger
|
/// returns true if it's debugger
|
||||||
@property bool isDebugger();
|
@property bool isDebugger();
|
||||||
|
@ -53,15 +55,20 @@ mixin template ExecutableParams() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// provides _terminalExecutable and setTerminalExecutable setter
|
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
|
||||||
mixin template TerminalParams() {
|
mixin template TerminalParams() {
|
||||||
|
|
||||||
/// executable file name for external console/terminal
|
/// executable file name for external console/terminal
|
||||||
protected string _terminalExecutable;
|
protected string _terminalExecutable;
|
||||||
|
protected string _terminalTty;
|
||||||
|
|
||||||
/// set external terminal parameters before execution
|
/// set external terminal parameters before execution
|
||||||
void setTerminalExecutable(string terminalExecutable) {
|
void setTerminalExecutable(string terminalExecutable) {
|
||||||
_terminalExecutable = terminalExecutable;
|
_terminalExecutable = terminalExecutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTerminalTty(string terminalTty) {
|
||||||
|
_terminalTty = terminalTty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class ProgramExecutionNoDebug : Thread, ProgramExecution {
|
||||||
// parameters
|
// parameters
|
||||||
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
|
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
|
||||||
mixin ExecutableParams;
|
mixin ExecutableParams;
|
||||||
/// provides _terminalExecutable and setTerminalExecutable setter
|
/// provides _terminalExecutable, _terminalTty, setTerminalExecutable, and setTerminalTty
|
||||||
mixin TerminalParams;
|
mixin TerminalParams;
|
||||||
|
|
||||||
protected ProgramExecutionStatusListener _listener;
|
protected ProgramExecutionStatusListener _listener;
|
||||||
|
|
|
@ -115,9 +115,11 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Pid terminalPid;
|
Pid terminalPid;
|
||||||
string terminalTty;
|
string externalTerminalTty;
|
||||||
|
|
||||||
string startTerminal() {
|
string startTerminal() {
|
||||||
|
if (!_terminalTty.empty)
|
||||||
|
return _terminalTty;
|
||||||
Log.d("Starting terminal ", _terminalExecutable);
|
Log.d("Starting terminal ", _terminalExecutable);
|
||||||
import std.random;
|
import std.random;
|
||||||
import std.file;
|
import std.file;
|
||||||
|
@ -125,7 +127,7 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
import std.string;
|
import std.string;
|
||||||
import core.thread;
|
import core.thread;
|
||||||
uint n = uniform(0, 0x10000000, rndGen());
|
uint n = uniform(0, 0x10000000, rndGen());
|
||||||
terminalTty = null;
|
externalTerminalTty = null;
|
||||||
string termfile = buildPath(tempDir, format("dlangide-term-name-%07x.tmp", n));
|
string termfile = buildPath(tempDir, format("dlangide-term-name-%07x.tmp", n));
|
||||||
Log.d("temp file for tty name: ", termfile);
|
Log.d("temp file for tty name: ", termfile);
|
||||||
try {
|
try {
|
||||||
|
@ -151,27 +153,29 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
}
|
}
|
||||||
// read TTY from file
|
// read TTY from file
|
||||||
if (exists(termfile)) {
|
if (exists(termfile)) {
|
||||||
terminalTty = readText(termfile);
|
externalTerminalTty = readText(termfile);
|
||||||
if (terminalTty.endsWith("\n"))
|
if (externalTerminalTty.endsWith("\n"))
|
||||||
terminalTty = terminalTty[0 .. $-1];
|
externalTerminalTty = externalTerminalTty[0 .. $-1];
|
||||||
// delete file
|
// delete file
|
||||||
remove(termfile);
|
remove(termfile);
|
||||||
Log.d("Terminal tty: ", terminalTty);
|
Log.d("Terminal tty: ", externalTerminalTty);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("Failed to start terminal ", e);
|
Log.e("Failed to start terminal ", e);
|
||||||
killTerminal();
|
killTerminal();
|
||||||
}
|
}
|
||||||
if (terminalTty.length == 0) {
|
if (externalTerminalTty.length == 0) {
|
||||||
Log.i("Cannot start terminal");
|
Log.i("Cannot start terminal");
|
||||||
killTerminal();
|
killTerminal();
|
||||||
} else {
|
} else {
|
||||||
Log.i("Terminal: ", terminalTty);
|
Log.i("Terminal: ", externalTerminalTty);
|
||||||
}
|
}
|
||||||
return terminalTty;
|
return externalTerminalTty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTerminalActive() {
|
bool isTerminalActive() {
|
||||||
|
if (!_terminalTty.empty)
|
||||||
|
return true;
|
||||||
if (_terminalExecutable.empty)
|
if (_terminalExecutable.empty)
|
||||||
return true;
|
return true;
|
||||||
if (terminalPid is null)
|
if (terminalPid is null)
|
||||||
|
@ -188,6 +192,8 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void killTerminal() {
|
void killTerminal() {
|
||||||
|
if (!_terminalTty.empty)
|
||||||
|
return;
|
||||||
if (_terminalExecutable.empty)
|
if (_terminalExecutable.empty)
|
||||||
return;
|
return;
|
||||||
if (terminalPid is null)
|
if (terminalPid is null)
|
||||||
|
@ -208,16 +214,18 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
override void startDebugging() {
|
override void startDebugging() {
|
||||||
Log.d("GDBInterface.startDebugging()");
|
Log.d("GDBInterface.startDebugging()");
|
||||||
string[] debuggerArgs;
|
string[] debuggerArgs;
|
||||||
if (!_terminalExecutable.empty) {
|
if (!_terminalExecutable.empty || !_terminalTty.empty) {
|
||||||
terminalTty = startTerminal();
|
externalTerminalTty = startTerminal();
|
||||||
if (terminalTty.length == 0) {
|
if (externalTerminalTty.length == 0) {
|
||||||
//_callback.onResponse(ResponseCode.CannotRunDebugger, "Cannot start terminal");
|
//_callback.onResponse(ResponseCode.CannotRunDebugger, "Cannot start terminal");
|
||||||
_status = ExecutionStatus.Error;
|
_status = ExecutionStatus.Error;
|
||||||
_stopRequested = true;
|
_stopRequested = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debuggerArgs ~= "-tty";
|
if (!USE_INIT_SEQUENCE) {
|
||||||
debuggerArgs ~= terminalTty;
|
debuggerArgs ~= "-tty";
|
||||||
|
debuggerArgs ~= externalTerminalTty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
debuggerArgs ~= "--interpreter=mi";
|
debuggerArgs ~= "--interpreter=mi";
|
||||||
debuggerArgs ~= "--silent";
|
debuggerArgs ~= "--silent";
|
||||||
|
@ -677,8 +685,8 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
initRequestsWarnings = 0;
|
initRequestsWarnings = 0;
|
||||||
finishedInitRequests = 0;
|
finishedInitRequests = 0;
|
||||||
submitRequest(new GDBInitRequest("-environment-cd " ~ quotePathIfNeeded(_executableWorkingDir), true));
|
submitRequest(new GDBInitRequest("-environment-cd " ~ quotePathIfNeeded(_executableWorkingDir), true));
|
||||||
if (terminalTty)
|
if (externalTerminalTty)
|
||||||
submitRequest(new GDBInitRequest("-inferior-tty-set " ~ terminalTty, true));
|
submitRequest(new GDBInitRequest("-inferior-tty-set " ~ quotePathIfNeeded(externalTerminalTty), true));
|
||||||
|
|
||||||
submitRequest(new GDBInitRequest("-gdb-set breakpoint pending on", false));
|
submitRequest(new GDBInitRequest("-gdb-set breakpoint pending on", false));
|
||||||
submitRequest(new GDBInitRequest("-enable-pretty-printing", false));
|
submitRequest(new GDBInitRequest("-enable-pretty-printing", false));
|
||||||
|
|
|
@ -179,6 +179,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case ExecutionStatus.Error:
|
case ExecutionStatus.Error:
|
||||||
_logPanel.logLine("Cannot run program " ~ process.executableFile);
|
_logPanel.logLine("Cannot run program " ~ process.executableFile);
|
||||||
|
_logPanel.activateLogTab();
|
||||||
break;
|
break;
|
||||||
case ExecutionStatus.Finished:
|
case ExecutionStatus.Finished:
|
||||||
_logPanel.logLine("Program " ~ process.executableFile ~ " finished with exit code " ~ to!string(exitCode));
|
_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);
|
_logPanel.logLine("Starting debugger for " ~ executableFileName);
|
||||||
_statusLine.setBackgroundOperationStatus("debug-run", program.isDebugger ? "debugging..."d : "running..."d);
|
_statusLine.setBackgroundOperationStatus("debug-run", program.isDebugger ? "debugging..."d : "running..."d);
|
||||||
string[string] env;
|
string[string] env;
|
||||||
|
string tty = _logPanel.terminalDeviceName;
|
||||||
program.setExecutableParams(executableFileName, args, workingDirectory, env);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1375,6 +1382,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
||||||
_logPanel.logLine("No project is opened");
|
_logPanel.logLine("No project is opened");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_logPanel.activateLogTab();
|
||||||
if (!listener) {
|
if (!listener) {
|
||||||
if (buildOp == BuildOperation.Upgrade || buildOp == BuildOperation.Build || buildOp == BuildOperation.Rebuild) {
|
if (buildOp == BuildOperation.Upgrade || buildOp == BuildOperation.Build || buildOp == BuildOperation.Rebuild) {
|
||||||
listener = delegate(int result) {
|
listener = delegate(int result) {
|
||||||
|
|
|
@ -132,12 +132,29 @@ class OutputPanel : DockWindow {
|
||||||
|
|
||||||
@property TabWidget getTabs() { return _tabs;}
|
@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) {
|
this(string id) {
|
||||||
_showCloseButton = false;
|
_showCloseButton = false;
|
||||||
dockAlignment = DockAlignment.Bottom;
|
dockAlignment = DockAlignment.Bottom;
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// terminal device for Console tab
|
||||||
|
@property string terminalDeviceName() {
|
||||||
|
if (_terminalWidget)
|
||||||
|
return _terminalWidget.deviceName;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
override protected Widget createBodyWidget() {
|
override protected Widget createBodyWidget() {
|
||||||
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
||||||
_tabs = new TabWidget("OutputPanelTabs", Align.Bottom);
|
_tabs = new TabWidget("OutputPanelTabs", Align.Bottom);
|
||||||
|
|
|
@ -671,6 +671,10 @@ class TerminalWidget : WidgetGroup, OnScrollHandler {
|
||||||
_device.write(chars.toUTF8);
|
_device.write(chars.toUTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetTerminal() {
|
||||||
|
_content.resetTerminal();
|
||||||
|
}
|
||||||
|
|
||||||
private dchar[] outputChars;
|
private dchar[] outputChars;
|
||||||
// write utf32
|
// write utf32
|
||||||
void write(dstring chars) {
|
void write(dstring chars) {
|
||||||
|
@ -874,7 +878,9 @@ class TerminalDevice : Thread {
|
||||||
break;
|
break;
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
// read data from client
|
// 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)
|
if (closed)
|
||||||
break;
|
break;
|
||||||
if (bytesRead && onBytesRead.assigned) {
|
if (bytesRead && onBytesRead.assigned) {
|
||||||
|
@ -887,6 +893,7 @@ class TerminalDevice : Thread {
|
||||||
Log.d("TerminalDevice client disconnecting");
|
Log.d("TerminalDevice client disconnecting");
|
||||||
connected = false;
|
connected = false;
|
||||||
// disconnect client
|
// disconnect client
|
||||||
|
FlushFileBuffers(hpipe);
|
||||||
DisconnectNamedPipe(hpipe);
|
DisconnectNamedPipe(hpipe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -983,11 +990,12 @@ class TerminalDevice : Thread {
|
||||||
import std.uuid;
|
import std.uuid;
|
||||||
_name = "\\\\.\\pipe\\dlangide-terminal-" ~ randomUUID().toString;
|
_name = "\\\\.\\pipe\\dlangide-terminal-" ~ randomUUID().toString;
|
||||||
hpipe = CreateNamedPipeA(cast(const(char)*)_name.toStringz,
|
hpipe = CreateNamedPipeA(cast(const(char)*)_name.toStringz,
|
||||||
PIPE_ACCESS_DUPLEX,
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, // dwOpenMode
|
||||||
cast(uint)PIPE_TYPE_BYTE,
|
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,
|
1,
|
||||||
16384,
|
1, //16384,
|
||||||
16384,
|
1, //16384,
|
||||||
50,
|
50,
|
||||||
null);
|
null);
|
||||||
if (hpipe == INVALID_HANDLE_VALUE) {
|
if (hpipe == INVALID_HANDLE_VALUE) {
|
||||||
|
|
Loading…
Reference in New Issue