From fe4800b68f01d4ffc90c6ff159b9b316119613f8 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Tue, 5 Apr 2016 09:51:22 +0200 Subject: [PATCH 01/10] prevent words from the dictionary prefixing smart hints --- qutebrowser/browser/hints.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 9ec14388f..b821e43c7 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -1068,12 +1068,16 @@ class WordHinter: return any(hint.startswith(e) or e.startswith(hint) for e in existing) - def new_hint_for(self, elem, existing): + def filter_prefixes(self, hints, existing): + return (h for h in hints if not self.any_prefix(h, existing)) + + def new_hint_for(self, elem, existing, fallback): """Return a hint for elem, not conflicting with the existing.""" new = self.tag_words_to_hints(self.extract_tag_words(elem)) - no_prefixes = (h for h in new if not self.any_prefix(h, existing)) + new_no_prefixes = self.filter_prefixes(new, existing) + fallback_no_prefixes = self.filter_prefixes(fallback, existing) # either the first good, or None - return next(no_prefixes, None) + return next(new_no_prefixes, next(fallback_no_prefixes)) def hint(self, elems): """Produce hint labels based on the html tags. @@ -1093,7 +1097,7 @@ class WordHinter: used_hints = set() words = iter(self.words) for elem in elems: - hint = self.new_hint_for(elem, used_hints) or next(words) + hint = self.new_hint_for(elem, used_hints, words) used_hints.add(hint) hints.append(hint) return hints From 7d9d4937aaa910087889a74862d3761e06995580 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Wed, 13 Apr 2016 11:25:54 +0200 Subject: [PATCH 02/10] initial testing - local tox does not work yet --- tests/integration/data/hinting.txt | 1 + tests/integration/data/hints/issue1393.html | 38 +++++++++++++++++++++ tests/integration/data/l33t.txt | 1 + tests/integration/data/smart.txt | 1 + tests/integration/data/words.txt | 1 + tests/integration/test_hints_html.py | 34 ++++++++++++++++++ 6 files changed, 76 insertions(+) create mode 100644 tests/integration/data/hinting.txt create mode 100644 tests/integration/data/hints/issue1393.html create mode 100644 tests/integration/data/l33t.txt create mode 100644 tests/integration/data/smart.txt create mode 100644 tests/integration/data/words.txt diff --git a/tests/integration/data/hinting.txt b/tests/integration/data/hinting.txt new file mode 100644 index 000000000..13db8e00b --- /dev/null +++ b/tests/integration/data/hinting.txt @@ -0,0 +1 @@ +hinting diff --git a/tests/integration/data/hints/issue1393.html b/tests/integration/data/hints/issue1393.html new file mode 100644 index 000000000..c1269d517 --- /dev/null +++ b/tests/integration/data/hints/issue1393.html @@ -0,0 +1,38 @@ + + + + + Let's Hint some words + + +

Word hints

+

This page contains links to be hinted with words. The two + kinds of word hints will be described below.

+ +

Smart hints

+

In qutebrowser, urls can not only be hinted with letters and + numbers, but also with words. When there is + a sensible url text available, qutebrowser will even use that + text to create a smart hint.

+ +

Filled hints

+

When no smart hints are available, because the hint text is + too short or l33t to + use, words from a dictionary will be used.

+ +

The current dictionary contains only the words: one, two, + three, four and five. As there are for none-smart hints in this + page, all five words should be used.

+ +

Hint conflicts

+

Of course, hints have to be unique. For instance, all hints + below should get a different hint, whether they're smart or + not:

