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); _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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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