~bzg/org-mode

17072a46908b2bf75df85c19306417171b8eeae9 — Ihor Radchenko a month ago b42867b
Allow clock elements without timestamp, like CLOCK: => 12:00

This syntax has been introduced in Org 4.78, but not supported later,
when Org element parser have been created.  Fix this omission to not
remove an existing (and announced!) feature.

This kind of clock is of limited use though - all the customizations
relying upon knowing _when_ clocking time was recorded, like ranges in
clock tables or limits on the displayed clocked-in time, will include
such clocks unconditionally.  So, not adding this to the manual, as it
is not very clear how to use it in actual workflow.

* lisp/org-element.el (org-element-clock-line-re): Update the regexp.
(org-element-clock-parser): Do not assume that timestamp always
follows CLOCK: line.
* testing/lisp/test-org-element.el (test-org-element/clock-parser):
(test-org-element/clock-interpreter): Add tests checking parser and
interpreter output of clocks without timestamps.

Link: https://orgmode.org/list/87frvpyzrf.fsf@localhost
2 files changed, 34 insertions(+), 14 deletions(-)

M lisp/org-element.el
M testing/lisp/test-org-element.el
M lisp/org-element.el => lisp/org-element.el +19 -12
@@ 126,17 126,24 @@ Key is located in match group 1.")
Style, if any, is located in match group 1.")

(defconst org-element-clock-line-re
  (rx-to-string
   `(seq
     line-start (0+ (or ?\t ?\s))
     "CLOCK: "
     (regexp ,org-ts-regexp-inactive)
     (opt "--"
          (regexp ,org-ts-regexp-inactive)
          (1+ (or ?\t ?\s)) "=>" (1+ (or ?\t ?\s))
          (1+ digit) ":" digit digit)
     (0+ (or ?\t ?\s))
     line-end))
  (let ((duration ; "=> 212:12"
         '(seq
           (1+ (or ?\t ?\s)) "=>" (1+ (or ?\t ?\s))
           (1+ digit) ":" digit digit)))
    (rx-to-string
     `(seq
       line-start (0+ (or ?\t ?\s))
       "CLOCK:"
       (or
        (seq
         (1+ (or ?\t ?\s))
         (regexp ,org-ts-regexp-inactive)
         (opt "--"
              (regexp ,org-ts-regexp-inactive)
              ,duration))
        ,duration)
       (0+ (or ?\t ?\s))
       line-end)))
  "Regexp matching a clock line.")

(defconst org-element-comment-string "COMMENT"


@@ 2295,7 2302,7 @@ Return a new syntax node of `clock' type containing `:status',
	   (value (progn (search-forward "CLOCK:" (line-end-position))
			 (skip-chars-forward " \t")
			 (org-element-timestamp-parser)))
	   (duration (and (search-forward " => " (line-end-position) t)
	   (duration (and (search-forward "=> " (line-end-position) t)
			  (progn (skip-chars-forward " \t")
				 (looking-at "\\(\\S-+\\)[ \t]*$"))
			  (match-string-no-properties 1)))

M testing/lisp/test-org-element.el => testing/lisp/test-org-element.el +15 -2
@@ 1175,7 1175,15 @@ CLOCK: [2023-10-13 Fri 14:40]--[2023-10-13 Fri 14:51] =>  0:11"
    (should (equal (org-element-property :raw-value
					 (org-element-property :value clock))
		   "[2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02]"))
    (should (equal (org-element-property :duration clock) "0:01"))))
    (should (equal (org-element-property :duration clock) "0:01")))
  ;; Closed clock without timestamp.
  (let ((clock
	 (org-test-with-temp-text
	     "CLOCK: =>  0:11"
	   (org-element-at-point))))
    (should (eq (org-element-property :status clock) 'closed))
    (should-not (org-element-property :value clock))
    (should (equal (org-element-property :duration clock) "0:11"))))


;;;; Code


@@ 3682,7 3690,12 @@ Outside list"
   (string-match
    "CLOCK: \\[2012-01-01 .* 00:01\\]--\\[2012-01-01 .* 00:02\\] =>  0:01"
    (org-test-parse-and-interpret "
CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] =>  0:01"))))
CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] =>  0:01")))
  ;; Closed clock without timestamp.
  (should
   (string-match
    "CLOCK:  =>  0:01"
    (org-test-parse-and-interpret "CLOCK: => 0:01"))))

(ert-deftest test-org-element/comment-interpreter ()
  "Test comment interpreter."