+ + + diff --git a/tests/integration/data/l33t.txt b/tests/integration/data/l33t.txt new file mode 100644 index 000000000..1e2266cec --- /dev/null +++ b/tests/integration/data/l33t.txt @@ -0,0 +1 @@ +l33t diff --git a/tests/integration/data/smart.txt b/tests/integration/data/smart.txt new file mode 100644 index 000000000..c2d01532a --- /dev/null +++ b/tests/integration/data/smart.txt @@ -0,0 +1 @@ +smart diff --git a/tests/integration/data/words.txt b/tests/integration/data/words.txt new file mode 100644 index 000000000..71af1a951 --- /dev/null +++ b/tests/integration/data/words.txt @@ -0,0 +1 @@ +words diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index cc668193d..23f04fdc9 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -1,3 +1,4 @@ + # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: # Copyright 2016 Florian Bruhin (The Compiler) @@ -21,10 +22,12 @@ import os import os.path +import re import yaml import pytest import bs4 +import textwrap def collect_tests(): @@ -54,3 +57,34 @@ def test_hints(test_name, quteproc): quteproc.wait_for(message='hints: a', category='hints') quteproc.send_cmd(':follow-hint a') quteproc.wait_for_load_finished('data/' + parsed['target']) + + +def test_word_hints_issue1393(quteproc, tmpdir): + dict_file = tmpdir / 'dict' + dict_file.write(textwrap.dedent(""" + alpha + beta + gamma + delta + epsilon + """)) + targets = [ + ('words', 'words.txt'), + ('smart', 'smart.txt'), + ('hinting', 'hinting.txt'), + ('alpha', 'l33t.txt'), + ('beta', 'l33t.txt'), + ('gamma', 'l33t.txt'), + ('delta', 'l33t.txt'), + ('epsilon', 'l33t.txt'), + ] + + quteproc.set_setting('hints', 'mode', 'words') + quteproc.set_setting('hints', 'dictionary', str(dict_file)) + + for hint, target in targets: + quteproc.open_path('data/hints/issue1393.html') + quteproc.send_cmd(':hint') + quteproc.wait_for(message=re.compile('hints: .*'), category='hints') + quteproc.send_cmd(':follow-hint {}'.format(hint)) + quteproc.wait_for_load_finished('data/{}'.format(target)) From 9633e79d8727a7caadda24dbea5acb257923a739 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Wed, 13 Apr 2016 11:34:06 +0200 Subject: [PATCH 03/10] why don't I even know my own options --- tests/integration/test_hints_html.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index 23f04fdc9..d31f09b33 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -79,7 +79,7 @@ def test_word_hints_issue1393(quteproc, tmpdir): ('epsilon', 'l33t.txt'), ] - quteproc.set_setting('hints', 'mode', 'words') + quteproc.set_setting('hints', 'mode', 'word') quteproc.set_setting('hints', 'dictionary', str(dict_file)) for hint, target in targets: From ae72841856a3374980c839f9d7543f949e28d9c7 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Wed, 13 Apr 2016 12:10:09 +0200 Subject: [PATCH 04/10] read the wait_for code --- tests/integration/test_hints_html.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index d31f09b33..3fe08e88e 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -85,6 +85,6 @@ def test_word_hints_issue1393(quteproc, tmpdir): for hint, target in targets: quteproc.open_path('data/hints/issue1393.html') quteproc.send_cmd(':hint') - quteproc.wait_for(message=re.compile('hints: .*'), category='hints') + quteproc.wait_for(message='hints: *', category='hints') quteproc.send_cmd(':follow-hint {}'.format(hint)) quteproc.wait_for_load_finished('data/{}'.format(target)) From fdb630555d7a68a1335e6d01d972bf1bccf2b722 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Mon, 25 Apr 2016 10:12:21 +0200 Subject: [PATCH 05/10] make robust against short dicts --- qutebrowser/browser/hints.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index b821e43c7..df1209918 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -1077,7 +1077,8 @@ class WordHinter: new_no_prefixes = self.filter_prefixes(new, existing) fallback_no_prefixes = self.filter_prefixes(fallback, existing) # either the first good, or None - return next(new_no_prefixes, next(fallback_no_prefixes)) + return (next(new_no_prefixes, None) + or next(fallback_no_prefixes, None)) def hint(self, elems): """Produce hint labels based on the html tags. @@ -1098,6 +1099,8 @@ class WordHinter: words = iter(self.words) for elem in elems: hint = self.new_hint_for(elem, used_hints, words) + if not hint: + raise WordHintingError("Not enough words in the dictionary.") used_hints.add(hint) hints.append(hint) return hints From 2d71c541c675a449909725edd9f4a421b9fbaffb Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Mon, 25 Apr 2016 10:48:47 +0200 Subject: [PATCH 06/10] allow swapping dict at runtime --- qutebrowser/browser/hints.py | 8 ++++++-- tests/integration/test_hints_html.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index df1209918..352e592cd 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -1004,11 +1004,14 @@ class WordHinter: def __init__(self): # will be initialized on first use. self.words = set() + self.dictionary = None def ensure_initialized(self): """Generate the used words if yet uninialized.""" - if not self.words: - dictionary = config.get("hints", "dictionary") + dictionary = config.get("hints", "dictionary") + if not self.words or self.dictionary != dictionary: + self.words.clear() + self.dictionary = dictionary try: with open(dictionary, encoding="UTF-8") as wordfile: alphabet = set(string.ascii_lowercase) @@ -1104,3 +1107,4 @@ class WordHinter: used_hints.add(hint) hints.append(hint) return hints + diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index 3fe08e88e..6ac7bf595 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -62,21 +62,21 @@ def test_hints(test_name, quteproc): def test_word_hints_issue1393(quteproc, tmpdir): dict_file = tmpdir / 'dict' dict_file.write(textwrap.dedent(""" - alpha + alph beta - gamma - delta - epsilon + gamm + delt + epsi """)) targets = [ ('words', 'words.txt'), ('smart', 'smart.txt'), ('hinting', 'hinting.txt'), - ('alpha', 'l33t.txt'), + ('alph', 'l33t.txt'), ('beta', 'l33t.txt'), - ('gamma', 'l33t.txt'), - ('delta', 'l33t.txt'), - ('epsilon', 'l33t.txt'), + ('gamm', 'l33t.txt'), + ('delt', 'l33t.txt'), + ('epsi', 'l33t.txt'), ] quteproc.set_setting('hints', 'mode', 'word') From b7ba3cd53e4225c85eca85e4d0e52884b3cfdb86 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Mon, 25 Apr 2016 11:35:16 +0200 Subject: [PATCH 07/10] fix flake and pep remarks --- qutebrowser/browser/hints.py | 5 ++--- tests/integration/test_hints_html.py | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 352e592cd..eb7b7045c 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -1080,8 +1080,8 @@ class WordHinter: new_no_prefixes = self.filter_prefixes(new, existing) fallback_no_prefixes = self.filter_prefixes(fallback, existing) # either the first good, or None - return (next(new_no_prefixes, None) - or next(fallback_no_prefixes, None)) + return (next(new_no_prefixes, None) or + next(fallback_no_prefixes, None)) def hint(self, elems): """Produce hint labels based on the html tags. @@ -1107,4 +1107,3 @@ class WordHinter: used_hints.add(hint) hints.append(hint) return hints - diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index 6ac7bf595..b4a05712c 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -22,7 +22,6 @@ import os import os.path -import re import yaml import pytest From 86d08f741c365c284db908210d7328d1481d03e9 Mon Sep 17 00:00:00 2001 From: Felix Van der Jeugt Date: Fri, 29 Apr 2016 21:56:24 +0200 Subject: [PATCH 08/10] shorten page and wait for load finished --- tests/integration/data/hints/issue1393.html | 6 ------ tests/integration/test_hints_html.py | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/integration/data/hints/issue1393.html b/tests/integration/data/hints/issue1393.html index c1269d517..a292b6e5f 100644 --- a/tests/integration/data/hints/issue1393.html +++ b/tests/integration/data/hints/issue1393.html @@ -6,8 +6,6 @@

