Merge remote-tracking branch 'origin/pr/3590' into tab-mode

This commit is contained in:
Florian Bruhin 2018-06-14 15:40:58 +02:00
commit 1335fccba1
4 changed files with 85 additions and 20 deletions

View File

@ -30,6 +30,9 @@ from qutebrowser.config import config
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.utils import usertypes, log, objreg, utils from qutebrowser.utils import usertypes, log, objreg, utils
INPUT_MODES = [usertypes.KeyMode.insert, usertypes.KeyMode.passthrough]
PROMPT_MODES = [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]
@attr.s(frozen=True) @attr.s(frozen=True)
class KeyEvent: class KeyEvent:
@ -121,6 +124,7 @@ class ModeManager(QObject):
Attributes: Attributes:
mode: The mode we're currently in. mode: The mode we're currently in.
_win_id: The window ID of this ModeManager _win_id: The window ID of this ModeManager
_prev_mode: Mode before a prompt popped up
_parsers: A dictionary of modes and their keyparsers. _parsers: A dictionary of modes and their keyparsers.
_forward_unbound_keys: If we should forward unbound keys. _forward_unbound_keys: If we should forward unbound keys.
_releaseevents_to_pass: A set of KeyEvents where the keyPressEvent was _releaseevents_to_pass: A set of KeyEvents where the keyPressEvent was
@ -144,6 +148,7 @@ class ModeManager(QObject):
super().__init__(parent) super().__init__(parent)
self._win_id = win_id self._win_id = win_id
self._parsers = {} self._parsers = {}
self._prev_mode = usertypes.KeyMode.normal
self.mode = usertypes.KeyMode.normal self.mode = usertypes.KeyMode.normal
self._releaseevents_to_pass = set() self._releaseevents_to_pass = set()
@ -240,9 +245,8 @@ class ModeManager(QObject):
mode, '' if reason is None else ' (reason: {})'.format(reason))) mode, '' if reason is None else ' (reason: {})'.format(reason)))
if mode not in self._parsers: if mode not in self._parsers:
raise ValueError("No keyparser for mode {}".format(mode)) raise ValueError("No keyparser for mode {}".format(mode))
prompt_modes = (usertypes.KeyMode.prompt, usertypes.KeyMode.yesno) if self.mode == mode or (self.mode in PROMPT_MODES and
if self.mode == mode or (self.mode in prompt_modes and mode in PROMPT_MODES):
mode in prompt_modes):
log.modes.debug("Ignoring request as we're in mode {} " log.modes.debug("Ignoring request as we're in mode {} "
"already.".format(self.mode)) "already.".format(self.mode))
return return
@ -254,6 +258,11 @@ class ModeManager(QObject):
return return
log.modes.debug("Overriding mode {}.".format(self.mode)) log.modes.debug("Overriding mode {}.".format(self.mode))
self.left.emit(self.mode, mode, self._win_id) self.left.emit(self.mode, mode, self._win_id)
if (mode in PROMPT_MODES and self.mode in INPUT_MODES and
config.val.tabs.mode_on_change == 'restore'):
self._prev_mode = self.mode
else:
self._prev_mode = usertypes.KeyMode.normal
self.mode = mode self.mode = mode
self.entered.emit(mode, self._win_id) self.entered.emit(mode, self._win_id)
@ -301,6 +310,9 @@ class ModeManager(QObject):
self.clear_keychain() self.clear_keychain()
self.mode = usertypes.KeyMode.normal self.mode = usertypes.KeyMode.normal
self.left.emit(mode, self.mode, self._win_id) self.left.emit(mode, self.mode, self._win_id)
if mode in PROMPT_MODES:
self.enter(self._prev_mode,
reason='restore mode before {}'.format(mode.name))
@cmdutils.register(instance='mode-manager', name='leave-mode', @cmdutils.register(instance='mode-manager', name='leave-mode',
not_modes=[usertypes.KeyMode.normal], scope='window') not_modes=[usertypes.KeyMode.normal], scope='window')

View File

@ -492,6 +492,7 @@ class MainWindow(QWidget):
self.tabbed_browser.cur_fullscreen_requested.connect(status.maybe_hide) self.tabbed_browser.cur_fullscreen_requested.connect(status.maybe_hide)
# command input / completion # command input / completion
mode_manager.entered.connect(self.tabbed_browser.on_mode_entered)
mode_manager.left.connect(self.tabbed_browser.on_mode_left) mode_manager.left.connect(self.tabbed_browser.on_mode_left)
cmd.clear_completion_selection.connect( cmd.clear_completion_selection.connect(
completion_obj.on_clear_completion_selection) completion_obj.on_clear_completion_selection)

View File

