forked from jkitchin/scimax
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathorg-db-fulltext.el
90 lines (67 loc) · 2.51 KB
/
org-db-fulltext.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
;;; org-db-fulltext.el --- Fulltext search for org-db
;;; Commentary:
;;
;; Add fulltext search for org-db.
;;
;; TODO replace org-db-ft
(require 'org-db)
(defcustom org-db-fulltext "org-db-fulltext.sqlite"
"Name of the sqlite database file for full-text search."
:type 'string
:group 'org-db)
(defvar org-db-ft nil
"Variable for the ‘org-db’ full-text connection.")
(defmacro with-org-db-ft (&rest body)
"Run BODY commands in an org-db context where we open the database, and close it at the end.
BODY should be regular commands. They can use the variable `org-db' in them."
`(progn
(unless (and org-db-ft (emacsql-live-p org-db-ft))
(setq org-db-ft (emacsql-sqlite (expand-file-name org-db-fulltext org-db-root) :debug t)))
(prog1
(progn
,@body)
(emacsql-close org-db-ft)
(emacsql-close org-db-ft)
(setq org-db-ft nil))))
;; Make sure the database and table exists
(with-org-db-ft
(emacsql org-db-ft [:create-virtual-table :if :not :exists fulltext
:using :fts5
([filename contents])]))
(defun org-db-fulltext-update (_filename-id _parse-tree)
"Insert the full text for searching."
(with-org-db-ft
(emacsql org-db-ft [:delete :from fulltext :where (= filename $s1)] (buffer-file-name))
(emacsql org-db-ft [:insert :into fulltext :values [$s1 $s2]]
(buffer-file-name)
(save-restriction
(widen)
(buffer-substring-no-properties (point-min) (point-max))))))
(add-to-list 'org-db-update-functions #'org-db-fulltext-update t)
(defun org-db-fulltext-search ()
"Search the fulltext database.
This function opens the file at the first match of your query string.
This uses ivy right now, since it is so fast. On day I might have
to change this. It could be nice to find some way to read in an
emacsql query like :match '\"something.\" Alternatively, I may
need a better async version."
(interactive)
(let ((candidates (with-org-db-ft
(emacsql org-db-ft [:select [contents filename] :from fulltext]))))
(ivy-read "query: " candidates
:action (lambda (x)
(find-file (cadr x))
(goto-char (point-min))
(re-search-forward ivy-text)
(goto-char (match-beginning 0))))))
(defun org-db-ft-transformer (s)
"This only shows lines that match the selected pattern."
(s-join "\n"
(cl-loop for x in (split-string s "\n")
if (string-match-p ivy-text x)
collect x)))
(ivy-set-display-transformer
'org-db-fulltext-search
'org-db-ft-transformer)
(provide 'org-db-fulltext)
;;; org-db-fulltext.el ends here