Word hints

-

This page contains links to be hinted with words. The two - kinds of word hints will be described below.

Smart hints

In qutebrowser, urls can not only be hinted with letters and @@ -20,10 +18,6 @@ too short or l33t to use, words from a dictionary will be used.

-

The current dictionary contains only the words: one, two, - three, four and five. As there are for none-smart hints in this - page, all five words should be used.

-

Hint conflicts

Of course, hints have to be unique. For instance, all hints below should get a different hint, whether they're smart or diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index b4a05712c..9a73335b4 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -83,6 +83,7 @@ def test_word_hints_issue1393(quteproc, tmpdir): for hint, target in targets: quteproc.open_path('data/hints/issue1393.html') + quteproc.wait_for_load_finished('data/hints/issue1393.html') quteproc.send_cmd(':hint') quteproc.wait_for(message='hints: *', category='hints') quteproc.send_cmd(':follow-hint {}'.format(hint)) From e04bf2b74b1a496cb2b58a833da2c1a91b989dc9 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Apr 2016 14:08:51 +0200 Subject: [PATCH 09/10] Regenerate authors --- README.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.asciidoc b/README.asciidoc index 52cb56215..281582cc3 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -146,8 +146,8 @@ Contributors, sorted by the number of commits in descending order: * Lamar Pavel * Bruno Oliveira * Alexander Cogneau -* Martin Tournoij * Felix Van der Jeugt +* Martin Tournoij * Raphael Pierzina * Joel Torstensson * Ryan Roden-Corrent From 580f3ed7dcf56c2ed103b3359e1449915b32d4f0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Apr 2016 14:09:14 +0200 Subject: [PATCH 10/10] Remove added blank line --- tests/integration/test_hints_html.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py index 9a73335b4..2a1566c1f 100644 --- a/tests/integration/test_hints_html.py +++ b/tests/integration/test_hints_html.py @@ -1,4 +1,3 @@ - # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: # Copyright 2016 Florian Bruhin (The Compiler)