Start using KeyParser for command mode

This commit is contained in:
Florian Bruhin 2014-04-25 07:50:21 +02:00
parent 30a6b5610e
commit 55a8da7f1b
5 changed files with 88 additions and 74 deletions

View File

@ -129,6 +129,7 @@ class QuteBrowser(QApplication):
'hint': HintKeyParser(self), 'hint': HintKeyParser(self),
'insert': PassthroughKeyParser('keybind.insert', self), 'insert': PassthroughKeyParser('keybind.insert', self),
'passthrough': PassthroughKeyParser('keybind.passthrough', self), 'passthrough': PassthroughKeyParser('keybind.passthrough', self),
'command': PassthroughKeyParser('keybind.command', self),
} }
self._init_cmds() self._init_cmds()
self.mainwindow = MainWindow() self.mainwindow = MainWindow()
@ -140,7 +141,8 @@ class QuteBrowser(QApplication):
modes.manager.register('passthrough', modes.manager.register('passthrough',
self._keyparsers['passthrough'].handle, self._keyparsers['passthrough'].handle,
passthrough=True) passthrough=True)
modes.manager.register('command', None, passthrough=True) modes.manager.register('command', self._keyparsers['command'].handle,
passthrough=True)
self.modeman = modes.manager # for commands self.modeman = modes.manager # for commands
self.installEventFilter(modes.manager) self.installEventFilter(modes.manager)
self.setQuitOnLastWindowClosed(False) self.setQuitOnLastWindowClosed(False)
@ -302,12 +304,11 @@ class QuteBrowser(QApplication):
tabs.cur_link_hovered.connect(status.url.set_hover_url) tabs.cur_link_hovered.connect(status.url.set_hover_url)
# command input / completion # command input / completion
cmd.esc_pressed.connect(tabs.setFocus) modes.manager.left.connect(tabs.on_mode_left)
cmd.clear_completion_selection.connect( cmd.clear_completion_selection.connect(
completion.on_clear_completion_selection) completion.on_clear_completion_selection)
cmd.hide_completion.connect(completion.hide) cmd.hide_completion.connect(completion.hide)
cmd.textChanged.connect(completion.on_cmd_text_changed) cmd.textChanged.connect(completion.on_cmd_text_changed)
cmd.tab_pressed.connect(completion.on_tab_pressed)
completion.change_completed_part.connect(cmd.on_change_completed_part) completion.change_completed_part.connect(cmd.on_change_completed_part)
def _recover_pages(self): def _recover_pages(self):

View File

@ -89,7 +89,12 @@ SECTION_DESC = {
"supported in this mode.\n" "supported in this mode.\n"
"An useful command to map here is the hidden command leave_mode."), "An useful command to map here is the hidden command leave_mode."),
'keybind.passthrough': ( 'keybind.passthrough': (
"Keybindings for hint passthrough.\n" "Keybindings for hint mode.\n"
"Since normal keypresses are passed through, only special keys are "
"supported in this mode.\n"
"An useful command to map here is the hidden command leave_mode."),
'keybind.command': (
"Keybindings for command mode.\n"
"Since normal keypresses are passed through, only special keys are " "Since normal keypresses are passed through, only special keys are "
"supported in this mode.\n" "supported in this mode.\n"
"An useful command to map here is the hidden command leave_mode."), "An useful command to map here is the hidden command leave_mode."),
@ -448,6 +453,15 @@ DATA = OrderedDict([
('<Escape>', 'leave_mode'), ('<Escape>', 'leave_mode'),
)), )),
('keybind.command', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(),
('<Escape>', 'leave_mode'),
('<Up>', 'command_history_prev'),
('<Down>', 'command_history_next'),
('<Shift-Tab>', 'command_item_prev'),
('<Tab>', 'command_item_next'),
)),
('aliases', sect.ValueList( ('aliases', sect.ValueList(
types.Command(), types.Command(), types.Command(), types.Command(),
)), )),

View File

