more extensive smart hinting

This commit is contained in:
Felix Van der Jeugt 2015-12-13 23:40:36 +01:00
parent 2f9051c6e1
commit 1dfcf99d22

View File

@ -19,11 +19,13 @@
"""A HintManager to draw hints over links.""" """A HintManager to draw hints over links."""
import os
import string
import math
import functools
import collections import collections
import itertools
import functools
import math
import os
import re
import string
from PyQt5.QtCore import (pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl, from PyQt5.QtCore import (pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl,
QTimer) QTimer)
@ -49,7 +51,6 @@ Target = usertypes.enum('Target', ['normal', 'tab', 'tab_fg', 'tab_bg',
'fill', 'hover', 'download', 'userscript', 'fill', 'hover', 'download', 'userscript',
'spawn']) 'spawn'])
@pyqtSlot(usertypes.KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_entered(mode, win_id): def on_mode_entered(mode, win_id):
"""Stop hinting when insert mode was entered.""" """Stop hinting when insert mode was entered."""
@ -139,6 +140,8 @@ class HintManager(QObject):
Target.spawn: "Spawn command via hint", Target.spawn: "Spawn command via hint",
} }
FIRST_ALPHABETIC = re.compile('[A-Za-z]{3,}')
mouse_event = pyqtSignal('QMouseEvent') mouse_event = pyqtSignal('QMouseEvent')
start_hinting = pyqtSignal(usertypes.ClickTarget) start_hinting = pyqtSignal(usertypes.ClickTarget)
stop_hinting = pyqtSignal() stop_hinting = pyqtSignal()
@ -247,27 +250,42 @@ class HintManager(QObject):
A list of hint strings, in the same order as the elements. A list of hint strings, in the same order as the elements.
""" """
def html_text_to_hint(text): def html_elem_to_hints(elem):
if not text: return None candidates = []
hint = text.split()[0].lower() if elem.tagName() == "IMG":
if hint.isalpha(): "alt" in elem and candidates.append(elem["alt"])
return hint "title" in elem and candidates.append(elem["title"])
return None "src" in elem and candidates.append(elem["src"].split('/')[-1])
elif elem.tagName() == "A":
candidates.append(str(elem))
"title" in elem and candidates.append(elem["title"])
"href" in elem and candidates.append(elem["href"].split('/')[-1])
elif elem.tagName() == "INPUT":
"name" in elem and candidates.append(elem["name"])
for candidate in candidates:
if not candidate: continue
match = self.FIRST_ALPHABETIC.search(candidate)
if not match: continue
yield candidate[match.start():match.end()].lower()
def is_prefix(hint, existing): def is_prefix(hint, existing):
return set(hint[:i+1] for i in range(len(hint))) & set(existing) return set(hint[:i+1] for i in range(len(hint))) & set(existing)
def first_good_hint(new, existing):
for hint in new:
# some none's
if not hint: continue
if len(hint) < 3: continue
# not a prefix of an existing hint
if set(hint[:i+1] for i in range(len(hint))) & set(existing): continue
return hint
hints = [] hints = []
hintss = set() used_hints = set()
words = iter(self._words) words = iter(self._initialize_word_hints())
for elem in elems: for elem in elems:
hint = html_text_to_hint(str(elem)) hint = first_good_hint(html_elem_to_hints(elem), used_hints) or next(words)
if hint and len(hint) >= 3 and not is_prefix(hint, hintss): used_hints.add(hint)
hint = next(hint[:i] for i in range(3, len(hint) + 1)
if not is_prefix(hint[:i], hintss))
while not hint or is_prefix(hint, hintss):
hint = next(words)
hintss.add(hint)
hints.append(hint) hints.append(hint)
return hints return hints