branch: externals/xeft commit ea433359930bea3aecd47bd7be07ba362916cf83 Author: Yuan Fu <caso...@gmail.com> Commit: Yuan Fu <caso...@gmail.com>
Extend handled query syntax and document it * README.md: Document query syntax. * xeft.el (xeft--highlight-search-phrase, xeft--tighten-search-phrase): Support more query syntax. --- README.md | 23 +++++++++++++++++++++++ xeft.el | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3cf2e067a5..e3d35eccf6 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,29 @@ to t. See the “xeft” customize group for more custom options and faces. +# Queries + +On search queries: + +Since Xeft uses Xapian, it supports the query syntax Xapian supports: + +``` +AND, NOT, OR, XOR and parenthesizes ++word1 -word2 which matches documents that contains WORD1 but not + WORD2. +word1 NEAR word2 which matches documents in where word1 is near word2. +word1 ADJ word2 which matches documents in where word1 is near word2 + and word1 comes before word2 +"word1 word2" which matches exactly “word1 word2” +``` + +Xeft deviates from Xapian in one aspect: consecutive phrases have +implied `AND` between them. So `word1 word2 word3` is actually seen as +`word1 AND word2 AND word3`. + +See https://xapian.org/docs/queryparser.html for Xapian’s official +documentation on query syntax. + # building the dynamic module To build the module, you need to have Xapian installed. On Mac, it can diff --git a/xeft.el b/xeft.el index 3d19dd61b4..857c224431 100644 --- a/xeft.el +++ b/xeft.el @@ -31,6 +31,27 @@ ;; 3. Xeft saves the current window configuration before switching to ;; Xeft buffer. When Xeft buffer is killed, Xeft restores the saved ;; window configuration. +;; +;; On search queries: +;; +;; Since Xeft uses Xapian, it supports the query syntax Xapian +;; supports: +;; +;; AND, NOT, OR, XOR and parenthesizes +;; +word1 -word2 which matches documents that contains WORD1 but not +;; WORD2. +;; word1 NEAR word2 which matches documents in where word1 is near word2. +;; word1 ADJ word2 which matches documents in where word1 is near word2 +;; and word1 comes before word2 +;; "word1 word2" which matches exactly “word1 word2” +;; +;; Xeft deviates from Xapian in one aspect: consecutive phrases have +;; implied “AND” between them. So "word1 word2 word3" is actually seen +;; as "word1 AND word2 AND word3". See ‘xeft--tighten-search-phrase’ +;; for how exactly is it done. +;; +;; See https://xapian.org/docs/queryparser.html for Xapian’s official +;; documentation on query syntax. ;;; Code: @@ -345,7 +366,8 @@ If SELECT is non-nil, select the buffer after displaying it." "Highlight search phrases in buffer." (let ((keyword-list (cl-remove-if (lambda (word) - (member word '("OR" "AND" "XOR" "NOT"))) + (or (member word '("OR" "AND" "XOR" "NOT" "NEAR")) + (string-prefix-p "ADJ" word))) (split-string (xeft--get-search-phrase)))) (inhibit-read-only t)) (dolist (keyword keyword-list) @@ -456,16 +478,29 @@ Once refreshed the buffer, set this to nil.") (defun xeft--tighten-search-phrase (phrase) "Basically insert AND between each term in PHRASE." - (let ((lst (split-string phrase))) + (let ((lst (split-string phrase)) + (in-quote nil)) + ;; Basically we only insert AND between two normal phrases, and + ;; don’t insert if any of the two is an operator (AND, OR, +/-, + ;; etc), we also don’t insert AND in quoted phrases. (string-join (append (cl-loop for idx from 0 to (- (length lst) 2) for this = (nth idx lst) for next = (nth (1+ idx) lst) collect this - if (not (or (member this '("AND" "NOT" "OR" "XOR")) - (memq (aref this 0) '(?+ ?-)) - (member next '("AND" "NOT" "OR" "XOR")) - (memq (aref next 0) '(?+ ?-)))) + if (and (not in-quote) (eq (aref this 0) ?\")) + do (setq in-quote t) + if (and in-quote + (eq (aref this (1- (length this))) ?\")) + do (setq in-quote nil) + if (not + (or in-quote + (member this '("AND" "NOT" "OR" "XOR" "NEAR")) + (string-prefix-p "ADJ" this) + (memq (aref this 0) '(?+ ?-)) + (member next '("AND" "NOT" "OR" "XOR" "NEAR")) + (string-prefix-p "ADJ" next) + (memq (aref next 0) '(?+ ?-)))) collect "AND") (last lst)) " ")))