@ -199,6 +199,30 @@ class CompletionView(QTreeView):
logging.debug("No completion model for {}.".format(compl)) logging.debug("No completion model for {}.".format(compl))
return None return None
def _next_prev_item(self, prev):
"""Handle a tab press for the CompletionView.
Select the previous/next item and write the new text to the
statusbar.
Args:
prev: True for prev item, False for next one.
Emit:
change_completed_part: When a completion took place.
"""
if not self._completing:
# No completion running at the moment, ignore keypress
return
idx = self._next_idx(prev)
self.selectionModel().setCurrentIndex(
idx, QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.Rows)
data = self._model.data(idx)
if data is not None:
self._ignore_next = True
self.change_completed_part.emit(data)
def set_model(self, model): def set_model(self, model):
"""Switch completion to a new model. """Switch completion to a new model.
@ -265,31 +289,6 @@ class CompletionView(QTreeView):
if self._enabled: if self._enabled:
self.show() self.show()
@pyqtSlot(bool)
def on_tab_pressed(self, shift):
"""Handle a tab press for the CompletionView.
Select the previous/next item and write the new text to the
statusbar. Called by key_(s)tab_handler in statusbar.command.
Args:
shift: Whether shift is pressed or not.
Emit:
change_completed_part: When a completion took place.
"""
if not self._completing:
# No completion running at the moment, ignore keypress
return
idx = self._next_idx(shift)
self.selectionModel().setCurrentIndex(
idx, QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.Rows)
data = self._model.data(idx)
if data is not None:
self._ignore_next = True
self.change_completed_part.emit(data)
@pyqtSlot() @pyqtSlot()
def on_clear_completion_selection(self): def on_clear_completion_selection(self):
"""Clear the selection model when an item is activated.""" """Clear the selection model when an item is activated."""
@ -298,6 +297,16 @@ class CompletionView(QTreeView):
selmod.clearSelection() selmod.clearSelection()
selmod.clearCurrentIndex() selmod.clearCurrentIndex()
@cmdutils.register(instance='mainwindow.completion')
def command_item_prev(self):
"""Select the previous completion item."""
self._next_prev_item(prev=True)
@cmdutils.register(instance='mainwindow.completion')
def command_item_next(self):
"""Select the next completion item."""
self._next_prev_item(prev=False)
class _CompletionItemDelegate(QStyledItemDelegate): class _CompletionItemDelegate(QStyledItemDelegate):

View File

