From 1c5695fdbdaeb1bea6c5ffc0955830af3bf55dd5 Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Thu, 22 Mar 2018 19:51:07 +0530 Subject: [PATCH] Fix #253: Localize tag error check, fix tag exclusion --- README.md | 4 ++-- buku.1 | 4 ++-- buku.py | 44 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2e7c408..d117191 100644 --- a/README.md +++ b/README.md @@ -365,9 +365,9 @@ PROMPT KEYS: 20. **Search** for bookmarks matching **ALL** of the tags `kernel`, `debugging`, `general kernel concepts`: $ buku --stag kernel + debugging + general kernel concepts -21. **Search** for bookmarks matching both the tags `kernel` and `debugging`, but **excluding** bookmarks matching the tag `general kernel concepts`: +21. **Search** for bookmarks matching both the tags `kernel` and `debugging`, but **excluding** bookmarks matching the tags `general kernel concepts` and `books`: - $ buku --stag kernel + debugging - general kernel concepts + $ buku --stag kernel + debugging - general kernel concepts, books 22. List **all unique tags** alphabetically: $ buku --stag diff --git a/buku.1 b/buku.1 index 207682f..056d166 100644 --- a/buku.1 +++ b/buku.1 @@ -628,11 +628,11 @@ The last index is moved to the deleted index to keep the DB compact. .EE .PP .IP 21. 4 -\fBSearch\fR for bookmarks matching both the tags `kernel` and `debugging`, but \fBexcluding\fR bookmarks matching the tag 'general kernel concepts': +\fBSearch\fR for bookmarks matching both the tags `kernel` and `debugging`, but \fBexcluding\fR bookmarks matching the tags 'general kernel concepts' and 'books': .PP .EX .IP -.B buku --stag kernel + debugging - general kernel concepts +.B buku --stag kernel + debugging - general kernel concepts, books .IP 22. 4 List \fBall unique tags\fR alphabetically: .PP diff --git a/buku.py b/buku.py index 76a4915..f9fd313 100755 --- a/buku.py +++ b/buku.py @@ -1201,12 +1201,14 @@ class BukuDb: List of search results, or None if no matches. """ - # do not allow combination of search logics - if ' + ' in tags and ',' in tags: + tags, search_operator, excluded_tags = prep_tag_search(tags) + if search_operator is None: logerr("Cannot use both '+' and ',' in same search") return None - tags, search_operator, excluded_tags = prep_tag_search(tags) + logdbg('tags: %s', tags) + logdbg('search_operator: %s', search_operator) + logdbg('excluded_tags: %s', excluded_tags) if search_operator == 'AND': query = "SELECT id, url, metadata, tags, desc FROM bookmarks WHERE tags LIKE '%' || ? || '%' " @@ -2949,6 +2951,22 @@ def prep_tag_search(tags): a regex string of tags or None if ' - ' delimiter not in tags). """ + exclude_only = False + + # tags may begin with `- ` if only exclusion list is provided + if tags.startswith('- '): + tags = ' ' + tags + exclude_only = True + + # tags may start with `+ ` etc., tricky test case + if tags.startswith(('+ ', ', ')): + tags = tags[2:] + + # tags may end with ` -` etc., tricky test case + if tags.endswith((' -', ' +', ' ,')): + tags = tags[:-2] + + # tag exclusion list can be separated by comma (,), so split it first excluded_tags = None if ' - ' in tags: tags, excluded_tags = tags.split(' - ', 1) @@ -2957,13 +2975,21 @@ def prep_tag_search(tags): # join with pipe to construct regex string excluded_tags = '|'.join(excluded_taglist) - search_operator = 'OR' - tag_delim = ',' - if ' + ' in tags: - search_operator = 'AND' - tag_delim = ' + ' + if exclude_only: + search_operator = 'OR' + tags = [''] + else: + # do not allow combination of search logics in tag inclusion list + if ' + ' in tags and ',' in tags: + return None, None, None - tags = [delim_wrap(t.strip()) for t in tags.split(tag_delim)] + search_operator = 'OR' + tag_delim = ',' + if ' + ' in tags: + search_operator = 'AND' + tag_delim = ' + ' + + tags = [delim_wrap(t.strip()) for t in tags.split(tag_delim)] return tags, search_operator, excluded_tags