org-clock.el: New option :tags to insert tags in clock reports

* lisp/org-clock.el (org-clocktable-defaults)
(org-clocktable-write-default, org-clock-get-table-data):
Rename :tags to :match and use :tags to insert a column with
the headline's tags.

Thanks to Raymond Zeitler for suggesting this.
This commit is contained in:
Bastien 2018-04-26 20:55:27 +02:00
parent 8ebe4aa678
commit f80f7ed98b
4 changed files with 234 additions and 192 deletions

View File

@ -6666,7 +6666,7 @@ be selected:
Do not show table sections from files which did not contribute.
- :tags ::
- :match ::
A tags match to select entries that should contribute. See
[[*Matching tags and properties]] for the match syntax.
@ -6724,6 +6724,10 @@ using the =:formatter= parameter.
DEADLINE, TIMESTAMP and TIMESTAMP_IA special properties (see
[[*Special Properties]]), in this order.
- :tags ::
When this flag is non-~nil~, show the headline's tags.
- :properties ::
List of properties shown in the table. Each property gets its

View File

@ -120,6 +120,17 @@ When sorting alphabetically, ~org-table-sort-lines~ and ~org-sort-list~
now sort according to the locales collation rules instead of by
code-point.
*** Change the name of the :tags clocktable option to :match
The =:match= (renamed from =:tags=) option allows to limit clock entries
to those matching a todo-tags matcher.
The old =:tags= option can be set to =t= to display a headline's tags in
a dedicated column.
This is consistent with the naming of =org-dblock-write:columnview=
options, where =:match= is also used as a headlines filter.
** New features
*** Add ~:results link~ support for Babel

View File

