4545 " Functions called when selecting an entry."
4646 :type 'hook )
4747
48+ (defcustom org-ql-find-snippet-function #'org-ql-find--snippet-simple
49+ ; ; TODO: I'd like to make the -regexp one the default, but with
50+ ; ; default Emacs completion affixation, it can sometimes be a bit
51+ ; ; slow, and I don't want that to be a user's first impression. It
52+ ; ; may be possible to further optimize the -regexp one so that it
53+ ; ; can be used by default. In the meantime, the -simple one seems
54+ ; ; fast enough for general use.
55+ " Function used to annotate results in `org-ql-find' .
56+ Function is called at entry beginning. (When set to
57+ `org-ql-find--snippet-regexp' , it is called with a regexp
58+ matching plain query tokens.)"
59+ :type '(choice (function-item :tag " Show context around search terms" org-ql-find--snippet-regexp)
60+ (function-item :tag " Show first N characters" org-ql-find--snippet-simple)
61+ (function :tag " Custom function" )))
62+
63+ (defcustom org-ql-find-snippet-length 51
64+ " Size of snippets of entry content to include in `org-ql-find' annotations.
65+ Only used when `org-ql-find-snippet-function' is set to
66+ `org-ql-find--snippet-regexp' ."
67+ :type 'integer )
68+
69+ (defcustom org-ql-find-snippet-minimum-token-length 3
70+ " Query tokens shorter than this many characters are ignored.
71+ That is, they are not included when gathering entry snippets.
72+ This avoids too-small tokens causing performance problems."
73+ :type 'integer )
74+
75+ (defcustom org-ql-find-snippet-prefix nil
76+ " String prepended to snippets.
77+ For an experience like `org-rifle' , use a newline."
78+ :type '(choice (const :tag " None (shown on same line)" nil )
79+ (const :tag " New line (shown under heading)" " \n " )
80+ string))
81+
4882(defface org-ql-find-snippet '((t (:inherit font-lock-comment-face )))
4983 " Snippets." )
5084
@@ -81,7 +115,8 @@ single predicate)."
81115 ; ; made possible by the example Clemens Radermacher shared at
82116 ; ; <https://github.com/radian-software/selectrum/issues/114#issuecomment-744041532>.
83117 (let ((table (make-hash-table :test #'equal ))
84- (window-width (window-width )))
118+ (window-width (window-width ))
119+ query-tokens snippet-regexp)
85120 (cl-labels ((action
86121 () (font-lock-ensure (point-at-bol ) (point-at-eol ))
87122 (let* ((path (thread-first (org-get-outline-path t t )
@@ -106,17 +141,15 @@ single predicate)."
106141 " " )
107142 collect (list completion todo-state snippet)))
108143 (annotate (candidate)
109- (or (snippet (gethash candidate table)) " " ))
144+ (while-no-input
145+ ; ; Using `while-no-input' here doesn't make it as
146+ ; ; responsive as, e.g. Helm while typing, but it seems to
147+ ; ; help a little when using the org-rifle-style snippets.
148+ (or (snippet (gethash candidate table)) " " )))
110149 (snippet (marker)
111150 (org-with-point-at marker
112- (org-end-of-meta-data t )
113- (unless (org-at-heading-p )
114- (let ((end (min (+ (point ) 51 )
115- (org-entry-end-position ))))
116- (truncate-string-to-width
117- (replace-regexp-in-string " \n " " " (buffer-substring (point ) end)
118- t t )
119- 50 nil nil t )))))
151+ (or (funcall org-ql-find-snippet-function snippet-regexp)
152+ (org-ql-find--snippet-simple))))
120153 (group (candidate transform)
121154 (pcase transform
122155 (`nil (buffer-name (marker-buffer (gethash candidate table))))
@@ -134,6 +167,21 @@ single predicate)."
134167 (`t (unless (string-empty-p str)
135168 (when query-filter
136169 (setf str (funcall query-filter str)))
170+ (pcase org-ql-find-snippet-function
171+ ('org-ql-find--snippet-regexp
172+ (setf query-tokens
173+ ; ; Remove any tokens that specify predicates or are too short.
174+ (--select (not (or (string-match-p (rx bos (1+ (not (any " :" ))) " :" ) it)
175+ (< (length it) org-ql-find-snippet-minimum-token-length)))
176+ (split-string str nil t (rx space)))
177+ snippet-regexp (when query-tokens
178+ ; ; Limiting each context word to 15 characters
179+ ; ; prevents excessively long, non-word strings
180+ ; ; from ending up in snippets, which can
181+ ; ; adversely affect performance.
182+ (rx-to-string `(seq (optional (repeat 1 3 (repeat 1 15 (not space)) (0+ space)))
183+ bow (or ,@query-tokens ) (0+ (not space))
184+ (optional (repeat 1 3 (0+ space) (repeat 1 15 (not space))))))))))
137185 (org-ql-select buffers-files (org-ql--query-string-to-sexp (concat query-prefix str))
138186 :action #'action ))))))
139187 (let* ((completion-styles '(org-ql-find))
@@ -181,6 +229,33 @@ multiple buffers to search with completion."
181229 (current-buffer ))))
182230 (org-ql-find buffers-files :prompt " Find outline path: " :query-prefix " outline-path:" ))
183231
232+ (defun org-ql-find--snippet-simple (&optional _regexp )
233+ " Return a snippet of the current entry.
234+ Returns up to `org-ql-find-snippet-length' characters."
235+ (org-end-of-meta-data t )
236+ (unless (org-at-heading-p )
237+ (let ((end (min (+ (point ) org-ql-find-snippet-length)
238+ (org-entry-end-position ))))
239+ (concat org-ql-find-snippet-prefix
240+ (truncate-string-to-width
241+ (replace-regexp-in-string " \n " " " (buffer-substring (point ) end)
242+ t t )
243+ 50 nil nil t )))))
244+
245+ (defun org-ql-find--snippet-regexp (regexp )
246+ " Return a snippet of the current entry's matches for REGEXP."
247+ ; ; REGEXP may be nil if there are no qualifying tokens in the query.
248+ (when regexp
249+ (org-end-of-meta-data t )
250+ (unless (org-at-heading-p )
251+ (let* ((end (org-entry-end-position ))
252+ (snippets (cl-loop while (re-search-forward regexp end t )
253+ concat (match-string 0 ) concat " …"
254+ do (goto-char (match-end 0 )))))
255+ (unless (string-empty-p snippets)
256+ (concat org-ql-find-snippet-prefix
257+ (replace-regexp-in-string (rx (1+ " \n " )) " " snippets t t )))))))
258+
184259(provide 'org-ql-find )
185260
186261; ;; org-ql-find.el ends here
0 commit comments