Skip to content

Commit 6e7371c

Browse files
committed
Add: (org-ql-find) Snippet functions
The default is even more like org-rifle now.
1 parent ede1a6b commit 6e7371c

File tree

1 file changed

+85
-10
lines changed

1 file changed

+85
-10
lines changed

Diff for: org-ql-find.el

+85-10
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,40 @@
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

Comments
 (0)