##// END OF EJS Templates
Merge pull request #3409 from pankajp/qt-console-freeze-on-output-clip...
Min RK -
r11532:0397c02f merge
parent child Browse files
Show More
@@ -9,6 +9,7 b' import os.path'
9 import re
9 import re
10 import sys
10 import sys
11 from textwrap import dedent
11 from textwrap import dedent
12 import time
12 from unicodedata import category
13 from unicodedata import category
13 import webbrowser
14 import webbrowser
14
15
@@ -291,6 +292,21 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
291 self._reading_callback = None
292 self._reading_callback = None
292 self._tab_width = 8
293 self._tab_width = 8
293
294
295 # List of strings pending to be appended as plain text in the widget.
296 # The text is not immediately inserted when available to not
297 # choke the Qt event loop with paint events for the widget in
298 # case of lots of output from kernel.
299 self._pending_insert_text = []
300
301 # Timer to flush the pending stream messages. The interval is adjusted
302 # later based on actual time taken for flushing a screen (buffer_size)
303 # of output text.
304 self._pending_text_flush_interval = QtCore.QTimer(self._control)
305 self._pending_text_flush_interval.setInterval(100)
306 self._pending_text_flush_interval.setSingleShot(True)
307 self._pending_text_flush_interval.timeout.connect(
308 self._flush_pending_stream)
309
294 # Set a monospaced font.
310 # Set a monospaced font.
295 self.reset_font()
311 self.reset_font()
296
312
@@ -877,8 +893,11 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
877 # Determine where to insert the content.
893 # Determine where to insert the content.
878 cursor = self._control.textCursor()
894 cursor = self._control.textCursor()
879 if before_prompt and (self._reading or not self._executing):
895 if before_prompt and (self._reading or not self._executing):
896 self._flush_pending_stream()
880 cursor.setPosition(self._append_before_prompt_pos)
897 cursor.setPosition(self._append_before_prompt_pos)
881 else:
898 else:
899 if insert != self._insert_plain_text:
900 self._flush_pending_stream()
882 cursor.movePosition(QtGui.QTextCursor.End)
901 cursor.movePosition(QtGui.QTextCursor.End)
883 start_pos = cursor.position()
902 start_pos = cursor.position()
884
903
@@ -1459,6 +1478,20 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1459
1478
1460 return False
1479 return False
1461
1480
1481 def _flush_pending_stream(self):
1482 """ Flush out pending text into the widget. """
1483 text = self._pending_insert_text
1484 self._pending_insert_text = []
1485 buffer_size = self._control.document().maximumBlockCount()
1486 if buffer_size > 0:
1487 text = self._get_last_lines_from_list(text, buffer_size)
1488 text = ''.join(text)
1489 t = time.time()
1490 self._insert_plain_text(self._get_end_cursor(), text, flush=True)
1491 # Set the flush interval to equal the maximum time to update text.
1492 self._pending_text_flush_interval.setInterval(max(100,
1493 (time.time()-t)*1000))
1494
1462 def _format_as_columns(self, items, separator=' '):
1495 def _format_as_columns(self, items, separator=' '):
1463 """ Transform a list of strings into a single string with columns.
1496 """ Transform a list of strings into a single string with columns.
1464
1497
@@ -1540,6 +1573,43 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1540 else:
1573 else:
1541 return None
1574 return None
1542
1575
1576 def _get_last_lines(self, text, num_lines, return_count=False):
1577 """ Return last specified number of lines of text (like `tail -n`).
1578 If return_count is True, returns a tuple of clipped text and the
1579 number of lines in the clipped text.
1580 """
1581 pos = len(text)
1582 if pos < num_lines:
1583 if return_count:
1584 return text, text.count('\n') if return_count else text
1585 else:
1586 return text
1587 i = 0
1588 while i < num_lines:
1589 pos = text.rfind('\n', None, pos)
1590 if pos == -1:
1591 pos = None
1592 break
1593 i += 1
1594 if return_count:
1595 return text[pos:], i
1596 else:
1597 return text[pos:]
1598
1599 def _get_last_lines_from_list(self, text_list, num_lines):
1600 """ Return the list of text clipped to last specified lines.
1601 """
1602 ret = []
1603 lines_pending = num_lines
1604 for text in reversed(text_list):
1605 text, lines_added = self._get_last_lines(text, lines_pending,
1606 return_count=True)
1607 ret.append(text)
1608 lines_pending -= lines_added
1609 if lines_pending <= 0:
1610 break
1611 return ret[::-1]
1612
1543 def _get_prompt_cursor(self):
1613 def _get_prompt_cursor(self):
1544 """ Convenience method that returns a cursor for the prompt position.
1614 """ Convenience method that returns a cursor for the prompt position.
1545 """
1615 """
@@ -1644,10 +1714,29 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1644 cursor.endEditBlock()
1714 cursor.endEditBlock()
1645 return text
1715 return text
1646
1716
1647 def _insert_plain_text(self, cursor, text):
1717 def _insert_plain_text(self, cursor, text, flush=False):
1648 """ Inserts plain text using the specified cursor, processing ANSI codes
1718 """ Inserts plain text using the specified cursor, processing ANSI codes
1649 if enabled.
1719 if enabled.
1650 """
1720 """
1721 # maximumBlockCount() can be different from self.buffer_size in
1722 # case input prompt is active.
1723 buffer_size = self._control.document().maximumBlockCount()
1724
1725 if self._executing and not flush and \
1726 self._pending_text_flush_interval.isActive():
1727 self._pending_insert_text.append(text)
1728 if buffer_size > 0:
1729 self._pending_insert_text = self._get_last_lines_from_list(
1730 self._pending_insert_text, buffer_size)
1731 return
1732
1733 if self._executing and not self._pending_text_flush_interval.isActive():
1734 self._pending_text_flush_interval.start()
1735
1736 # Clip the text to last `buffer_size` lines.
1737 if buffer_size > 0:
1738 text = self._get_last_lines(text, buffer_size)
1739
1651 cursor.beginEditBlock()
1740 cursor.beginEditBlock()
1652 if self.ansi_codes:
1741 if self.ansi_codes:
1653 for substring in self._ansi_processor.split_string(text):
1742 for substring in self._ansi_processor.split_string(text):
General Comments 0
You need to be logged in to leave comments. Login now