history_console_widget.py
163 lines
| 6.0 KiB
| text/x-python
|
PythonLexer
epatters
|
r2983 | # System library imports | ||
from PyQt4 import QtGui | ||||
# Local imports | ||||
from console_widget import ConsoleWidget | ||||
class HistoryConsoleWidget(ConsoleWidget): | ||||
""" A ConsoleWidget that keeps a history of the commands that have been | ||||
epatters
|
r2984 | executed and provides a readline-esque interface to this history. | ||
epatters
|
r2983 | """ | ||
#--------------------------------------------------------------------------- | ||||
# 'object' interface | ||||
#--------------------------------------------------------------------------- | ||||
def __init__(self, *args, **kw): | ||||
super(HistoryConsoleWidget, self).__init__(*args, **kw) | ||||
epatters
|
r2984 | |||
# HistoryConsoleWidget protected variables. | ||||
epatters
|
r2983 | self._history = [] | ||
self._history_index = 0 | ||||
epatters
|
r2984 | self._history_prefix = '' | ||
epatters
|
r2983 | |||
#--------------------------------------------------------------------------- | ||||
# 'ConsoleWidget' public interface | ||||
#--------------------------------------------------------------------------- | ||||
def execute(self, source=None, hidden=False, interactive=False): | ||||
""" Reimplemented to the store history. | ||||
""" | ||||
if not hidden: | ||||
history = self.input_buffer if source is None else source | ||||
executed = super(HistoryConsoleWidget, self).execute( | ||||
source, hidden, interactive) | ||||
if executed and not hidden: | ||||
# Save the command unless it was an empty string or was identical | ||||
# to the previous command. | ||||
history = history.rstrip() | ||||
if history and (not self._history or self._history[-1] != history): | ||||
self._history.append(history) | ||||
# Move the history index to the most recent item. | ||||
self._history_index = len(self._history) | ||||
return executed | ||||
#--------------------------------------------------------------------------- | ||||
# 'ConsoleWidget' abstract interface | ||||
#--------------------------------------------------------------------------- | ||||
def _up_pressed(self): | ||||
""" Called when the up key is pressed. Returns whether to continue | ||||
processing the event. | ||||
""" | ||||
prompt_cursor = self._get_prompt_cursor() | ||||
if self._get_cursor().blockNumber() == prompt_cursor.blockNumber(): | ||||
epatters
|
r2984 | # Set a search prefix based on the cursor position. | ||
col = self._get_input_buffer_cursor_column() | ||||
input_buffer = self.input_buffer | ||||
if self._history_index == len(self._history) or \ | ||||
(self._history_prefix and col != len(self._history_prefix)): | ||||
self._history_index = len(self._history) | ||||
self._history_prefix = input_buffer[:col] | ||||
# Perform the search. | ||||
self.history_previous(self._history_prefix) | ||||
# Go to the first line of the prompt for seemless history scrolling. | ||||
# Emulate readline: keep the cursor position fixed for a prefix | ||||
# search. | ||||
epatters
|
r2983 | cursor = self._get_prompt_cursor() | ||
epatters
|
r2984 | if self._history_prefix: | ||
cursor.movePosition(QtGui.QTextCursor.Right, | ||||
n=len(self._history_prefix)) | ||||
else: | ||||
cursor.movePosition(QtGui.QTextCursor.EndOfLine) | ||||
epatters
|
r2983 | self._set_cursor(cursor) | ||
return False | ||||
epatters
|
r2984 | |||
epatters
|
r2983 | return True | ||
def _down_pressed(self): | ||||
""" Called when the down key is pressed. Returns whether to continue | ||||
processing the event. | ||||
""" | ||||
end_cursor = self._get_end_cursor() | ||||
if self._get_cursor().blockNumber() == end_cursor.blockNumber(): | ||||
epatters
|
r2984 | |||
# Perform the search. | ||||
self.history_next(self._history_prefix) | ||||
# Emulate readline: keep the cursor position fixed for a prefix | ||||
# search. (We don't need to move the cursor to the end of the buffer | ||||
# in the other case because this happens automatically when the | ||||
# input buffer is set.) | ||||
if self._history_prefix: | ||||
cursor = self._get_prompt_cursor() | ||||
cursor.movePosition(QtGui.QTextCursor.Right, | ||||
n=len(self._history_prefix)) | ||||
self._set_cursor(cursor) | ||||
epatters
|
r2983 | return False | ||
epatters
|
r2984 | |||
epatters
|
r2983 | return True | ||
#--------------------------------------------------------------------------- | ||||
# 'HistoryConsoleWidget' public interface | ||||
#--------------------------------------------------------------------------- | ||||
epatters
|
r2984 | def history_previous(self, prefix=''): | ||
""" If possible, set the input buffer to a previous item in the history. | ||||
epatters
|
r2983 | |||
epatters
|
r2984 | Parameters: | ||
----------- | ||||
prefix : str, optional | ||||
If specified, search for an item with this prefix. | ||||
epatters
|
r2983 | """ | ||
epatters
|
r2984 | index = self._history_index | ||
while index > 0: | ||||
index -= 1 | ||||
history = self._history[index] | ||||
if history.startswith(prefix): | ||||
break | ||||
else: | ||||
history = None | ||||
if history is not None: | ||||
self._history_index = index | ||||
self.input_buffer = history | ||||
def history_next(self, prefix=''): | ||||
""" Set the input buffer to a subsequent item in the history, or to the | ||||
original search prefix if there is no such item. | ||||
Parameters: | ||||
----------- | ||||
prefix : str, optional | ||||
If specified, search for an item with this prefix. | ||||
""" | ||||
while self._history_index < len(self._history) - 1: | ||||
epatters
|
r2983 | self._history_index += 1 | ||
epatters
|
r2984 | history = self._history[self._history_index] | ||
if history.startswith(prefix): | ||||
break | ||||
else: | ||||
self._history_index = len(self._history) | ||||
history = prefix | ||||
self.input_buffer = history | ||||
epatters
|
r2983 | |||
epatters
|
r2985 | #--------------------------------------------------------------------------- | ||
# 'HistoryConsoleWidget' protected interface | ||||
#--------------------------------------------------------------------------- | ||||
def _set_history(self, history): | ||||
epatters
|
r2983 | """ Replace the current history with a sequence of history items. | ||
""" | ||||
self._history = list(history) | ||||
self._history_index = len(self._history) | ||||