Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] PR: Create widget to manage list history #622

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
116 changes: 109 additions & 7 deletions qtconsole/history_console_widget.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import os
import os.path

from qtpy import QtGui
from qtpy import QtCore, QtGui, QtWidgets

from traitlets import Bool
from .console_widget import ConsoleWidget
from .completion_widget import CompletionWidget


class HistoryListWidget(CompletionWidget):
""" A widget for GUI list history.
"""
complete_current = QtCore.Signal(str)

def _complete_current(self):
""" Perform the completion with the currently selected item.
"""
text = self.currentItem().data(QtCore.Qt.UserRole)
self.parent()._store_edits()
self.parent().input_buffer = text
self.complete_current.emit(text)
self.hide()


class HistoryConsoleWidget(ConsoleWidget):
Expand All @@ -31,6 +49,15 @@ def __init__(self, *args, **kw):
self._history_edits = {}
self._history_index = 0
self._history_prefix = ''
self.droplist_history = QtWidgets.QAction("Show related history execution entries",
self,
shortcut="Ctrl+Shift+R",
shortcutContext=QtCore.Qt.WidgetWithChildrenShortcut,
triggered=self._show_history_droplist
)
self.addAction(self.droplist_history)
self._history_list_widget = HistoryListWidget(self, self.gui_completion_height)
self._history_list_widget.complete_current.connect(self.change_input_buffer)

#---------------------------------------------------------------------------
# 'ConsoleWidget' public interface
Expand Down Expand Up @@ -142,6 +169,70 @@ def _down_pressed(self, shift_modifier):

return True

def _show_history_droplist(self):
# Perform the search.
prompt_cursor = self._get_prompt_cursor()
if self._get_cursor().blockNumber() == prompt_cursor.blockNumber():

# Set a search prefix based on the cursor position.
pos = self._get_input_buffer_cursor_pos()
input_buffer = self.input_buffer
# use the *shortest* of the cursor column and the history prefix
# to determine if the prefix has changed
n = min(pos, len(self._history_prefix))

# prefix changed, restart search from the beginning
if self._history_prefix[:n] != input_buffer[:n]:
self._history_index = len(self._history)

# the only time we shouldn't set the history prefix
# to the line up to the cursor is if we are already
# in a simple scroll (no prefix),
# and the cursor is at the end of the first line

# check if we are at the end of the first line
c = self._get_cursor()
current_pos = c.position()
c.movePosition(QtGui.QTextCursor.EndOfBlock)
at_eol = c.position() == current_pos

if (
self._history_index == len(self._history)
or not (self._history_prefix == "" and at_eol)
or not (
self._get_edited_history(self._history_index)[:pos]
== input_buffer[:pos]
)
):
self._history_prefix = input_buffer[:pos]
items = self._history
items.reverse()
if self._history_prefix:
items = [
item
for item in items
if item.startswith(self._history_prefix)
]

cursor = self._get_cursor()
pos = len(self._history_prefix)
cursor_pos = self._get_input_buffer_cursor_pos()
cursor.movePosition(QtGui.QTextCursor.Left, n=(cursor_pos - pos))
# This line actually applies the move to control's cursor
self._control.setTextCursor(cursor)

self._history_list_widget.cancel_completion()
if len(items) == 1:
self._history_list_widget.show_items(
cursor, items
)
elif len(items) > 1:
current_pos = self._control.textCursor().position()
prefix = os.path.commonprefix(items)
self._history_list_widget.show_items(
cursor, items, prefix_length=len(prefix)
)

#---------------------------------------------------------------------------
# 'HistoryConsoleWidget' public interface
#---------------------------------------------------------------------------
Expand Down Expand Up @@ -173,9 +264,7 @@ def history_previous(self, substring='', as_prefix=True):
break

if replace:
self._store_edits()
self._history_index = index
self.input_buffer = history
self.change_input_buffer(history, index=index)

return replace

Expand Down Expand Up @@ -206,9 +295,7 @@ def history_next(self, substring='', as_prefix=True):
break

if replace:
self._store_edits()
self._history_index = index
self.input_buffer = history
self.change_input_buffer(history, index=index)

return replace

Expand All @@ -222,6 +309,21 @@ def history_tail(self, n=10):
"""
return self._history[-n:]

@QtCore.Slot(str)
def change_input_buffer(self, buffer, index=0):
"""Change input_buffer value while storing edits and updating history index.

Parameters
----------
buffer : str
New value for the inpur buffer.
index : int, optional
History index to set. The default is 0.
"""
self._store_edits()
self._history_index = index
self.input_buffer = buffer

#---------------------------------------------------------------------------
# 'HistoryConsoleWidget' protected interface
#---------------------------------------------------------------------------
Expand Down
Loading