Repository: qutebrowser/qutebrowser

Issue:
Tabline color messed up after a series of mode transitions
**Version info (see `:version`)**:

```
qutebrowser v1.6.0
Git commit: 
Backend: QtWebEngine (Chromium 65.0.3325.230)

CPython: 3.6.7
Qt: 5.11.1
PyQt: 5.11.2

sip: 4.19.12
colorama: 0.3.7
pypeg2: 2.15
jinja2: 2.10
pygments: 2.2.0
yaml: 3.12
cssutils: no
attr: 18.2.0
PyQt5.QtWebEngineWidgets: yes
PyQt5.QtWebKitWidgets: no
pdf.js: no
sqlite: 3.23.1
QtNetwork SSL: no
```

**Description**

I've come up with a decently complicated script that lets me do the following

- Search for text inside an input from the page
- Enter **Caret Selection Mode** - This will focus the input and select the pattern inside of it (used to extract the cursor's position at selections' start)
- Leave **Caret Selection Mode** 
- Re-focus the input (since we should be in normal mode after leaving **Caret Selection Mode** )
- Tab away and Shift-Tab back to the input (workaround from [StackOverflow](https://stackoverflow.com/a/19206832/8401696))
- Re-position the cursor at the start of where should have been the start of the previous selection
- Start Insert Mode

In summary, it targets a text inside an input element and starts insert mode. [Demo video](https://youtu.be/C6Les3ZbwWo)

Code (I had to shorten attribute names due to the text length limit):
`
config.bind('gl', 'enter-mode caret ;; jseval [document.activeElement].map(e => { e.setAttribute("_g", new Date().getTime()); e.setAttribute("_s", e.selectionStart) }) ;; leave-mode ;; enter-mode normal ;; jseval [Array.from(document.querySelectorAll("[_g]")).sort((a,b) => b.getAttribute("_g") - a.getAttribute("_g"))[0]].map(e => {e.focus();e.click();setTimeout(() => e.setSelectionRange(e.getAttribute("_s"),e.getAttribute("_s")), 200) }) ;; fake-key <tab> ;; fake-key <shift-tab> ;; enter-mode insert')
`

The problem is that after leaving **Caret Selection Mode** , the bottom bar will be bugged with the pink color from caret mode and it doesn't go away. _Happens 100% of the time._

On another note, if I may ask, is there a way to suppress the annoying JSEval panel popping up at the bottom?


Discussion:

João Paulo writes:

Debug log:

18:39:06 DEBUG    completion completer:_get_new_completion:108 No completion in position 37
18:39:06 DEBUG    completion completer:_update_completion:244 Clearing completion
18:39:06 DEBUG    modes      modeman:_handle_keyrelease:219 filter: False
18:39:06 DEBUG    modes      modeman:_handle_keyrelease:219 filter: True
18:39:06 DEBUG    modes      modeman:_handle_keypress:172 got keypress in mode KeyMode.command - delegating to <qutebrowser.keyinput.modeparsers.PassthroughKeyParser mode='command'>
18:39:06 DEBUG    modes      modeman:_handle_keypress:199 match: 2, forward_unbound_keys: auto, passthrough: True, is_non_alnum: True, dry_run: True --> filter: True (focused: <qutebrowser.mainwindow.statusbar.command.Command>)
18:39:06 DEBUG    modes      modeman:_handle_keypress:172 got keypress in mode KeyMode.command - delegating to <qutebrowser.keyinput.modeparsers.PassthroughKeyParser mode='command'>
18:39:06 DEBUG    commands   command:run:534 command called: command-accept
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.mainwindow.statusbar.command.Command.command_accept(<qutebrowser.mainwindow.statusbar.command.Command>, False)
18:39:06 DEBUG    save       savemanager:mark_dirty:71 Marking command-history as dirty.
18:39:06 DEBUG    modes      modeman:leave:313 Leaving mode KeyMode.command (reason: cmd accept)
18:39:06 DEBUG    statusbar  text:set_text:57 Setting normal text to ''.
18:39:06 DEBUG    statusbar  bar:set_mode_active:286 Setting command flag to False
18:39:06 DEBUG    completion completer:schedule_completion_update:215 Scheduling completion update.
18:39:06 DEBUG    completion completer:schedule_completion_update:212 Ignoring update because there were no changes.
18:39:06 DEBUG    statusbar  bar:_hide_cmd_widget:320 Hiding cmd widget
18:39:06 DEBUG    misc       app:on_focus_object_changed:836 Focus object changed: <qutebrowser.mainwindow.mainwindow.MainWindow>
18:39:06 DEBUG    misc       app:on_focus_object_changed:836 Focus object changed: <qutebrowser.mainwindow.statusbar.text.Text text=''>
18:39:06 DEBUG    modes      tabbedbrowser:on_mode_left:683 Left status-input mode, focusing <qutebrowser.browser.webengine.webenginetab.WebEngineTab tab_id=0 url='https://github.com/qutebrowser/qutebrowser/issues/4619'>
18:39:06 DEBUG    misc       app:on_focus_object_changed:836 Focus object changed: <PyQt5.QtWidgets.QWidget object at 0x7ff230123ee8>
18:39:06 DEBUG    commands   command:run:534 command called: enter-mode ['caret']
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.keyinput.modeman.ModeManager.enter_mode(<qutebrowser.keyinput.modeman.ModeManager mode=<KeyMode.normal: 1>>, 'caret')
18:39:06 DEBUG    modes      modeman:enter:250 Entering mode KeyMode.caret (reason: command)
18:39:06 DEBUG    statusbar  text:set_text:57 Setting normal text to '-- CARET MODE --'.
18:39:06 DEBUG    commands   command:run:534 command called: jseval ['[document.activeElement].map(e => { e.setAttribute("_g", new Date().getTime()); e.setAttribute("_s", e.selectionStart) })']
18:39:06 DEBUG    commands   argparser:multitype_conv:158 Trying to parse None as <enum 'JsWorld'>
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.browser.commands.CommandDispatcher.jseval(<qutebrowser.browser.commands.CommandDispatcher>, '[document.activeElement].map(e => { e.setAttribute("_g", new Date().getTime()); e.setAttribute("_s", e.selectionStart) })', False, False, world=None)
18:39:06 DEBUG    commands   command:run:534 command called: leave-mode
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.keyinput.modeman.ModeManager.leave_current_mode(<qutebrowser.keyinput.modeman.ModeManager mode=<KeyMode.caret: 8>>)
18:39:06 DEBUG    modes      modeman:leave:313 Leaving mode KeyMode.caret (reason: leave current)
18:39:06 DEBUG    statusbar  text:set_text:57 Setting normal text to ''.
18:39:06 DEBUG    statusbar  bar:set_mode_active:294 Setting caret mode off
18:39:06 DEBUG    commands   command:run:534 command called: enter-mode ['normal']
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.keyinput.modeman.ModeManager.enter_mode(<qutebrowser.keyinput.modeman.ModeManager mode=<KeyMode.normal: 1>>, 'normal')
18:39:06 DEBUG    modes      modeman:leave:313 Leaving mode KeyMode.normal (reason: enter normal: command)
18:39:06 DEBUG    commands   command:run:534 command called: jseval ['[Array.from(document.querySelectorAll("[_g]")).sort((a,b) => b.getAttribute("_g") - a.getAttribute("_g"))[0]].map(e => {e.focus();e.click();setTimeout(() => e.setSelectionRange(e.getAttribute("_s"),e.getAttribute("_s")), 200) })']
18:39:06 DEBUG    commands   argparser:multitype_conv:158 Trying to parse None as <enum 'JsWorld'>
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.browser.commands.CommandDispatcher.jseval(<qutebrowser.browser.commands.CommandDispatcher>, '[Array.from(document.querySelectorAll("[_g]")).sort((a,b) => b.getAttribute("_g") - a.getAttribute("_g"))[0]].map(e => {e.focus();e.click();setTimeout(() => e.setSelectionRange(e.getAttribute("_s"),…, False, False, world=None)
18:39:06 DEBUG    commands   command:run:534 command called: fake-key ['<tab>']
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.browser.commands.CommandDispatcher.fake_key(<qutebrowser.browser.commands.CommandDispatcher>, '<tab>', False)
18:39:06 DEBUG    commands   command:run:534 command called: fake-key ['<shift-tab>']
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.browser.commands.CommandDispatcher.fake_key(<qutebrowser.browser.commands.CommandDispatcher>, '<shift-tab>', False)
18:39:06 DEBUG    commands   command:run:534 command called: enter-mode ['insert']
18:39:06 DEBUG    commands   command:run:549 Calling qutebrowser.keyinput.modeman.ModeManager.enter_mode(<qutebrowser.keyinput.modeman.ModeManager mode=<KeyMode.normal: 1>>, 'insert')
18:39:06 DEBUG    modes      modeman:enter:250 Entering mode KeyMode.insert (reason: command)
18:39:06 DEBUG    modes      modeman:leave:307 Ignoring leave request for KeyMode.hint (reason insert mode) as we're in mode KeyMode.insert
18:39:06 DEBUG    statusbar  text:set_text:57 Setting normal text to '-- INSERT MODE --'.
18:39:06 DEBUG    statusbar  bar:set_mode_active:280 Setting insert flag to True
18:39:06 DEBUG    modes      modeman:_handle_keypress:199 match: 2, forward_unbound_keys: auto, passthrough: True, is_non_alnum: True, dry_run: False --> filter: True (focused: <PyQt5.QtWidgets.QWidget object at 0x7ff230123ee8>)
18:39:06 DEBUG    signals    signalfilter:_filter_signals:86 emitting: cur_caret_selection_toggled(False) (tab 0)
18:39:06 DEBUG    statusbar  bar:on_caret_selection_toggled:375 Setting caret selection False
18:39:06 DEBUG    statusbar  text:set_text:57 Setting normal text to '-- CARET MODE --'.
18:39:06 INFO     message    message:info:81 [None]
18:39:06 DEBUG    misc       mainwindow:_update_overlay_geometry:305 new geometry for <qutebrowser.mainwindow.messageview.MessageView object at 0x7ff230173d38>: PyQt5.QtCore.QRect(0, 1023, 959, 20)
18:39:06 INFO     message    message:info:81 [None]
18:39:06 DEBUG    misc       app:on_focus_object_changed:836 Focus object changed: <qutebrowser.mainwindow.tabwidget.TabBar count=1>
18:39:06 DEBUG    js         shared:javascript_log_message:146 [https://github.com/qutebrowser/qutebrowser/issues/4619:1] Uncaught TypeError: e.setSelectionRange is not a function
18:39:09 DEBUG    commands   command:run:534 command called: leave-mode
18:39:09 DEBUG    commands   command:run:549 Calling qutebrowser.keyinput.modeman.ModeManager.leave_current_mode(<qutebrowser.keyinput.modeman.ModeManager mode=<KeyMode.insert: 6>>)
18:39:09 DEBUG    modes      modeman:leave:313 Leaving mode KeyMode.insert (reason: leave current)
18:39:09 DEBUG    statusbar  text:set_text:57 Setting normal text to ''.
18:39:09 DEBUG    statusbar  bar:set_mode_active:280 Setting insert flag to False
18:39:09 DEBUG    modes      modeman:_handle_keyrelease:219 filter: True
18:39:11 DEBUG    misc       app:on_focus_object_changed:836 Focus object changed: None
18:39:17 DEBUG    destroy    lineparser:_after_save:80 Saved to /tmp/qutebrowser-basedir-z54mwep1/data/cmd-history

> The problem is that after leaving **Caret Selection Mode** , the bottom bar will be bugged with the pink color from caret mode and it doesn't go away. _Happens 100% of the time._

Workaround is to toggle caret mode.

More specific log of relevant functions:

mode: KeyMode.command , val: True
ColorFlags(prompt=False, insert=False, command=True, caret=<CaretMode.off: 1>, private=False, passthrough=False)
mode: KeyMode.command , val: False
ColorFlags(prompt=False, insert=False, command=False, caret=<CaretMode.off: 1>, private=False, passthrough=False)
mode: KeyMode.caret , val: True
ColorFlags(prompt=False, insert=False, command=False, caret=<CaretMode.off: 1>, private=False, passthrough=False)
running setInitialCursor
mode: KeyMode.caret , val: False
ColorFlags(prompt=False, insert=False, command=False, caret=<CaretMode.off: 1>, private=False, passthrough=False)
mode: KeyMode.insert , val: True
ColorFlags(prompt=False, insert=True, command=False, caret=<CaretMode.off: 1>, private=False, passthrough=False)
setInitialCursor callback
caret_selection_toggle: False
19:12:30 INFO: [None]
19:12:30 INFO: [None]
mode: KeyMode.insert , val: False
ColorFlags(prompt=False, insert=False, command=False, caret=<CaretMode.on: 2>, private=False, passthrough=False)

Looks like the caret callback is running too late, because the js dosen't get
a chance to run. Can you reproduce this without a script like this? I think we
can just drop the callbacks if we have left caret mode to fix this.

> On another note, if I may ask, is there a way to suppress the annoying JSEval panel popping up at the bottom?

Try --quiet


Resolving patch:
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -437,6 +437,7 @@ def __init__(self,
         self._tab = tab
         self._widget = None
         self.selection_enabled = False
+        self._mode_manager = mode_manager
         mode_manager.entered.connect(self._on_mode_entered)
         mode_manager.left.connect(self._on_mode_left)
 
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -270,6 +270,9 @@ def _on_mode_entered(self, mode):
 
     def _selection_cb(self, enabled):
         """Emit selection_toggled based on setInitialCursor."""
+        if self._mode_manager.mode != usertypes.KeyMode.caret:
+            log.webview.debug("Ignoring selection cb due to mode change.")
+            return
         if enabled is None:
             log.webview.debug("Ignoring selection status None")
             return


Test patch: