From f6269c41da28b2c992e858154edbbfad6050455d Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 30 Jan 2018 09:58:31 +1000 Subject: [PATCH] [console] Allow breaking execution of scripts via Ctrl-C This allows (in some circumstances) scripts running in the console to be halted via the Ctrl (or Meta) + C shortcut. (It's only possible to catch and abort when the script is printing outputs to the console - because this triggers QCoreApplication.processEvents() calls. Without these calls the whole QGIS application is unresponsive during script execution and there's no ability to even catch a shortcut in order to halt the execution. Still, even with this limitation it's handy to be able to break out of lengthy: for f in iface.activeLayer().getFeatures(): print(f.attributes()) loops!) --- python/console/console_output.py | 5 +++++ python/console/console_sci.py | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/python/console/console_output.py b/python/console/console_output.py index d2209a2211a..444bd59126f 100644 --- a/python/console/console_output.py +++ b/python/console/console_output.py @@ -39,6 +39,7 @@ class writeOut(object): self.sO = shellOut self.out = None self.style = style + self.fire_keyboard_interrupt = False def write(self, m): if self.style == "_traceback": @@ -62,6 +63,10 @@ class writeOut(object): if self.style != "_traceback": QCoreApplication.processEvents() + if self.fire_keyboard_interrupt: + self.fire_keyboard_interrupt = False + raise KeyboardInterrupt + def move_cursor_to_end(self): """Move cursor to end of text""" line, index = self.get_end_pos() diff --git a/python/console/console_sci.py b/python/console/console_sci.py index 64113287f8e..e8a2f60a39b 100644 --- a/python/console/console_sci.py +++ b/python/console/console_sci.py @@ -378,9 +378,16 @@ class ShellScintilla(QsciScintilla, code.InteractiveInterpreter): if not self.is_cursor_on_edition_zone() or startLine < endLine: # allow copying and selecting if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier): - if e.key() in (Qt.Key_C, Qt.Key_A): + if e.key() == Qt.Key_C: + # only catch and return from Ctrl-C here if there's a selection + if self.hasSelectedText(): + QsciScintilla.keyPressEvent(self, e) + return + elif e.key() == Qt.Key_A: QsciScintilla.keyPressEvent(self, e) - return + return + else: + return # allow selection if e.modifiers() & Qt.ShiftModifier: if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home, Qt.Key_End): @@ -389,6 +396,11 @@ class ShellScintilla(QsciScintilla, code.InteractiveInterpreter): # all other keystrokes get sent to the input line self.move_cursor_to_end() + if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_C and not self.hasSelectedText(): + # keyboard interrupt + sys.stdout.fire_keyboard_interrupt = True + return + line, index = self.getCursorPosition() cmd = self.text(line) @@ -602,12 +614,14 @@ class ShellScintilla(QsciScintilla, code.InteractiveInterpreter): sys.stderr.write(txt) def writeCMD(self, txt): + sys.stdout.fire_keyboard_interrupt = False if len(txt) > 0: getCmdString = self.text() prompt = getCmdString[0:4] sys.stdout.write(prompt + txt + '\n') def runsource(self, source, filename='', symbol='single'): + sys.stdout.fire_keyboard_interrupt = False hook = sys.excepthook try: def excepthook(etype, value, tb):