diff --git a/src/ddebug/common/debugger.d b/src/ddebug/common/debugger.d index be81f06..ba45702 100644 --- a/src/ddebug/common/debugger.d +++ b/src/ddebug/common/debugger.d @@ -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; diff --git a/src/ddebug/common/execution.d b/src/ddebug/common/execution.d index d7330de..c379344 100644 --- a/src/ddebug/common/execution.d +++ b/src/ddebug/common/execution.d @@ -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; + } } diff --git a/src/ddebug/common/nodebug.d b/src/ddebug/common/nodebug.d index 92b7bd9..30cc0d1 100644 --- a/src/ddebug/common/nodebug.d +++ b/src/ddebug/common/nodebug.d @@ -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; diff --git a/src/ddebug/gdb/gdbinterface.d b/src/ddebug/gdb/gdbinterface.d index 62167f1..f24f810 100644 --- a/src/ddebug/gdb/gdbinterface.d +++ b/src/ddebug/gdb/gdbinterface.d @@ -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)); diff --git a/src/dlangide/ui/frame.d b/src/dlangide/ui/frame.d index 8a74f38..4b3ece1 100644 --- a/src/dlangide/ui/frame.d +++ b/src/dlangide/ui/frame.d @@ -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) { diff --git a/src/dlangide/ui/outputpanel.d b/src/dlangide/ui/outputpanel.d index ccc6098..f1b90f2 100644 --- a/src/dlangide/ui/outputpanel.d +++ b/src/dlangide/ui/outputpanel.d @@ -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); diff --git a/src/dlangide/ui/terminal.d b/src/dlangide/ui/terminal.d index 156dd9a..e2d6316 100644 --- a/src/dlangide/ui/terminal.d +++ b/src/dlangide/ui/terminal.d @@ -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) {