Skip to content

Commit

Permalink
Merge pull request #98 from andfoy/close_terminal
Browse files Browse the repository at this point in the history
PR: Close terminal tab if process was closed
  • Loading branch information
andfoy committed Jul 28, 2017
2 parents 5653e75 + 49a3e53 commit 24ad52a
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 8 deletions.
6 changes: 6 additions & 0 deletions spyder_terminal/server/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var term,
path,
curFont;

var alive = true;
var lineEnd = '\n';
var clearCmd = 'clear';
var myHeaders = new Headers();
Expand Down Expand Up @@ -125,6 +126,7 @@ function exec(cmd)
}

function closeTerm() {
alive = false;
console.log("Closed via server");
term.writeln("Pipe closed");
}
Expand All @@ -141,6 +143,10 @@ function scrollTerm(delta) {
$('.xterm-viewport').animate({ scrollTop: curScrollPos }, 0);
}

function isAlive() {
return alive;
}

function runRealTerminal() {
term.attach(socket);
term._initialized = true;
Expand Down
3 changes: 2 additions & 1 deletion spyder_terminal/server/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ def test_terminal_communication(self):
sock.write_message(' ' + test_msg)
msg = ''
while test_msg not in msg:
msg = yield sock.read_message()
msg += yield sock.read_message()
print(msg)
msg = ''.join(msg.rstrip())
self.assertTrue(test_msg in msg)

# @pytest.mark.skipif(os.name == 'nt', reason="It doesn't work on Windows")
Expand Down
5 changes: 4 additions & 1 deletion spyder_terminal/terminalplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class TerminalPlugin(SpyderPluginWidget):
URL_ISSUES = ' https://github.com/spyder-ide/spyder-terminal/issues'
CONF_SECTION = 'terminal'
focus_changed = Signal()
server_is_ready = Signal()
MAX_SERVER_CONTACT_RETRIES = 40

def __init__(self, parent):
Expand Down Expand Up @@ -142,7 +143,7 @@ def __wait_server_to_start(self):
code = 500

if self.server_retries == self.MAX_SERVER_CONTACT_RETRIES:
QMessageBox.Critical(self, _('Spyder Terminal Error'),
QMessageBox.critical(self, _('Spyder Terminal Error'),
_("Terminal server could not be located at "
'<a href="http://127.0.0.1:{0}">'
'http://127.0.0.1:{0}</a>,'
Expand All @@ -158,6 +159,7 @@ def __wait_server_to_start(self):
self.server_retries += 1
QTimer.singleShot(250, self.__wait_server_to_start)
elif code == 200:
self.server_is_ready.emit()
self.create_new_term(give_focus=False)

# ------ SpyderPluginMixin API --------------------------------
Expand Down Expand Up @@ -310,6 +312,7 @@ def create_new_term(self, name=None, give_focus=True, path=None):
term = TerminalWidget(self, self.port, path=path,
font=font.family())
self.add_tab(term)
term.terminal_closed.connect(lambda: self.close_term(term=term))

def close_term(self, index=None, term=None):
"""Close a terminal tab."""
Expand Down
40 changes: 38 additions & 2 deletions spyder_terminal/tests/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
TERM_UP = 10000
WINDOWS = os.name == 'nt'

EXIT = 'exit'
CLEAR = 'clear'
if WINDOWS:
CLEAR = 'cls'
Expand All @@ -51,6 +52,12 @@ def callback(data):
return LOCATION in termwidget.body.toHtml()


def check_num_tabs(terminal, ref_value):
"""Check if total number of terminal tabs has changed."""
value = len(terminal.get_terms())
return value != ref_value


@pytest.fixture(scope="module")
def setup_terminal(qtbot):
"""Set up the Notebook plugin."""
Expand All @@ -64,6 +71,8 @@ def setup_terminal(qtbot):
def test_terminal_font(qtbot):
"""Test if terminal loads a custom font."""
terminal = setup_terminal(qtbot)
# blocker = qtbot.waitSignal(terminal.server_is_ready, timeout=TERM_UP)
# blocker.wait()
qtbot.wait(TERM_UP)

term = terminal.get_current_term()
Expand All @@ -79,10 +88,13 @@ def test_terminal_font(qtbot):
def test_terminal_tab_title(qtbot):
"""Test if terminal tab titles are numbered sequentially."""
terminal = setup_terminal(qtbot)
# blocker = qtbot.waitSignal(terminal.server_is_ready, timeout=TERM_UP)
# blocker.wait()
qtbot.wait(TERM_UP)
terminal.create_new_term()
num_1 = int(terminal.tabwidget.tabText(0)[-1])
num_2 = int(terminal.tabwidget.tabText(1)[-1])
terminal.create_new_term()
num_1 = int(terminal.tabwidget.tabText(1)[-1])
num_2 = int(terminal.tabwidget.tabText(2)[-1])
assert num_2 == num_1 + 1
terminal.closing_plugin()

Expand All @@ -91,6 +103,8 @@ def test_new_terminal(qtbot):
"""Test if a new terminal is added."""
# Setup widget
terminal = setup_terminal(qtbot)
# blocker = qtbot.waitSignal(terminal.server_is_ready, timeout=TERM_UP)
# blocker.wait()
qtbot.wait(TERM_UP)

# Test if server is running
Expand Down Expand Up @@ -131,3 +145,25 @@ def test_output_redirection(qtbot):
stderr = osp.join(getcwd(), 'spyder_terminal_err.log')
assert osp.exists(stdout) and osp.exists(stderr)
terminal.closing_plugin()


def test_close_terminal_manually(qtbot):
"""Test if terminal tab is closed after process was finished manually."""
# Setup widget
terminal = setup_terminal(qtbot)

# blocker = qtbot.waitSignal(terminal.server_is_ready, timeout=TERM_UP)
# blocker.wait()
qtbot.wait(TERM_UP)

terminal.create_new_term()
initial_num = len(terminal.get_terms())
term = terminal.get_current_term()
qtbot.wait(1000)

term.exec_cmd(EXIT)

qtbot.waitUntil(lambda: check_num_tabs(terminal, initial_num),
timeout=TERM_UP)
final_num = len(terminal.get_terms())
assert final_num == initial_num - 1
20 changes: 16 additions & 4 deletions spyder_terminal/widgets/terminalgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import sys

from spyder.config.base import _, DEV
from qtpy.QtCore import Qt, QUrl, Signal, Slot, QObject, QEvent
from qtpy.QtWidgets import (QMenu, QFrame, QVBoxLayout, QWidget, QShortcut)
from qtpy.QtCore import Qt, QUrl, Slot, QEvent, QTimer, Signal
from qtpy.QtWidgets import (QMenu, QFrame, QVBoxLayout, QWidget)
from qtpy.QtGui import QKeySequence
from spyder.widgets.browser import WebView
from spyder.utils import icon_manager as ima
Expand All @@ -26,6 +26,9 @@
class TerminalWidget(QFrame):
"""Terminal widget."""

terminal_closed = Signal()
terminal_ready = Signal()

def __init__(self, parent, port, path='~', font=None):
"""Frame main constructor."""
QWidget.__init__(self, parent)
Expand All @@ -43,6 +46,7 @@ def __init__(self, parent, port, path='~', font=None):
self.body = self.view.document

self.view.page().loadFinished.connect(self.setup_term)
QTimer.singleShot(250, self.__alive_loopback)

@Slot(bool)
def setup_term(self, finished):
Expand Down Expand Up @@ -74,9 +78,17 @@ def exec_cmd(self, cmd):
"""Execute a command inside the terminal."""
self.eval_javascript('exec("{0}")'.format(cmd))

def __alive_loopback(self):
alive = self.is_alive()
if not alive:
self.terminal_closed.emit()
else:
QTimer.singleShot(250, self.__alive_loopback)

def is_alive(self):
"""Check if xterm is ready."""
return self.eval_javascript('consoleReady()')
"""Check if terminal process is alive."""
alive = self.eval_javascript('isAlive()')
return alive


class TermView(WebView):
Expand Down

0 comments on commit 24ad52a

Please sign in to comment.