Skip to content

Commit cff683d

Browse files
committed
Merge branch 'master' into improve-date-merged
2 parents 98bedd2 + 375bde4 commit cff683d

7 files changed

+185
-44
lines changed

README.org

+9
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ Every selector requires an argument, even if it's just ~t~, e.g. ~:anything~, ~:
168168
+ =:anything= :: Select every item, no matter what. This is probably most useful with ~:discard~, because it doesn't actually test anything, so it's faster than, e.g. ~:regexp "."~, which has to get the entry text for every item.
169169
+ =:auto-category= :: This automatically groups items by their category (usually the filename it's in, without the =.org= suffix).
170170
+ ~:auto-dir-name~ :: This automatically groups items by the directory name of their source buffer.
171+
+ =:auto-date= :: This automatically groups items by their earliest of scheduled date or deadline, formatted according to variable ~org-super-agenda-date-format~.
171172
+ =:auto-group= :: This selects items that have the =agenda-group= Org property set. By setting this property for a subtree, every item in it will be sorted into an agenda group by that name and placed into the agenda where the ~:auto-group~ selector is ([[examples.org#automatically-by-group][example]]).
172173
+ ~:auto-map~ :: This automatically groups items by the value returned when applying each item to the given function as a string from the agenda buffer ([[examples.org#automatically-by-mapping-a-function][example]]). The function should return a string to be used as the grouping key and as the header for its group.
173174
+ ~:auto-parent~ :: This automatically groups items by their parent heading. This is surprisingly handy, especially if you group tasks hierarchically by project and use agenda restrictions to limit the agenda to a subtree.
@@ -218,6 +219,14 @@ These selectors take one argument alone, or multiple arguments in a list.
218219

219220
** 1.2-pre
220221

222+
*Added*
223+
+ Selector ~:auto-date~, which groups items by their earliest of scheduled date or deadline, formatted according to variable ~org-super-agenda-date-format~.
224+
+ Option ~org-super-agenda-date-format~, used to format date headers in the ~:auto-date~ selector.
225+
+ To-do keyword faces are applied to keywords in group headers.
226+
227+
*Changed*
228+
+ Group headers face is now appended to face list instead of overriding it.
229+
221230
*Fixed*
222231
+ =:children todo= group selection ([[https://github.com/alphapapa/org-super-agenda/issues/75][#75]]). (Thanks to [[https://github.com/bleggett][Ben Leggett]].)
223232
+ =:children= group headings.

examples.org

+7-6
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,18 @@ This example groups items by the value of their =ProjectId= property (a more fle
152152
You can also use one or more arbitrary predicate functions, including lambdas. Note that, since the group list is already quoted, function name symbols are not quoted again, nor is ~#'~ used.
153153

154154
#+BEGIN_SRC elisp
155-
(defun pizza-p (item)
156-
(s-matches? "pizza" item))
155+
(defun emacs-p (item)
156+
(s-matches? "emacs" item))
157157

158158
(let ((org-super-agenda-groups
159-
'((:pred pizza-p))))
159+
'((:pred emacs-p))))
160160
(org-agenda-list))
161161

162162
(let ((org-super-agenda-groups
163-
'((:pred (pizza-p
164-
(lambda (item)
165-
(s-matches? "Skype" item)))))))
163+
'((:pred
164+
;; A list of two functions
165+
(emacs-p (lambda (item)
166+
(s-matches? "Lisp" item)))))))
166167
(org-agenda-list))
167168
#+END_SRC
168169

notes.org

+1-1
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ CLOSED: [2017-07-28 Fri 00:02]
12601260
- State "DONE" from "TODO" [2017-07-28 Fri 00:02]
12611261
:END:
12621262

1263-
#+BEGIN_SRC elisp
1263+
#+BEGIN_SRC elisp :results silent
12641264
(defun osa/describe-groupers ()
12651265
(require 'dash-functional)
12661266
(let ((groups (cl-loop for (group-type fn) on org-super-agenda-group-types by 'cddr

org-super-agenda.el

+73-10
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ only with point on the group headers (e.g. use `origami' to fold
142142
group headings by binding a key to `origami-toggle-node' in this
143143
map).")
144144

145+
;;;; Customization
146+
145147
(defgroup org-super-agenda nil
146148
"Settings for `org-super-agenda'."
147149
:group 'org
@@ -183,6 +185,11 @@ making it stretch across the screen."
183185
"String inserted before group headers."
184186
:type 'string)
185187

188+
(defcustom org-super-agenda-date-format "%e %B %Y"
189+
"Format string for date headers.
190+
See `format-time-string'."
191+
:type 'string)
192+
186193
;;;; Faces
187194

188195
(defface org-super-agenda-header '((t (:inherit org-agenda-structure)))
@@ -222,6 +229,20 @@ If ANY is non-nil, return as soon as FORM returns non-nil."
222229

223230
;;;; Support functions
224231

232+
(defun org-super-agenda--org-timestamp-element< (a b)
233+
"Return non-nil if A's date element is earlier than B's.
234+
A and B are Org timestamp elements."
235+
;; Copied from `org-ql'.
236+
(cl-macrolet ((ts (ts)
237+
`(when ,ts
238+
(org-timestamp-format ,ts "%s"))))
239+
(let* ((a-ts (ts a))
240+
(b-ts (ts b)))
241+
(cond ((and a-ts b-ts)
242+
(string< a-ts b-ts))
243+
(a-ts t)
244+
(b-ts nil)))))
245+
225246
(defsubst org-super-agenda--get-marker (s)
226247
"Return `org-marker' text properties of string S."
227248
(org-find-text-property-in-string 'org-marker s))
@@ -240,12 +261,13 @@ Prepended with `org-super-agenda-header-separator'."
240261
(pcase s
241262
('none "")
242263
(_ (setq s (concat " " s))
243-
(org-add-props s nil 'face 'org-super-agenda-header
244-
'keymap org-super-agenda-header-map
245-
;; NOTE: According to the manual, only `keymap' should be necessary, but in my
246-
;; testing, it only takes effect in Agenda buffers when `local-map' is set, so
247-
;; we'll use both.
248-
'local-map org-super-agenda-header-map)
264+
(add-face-text-property 0 (length s) 'org-super-agenda-header t s)
265+
(org-add-props s nil
266+
'keymap org-super-agenda-header-map
267+
;; NOTE: According to the manual, only `keymap' should be necessary, but in my
268+
;; testing, it only takes effect in Agenda buffers when `local-map' is set, so
269+
;; we'll use both.
270+
'local-map org-super-agenda-header-map)
249271
(concat org-super-agenda-header-separator s))))
250272

251273
(defsubst org-super-agenda--get-priority-cookie (s)
@@ -641,7 +663,9 @@ Argument may be a string or list of strings, or `t' to match any
641663
keyword, or `nil' to match only non-todo items."
642664
:section-name (pcase (car args)
643665
((pred stringp) ;; To-do keyword given
644-
(concat (s-join " and " args) " items"))
666+
(concat (s-join " and " (--map (propertize it 'face (org-get-todo-face it))
667+
args))
668+
" items"))
645669
('t ;; Test for any to-do keyword
646670
"Any TODO keyword")
647671
('nil ;; Test for not having a to-do keyword
@@ -777,7 +801,8 @@ The string should be the priority cookie letter, e.g. \"A\".")
777801
;;;;; Auto-grouping
778802

779803
(cl-defmacro org-super-agenda--def-auto-group (name docstring-ending
780-
&key keyword key-form (header-form 'key))
804+
&key keyword key-form
805+
(header-form 'key) (key-sort-fn #'string<))
781806
"Define an auto-grouping function.
782807
783808
The function will be named `org-super-agenda--auto-group-NAME'.
@@ -790,6 +815,9 @@ Items will be grouped by the value of KEY-FORM evaluated for each
790815
item, with the variable `item' bound to the string from the
791816
agenda buffer.
792817
818+
Group headers will be sorted by KEY-SORT-FN; usually the default
819+
will suffice.
820+
793821
The groups' headers will be the value of HEADER-FORM, evaluated
794822
for each group after items are grouped, with the variable `key'
795823
bound to the group's key. The form defaults to `key'.
@@ -821,14 +849,48 @@ of the arguments to the function."
821849
else collect item into non-matching
822850
finally return (list ,keyword
823851
non-matching
824-
(cl-loop for key in (sort (ht-keys groups) #'string<)
852+
(cl-loop for key in (sort (ht-keys groups) #',key-sort-fn)
825853
for name = ,header-form
826854
collect (list :name name
827855
:items (nreverse (ht-get groups key)))))))
828856
(setq org-super-agenda-group-types (plist-put org-super-agenda-group-types
829857
,keyword #',fn-name))
830858
(add-to-list 'org-super-agenda-auto-selector-keywords ,keyword)))))
831859

860+
;; TODO: auto-year and auto-month groups. Maybe also auto-quarter, auto-week, etc. Maybe also auto-next-7-days, something like that.
861+
862+
(org-super-agenda--def-auto-group date
863+
"their earliest deadline or scheduled date (formatted according to `org-super-agenda-date-format', which see)"
864+
:keyword :auto-date
865+
;; This is convoluted, mainly because dates and times in Emacs are kind of
866+
;; insane. Good luck parsing a simple "%e %B %Y"-formatted time back to a
867+
;; time value that can be compared. It's virtually impossible, at least
868+
;; without a lot of work (hence my ts.el package, but it's not yet mature
869+
;; enough to use here). So we store the Org timestamp element in the text
870+
;; properties of the formatted time.
871+
:key-form (cl-flet ((get-date-type (type)
872+
(when-let* ((date-string (org-entry-get (point) type)))
873+
(with-temp-buffer
874+
;; FIXME: Hack: since we're using (org-element-property
875+
;; :type date-element) below, we need this date parsed
876+
;; into an org-element element.
877+
(insert date-string)
878+
(goto-char 0)
879+
(org-element-timestamp-parser)))))
880+
(org-super-agenda--when-with-marker-buffer (org-super-agenda--get-marker item)
881+
;; MAYBE: Also check CLOSED date.
882+
(let ((earliest-ts (car (sort (list (get-date-type "SCHEDULED")
883+
(get-date-type "DEADLINE"))
884+
#'org-super-agenda--org-timestamp-element<))))
885+
(pcase earliest-ts
886+
('nil nil)
887+
(_ (propertize (org-timestamp-format earliest-ts org-super-agenda-date-format)
888+
'org-super-agenda-ts earliest-ts))))))
889+
:key-sort-fn (lambda (a b)
890+
(org-super-agenda--org-timestamp-element<
891+
(get-text-property 0 'org-super-agenda-ts a)
892+
(get-text-property 0 'org-super-agenda-ts b))))
893+
832894
(org-super-agenda--def-auto-group items "their AGENDA-GROUP property"
833895
:keyword :auto-group
834896
:key-form (org-entry-get (org-super-agenda--get-marker item)
@@ -857,7 +919,8 @@ of the arguments to the function."
857919

858920
(org-super-agenda--def-auto-group todo "their to-do keyword"
859921
:keyword :auto-todo
860-
:key-form (org-find-text-property-in-string 'todo-state item)
922+
:key-form (when-let* ((keyword (org-find-text-property-in-string 'todo-state item)))
923+
(propertize keyword 'face (org-get-todo-face keyword)))
861924
:header-form (concat "To-do: " key))
862925

863926
(org-super-agenda--def-auto-group dir-name "their parent heading"

org-super-agenda.info

+43-27
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ Every selector requires an argument, even if it’s just ‘t’, e.g.
310310
‘:auto-dir-name’
311311
This automatically groups items by the directory name of their
312312
source buffer.
313+
‘:auto-date’
314+
This automatically groups items by their earliest of scheduled date
315+
or deadline, formatted according to variable
316+
‘org-super-agenda-date-format’.
313317
‘:auto-group’
314318
This selects items that have the ‘agenda-group’ Org property set.
315319
By setting this property for a subtree, every item in it will be
@@ -488,8 +492,20 @@ File: README.info, Node: 12-pre, Next: 111, Up: Changelog
488492
6.1 1.2-pre
489493
===========
490494

491-
*Fixed*
492-
• ‘:children todo’ group selection (#75
495+
*Added*
496+
• Selector ‘:auto-date’, which groups items by their earliest of
497+
scheduled date or deadline, formatted according to variable
498+
‘org-super-agenda-date-format’.
499+
• Option ‘org-super-agenda-date-format’, used to format date headers
500+
in the ‘:auto-date’ selector.
501+
• To-do keyword faces are applied to keywords in group headers.
502+
503+
*Changed*
504+
• Group headers face is now appended to face list instead of
505+
overriding it.
506+
507+
*Fixed*
508+
• :children todo group selection (#75
493509
(https://github.com/alphapapa/org-super-agenda/issues/75)).
494510
(Thanks to Ben Leggett (https://github.com/bleggett).)
495511
• ‘:children’ group headings.
@@ -642,31 +658,31 @@ File: README.info, Node: Credits, Prev: Development, Up: Top
642658

643659
Tag Table:
644660
Node: Top222
645-
Node: Introduction802
646-
Node: Contents2214
647-
Node: Screenshots2367
648-
Node: Installation2608
649-
Node: MELPA2769
650-
Node: Manual installation2922
651-
Node: Usage3355
652-
Node: Examples4337
653-
Node: Group selectors7906
654-
Node: Keywords9095
655-
Node: Special selectors9824
656-
Node: Normal selectors12479
657-
Node: Tips17402
658-
Node: Changelog18283
659-
Node: 12-pre18501
660-
Node: 11118862
661-
Node: 1119041
662-
Node: 10320625
663-
Node: 10220836
664-
Node: 10120970
665-
Node: 10021308
666-
Node: Development21413
667-
Node: Bugs21815
668-
Node: Tests22509
669-
Node: Credits22846
661+
Node: Introduction824
662+
Node: Contents2232
663+
Node: Screenshots2385
664+
Node: Installation2622
665+
Node: MELPA2783
666+
Node: Manual installation2930
667+
Node: Usage3321
668+
Node: Examples4297
669+
Node: Group selectors7782
670+
Node: Keywords8971
671+
Node: Special selectors9712
672+
Node: Normal selectors12555
673+
Node: Tips17186
674+
Node: Changelog18037
675+
Node: 12-pre18262
676+
Node: 11119089
677+
Node: 1119262
678+
Node: 10320834
679+
Node: 10221045
680+
Node: 10121179
681+
Node: 10021517
682+
Node: Development21622
683+
Node: Bugs22024
684+
Node: Tests22677
685+
Node: Credits22996
670686

671687
End Tag Table
672688

test/results.el

+47
Original file line numberDiff line numberDiff line change
@@ -1830,4 +1830,51 @@ Wednesday 5 July 2017
18301830
ideas: Scheduled: SOMEDAY Rewrite Emacs in Common Lisp :Emacs:elisp:computers:software:programming:
18311831
test: In 16 d.: TODO [#B] Internet :bills:
18321832
test: Scheduled: TODO [#C] Get haircut :personal:@town:
1833+
" "415e1172e603da0549cd21c3d9ecf418" "Day-agenda (W27):
1834+
Wednesday 5 July 2017
1835+
1836+
4 July 2017
1837+
ambition: Sched. 1x: TODO [#A] Skype with president of Antarctica :universe:ambition:world::meetings:
1838+
1839+
5 July 2017
1840+
test: 18:00...... Scheduled: TODO Order a pizza :food:dinner:
1841+
test: Scheduled: TODO [#B] Fix flux capacitor :spaceship:shopping:@computer:
1842+
test: Scheduled: TODO Shop for groceries :food:shopping:@town:
1843+
ideas: Scheduled: SOMEDAY Rewrite Emacs in Common Lisp :Emacs:elisp:computers:software:programming:
1844+
test: Deadline: CHECK /r/emacs :website:Emacs:
1845+
test: Scheduled: TODO [#C] Get haircut :personal:@town:
1846+
ambition: TODO Practice leaping tall ! :universe:ambition::personal:
1847+
1848+
7 July 2017
1849+
ambition: In 2 d.: TODO [#A] Take over the world :universe:ambition::world:
1850+
1851+
10 July 2017
1852+
ambition: In 5 d.: TODO [#B] Renew membership in supervillain club :universe:ambition::
1853+
1854+
15 July 2017
1855+
ambition: In 10 d.: TODO [#A] Take over the universe :universe:ambition:
1856+
1857+
21 July 2017
1858+
test: In 16 d.: TODO [#B] Internet :bills:
1859+
1860+
1 August 2017
1861+
test: In 27 d.: TODO [#A] Spaceship lease :bills:spaceship:
1862+
1863+
27 August 2017
1864+
ambition: In 53 d.: WAITING Visit the moon :universe:ambition::space:travel:
1865+
1866+
20 September 2017
1867+
ambition: In 77 d.: TODO Visit Mars :universe:ambition::space:travel:planet:
1868+
1869+
Other items
1870+
test: 7:02...... Sunrise (12:04 of daylight)
1871+
8:00...... ----------------
1872+
10:00...... ----------------
1873+
12:00...... now - - - - - - - - - - - - - - - - - - - - - - - - -
1874+
12:00...... ----------------
1875+
14:00...... ----------------
1876+
16:00...... ----------------
1877+
18:00...... ----------------
1878+
test: 19:07...... Sunset
1879+
20:00...... ----------------
18331880
"))

test/test.el

+5
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ buffer and do not save the results."
625625
(should (org-super-agenda--test-run
626626
:groups '((:auto-category t)))))
627627

628+
(ert-deftest org-super-agenda--test-:auto-date ()
629+
;; DONE: Works.
630+
(should (org-super-agenda--test-run
631+
:groups '((:auto-date t)))))
632+
628633
(ert-deftest org-super-agenda--test-:auto-group ()
629634
;; DONE: Works.
630635
(should (org-super-agenda--test-run

0 commit comments

Comments
 (0)