##// END OF EJS Templates
Backport PR #2738: Unicode content crashes the pager (console)...
Backport PR #2738: Unicode content crashes the pager (console) We've run into an interesting bug in the astropy project. https://github.com/astropy/astropy/issues/600 When displaying a docstring that contains Unicode and is also long enough that it gets sent to the pager it fails since the docstring can't be sent to the pager as ascii. This crashes in the middle of sending content to the pager, so the shell ends up in an inconsistent state and stops echoing the keyboard etc. The fix (attached) is merely to encode the content sent to the pager in the same encoding as the terminal (`sys.stdout.encoding`). Strictly speaking, this isn't always the right thing to do, since the pager may be configured to expect a different encoding than the terminal, but that is sort of an irrational way to configure a machine... ;) For example, `less`, in the absence of any special environment variables to tell it otherwise, uses the standard `LC*` environment variables to determine what to do, which should be the same mechanism the terminal also uses by default. If anyone can suggest a better fix, I'm all for it. Perhaps it should be configurable, defaulting to `sys.stdout.encoding`?

File last commit:

r7393:68781aae
r9853:7f9a133e
Show More
completion_widget.py
138 lines | 5.2 KiB | text/x-python | PythonLexer
epatters
Initial checkin of Qt frontend code.
r2602 # System library imports
Evan Patterson
Paved the way for PySide support....
r3304 from IPython.external.qt import QtCore, QtGui
epatters
Initial checkin of Qt frontend code.
r2602
class CompletionWidget(QtGui.QListWidget):
""" A widget for GUI tab completion.
"""
#--------------------------------------------------------------------------
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 # 'QObject' interface
epatters
Initial checkin of Qt frontend code.
r2602 #--------------------------------------------------------------------------
Matthias BUSSONNIER
new completer for qtconsole....
r7389 def __init__(self, console_widget):
epatters
Initial checkin of Qt frontend code.
r2602 """ Create a completion widget that is attached to the specified Qt
text edit widget.
"""
Matthias BUSSONNIER
fix gui=droplist
r7390 text_edit = console_widget._control
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 assert isinstance(text_edit, (QtGui.QTextEdit, QtGui.QPlainTextEdit))
super(CompletionWidget, self).__init__()
self._text_edit = text_edit
epatters
Initial checkin of Qt frontend code.
r2602
self.setAttribute(QtCore.Qt.WA_StaticContents)
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 self.setWindowFlags(QtCore.Qt.ToolTip | QtCore.Qt.WindowStaysOnTopHint)
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 # Ensure that the text edit keeps focus when widget is displayed.
self.setFocusProxy(self._text_edit)
epatters
Initial checkin of Qt frontend code.
r2602
self.setFrameShadow(QtGui.QFrame.Plain)
self.setFrameShape(QtGui.QFrame.StyledPanel)
self.itemActivated.connect(self._complete_current)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 def eventFilter(self, obj, event):
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 """ Reimplemented to handle keyboard input and to auto-hide when the
text edit loses focus.
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 """
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 if obj == self._text_edit:
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 etype = event.type()
if etype == QtCore.QEvent.KeyPress:
key, text = event.key(), event.text()
Bernardo B. Marques
remove all trailling spaces
r4872 if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter,
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 QtCore.Qt.Key_Tab):
self._complete_current()
return True
elif key == QtCore.Qt.Key_Escape:
self.hide()
return True
Bernardo B. Marques
remove all trailling spaces
r4872 elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown,
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 QtCore.Qt.Key_Home, QtCore.Qt.Key_End):
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 self.keyPressEvent(event)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 return True
elif etype == QtCore.QEvent.FocusOut:
self.hide()
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 return super(CompletionWidget, self).eventFilter(obj, event)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744
#--------------------------------------------------------------------------
# 'QWidget' interface
#--------------------------------------------------------------------------
epatters
Initial checkin of Qt frontend code.
r2602 def hideEvent(self, event):
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 """ Reimplemented to disconnect signal handlers and event filter.
epatters
Initial checkin of Qt frontend code.
r2602 """
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 super(CompletionWidget, self).hideEvent(event)
self._text_edit.cursorPositionChanged.disconnect(self._update_current)
self._text_edit.removeEventFilter(self)
epatters
Initial checkin of Qt frontend code.
r2602
def showEvent(self, event):
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 """ Reimplemented to connect signal handlers and event filter.
epatters
Initial checkin of Qt frontend code.
r2602 """
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 super(CompletionWidget, self).showEvent(event)
self._text_edit.cursorPositionChanged.connect(self._update_current)
self._text_edit.installEventFilter(self)
epatters
Initial checkin of Qt frontend code.
r2602
#--------------------------------------------------------------------------
# 'CompletionWidget' interface
#--------------------------------------------------------------------------
def show_items(self, cursor, items):
""" Shows the completion widget with 'items' at the position specified
by 'cursor'.
"""
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 text_edit = self._text_edit
epatters
Initial checkin of Qt frontend code.
r2602 point = text_edit.cursorRect(cursor).bottomRight()
point = text_edit.mapToGlobal(point)
Prabhu Ramachandran
BUG: Completion widget position and pager focus....
r4976 height = self.sizeHint().height()
epatters
Initial checkin of Qt frontend code.
r2602 screen_rect = QtGui.QApplication.desktop().availableGeometry(self)
Prabhu Ramachandran
BUG: Completion widget position and pager focus....
r4976 if screen_rect.size().height() - point.y() - height < 0:
epatters
Initial checkin of Qt frontend code.
r2602 point = text_edit.mapToGlobal(text_edit.cursorRect().topRight())
Prabhu Ramachandran
BUG: Completion widget position and pager focus....
r4976 point.setY(point.y() - height)
epatters
Initial checkin of Qt frontend code.
r2602 self.move(point)
self._start_position = cursor.position()
self.clear()
self.addItems(items)
self.setCurrentRow(0)
self.show()
#--------------------------------------------------------------------------
# Protected interface
#--------------------------------------------------------------------------
def _complete_current(self):
""" Perform the completion with the currently selected item.
"""
self._current_text_cursor().insertText(self.currentItem().text())
self.hide()
def _current_text_cursor(self):
""" Returns a cursor with text between the start position and the
current position selected.
"""
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 cursor = self._text_edit.textCursor()
epatters
Initial checkin of Qt frontend code.
r2602 if cursor.position() >= self._start_position:
Bernardo B. Marques
remove all trailling spaces
r4872 cursor.setPosition(self._start_position,
epatters
Initial checkin of Qt frontend code.
r2602 QtGui.QTextCursor.KeepAnchor)
return cursor
Bernardo B. Marques
remove all trailling spaces
r4872
epatters
Initial checkin of Qt frontend code.
r2602 def _update_current(self):
""" Updates the current item based on the current text.
"""
epatters
Made use of plain text consistent.
r2720 prefix = self._current_text_cursor().selection().toPlainText()
epatters
Initial checkin of Qt frontend code.
r2602 if prefix:
Bernardo B. Marques
remove all trailling spaces
r4872 items = self.findItems(prefix, (QtCore.Qt.MatchStartsWith |
epatters
Initial checkin of Qt frontend code.
r2602 QtCore.Qt.MatchCaseSensitive))
if items:
self.setCurrentItem(items[0])
else:
self.hide()
else:
self.hide()
Matthias BUSSONNIER
fix gui=droplist
r7390
Matthias BUSSONNIER
new completer for qtconsole...
r7393 def cancel_completion(self):
Matthias BUSSONNIER
fix gui=droplist
r7390 self.hide()