Qutebrowser: RecursionError with rapid number hints

Created on 11 Nov 2016  路  2Comments  路  Source: qutebrowser/qutebrowser

When using rapid hints in number mode e.g. on https://github.com/The-Compiler/qutebrowser/issues and filtering by text until only one hint matches (e.g. by typing pull so pulse doesn't match anymore), we get this on both master and v0.8.x:

06:47:05 DEBUG    commands   command:run:523 command called: hint ['--rapid', 'links', 'tab-bg']
06:47:05 DEBUG    commands   command:run:538 Calling qutebrowser.browser.hints.HintManager.start(<qutebrowser.browser.hints.HintManager object at 0x7f619c055438>, True, <Group.links: 2>, <Target.tab_bg: 5>, win_id=0, mode=None)
06:47:05 DEBUG    hints      hints:_start_cb:575 hints: 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
06:47:05 DEBUG    message    message:set_text:221 Follow hint in background tab (rapid mode)...
06:47:05 DEBUG    statusbar  text:set_text:55 Setting normal text to 'Follow hint in background tab (rapid mode)...'.
06:47:05 DEBUG    modes      modeman:enter:237 Entering mode KeyMode.hint (reason: HintManager.start)
06:47:05 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: True, forward-unbound-keys: auto, passthrough: False, is_non_alnum: False --> filter: True (focused: <qutebrowser.browser.webkit.webview.WebView tab_id=0 url='https://github.com/The-Compiler/qutebrowser/issues'>)
06:47:05 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.hint - delegating to <qutebrowser.keyinput.modeparsers.HintKeyParser supports_chains=True supports_count=False>
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Got key: 0x50 / text: 'p'
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Giving up with 'p', no matches
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 discarding keystring 'p'.
06:47:06 DEBUG    hints      hints:handle_partial_key:745 Handling new keystring: ''
06:47:06 DEBUG    keyboard   modeparsers:_handle_special_key:168 Got special key 0x50 text p
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: True, forward-unbound-keys: auto, passthrough: False, is_non_alnum: False --> filter: True (focused: <qutebrowser.browser.webkit.webview.WebView tab_id=0 url='https://github.com/The-Compiler/qutebrowser/issues'>)
06:47:06 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.hint - delegating to <qutebrowser.keyinput.modeparsers.HintKeyParser supports_chains=True supports_count=False>
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Got key: 0x55 / text: 'u'
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Giving up with 'u', no matches
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 discarding keystring 'u'.
06:47:06 DEBUG    hints      hints:handle_partial_key:745 Handling new keystring: ''
06:47:06 DEBUG    keyboard   modeparsers:_handle_special_key:168 Got special key 0x55 text u
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: True, forward-unbound-keys: auto, passthrough: False, is_non_alnum: False --> filter: True (focused: <qutebrowser.browser.webkit.webview.WebView tab_id=0 url='https://github.com/The-Compiler/qutebrowser/issues'>)
06:47:06 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.hint - delegating to <qutebrowser.keyinput.modeparsers.HintKeyParser supports_chains=True supports_count=False>
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Got key: 0x4c / text: 'l'
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Giving up with 'l', no matches
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 discarding keystring 'l'.
06:47:06 DEBUG    hints      hints:handle_partial_key:745 Handling new keystring: ''
06:47:06 DEBUG    keyboard   modeparsers:_handle_special_key:168 Got special key 0x4c text l
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: True, forward-unbound-keys: auto, passthrough: False, is_non_alnum: False --> filter: True (focused: <qutebrowser.browser.webkit.webview.WebView tab_id=0 url='https://github.com/The-Compiler/qutebrowser/issues'>)
06:47:06 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
06:47:06 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.hint - delegating to <qutebrowser.keyinput.modeparsers.HintKeyParser supports_chains=True supports_count=False>
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Got key: 0x4c / text: 'l'
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 Giving up with 'l', no matches
06:47:06 DEBUG    keyboard   basekeyparser:_debug_log:112 discarding keystring 'l'.
06:47:06 DEBUG    hints      hints:handle_partial_key:745 Handling new keystring: ''
06:47:06 DEBUG    keyboard   modeparsers:_handle_special_key:168 Got special key 0x4c text l
06:47:07 ERROR    misc       crashsignal:exception_hook:211 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/app.py", line 864, in eventFilter
    return handler(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/app.py", line 824, in _handle_key_event
    return man.eventFilter(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py", line 326, in eventFilter
    return self._eventFilter_keypress(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py", line 167, in _eventFilter_keypress
    handled = parser.handle(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeparsers.py", line 222, in handle
    return self._handle_special_key(e)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeparsers.py", line 197, in _handle_special_key
    hintmanager.filter_hints(self._filtertext)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/hints.py", line 814, in filter_hints
    visible=self._context.labels)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/hints.py", line 741, in _handle_auto_follow
    self._fire(*visible)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/hints.py", line 867, in _fire
    self.filter_hints(None)
# [...]
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/hints.py", line 867, in _fire
    self.filter_hints(None)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/hints.py", line 781, in filter_hints
    if self._filter_matches(filterstr, str(label.elem)):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/webelem.py", line 90, in __str__
    return self.text()
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/webkit/webkitelem.py", line 121, in text
    if self.is_content_editable() or not use_js:
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/webelem.py", line 200, in is_content_editable
    return self['contenteditable'].lower() not in ['false', 'inherit']
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/webkit/webkitelem.py", line 56, in __getitem__
    if key not in self:
RecursionError: maximum recursion depth exceeded

Reports:

exception hints 0 - high

Most helpful comment

Are you currently working on that? I've looked into this and basically when HintManager wants to clear hints after rapid number-mode fires, it calls filter_hints(None). Unfortunately filter_hints on None uses arg from previous call which is obviously a match. So _fire calls filter_hints, which calls _fire... until the RecursionError pops out. So you can do something like:

self._context.filterstr = "" # or None, not sure which looks better
self.filter_hints(None)

But then there's another issue - HintKeyParser keeps its own filtertext variable, which holds user hint keystrokes and it doesn't reset after firing with rapid number-mode. So if you want to follow projects it follows on proj and reset labels but not the filtertext, so if you now press e it fires projects again, if you press anything else, it exits rapid (since there's no projx on page, for example).

So with this dirty solution it does work, but I'm not sure how to make it less hackish:

# HintManager._fire, something around line 876
self._context.filterstr = ""
self.filter_hints(None)
keyparsers = objreg.get('keyparsers', scope='window',
                        window=self._win_id)
keyparsers[usertypes.KeyMode.hint]._filtertext = ''

I hope it helps somehow!

All 2 comments

Are you currently working on that? I've looked into this and basically when HintManager wants to clear hints after rapid number-mode fires, it calls filter_hints(None). Unfortunately filter_hints on None uses arg from previous call which is obviously a match. So _fire calls filter_hints, which calls _fire... until the RecursionError pops out. So you can do something like:

self._context.filterstr = "" # or None, not sure which looks better
self.filter_hints(None)

But then there's another issue - HintKeyParser keeps its own filtertext variable, which holds user hint keystrokes and it doesn't reset after firing with rapid number-mode. So if you want to follow projects it follows on proj and reset labels but not the filtertext, so if you now press e it fires projects again, if you press anything else, it exits rapid (since there's no projx on page, for example).

So with this dirty solution it does work, but I'm not sure how to make it less hackish:

# HintManager._fire, something around line 876
self._context.filterstr = ""
self.filter_hints(None)
keyparsers = objreg.get('keyparsers', scope='window',
                        window=self._win_id)
keyparsers[usertypes.KeyMode.hint]._filtertext = ''

I hope it helps somehow!

Thanks for the investigation, that definitely helps! I haven't had time to take a closer look at this yet, and I'll probably only do after v0.9.0 is released.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brianbuccola picture brianbuccola  路  3Comments

The-Compiler picture The-Compiler  路  3Comments

orangecms picture orangecms  路  3Comments

Chinggis6 picture Chinggis6  路  4Comments

agguser picture agguser  路  4Comments