summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Mehne <julian.mehne@posteo.de>2017-12-01 15:22:01 +0100
committerJulian Mehne <julian.mehne@posteo.de>2017-12-02 00:19:37 +0100
commitf89555064a810ad7fcb3cbe079639ac3f83ff07c (patch)
tree0e362e56dcf164374693079234610e6c4106f50b
parent054d2a932e7cb8d18dae258750ed26fb86e650b9 (diff)
Allow regex special characters in tagstrings.
Fixes the following crashes: 1. tag completion with regex special chars :search tag:[<tab> 2. Changing tag representation of an (existing) tag with regex special chars: [tags] [[my**tag]] normal = '','', 'white','light red', 'white','#d66' 3. Contact completion with regex special chars and no external command: To:**foo<tab>
-rw-r--r--alot/addressbook/__init__.py2
-rw-r--r--alot/completion.py2
-rw-r--r--alot/settings/manager.py2
-rw-r--r--tests/addressbook/init_test.py9
-rw-r--r--tests/completion_test.py9
-rw-r--r--tests/settings/manager_test.py12
6 files changed, 33 insertions, 3 deletions
diff --git a/alot/addressbook/__init__.py b/alot/addressbook/__init__.py
index 17800b33..28c4ecc7 100644
--- a/alot/addressbook/__init__.py
+++ b/alot/addressbook/__init__.py
@@ -34,7 +34,7 @@ class AddressBook(object):
def lookup(self, query=''):
"""looks up all contacts where name or address match query"""
res = []
- query = re.compile('.*%s.*' % query, self.reflags)
+ query = re.compile('.*%s.*' % re.escape(query), self.reflags)
for name, email in self.get_contacts():
if query.match(name) or query.match(email):
res.append((name, email))
diff --git a/alot/completion.py b/alot/completion.py
index 78b22d5b..48824909 100644
--- a/alot/completion.py
+++ b/alot/completion.py
@@ -75,7 +75,7 @@ class StringlistCompleter(Completer):
re_prefix = '.*' if self.match_anywhere else ''
def match(s, m):
- r = re_prefix + m + '.*'
+ r = '{}{}.*'.format(re_prefix, re.escape(m))
return re.match(r, s, flags=self.flags) is not None
return [(a, len(a)) for a in self.resultlist if match(a, pref)]
diff --git a/alot/settings/manager.py b/alot/settings/manager.py
index c71fba42..98d534fb 100644
--- a/alot/settings/manager.py
+++ b/alot/settings/manager.py
@@ -320,7 +320,7 @@ class SettingsManager(object):
fallback_focus = resolve_att(onebelow_focus, default_focus)
for sec in cfg['tags'].sections:
- if re.match('^' + sec + '$', tag):
+ if re.match('^{}$'.format(re.escape(sec)), tag):
normal = resolve_att(colourpick(cfg['tags'][sec]['normal']),
fallback_normal)
focus = resolve_att(colourpick(cfg['tags'][sec]['focus']),
diff --git a/tests/addressbook/init_test.py b/tests/addressbook/init_test.py
index a7f3f9b5..7f642933 100644
--- a/tests/addressbook/init_test.py
+++ b/tests/addressbook/init_test.py
@@ -65,3 +65,12 @@ class TestAddressBook(unittest.TestCase):
actual = abook.lookup('Own')
expected = [contacts[1]]
self.assertListEqual(actual, expected)
+
+ def test_lookup_can_handle_special_regex_chars(self):
+ contacts = [('name [work]', 'email@example.com'),
+ ('My Own Name', 'other@example.com'),
+ ('someone', 'someone@example.com')]
+ abook = _AddressBook(contacts)
+ actual = abook.lookup('[wor')
+ expected = [contacts[0]]
+ self.assertListEqual(actual, expected)
diff --git a/tests/completion_test.py b/tests/completion_test.py
index 855df03f..5b335779 100644
--- a/tests/completion_test.py
+++ b/tests/completion_test.py
@@ -87,3 +87,12 @@ class AbooksCompleterTest(unittest.TestCase):
expected = [(r""""all 'fanzy' \"stuff\" at, once" <all@example.com>""",
50)]
self._assert_only_one_list_entry(actual, expected)
+
+
+class StringlistCompleterTest(unittest.TestCase):
+ def test_dont_choke_on_special_regex_characters(self):
+ tags = ['[match]', 'nomatch']
+ completer = completion.StringlistCompleter(tags)
+ actual = completer.complete('[', 1)
+ expected = [(tags[0], len(tags[0]))]
+ self.assertListEqual(actual, expected)
diff --git a/tests/settings/manager_test.py b/tests/settings/manager_test.py
index a09dbf15..975bcb0e 100644
--- a/tests/settings/manager_test.py
+++ b/tests/settings/manager_test.py
@@ -94,6 +94,18 @@ class TestSettingsManager(unittest.TestCase):
setting = manager.get_notmuch_setting('foo', 'bar')
self.assertIsNone(setting)
+ def test_dont_choke_on_regex_special_chars_in_tagstring(self):
+ tag = 'to**do'
+ with tempfile.NamedTemporaryFile(delete=False) as f:
+ f.write(textwrap.dedent("""\
+ [tags]
+ [[{tag}]]
+ normal = '','', 'white','light red', 'white','#d66'
+ """.format(tag=tag)))
+ self.addCleanup(os.unlink, f.name)
+ manager = SettingsManager(alot_rc=f.name)
+ manager.get_tagstring_representation(tag)
+
class TestSettingsManagerGetAccountByAddress(utilities.TestCaseClassCleanup):
"""Test the get_account_by_address helper."""