@ -644,24 +644,32 @@ class TabbedBrowser(QWidget):
if config.val.tabs.tabs_are_windows: if config.val.tabs.tabs_are_windows:
self.widget.window().setWindowIcon(icon) self.widget.window().setWindowIcon(icon)
@pyqtSlot(usertypes.KeyMode)
def on_mode_entered(self, mode):
"""Save input mode when tabs.mode_on_change = restore."""
if (config.val.tabs.mode_on_change == 'restore' and
mode in modeman.INPUT_MODES):
tab = self.widget.currentWidget()
if tab is not None:
tab.data.input_mode = mode
@pyqtSlot(usertypes.KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Give focus to current tab if command mode was left.""" """Give focus to current tab if command mode was left."""
if mode in [usertypes.KeyMode.command, usertypes.KeyMode.prompt, widget = self.widget.currentWidget()
usertypes.KeyMode.yesno]: if widget is None:
widget = self.widget.currentWidget() return
if mode in [usertypes.KeyMode.command] + modeman.PROMPT_MODES:
log.modes.debug("Left status-input mode, focusing {!r}".format( log.modes.debug("Left status-input mode, focusing {!r}".format(
widget)) widget))
if widget is None:
return
widget.setFocus() widget.setFocus()
if config.val.tabs.mode_on_change == 'restore':
widget.data.input_mode = usertypes.KeyMode.normal
@pyqtSlot(int) @pyqtSlot(int)
def on_current_changed(self, idx): def on_current_changed(self, idx):
"""Set last-focused-tab and leave hinting mode when focus changed.""" """Set last-focused-tab and leave hinting mode when focus changed."""
mode_on_change = config.val.tabs.mode_on_change mode_on_change = config.val.tabs.mode_on_change
modes_to_save = [usertypes.KeyMode.insert,
usertypes.KeyMode.passthrough]
if idx == -1 or self.shutting_down: if idx == -1 or self.shutting_down:
# closing the last tab (before quitting) or shutting down # closing the last tab (before quitting) or shutting down
return return
@ -670,26 +678,28 @@ class TabbedBrowser(QWidget):
log.webview.debug("on_current_changed got called with invalid " log.webview.debug("on_current_changed got called with invalid "
"index {}".format(idx)) "index {}".format(idx))
return return
if self._now_focused is not None and mode_on_change == 'restore':
current_mode = modeman.instance(self._win_id).mode
if current_mode not in modes_to_save:
current_mode = usertypes.KeyMode.normal
self._now_focused.data.input_mode = current_mode
log.modes.debug("Current tab changed, focusing {!r}".format(tab)) log.modes.debug("Current tab changed, focusing {!r}".format(tab))
tab.setFocus() tab.setFocus()
modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret] modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
if mode_on_change != 'persist':
modes_to_leave += modes_to_save mm_instance = modeman.instance(self._win_id)
current_mode = mm_instance.mode
log.modes.debug("Mode before tab change: {} (mode_on_change = {})"
.format(current_mode.name, mode_on_change))
if mode_on_change == 'normal':
modes_to_leave += modeman.INPUT_MODES
for mode in modes_to_leave: for mode in modes_to_leave:
modeman.leave(self._win_id, mode, 'tab changed', maybe=True) modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
if mode_on_change == 'restore': if (mode_on_change == 'restore' and
modeman.enter(self._win_id, tab.data.input_mode, current_mode not in modeman.PROMPT_MODES):
'restore input mode for tab') modeman.enter(self._win_id, tab.data.input_mode, 'restore')
if self._now_focused is not None: if self._now_focused is not None:
objreg.register('last-focused-tab', self._now_focused, update=True, objreg.register('last-focused-tab', self._now_focused, update=True,
scope='window', window=self._win_id) scope='window', window=self._win_id)
log.modes.debug("Mode after tab change: {} (mode_on_change = {})"
.format(current_mode.name, mode_on_change))
self._now_focused = tab self._now_focused = tab
self.current_tab_changed.emit(tab) self.current_tab_changed.emit(tab)
QTimer.singleShot(0, self._update_window_title) QTimer.singleShot(0, self._update_window_title)

View File

@ -160,3 +160,45 @@ Feature: Keyboard input
And I press the key "c" And I press the key "c"
Then the message "foo 3" should be shown Then the message "foo 3" should be shown
And the message "foo 3" should be shown And the message "foo 3" should be shown
# test all tabs.mode_on_change modes
Scenario: mode on change normal
Given I set tabs.mode_on_change to normal
And I clean up open tabs
When I open about:blank
And I run :enter-mode insert
And I open about:blank in a new tab
Then "Entering mode KeyMode.insert (reason: command)" should be logged
And "Leaving mode KeyMode.insert (reason: tab changed)" should be logged
And "Mode before tab change: insert (mode_on_change = normal)" should be logged
And "Mode after tab change: normal (mode_on_change = normal)" should be logged
Scenario: mode on change persist
Given I set tabs.mode_on_change to persist
And I clean up open tabs
When I open about:blank
And I run :enter-mode insert
And I open about:blank in a new tab
Then "Entering mode KeyMode.insert (reason: command)" should be logged
And "Leaving mode KeyMode.insert (reason: tab changed)" should not be logged
And "Mode before tab change: insert (mode_on_change = persist)" should be logged
And "Mode after tab change: insert (mode_on_change = persist)" should be logged
Scenario: mode on change restore
Given I set tabs.mode_on_change to restore
And I clean up open tabs
When I open about:blank
And I run :enter-mode insert
And I open about:blank in a new tab
And I run :enter-mode passthrough
And I run :tab-focus 1
Then "Entering mode KeyMode.insert (reason: command)" should be logged
And "Mode before tab change: insert (mode_on_change = restore)" should be logged
And "Entering mode KeyMode.normal (reason: restore)" should be logged
And "Mode after tab change: normal (mode_on_change = restore)" should be logged
And "Entering mode KeyMode.passthrough (reason: command)" should be logged
And "Mode before tab change: passthrough (mode_on_change = restore)" should be logged
And "Entering mode KeyMode.insert (reason: restore)" should be logged
And "Mode after tab change: insert (mode_on_change = restore)" should be logged