1
1
; ;; org-db-agenda.el --- Agenda from org-db
2
2
3
3
; ;; Commentary:
4
- ; ;
4
+ ; ;
5
+
6
+ (require 'org-archive )
7
+ (require 'org-db )
8
+ (require 'pcache )
9
+
5
10
6
11
(defun org-db-agenda--candidates (before-date )
7
12
" Get headings with deadlines before BEFORE-DATE
@@ -11,27 +16,56 @@ today Due by today
11
16
+1m Due in a month
12
17
"
13
18
(interactive )
14
- (let* ((headings (emacsql org-db [:select [headlines:level headlines:title headlines:tags
15
- files:filename headlines:begin
16
- headlines:deadline
17
- files:last-updated
18
- headlines:todo-keyword]
19
- :from headlines
20
- :inner :join files
21
- :on (= files:rowid headlines:filename-id)
19
+ (let* ((deadline-headings (with-org-db
20
+ (emacsql org-db [:select [headlines:level headlines:title headlines:tags
21
+ files:filename headlines:begin
22
+ headlines:deadline
23
+ files:last-updated
24
+ headlines:todo-keyword]
25
+ :from headlines
26
+ :inner :join files
27
+ :on (= files:rowid headlines:filename-id)
22
28
; only get deadlines before now
23
- :where (and
24
- (= headlines:todo-keyword " TODO" )
25
- (< headlines:deadline $s1))
26
- :order :by headlines:deadline :desc ]
27
- (float-time (org-read-date t t before-date))))
28
- (candidates (cl-loop for (level title tags filename begin deadline last-updated todo-keyword) in headings
29
+ :where (and
30
+ (= headlines:todo-keyword " TODO" )
31
+ (is headlines:archivedp (not nil ))
32
+ (< headlines:deadline $s1))
33
+ :order :by headlines:deadline :desc ]
34
+ (float-time (org-read-date t t before-date)))))
35
+
36
+ (todo-headings (with-org-db
37
+ (emacsql org-db [:select [headlines:level headlines:title headlines:tags
38
+ files:filename headlines:begin
39
+ headlines:deadline
40
+ files:last-updated
41
+ headlines:todo-keyword]
42
+ :from headlines
43
+ :inner :join files
44
+ :on (= files:rowid headlines:filename-id)
45
+ ; ; headlines with TODO state but no deadline, and not archived
46
+ :where (and
47
+ (= headlines:todo-keyword " TODO" )
48
+ (is headlines:deadline (not nil ))
49
+ (is headlines:archivedp (not nil )))
50
+ :order :by files:last-updated :desc ])))
51
+ (ignores (pcache-get (pcache-repository :file " org-db-agenda-ignore" ) 'ignores ))
52
+ (candidates (cl-loop for (level title tags filename begin deadline last-updated todo-keyword)
53
+ in (append deadline-headings todo-headings)
54
+ when (not (member filename ignores))
29
55
collect
30
56
(cons
31
- (format " %2 0s|%1 00s|%2 0s|%s |%s "
32
- (s-pad-right 20 " " (format-time-string " <%Y-%m-%d %a %H:%M:%S>" (seconds-to-time deadline)))
57
+ (format " %2 8s|%1 00s|%2 0s|%s |%s "
58
+ (s-pad-right 28 " "
59
+ (if deadline
60
+ (format-time-string
61
+ " <%Y-%m-%d %a %H:%M:%S>"
62
+ (seconds-to-time deadline))
63
+ " " ))
33
64
34
- (s-pad-right 100 " " (concat (make-string level (string-to-char " *" )) " "
65
+ (s-pad-right 100 " " (concat (make-string
66
+ level
67
+ (string-to-char " *" ))
68
+ " "
35
69
todo-keyword " "
36
70
title))
37
71
(s-pad-right 20 " " (or tags " " ))
@@ -43,29 +77,119 @@ today Due by today
43
77
:title title)))))
44
78
candidates))
45
79
80
+
46
81
(defun org-db-agenda-transformer (candidate )
82
+ " Add colors to candidates."
47
83
(let* ((now (float-time (current-time )))
48
84
(ts (string-match org-element--timestamp-regexp candidate))
49
- (es (when ts (float-time (org-timestamp-to-time (org-timestamp-from-string (match-string 0 candidate)))))))
50
- (if es
51
- (if (> es now)
52
- (propertize candidate 'face '(:foreground " green4" ))
53
- (propertize candidate 'face '(:foreground " dark red" )))
54
- candidate)))
85
+ (es (when ts (float-time (org-timestamp-to-time
86
+ (org-timestamp-from-string
87
+ (match-string 0 candidate)))))))
88
+ (cond
89
+ ((null es) candidate)
90
+ ((> es now) (propertize candidate 'face '(:foreground " green4" )))
91
+ ((< es now) (propertize candidate 'face '(:foreground " dark red" ))))))
55
92
56
93
57
94
(ivy-configure 'org-db-agenda :display-transformer-fn
58
95
#'org-db-agenda-transformer )
59
96
60
97
98
+ (defun org-db-agenda--done (candidate )
99
+ " Mark the current candidate as done."
100
+ (let ((plist (cdr candidate)))
101
+ (find-file (plist-get plist :file ))
102
+ (goto-char (plist-get plist :begin ))
103
+ (org-todo " DONE" )
104
+ (save-buffer )
105
+ (org-db-update-buffer t )))
106
+
107
+
108
+ (defun org-db-agenda--archive (candidate )
109
+ " Mark the current candidate as done."
110
+ (let ((plist (cdr candidate)))
111
+ (find-file (plist-get plist :file ))
112
+ (goto-char (plist-get plist :begin ))
113
+ (org-archive-set-tag)
114
+ (save-buffer )
115
+ (org-db-update-buffer t )))
116
+
117
+
118
+ (defun org-db-agenda--archive-subtree (candidate )
119
+ " Mark the current candidate as done."
120
+ (let ((plist (cdr candidate)))
121
+ (find-file (plist-get plist :file ))
122
+ (goto-char (plist-get plist :begin ))
123
+ (org-archive-subtree )
124
+ (save-buffer )
125
+ (org-db-update-buffer t )))
126
+
127
+
128
+ (defun org-db-agenda--ignore (candidate )
129
+ " add CANDIDATE to ignore list."
130
+ (let* ((plist (cdr candidate))
131
+ (repo (pcache-repository :file " org-db-agenda-ignore" ))
132
+ (ignores (pcache-get repo 'ignores )))
133
+ (setq ignores (delete-dups (append ignores (list (plist-get plist :file )))))
134
+ (pcache-put repo 'ignores ignores)))
135
+
136
+
137
+ (defun org-db-agenda--update (candidate )
138
+ " Update current entry"
139
+ (let* ((plist (cdr candidate))
140
+ (fname (plist-get plist :file )))
141
+ (with-current-buffer (find-file-noselect fname)
142
+ (org-db-update-buffer t ))))
143
+
144
+
61
145
(defun org-db-agenda (before )
62
146
(interactive (list (read-string " Before (e.g. +2w)" " +2w" )))
63
147
(let* ((candidates (org-db-agenda--candidates before)))
64
148
(ivy-read " heading: " candidates
65
149
:caller 'org-db-agenda
66
150
:action
67
151
'(1
68
- (" o" org-db-headings--open " Open to heading." )))))
152
+ (" o" org-db-headings--open " Open to heading." )
153
+ (" d" org-db-agenda--done " Mark entry done" )
154
+ (" a" org-db-agenda--archive " Add archive tag" )
155
+ (" A" org-db-agenda--archive-subtree " Archive subtree" )
156
+ (" i" org-db-agenda--ignore " Ignore this file" )
157
+ (" u" org-db-agenda--update " Update file in database" )
158
+ (" U" (lambda (_ ) (org-db-agenda-refresh " +2w" )) " Refresh agenda database" )))))
159
+
160
+
161
+ (defun scimax-all-headings-done ()
162
+ " Mark all entries in buffer as DONE."
163
+ (interactive )
164
+ (org-map-entries
165
+ (lambda ()
166
+ (when (org-get-repeat )
167
+ (org-todo -1 ))
168
+ (when (string= (org-get-todo-state ) " TODO" )
169
+ (org-todo " DONE" )))))
170
+
171
+
172
+ (defun scimax-archive-todo-headings ()
173
+ " Make todo entries archived."
174
+ (interactive )
175
+ (org-map-entries
176
+ (lambda ()
177
+ (when (string= (org-get-todo-state ) " TODO" )
178
+ (org-archive-set-tag)))))
179
+
180
+
181
+ (defun org-db-agenda-refresh (before )
182
+ " Refresh agenda files."
183
+ (interactive (list (read-string " Before (e.g. +2w)" " +2w" )))
184
+ (cl-loop for candidate in (org-db-agenda--candidates before) do
185
+ (let* ((fname (plist-get (cdr candidate) :file ))
186
+ (open (get-file-buffer fname))
187
+ (buf (find-file-noselect fname)))
188
+ (with-current-buffer buf
189
+ (org-db-update-buffer t ))
190
+ (when (null open)
191
+ (kill-buffer buf)))))
192
+
69
193
70
194
71
195
(provide 'org-db-agenda )
0 commit comments