@ -24,6 +24,7 @@ from PyQt5.QtWidgets import (QWidget, QLineEdit, QProgressBar, QLabel,
from PyQt5.QtGui import QPainter, QKeySequence, QValidator from PyQt5.QtGui import QPainter, QKeySequence, QValidator
import qutebrowser.keyinput.modes as modes import qutebrowser.keyinput.modes as modes
import qutebrowser.commands.utils as cmdutils
from qutebrowser.keyinput.normalmode import STARTCHARS from qutebrowser.keyinput.normalmode import STARTCHARS
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet from qutebrowser.config.style import set_register_stylesheet, get_stylesheet
from qutebrowser.utils.url import urlstring from qutebrowser.utils.url import urlstring
@ -214,7 +215,6 @@ class _Command(QLineEdit):
Attributes: Attributes:
history: The command history object. history: The command history object.
_statusbar: The statusbar (parent) QWidget. _statusbar: The statusbar (parent) QWidget.
_shortcuts: Defined QShortcuts to prevent GCing.
_validator: The current command validator. _validator: The current command validator.
Signals: Signals:
@ -224,9 +224,6 @@ class _Command(QLineEdit):
arg: The search term. arg: The search term.
got_rev_search: Emitted when the user started a new reverse search. got_rev_search: Emitted when the user started a new reverse search.
arg: The search term. arg: The search term.
esc_pressed: Emitted when the escape key was pressed.
tab_pressed: Emitted when the tab key was pressed.
arg: Whether shift has been pressed.
clear_completion_selection: Emitted before the completion widget is clear_completion_selection: Emitted before the completion widget is
hidden. hidden.
hide_completion: Emitted when the completion widget should be hidden. hide_completion: Emitted when the completion widget should be hidden.
@ -237,8 +234,6 @@ class _Command(QLineEdit):
got_cmd = pyqtSignal(str) got_cmd = pyqtSignal(str)
got_search = pyqtSignal(str) got_search = pyqtSignal(str)
got_search_rev = pyqtSignal(str) got_search_rev = pyqtSignal(str)
esc_pressed = pyqtSignal()
tab_pressed = pyqtSignal(bool)
clear_completion_selection = pyqtSignal() clear_completion_selection = pyqtSignal()
hide_completion = pyqtSignal() hide_completion = pyqtSignal()
show_cmd = pyqtSignal() show_cmd = pyqtSignal()
@ -264,44 +259,6 @@ class _Command(QLineEdit):
self.returnPressed.connect(self._on_return_pressed) self.returnPressed.connect(self._on_return_pressed)
self.textEdited.connect(self.history.stop) self.textEdited.connect(self.history.stop)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
self._shortcuts = []
for (key, handler) in [
(Qt.Key_Escape, self.esc_pressed),
(Qt.Key_Up, self._on_key_up_pressed),
(Qt.Key_Down, self._on_key_down_pressed),
(Qt.Key_Tab | Qt.SHIFT, lambda: self.tab_pressed.emit(True)),
(Qt.Key_Tab, lambda: self.tab_pressed.emit(False))
]:
sc = QShortcut(self)
sc.setKey(QKeySequence(key))
sc.setContext(Qt.WidgetWithChildrenShortcut)
sc.activated.connect(handler)
self._shortcuts.append(sc)
@pyqtSlot()
def _on_key_up_pressed(self):
"""Handle Up presses (go back in history)."""
try:
if not self.history.browsing:
item = self.history.start(self.text().strip())
else:
item = self.history.previtem()
except (HistoryEmptyError, HistoryEndReachedError):
return
if item:
self.set_cmd_text(item)
@pyqtSlot()
def _on_key_down_pressed(self):
"""Handle Down presses (go forward in history)."""
if not self.history.browsing:
return
try:
item = self.history.nextitem()
except HistoryEndReachedError:
return
if item:
self.set_cmd_text(item)
@pyqtSlot() @pyqtSlot()
def _on_return_pressed(self): def _on_return_pressed(self):
@ -355,6 +312,31 @@ class _Command(QLineEdit):
self.setFocus() self.setFocus()
self.show_cmd.emit() self.show_cmd.emit()
@cmdutils.register(instance='mainwindow.status.cmd', hide=True)
def command_history_prev(self):
"""Handle Up presses (go back in history)."""
try:
if not self.history.browsing:
item = self.history.start(self.text().strip())
else:
item = self.history.previtem()
except (HistoryEmptyError, HistoryEndReachedError):
return
if item:
self.set_cmd_text(item)
@cmdutils.register(instance='mainwindow.status.cmd', hide=True)
def command_history_next(self):
"""Handle Down presses (go forward in history)."""
if not self.history.browsing:
return
try:
item = self.history.nextitem()
except HistoryEndReachedError:
return
if item:
self.set_cmd_text(item)
def focusInEvent(self, e): def focusInEvent(self, e):
"""Extend focusInEvent to enter command mode.""" """Extend focusInEvent to enter command mode."""
modes.enter("command") modes.enter("command")
@ -368,6 +350,8 @@ class _Command(QLineEdit):
- Clear completion selection - Clear completion selection
- Hide completion - Hide completion
FIXME we should rather do this on on_mode_left...
Args: Args:
e: The QFocusEvent. e: The QFocusEvent.
@ -375,7 +359,7 @@ class _Command(QLineEdit):
clear_completion_selection: Always emitted. clear_completion_selection: Always emitted.
hide_completion: Always emitted so the completion is hidden. hide_completion: Always emitted so the completion is hidden.
""" """
modes.leave("command") modes.maybe_leave("command")
if e.reason() in [Qt.MouseFocusReason, Qt.TabFocusReason, if e.reason() in [Qt.MouseFocusReason, Qt.TabFocusReason,
Qt.BacktabFocusReason, Qt.OtherFocusReason]: Qt.BacktabFocusReason, Qt.OtherFocusReason]:
self.setText('') self.setText('')

View File

@ -343,6 +343,12 @@ class TabbedBrowser(TabWidget):
else: else:
logging.debug('ignoring title change') logging.debug('ignoring title change')
@pyqtSlot(str)
def on_mode_left(self, mode):
"""Focus tabs if command mode was left."""
if mode == "command":
self.setFocus()
def resizeEvent(self, e): def resizeEvent(self, e):
"""Extend resizeEvent of QWidget to emit a resized signal afterwards. """Extend resizeEvent of QWidget to emit a resized signal afterwards.