45
45
" Functions called when selecting an entry."
46
46
:type 'hook )
47
47
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
+
48
82
(defface org-ql-find-snippet '((t (:inherit font-lock-comment-face )))
49
83
" Snippets." )
50
84
@@ -81,7 +115,8 @@ single predicate)."
81
115
; ; made possible by the example Clemens Radermacher shared at
82
116
; ; <https://github.com/radian-software/selectrum/issues/114#issuecomment-744041532>.
83
117
(let ((table (make-hash-table :test #'equal ))
84
- (window-width (window-width )))
118
+ (window-width (window-width ))
119
+ query-tokens snippet-regexp)
85
120
(cl-labels ((action
86
121
() (font-lock-ensure (point-at-bol ) (point-at-eol ))
87
122
(let* ((path (thread-first (org-get-outline-path t t )
@@ -106,17 +141,15 @@ single predicate)."
106
141
" " )
107
142
collect (list completion todo-state snippet)))
108
143
(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)) " " )))
110
149
(snippet (marker)
111
150
(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))))
120
153
(group (candidate transform)
121
154
(pcase transform
122
155
(`nil (buffer-name (marker-buffer (gethash candidate table))))
@@ -134,6 +167,21 @@ single predicate)."
134
167
(`t (unless (string-empty-p str)
135
168
(when query-filter
136
169
(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))))))))))
137
185
(org-ql-select buffers-files (org-ql--query-string-to-sexp (concat query-prefix str))
138
186
:action #'action ))))))
139
187
(let* ((completion-styles '(org-ql-find))
@@ -181,6 +229,33 @@ multiple buffers to search with completion."
181
229
(current-buffer ))))
182
230
(org-ql-find buffers-files :prompt " Find outline path: " :query-prefix " outline-path:" ))
183
231
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
+
184
259
(provide 'org-ql-find )
185
260
186
261
; ;; org-ql-find.el ends here
0 commit comments