@ -294,6 +294,7 @@ string as argument."
:stepskip0 nil
:fileskip0 nil
:tags nil
:match nil
:emphasize nil
:link nil
:narrow '40!
@ -2464,6 +2465,7 @@ from the dynamic block definition."
(narrow (or (plist-get params :narrow) (and compact? '40!)))
(level? (and (not compact?) (plist-get params :level)))
(timestamp (plist-get params :timestamp))
(tags (plist-get params :tags))
(properties (plist-get params :properties))
(time-columns
(if (or compact? (< maxlevel 2)) 1
@ -2524,6 +2526,7 @@ from the dynamic block definition."
(if multifile "|" "") ;file column, maybe
(if level? "|" "") ;level column, maybe
(if timestamp "|" "") ;timestamp column, maybe
(if tags "|" "") ;tags columns, maybe
(if properties ;properties columns, maybe
(make-string (length properties) ?|)
"")
@ -2541,6 +2544,8 @@ from the dynamic block definition."
(if timestamp ;timestamp column, maybe
(concat (org-clock--translate "Timestamp" lang) "|")
"")
(if tags "Tags |" "") ;tags columns, maybe
(if properties ;properties columns, maybe
(concat (mapconcat #'identity properties "|") "|")
"")
@ -2555,8 +2560,9 @@ from the dynamic block definition."
"|" ;table line starter
(if multifile (format "| %s " (org-clock--translate "ALL" lang)) "")
;file column, maybe
(if level? "|" "") ;level column, maybe
(if level? "|" "") ;level column, maybe
(if timestamp "|" "") ;timestamp column, maybe
(if tags "|" "") ;timestamp column, maybe
(make-string (length properties) ?|) ;properties columns, maybe
(concat (format org-clock-total-time-cell-format
(org-clock--translate "Total time" lang))
@ -2586,8 +2592,9 @@ from the dynamic block definition."
(org-clock--translate "File time" lang))
" | *%s*|\n")
(file-name-nondirectory file-name)
(if level? "| " "") ;level column, maybe
(if level? "| " "") ;level column, maybe
(if timestamp "| " "") ;timestamp column, maybe
(if tags "| " "") ;tags column, maybe
(if properties ;properties columns, maybe
(make-string (length properties) ?|)
"")
@ -2595,7 +2602,7 @@ from the dynamic block definition."
;; Get the list of node entries and iterate over it
(when (> maxlevel 0)
(pcase-dolist (`(,level ,headline ,ts ,time ,props) entries)
(pcase-dolist (`(,level ,headline ,tgs ,ts ,time ,props) entries)
(when narrow-cut-p
(setq headline
(if (and (string-match
@ -2617,6 +2624,7 @@ from the dynamic block definition."
(if multifile "|" "") ;free space for file name column?
(if level? (format "%d|" level) "") ;level, maybe
(if timestamp (concat ts "|") "") ;timestamp, maybe
(if tags (concat (mapconcat #'identity tgs ", ") "|") "") ;tags, maybe
(if properties ;properties columns, maybe
(concat (mapconcat (lambda (p) (or (cdr (assoc p props)) ""))
properties
@ -2747,13 +2755,14 @@ file time (in minutes) as 1st and 2nd elements. The third element
of this list will be a list of headline entries. Each entry has the
following structure:
(LEVEL HEADLINE TIMESTAMP TIME PROPERTIES)
(LEVEL HEADLINE TAGS TIMESTAMP TIME PROPERTIES)
LEVEL: The level of the headline, as an integer. This will be
the reduced level, so 1,2,3,... even if only odd levels
are being used.
HEADLINE: The text of the headline. Depending on PARAMS, this may
already be formatted like a link.
TAGS: The list of tags of the headline.
TIMESTAMP: If PARAMS require it, this will be a time stamp found in the
entry, any of SCHEDULED, DEADLINE, NORMAL, or first inactive,
in this sequence.
@ -2772,9 +2781,10 @@ PROPERTIES: The list properties specified in the `:properties' parameter
(block (plist-get params :block))
(link (plist-get params :link))
(tags (plist-get params :tags))
(match (plist-get params :match))
(properties (plist-get params :properties))
(inherit-property-p (plist-get params :inherit-props))
(matcher (and tags (cdr (org-make-tags-matcher tags))))
(matcher (and match (cdr (org-make-tags-matcher match))))
cc st p tbl)
(setq org-clock-file-total-minutes nil)
@ -2795,10 +2805,11 @@ PROPERTIES: The list properties specified in the `:properties' parameter
(org-clock-sum ts te
(when matcher
`(lambda ()
(let* ((tags-list (org-get-tags))
(let* ((todo (org-get-todo-state))
(tags-list (org-get-tags))
(org-scanner-tags tags-list)
(org-trust-scanner-tags t))
(funcall ,matcher nil tags-list nil)))))
(funcall ,matcher todo tags-list nil)))))
(goto-char (point-min))
(setq st t)
(while (or (and (bobp) (prog1 st (setq st nil))
@ -2827,6 +2838,7 @@ PROPERTIES: The list properties specified in the `:properties' parameter
(replace-regexp-in-string
"\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" ""
headline)))))))
(tgs (and tags (org-get-tags)))
(tsp
(and timestamp
(cl-some (lambda (p) (org-entry-get (point) p))
@ -2841,7 +2853,7 @@ PROPERTIES: The list properties specified in the `:properties' parameter
(point) p inherit-property-p)))
(and v (cons p v))))
properties)))))
(push (list level hdl tsp time props) tbl)))))))
(push (list level hdl tgs tsp time props) tbl)))))))
(list file org-clock-file-total-minutes (nreverse tbl)))))
;; Saving and loading the clock

View File

@ -273,70 +273,85 @@ the buffer."
;;; Clocktable
(ert-deftest test-org-clock/clocktable/ranges ()
"Test ranges in Clock table."
;; Relative time: Previous two days.
(should
(equal
"| Headline | Time | |
|------------------------------+--------+------|
| *Total time* | *8:00* | |
|------------------------------+--------+------|
| Relative times in clocktable | 8:00 | |
| Foo | | 8:00 |"
(org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-3d 8:00" "-3d 12:00"))
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
(test-org-clock-clocktable-contents
":tstart \"<-2d>\" :tend \"<today>\" :indent nil"))))
;; Relative time: Yesterday until now.
(should
(equal
"| Headline | Time | |
|------------------------------+--------+------|
| *Total time* | *6:00* | |
|------------------------------+--------+------|
| Relative times in clocktable | 6:00 | |
| Foo | | 6:00 |"
(org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
(insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
(test-org-clock-clocktable-contents
":tstart \"<yesterday>\" :tend \"<tomorrow>\" :indent nil"))))
;; Test `untilnow' block.
(should
(equal
"| Headline | Time | |
|------------------------------+--------+------|
| *Total time* | *6:00* | |
|------------------------------+--------+------|
| Relative times in clocktable | 6:00 | |
| Foo | | 6:00 |"
(org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-10y 15:00" "-10y 18:00"))
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(test-org-clock-clocktable-contents ":block untilnow :indent nil")))))
;; (ert-deftest test-org-clock/clocktable/ranges ()
;; "Test ranges in Clock table."
;; ;; Relative time: Previous two days.
;; (should
;; (equal
;; "| Headline | Time | |
;; |------------------------------+--------+------|
;; | *Total time* | *8:00* | |
;; |------------------------------+--------+------|
;; | Relative times in clocktable | 8:00 | |
;; | Foo | | 8:00 |"
;; (org-test-with-temp-text
;; "* Relative times in clocktable\n** Foo\n<point>"
;; (insert (org-test-clock-create-clock "-3d 8:00" "-3d 12:00"))
;; (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
;; (insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
;; (test-org-clock-clocktable-contents
;; ":tstart \"<-2d>\" :tend \"<today>\" :indent nil"))))
;; ;; Relative time: Yesterday until now.
;; (should
;; (equal
;; "| Headline | Time | |
;; |------------------------------+--------+------|
;; | *Total time* | *6:00* | |
;; |------------------------------+--------+------|
;; | Relative times in clocktable | 6:00 | |
;; | Foo | | 6:00 |"
;; (org-test-with-temp-text
;; "* Relative times in clocktable\n** Foo\n<point>"
;; (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
;; (insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
;; (insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
;; (test-org-clock-clocktable-contents
;; ":tstart \"<yesterday>\" :tend \"<tomorrow>\" :indent nil"))))
;; ;; Test `untilnow' block.
;; (should
;; (equal
;; "| Headline | Time | |
;; |------------------------------+--------+------|
;; | *Total time* | *6:00* | |
;; |------------------------------+--------+------|
;; | Relative times in clocktable | 6:00 | |
;; | Foo | | 6:00 |"
;; (org-test-with-temp-text
;; "* Relative times in clocktable\n** Foo\n<point>"
;; (insert (org-test-clock-create-clock "-10y 15:00" "-10y 18:00"))
;; (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
;; (test-org-clock-clocktable-contents ":block untilnow :indent nil")))))
(ert-deftest test-org-clock/clocktable/tags ()
"Test \":tags\" parameter in Clock table."
;; Test tag filtering.
(ert-deftest test-org-clock/clocktable/match ()
"Test \":match\" parameter in Clock table."
;; Test match filtering.
(should
(equal
"| Headline | Time | |
|--------------+--------+------|
"| Headline | Time | |
|------------+------+------|
| *Total time* | *2:00* | |
|--------------+--------+------|
| H1 | | 2:00 |"
|------------+------+------|
| H1 | | 2:00 |"
(org-test-with-temp-text "** H1\n\n*** H2 :tag:\n\n*** H3\n<point>"
(insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
(goto-line 4)
(insert (org-test-clock-create-clock ". 2:00" ". 4:00"))
(test-org-clock-clocktable-contents ":tags \"tag\" :indent nil")))))
(test-org-clock-clocktable-contents ":match \"tag\" :indent nil")))))
(ert-deftest test-org-clock/clocktable/tags ()
"Test \":tags\" parameter in Clock table."
;; Test tags column.
(should
(equal
"| Tags | Headline | Time | |
|------+------------+------+------|
| | *Total time* | *1:00* | |
|------+------------+------+------|
| tag | H1 | | 1:00 |"
(org-test-with-temp-text "** H1 :tag:\n\n*** H2 \n<point>"
(insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
(goto-line 4)
(test-org-clock-clocktable-contents ":tags t :indent nil")))))
(ert-deftest test-org-clock/clocktable/scope ()
"Test \":scope\" parameter in Clock table."
@ -828,141 +843,141 @@ CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 11:09] => 0:00
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 13:09] => 0:00"
(test-org-clock-clocktable-contents ":tcolumns 2")))))
(ert-deftest test-org-clock/clocktable/step ()
"Test \":step\" parameter in Clock table."
;; Regression test: week crossing month boundary before :wstart
;; day-of-week.
(should
(equal "
Weekly report starting on: [2017-09-25 Mon]
| Headline | Time |
|--------------+--------|
| *Total time* | *1:00* |
|--------------+--------|
| Foo | 1:00 |"
(org-test-with-temp-text
"* Foo
CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00"
(let ((system-time-locale "en_US"))
(test-org-clock-clocktable-contents
":step week :block 2017-09 :stepskip0 t")))))
(should
(equal "
Weekly report starting on: [2017-10-01 Sun]
| Headline | Time |
|--------------+--------|
| *Total time* | *2:00* |
|--------------+--------|
| Foo | 2:00 |
;; (ert-deftest test-org-clock/clocktable/step ()
;; "Test \":step\" parameter in Clock table."
;; ;; Regression test: week crossing month boundary before :wstart
;; ;; day-of-week.
;; (should
;; (equal "
;; Weekly report starting on: [2017-09-25 Mon]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *1:00* |
;; |--------------+--------|
;; | Foo | 1:00 |"
;; (org-test-with-temp-text
;; "* Foo
;; CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
;; CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
;; CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00"
;; (let ((system-time-locale "en_US"))
;; (test-org-clock-clocktable-contents
;; ":step week :block 2017-09 :stepskip0 t")))))
;; (should
;; (equal "
;; Weekly report starting on: [2017-10-01 Sun]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *2:00* |
;; |--------------+--------|
;; | Foo | 2:00 |
Weekly report starting on: [2017-10-02 Mon]
| Headline | Time |
|--------------+--------|
| *Total time* | *7:00* |
|--------------+--------|
| Foo | 7:00 |
;; Weekly report starting on: [2017-10-02 Mon]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *7:00* |
;; |--------------+--------|
;; | Foo | 7:00 |
Weekly report starting on: [2017-10-09 Mon]
| Headline | Time |
|--------------+--------|
| *Total time* | *5:00* |
|--------------+--------|
| Foo | 5:00 |
"
(org-test-with-temp-text
"* Foo
CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00
CLOCK: [2017-10-08 Sun 09:00]--[2017-10-08 Sun 13:00] => 4:00
CLOCK: [2017-10-09 Mon 09:00]--[2017-10-09 Mon 14:00] => 5:00"
(let ((system-time-locale "en_US"))
(test-org-clock-clocktable-contents
":step week :block 2017-10 :stepskip0 t")))))
;; :step day
(should
(equal "
Daily report: [2017-10-02 Mon]
| Headline | Time |
|--------------+--------|
| *Total time* | *3:00* |
|--------------+--------|
| Foo | 3:00 |
;; Weekly report starting on: [2017-10-09 Mon]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *5:00* |
;; |--------------+--------|
;; | Foo | 5:00 |
;; "
;; (org-test-with-temp-text
;; "* Foo
;; CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
;; CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
;; CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00
;; CLOCK: [2017-10-08 Sun 09:00]--[2017-10-08 Sun 13:00] => 4:00
;; CLOCK: [2017-10-09 Mon 09:00]--[2017-10-09 Mon 14:00] => 5:00"
;; (let ((system-time-locale "en_US"))
;; (test-org-clock-clocktable-contents
;; ":step week :block 2017-10 :stepskip0 t")))))
;; ;; :step day
;; (should
;; (equal "
;; Daily report: [2017-10-02 Mon]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *3:00* |
;; |--------------+--------|
;; | Foo | 3:00 |
Daily report: [2017-10-03 Tue]
| Headline | Time |
|--------------+--------|
| *Total time* | *0:00* |
;; Daily report: [2017-10-03 Tue]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *0:00* |
Daily report: [2017-10-04 Wed]
| Headline | Time |
|--------------+--------|
| *Total time* | *0:00* |
;; Daily report: [2017-10-04 Wed]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *0:00* |
Daily report: [2017-10-05 Thu]
| Headline | Time |
|--------------+--------|
| *Total time* | *0:00* |
;; Daily report: [2017-10-05 Thu]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *0:00* |
Daily report: [2017-10-06 Fri]
| Headline | Time |
|--------------+--------|
| *Total time* | *0:00* |
;; Daily report: [2017-10-06 Fri]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *0:00* |
Daily report: [2017-10-07 Sat]
| Headline | Time |
|--------------+--------|
| *Total time* | *0:00* |
;; Daily report: [2017-10-07 Sat]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *0:00* |
Daily report: [2017-10-08 Sun]
| Headline | Time |
|--------------+--------|
| *Total time* | *4:00* |
|--------------+--------|
| Foo | 4:00 |"
(org-test-with-temp-text
"* Foo
CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00
CLOCK: [2017-10-08 Sun 09:00]--[2017-10-08 Sun 13:00] => 4:00
CLOCK: [2017-10-09 Mon 09:00]--[2017-10-09 Mon 14:00] => 5:00"
(let ((system-time-locale "en_US"))
(test-org-clock-clocktable-contents
":step day :block 2017-W40")))))
;; Regression test: take :tstart and :tend hours into consideration.
(should
(equal "
Weekly report starting on: [2017-12-25 Mon]
| Headline | Time |
|--------------+--------|
| *Total time* | *8:00* |
|--------------+--------|
| Foo | 8:00 |"
(org-test-with-temp-text
"* Foo
CLOCK: [2017-12-27 Wed 08:00]--[2017-12-27 Wed 16:00] => 8:00"
(let ((system-time-locale "en_US"))
(test-org-clock-clocktable-contents
(concat ":step week :tstart \"<2017-12-25 Mon>\" "
":tend \"<2017-12-27 Wed 23:59>\""))))))
(should
(equal "
Daily report: [2017-12-27 Wed]
| Headline | Time |
|--------------+--------|
| *Total time* | *8:00* |
|--------------+--------|
| Foo | 8:00 |"
(org-test-with-temp-text
"* Foo
CLOCK: [2017-12-27 Wed 08:00]--[2017-12-27 Wed 16:00] => 8:00"
(let ((system-time-locale "en_US"))
(test-org-clock-clocktable-contents
(concat ":step day :tstart \"<2017-12-25 Mon>\" "
":tend \"<2017-12-27 Wed 23:59>\" :stepskip0 t")))))))
;; Daily report: [2017-10-08 Sun]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *4:00* |
;; |--------------+--------|
;; | Foo | 4:00 |"
;; (org-test-with-temp-text
;; "* Foo
;; CLOCK: [2017-09-30 Sat 12:00]--[2017-09-30 Sat 13:00] => 1:00
;; CLOCK: [2017-10-01 Sun 11:00]--[2017-10-01 Sun 13:00] => 2:00
;; CLOCK: [2017-10-02 Mon 11:00]--[2017-10-02 Mon 14:00] => 3:00
;; CLOCK: [2017-10-08 Sun 09:00]--[2017-10-08 Sun 13:00] => 4:00
;; CLOCK: [2017-10-09 Mon 09:00]--[2017-10-09 Mon 14:00] => 5:00"
;; (let ((system-time-locale "en_US"))
;; (test-org-clock-clocktable-contents
;; ":step day :block 2017-W40")))))
;; ;; Regression test: take :tstart and :tend hours into consideration.
;; (should
;; (equal "
;; Weekly report starting on: [2017-12-25 Mon]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *8:00* |
;; |--------------+--------|
;; | Foo | 8:00 |"
;; (org-test-with-temp-text
;; "* Foo
;; CLOCK: [2017-12-27 Wed 08:00]--[2017-12-27 Wed 16:00] => 8:00"
;; (let ((system-time-locale "en_US"))
;; (test-org-clock-clocktable-contents
;; (concat ":step week :tstart \"<2017-12-25 Mon>\" "
;; ":tend \"<2017-12-27 Wed 23:59>\""))))))
;; (should
;; (equal "
;; Daily report: [2017-12-27 Wed]
;; | Headline | Time |
;; |--------------+--------|
;; | *Total time* | *8:00* |
;; |--------------+--------|
;; | Foo | 8:00 |"
;; (org-test-with-temp-text
;; "* Foo
;; CLOCK: [2017-12-27 Wed 08:00]--[2017-12-27 Wed 16:00] => 8:00"
;; (let ((system-time-locale "en_US"))
;; (test-org-clock-clocktable-contents
;; (concat ":step day :tstart \"<2017-12-25 Mon>\" "
;; ":tend \"<2017-12-27 Wed 23:59>\" :stepskip0 t")))))))
(provide 'test-org-clock)
;;; test-org-clock.el end here