From: Ilya Chernyshov <ichernyshovvv@gmail.com>
To: Ihor Radchenko <yantar92@posteo.net>
Cc: emacs-orgmode <emacs-orgmode@gnu.org>
Subject: Re: [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
Date: Tue, 11 Jul 2023 20:16:50 +0700 [thread overview]
Message-ID: <87wmz6ziyl.fsf@gmail.com> (raw)
In-Reply-To: <87o7kiom6i.fsf@localhost>
[-- Attachment #1: Type: text/plain, Size: 822 bytes --]
Ihor Radchenko <yantar92@posteo.net> writes:
> The patch looks good in general, but there is at least one test failing
> when I run make test. May you please check?
Inside `org-timestamp-split-range', there was an attempt to intepret a
timestamp object with :type `active'/`inactive' and :range-type
`daterange'/`timerange' which caused an error. Fixed by setting
:range-type to nil before `(org-element-interpret-data split-ts)'.
> Also, see the attached diff where I suggest some comments to explain the
> code logic.
Looks good to me, I just changed a note about
`org-element-timestamp-parser' setting nil for end part if :type is
`active'/`inactive'. That's not true. The actual behavior is that it
sets end date/time to the same values as start date/time even if it's
`active'/`inactive'. So here is the patch:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-lisp-org-element.el-Add-new-timestamp-property-range.patch --]
[-- Type: text/x-patch, Size: 26559 bytes --]
From 823e7f39d33977854605485fcae814af0a3fdefe Mon Sep 17 00:00:00 2001
From: Ilya Chernyshov <ichernyshovvv@gmail.com>
Date: Sat, 18 Feb 2023 14:55:39 +0700
Subject: [PATCH] lisp/org-element.el: Add new timestamp property :range-type
* lisp/org-element.el (org-element-timestamp-interpreter): Preserve old
behavior when :range-type is `nil'. Take into account :range-type
value when interpreting ranges. When :range-type is `timerange',
return a timerange (<YYYY-mm-DD HH:MM-HH:MM>). If :range-type is
`daterange' return a daterange (<...>--<...>). When :range-type is
nil, return a daterange (as it was before). When :range-type is
`daterange' or `timerange' and :type is `active'/`inactive', throw an
error.
(org-element-timestamp-parser): Add :range-type property.
* lisp/org.el (org-timestamp-split-range): Make sure that :range-type
is nil for a split timestamp.
* testing/lisp/test-org-element.el
(test-org-element/timestamp-interpreter): Add new tests.
(test-org-element/timestamp-parser): Add tests for :range-type
property.
* etc/ORG-NEWS (Major changes and additions to Org API): Add news about this property.
---
etc/ORG-NEWS | 7 +
lisp/org-element.el | 215 +++++++++++++++-------------
lisp/org.el | 1 +
testing/lisp/test-org-element.el | 231 ++++++++++++++++++++++++++++++-
4 files changed, 355 insertions(+), 99 deletions(-)
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 973a97a2f..a4725ae8c 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -200,6 +200,13 @@ a newly created one.
Previously, one had to use
: (apply #'org-element-create 'section nil (org-element-contents node))
+**** New property ~:range-type~ for org-element timestamp object
+
+~org-element-timestamp-parser~ now adds =:range-type= property to each
+timestamp object. Possible values: ~timerange~, ~daterange~, ~nil~.
+
+~org-element-timestamp-interpreter~ takes into account this property
+and returns an appropriate timestamp string.
*** ~org-priority=show~ command no longer adjusts for scheduled/deadline
diff --git a/lisp/org-element.el b/lisp/org-element.el
index 1c9707573..075f64920 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -4043,7 +4043,7 @@ Assume point is at the target."
"Parse time stamp at point, if any.
When at a time stamp, return a new syntax node of `timestamp' type
-containing `:type', `:raw-value', `:year-start', `:month-start',
+containing `:type', `:range-type', `:raw-value', `:year-start', `:month-start',
`:day-start', `:hour-start', `:minute-start', `:year-end',
`:month-end', `:day-end', `:hour-end', `:minute-end',
`:repeater-type', `:repeater-value', `:repeater-unit',
@@ -4077,6 +4077,10 @@ Assume point is at the beginning of the timestamp."
(activep 'active)
((or date-end time-range) 'inactive-range)
(t 'inactive)))
+ (range-type (cond
+ (date-end 'daterange)
+ (time-range 'timerange)
+ (t nil)))
(repeater-props
(and (not diaryp)
(string-match "\\([.+]?\\+\\)\\([0-9]+\\)\\([hdwmy]\\)"
@@ -4123,6 +4127,7 @@ Assume point is at the beginning of the timestamp."
(org-element-create
'timestamp
(nconc (list :type type
+ :range-type range-type
:raw-value raw-value
:year-start year-start
:month-start month-start
@@ -4142,99 +4147,121 @@ Assume point is at the beginning of the timestamp."
(defun org-element-timestamp-interpreter (timestamp _)
"Interpret TIMESTAMP object as Org syntax."
- (let* ((repeat-string
- (concat
- (pcase (org-element-property :repeater-type timestamp)
- (`cumulate "+") (`catch-up "++") (`restart ".+"))
- (let ((val (org-element-property :repeater-value timestamp)))
- (and val (number-to-string val)))
- (pcase (org-element-property :repeater-unit timestamp)
- (`hour "h") (`day "d") (`week "w") (`month "m") (`year "y"))))
- (warning-string
- (concat
- (pcase (org-element-property :warning-type timestamp)
- (`first "--") (`all "-"))
- (let ((val (org-element-property :warning-value timestamp)))
- (and val (number-to-string val)))
- (pcase (org-element-property :warning-unit timestamp)
- (`hour "h") (`day "d") (`week "w") (`month "m") (`year "y"))))
- (build-ts-string
- ;; Build an Org timestamp string from TIME. ACTIVEP is
- ;; non-nil when time stamp is active. If WITH-TIME-P is
- ;; non-nil, add a time part. HOUR-END and MINUTE-END
- ;; specify a time range in the timestamp. REPEAT-STRING is
- ;; the repeater string, if any.
- (lambda (time activep &optional with-time-p hour-end minute-end)
- (let ((ts (format-time-string
- (org-time-stamp-format with-time-p)
- time)))
- (when (and hour-end minute-end)
- (string-match "[012]?[0-9]:[0-5][0-9]" ts)
- (setq ts
- (replace-match
- (format "\\&-%02d:%02d" hour-end minute-end)
- nil nil ts)))
- (unless activep (setq ts (format "[%s]" (substring ts 1 -1))))
- (dolist (s (list repeat-string warning-string))
- (when (org-string-nw-p s)
- (setq ts (concat (substring ts 0 -1)
- " "
- s
- (substring ts -1)))))
- ;; Return value.
- ts)))
- (type (org-element-property :type timestamp)))
- (pcase type
- ((or `active `inactive)
- (let* ((minute-start (org-element-property :minute-start timestamp))
- (minute-end (org-element-property :minute-end timestamp))
- (hour-start (org-element-property :hour-start timestamp))
- (hour-end (org-element-property :hour-end timestamp))
- (time-range-p (and hour-start hour-end minute-start minute-end
- (or (/= hour-start hour-end)
- (/= minute-start minute-end)))))
- (funcall
- build-ts-string
- (org-encode-time 0
- (or minute-start 0)
- (or hour-start 0)
- (org-element-property :day-start timestamp)
- (org-element-property :month-start timestamp)
- (org-element-property :year-start timestamp))
- (eq type 'active)
- (and hour-start minute-start)
- (and time-range-p hour-end)
- (and time-range-p minute-end))))
- ((or `active-range `inactive-range)
- (let ((minute-start (org-element-property :minute-start timestamp))
- (minute-end (org-element-property :minute-end timestamp))
- (hour-start (org-element-property :hour-start timestamp))
- (hour-end (org-element-property :hour-end timestamp)))
- (concat
- (funcall
- build-ts-string (org-encode-time
- 0
- (or minute-start 0)
- (or hour-start 0)
- (org-element-property :day-start timestamp)
- (org-element-property :month-start timestamp)
- (org-element-property :year-start timestamp))
- (eq type 'active-range)
- (and hour-start minute-start))
- "--"
- (funcall build-ts-string
- (org-encode-time
- 0
- (or minute-end 0)
- (or hour-end 0)
- (org-element-property :day-end timestamp)
- (org-element-property :month-end timestamp)
- (org-element-property :year-end timestamp))
- (eq type 'active-range)
- (and hour-end minute-end)))))
- (_ (org-element-property :raw-value timestamp)))))
-
-
+ (let((type (org-element-property :type timestamp)))
+ (if (member type '(active inactive inactive-range active-range))
+ (let ((day-start (org-element-property :day-start timestamp))
+ (month-start (org-element-property :month-start timestamp))
+ (year-start (org-element-property :year-start timestamp)))
+ ;; Return nil when start date is not available. Could also
+ ;; throw an error, but the current behavior is historical.
+ (when (and day-start month-start year-start)
+ (let* ((repeat-string
+ (concat
+ (pcase (org-element-property :repeater-type timestamp)
+ (`cumulate "+") (`catch-up "++") (`restart ".+"))
+ (let ((val (org-element-property :repeater-value timestamp)))
+ (and val (number-to-string val)))
+ (pcase (org-element-property :repeater-unit timestamp)
+ (`hour "h") (`day "d") (`week "w") (`month "m") (`year "y"))))
+ (range-type (org-element-property :range-type timestamp))
+ (warning-string
+ (concat
+ (pcase (org-element-property :warning-type timestamp)
+ (`first "--") (`all "-"))
+ (let ((val (org-element-property :warning-value timestamp)))
+ (and val (number-to-string val)))
+ (pcase (org-element-property :warning-unit timestamp)
+ (`hour "h") (`day "d") (`week "w") (`month "m") (`year "y"))))
+ (hour-start (org-element-property :hour-start timestamp))
+ (minute-start (org-element-property :minute-start timestamp))
+ (brackets
+ (if (member
+ type
+ '(inactive inactive-range))
+ (cons "[" "]")
+ (cons "<" ">")))
+ (timestamp-end
+ (concat
+ (and (org-string-nw-p repeat-string) (concat " " repeat-string))
+ (and (org-string-nw-p warning-string) (concat " " warning-string))
+ (cdr brackets))))
+ (concat
+ ;; Opening backet: [ or <
+ (car brackets)
+ ;; Starting date/time: YYYY-MM-DD DAY[ HH:MM]
+ (format-time-string
+ ;; `org-time-stamp-formats'.
+ (org-time-stamp-format
+ ;; Ignore time unless both HH:MM are available.
+ ;; Ignore means (car org-timestamp-formats).
+ (and minute-start hour-start)
+ 'no-brackets)
+ (org-encode-time
+ 0 (or minute-start 0) (or hour-start 0)
+ day-start month-start year-start))
+ ;; Range: -HH:MM or TIMESTAMP-END--[YYYY-MM-DD DAY HH:MM]
+ (let ((hour-end (org-element-property :hour-end timestamp))
+ (minute-end (org-element-property :minute-end timestamp)))
+ (pcase type
+ ((or `active `inactive)
+ ;; `org-element-timestamp-parser' uses this type
+ ;; when no time/date range is provided. So,
+ ;; should normally return nil in this clause.
+ (pcase range-type
+ (`nil
+ ;; `org-element-timestamp-parser' assigns end times for `active'/`inactive' TYPE
+ ;; if start time is not nil. But manually built timestamps
+ ;; may not contain end times, so check for end times anyway.
+ (when (and hour-start hour-end minute-start minute-end
+ (or (/= hour-start hour-end)
+ (/= minute-start minute-end)))
+ ;; Could also throw an error. Return range
+ ;; timestamp nevertheless to preserve
+ ;; historical behavior.
+ (format "-%02d:%02d" hour-end minute-end)))
+ ((or `timerange `daterange)
+ (error "`:range-type' must be `nil' for `active'/`inactive' type"))))
+ ;; Range must be present.
+ ((or `active-range `inactive-range)
+ (pcase range-type
+ ;; End time: -HH:MM.
+ ;; Fall back to start time if end time is not defined (arbitrary historical choice).
+ ;; Error will be thrown if both end and begin time is not defined.
+ (`timerange (format "-%02d:%02d" (or hour-end hour-start) (or minute-end minute-start)))
+ ;; End date: TIMESTAMP-END--[YYYY-MM-DD DAY HH:MM
+ ((or `daterange
+ ;; Should never happen in the output of `org-element-timestamp-parser'.
+ ;; Treat as an equivalent of `daterange' arbitrarily.
+ `nil)
+ (concat
+ ;; repeater + warning + closing > or ]
+ ;; This info is duplicated in date ranges.
+ timestamp-end
+ "--" (car brackets)
+ (format-time-string
+ ;; `org-time-stamp-formats'.
+ (org-time-stamp-format
+ ;; Ignore time unless both HH:MM are available.
+ ;; Ignore means (car org-timestamp-formats).
+ (and minute-end hour-end)
+ 'no-brackets)
+ (org-encode-time
+ ;; Closing HH:MM missing is a valid scenario.
+ 0 (or minute-end 0) (or hour-end 0)
+ ;; YEAR/MONTH/DAY-END will always be present
+ ;; for `daterange' range-type, as parsed by
+ ;; `org-element-timestamp-parser'.
+ ;; For manually constructed timestamp
+ ;; object, arbitrarily fall back to starting
+ ;; date.
+ (or (org-element-property :day-end timestamp) day-start)
+ (or (org-element-property :month-end timestamp) month-start)
+ (or (org-element-property :year-end timestamp) year-start)))))))))
+ ;; repeater + warning + closing > or ]
+ ;; This info is duplicated in date ranges.
+ timestamp-end))))
+ ;; diary type.
+ (org-element-property :raw-value timestamp))))
;;;; Underline
(defun org-element-underline-parser ()
diff --git a/lisp/org.el b/lisp/org.el
index 62278ec77..590f8ab96 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -20043,6 +20043,7 @@ Return a new timestamp object."
;; Set new type.
(org-element-put-property
split-ts :type (if (eq type 'active-range) 'active 'inactive))
+ (org-element-put-property split-ts :range-type nil)
;; Copy start properties over end properties if END is
;; non-nil. Otherwise, copy end properties over `start' ones.
(let ((p-alist '((:minute-start . :minute-end)
diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 283ade10f..2e3a249ab 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -3138,8 +3138,73 @@ Outside list"
(org-test-with-temp-text "<2012-03-29 Thu +1y -1y>"
(let ((ts (org-element-context)))
(list (org-element-property :repeater-type ts)
- (org-element-property :warning-type ts)))))))
-
+ (org-element-property :warning-type ts))))))
+ ;; :range-type property
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ nil))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ nil))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00-13:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'timerange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00-12:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'timerange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun>--<2023-07-02 Sun>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun>--<2023-07-03 Mon>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-02 Sun 12:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-03 Mon 13:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-02 Sun>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-03 Mon>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-02 Sun 13:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00>--<2023-07-02 Sun>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange))
+ (should
+ (eq
+ (org-test-with-temp-text "<2023-07-02 Sun 12:00 +5d>--<2023-07-02 Sun 13:00>"
+ (org-element-property :range-type (org-element-timestamp-parser)))
+ 'daterange)))
;;;; Underline
@@ -3685,6 +3750,14 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
'(timestamp
(:type active :year-start 2012 :month-start 3 :day-start 29
:hour-start 16 :minute-start 40)) nil)))
+ (should
+ (string-match
+ "<2012-03-29 .* 16:40>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:type active :year-start 2012 :month-start 3 :day-start 29
+ :hour-start 16 :minute-start 40 :year-end 2012 :month-end 3
+ :day-end 29 :hour-end 16 :minute-end 40)) nil)))
;; Inactive.
(should
(string-match "\\[2012-03-29 .* 16:40\\]"
@@ -3696,11 +3769,45 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
'(timestamp
(:type inactive :year-start 2012 :month-start 3 :day-start 29
:hour-start 16 :minute-start 40)) nil)))
- ;; Active range.
+ ;; Active daterange.
(should
(string-match "<2012-03-29 .* 16:40>--<2012-03-29 .* 16:41>"
(org-test-parse-and-interpret
"<2012-03-29 thu. 16:40>--<2012-03-29 thu. 16:41>")))
+ ;;; No end time, dates are not equal
+ (should
+ ;; Expected result: "<2012-03-29 Thu 16:40>--<2012-03-30 Fri>"
+ (string=
+ (format
+ "<%s>--<%s>"
+ (format-time-string (cdr org-time-stamp-formats) (org-encode-time 0 40 16 29 03 2012))
+ (format-time-string (car org-time-stamp-formats) (org-encode-time 0 0 0 30 03 2012)))
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:type active-range :year-start 2012 :month-start 3 :day-start 29
+ :hour-start 16 :minute-start 40 :year-end 2012 :month-end 3
+ :day-end 30)) nil)))
+ ;;; No start time, dates are not equal
+ (should
+ ;; Expected result: "<2012-03-29 Thu>--<2012-03-30 Fri 16:40>"
+ (string=
+ (format
+ "<%s>--<%s>"
+ (format-time-string (car org-time-stamp-formats) (org-encode-time 0 0 0 29 03 2012))
+ (format-time-string (cdr org-time-stamp-formats) (org-encode-time 0 40 16 30 03 2012)))
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:type active-range :year-start 2012 :month-start 3 :day-start 29
+ :hour-end 16 :minute-end 40 :year-end 2012 :month-end 3
+ :day-end 30)) nil)))
+ (should
+ (string-match
+ "<2012-03-29 .* 16:40>--<2012-03-29 .* 16:40>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:type active-range :year-start 2012 :month-start 3 :day-start 29
+ :hour-start 16 :minute-start 40 :year-end 2012 :month-end 3
+ :day-end 29 :hour-end 16 :minute-end 40)) nil)))
(should
(string-match
"<2012-03-29 .* 16:40>--<2012-03-29 .* 16:41>"
@@ -3709,7 +3816,7 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
(:type active-range :year-start 2012 :month-start 3 :day-start 29
:hour-start 16 :minute-start 40 :year-end 2012 :month-end 3
:day-end 29 :hour-end 16 :minute-end 41)) nil)))
- ;; Inactive range.
+ ;; Inactive daterange.
(should
(string-match "\\[2012-03-29 .* 16:40\\]--\\[2012-03-29 .* 16:41\\]"
(org-test-parse-and-interpret
@@ -3722,6 +3829,11 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
(:type inactive-range :year-start 2012 :month-start 3 :day-start 29
:hour-start 16 :minute-start 40 :year-end 2012 :month-end 3
:day-end 29 :hour-end 16 :minute-end 41)) nil)))
+ ;; Active timerange
+ (should
+ (string-match "<2012-03-29 .* 16:40-16:41>"
+ (org-test-parse-and-interpret
+ "<2012-03-29 thu. 16:40-16:41>")))
;; Diary.
(should (equal (org-test-parse-and-interpret "<%%diary-float t 4 2>")
"<%%diary-float t 4 2>\n"))
@@ -3767,7 +3879,116 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
(:type active-range :year-start 2012 :month-start 3 :day-start 29
:year-end 2012 :month-end 3 :day-end 30 :repeater-type cumulate
:repeater-value 1 :repeater-unit year))
- nil))))
+ nil)))
+ ;; Tests for :range-type property
+ ;;; Errors
+ (should-error
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type timerange
+ :type active
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 7 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 17 :minute-end 30))
+ nil))
+ (should-error
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type active :year-start 2023 :month-start 7 :day-start 10
+ :hour-start 17 :minute-start 30)) nil))
+ (should-error
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type timerange
+ :type inactive
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 7 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 17 :minute-end 30))
+ nil))
+ (should-error
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type inactive :year-start 2023 :month-start 7 :day-start 10
+ :hour-start 17 :minute-start 30)) nil))
+
+ ;;; End part is nil
+ (should
+ ;; Expected result: "<2023-07-10 Mon>--<2023-07-10 Mon>"
+ (string=
+ (format
+ "<%s>--<%s>"
+ (format-time-string (car org-time-stamp-formats) (org-encode-time 0 0 0 10 7 2023))
+ (format-time-string (car org-time-stamp-formats) (org-encode-time 0 0 0 10 7 2023)))
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type active-range :year-start 2023 :month-start 7 :day-start 10)) nil)))
+ (should
+ (string-match "<2023-07-10 .* 17:30-17:30>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type timerange
+ :type active-range :year-start 2023 :month-start 7 :day-start 10
+ :hour-start 17 :minute-start 30)) nil)))
+ (should
+ ;; Expected result: "<2023-07-10 Mon 17:30>--<2023-07-10 Mon>"
+ (string=
+ (format
+ "<%s>--<%s>"
+ (format-time-string (cdr org-time-stamp-formats) (org-encode-time 0 30 17 10 7 2023))
+ (format-time-string (car org-time-stamp-formats) (org-encode-time 0 0 0 10 7 2023)))
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type active-range :year-start 2023 :month-start 7 :day-start 10
+ :hour-start 17 :minute-start 30)) nil)))
+ ;;; End is equal to start
+ (should
+ (string-match "<2023-07-10 .* 17:30-17:30>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type timerange
+ :type active-range
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 7 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 17 :minute-end 30)) nil)))
+ (should
+ (string-match "<2023-07-10 .* 17:30>--<2023-07-10 .* 17:30>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type active-range
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 7 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 17 :minute-end 30)) nil)))
+ ;;;; End date is not equal to start date, but interpret the object as a timerange (:range-type 'timerange)
+ (should
+ (string-match "<2023-07-10 .* 17:30-18:30>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type timerange
+ :type active-range
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 8 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 18 :minute-end 30)) nil)))
+ ;;;; End date is not equal to start date, interpret the object as a daterange (:range-type 'daterange)
+ (should
+ (string-match "<2023-07-10 .* 17:30>--<2023-08-10 .* 18:30>"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (:range-type daterange
+ :type active-range
+ :year-start 2023 :month-start 7 :day-start 10
+ :year-end 2023 :month-end 8 :day-end 10
+ :hour-start 17 :minute-start 30
+ :hour-end 18 :minute-end 30)) nil))))
(ert-deftest test-org-element/verse-block-interpreter ()
"Test verse block interpretation."
--
2.40.1
[-- Attachment #3: Type: text/plain, Size: 123 bytes --]
> And please provide an additional patch for WORG:
> https://orgmode.org/worg/dev/org-element-api.html#org6ae377e
Sure.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0001-dev-org-element-api.org-Add-range-type-for-timestamp.patch --]
[-- Type: text/x-patch, Size: 874 bytes --]
From ea809755deef50cf91f41d50241ab86a0787f2cf Mon Sep 17 00:00:00 2001
From: Ilya Chernyshov <ichernyshovvv@gmail.com>
Date: Tue, 11 Jul 2023 19:00:40 +0700
Subject: [PATCH] dev/org-element-api.org: Add :range-type for timestamp
objects
---
dev/org-element-api.org | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dev/org-element-api.org b/dev/org-element-api.org
index baf7e8a1..ffcda274 100644
--- a/dev/org-element-api.org
+++ b/dev/org-element-api.org
@@ -708,6 +708,8 @@ Object.
(integer or ~nil~).
- ~:type~ :: Type of timestamp (symbol: ~active~, ~active-range~,
~diary~, ~inactive~, ~inactive-range~).
+- ~:range-type~ :: Type of range (symbol: ~daterange~, ~timerange~ or
+ ~nil~).
- ~:warning-type~ :: Type of warning, if any (symbol: ~all~, ~first~
or ~nil~)
- ~:warning-unit~ :: Unit of delay, if one is defined (symbol: ~year~,
--
2.40.1
next prev parent reply other threads:[~2023-07-11 13:18 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-19 12:25 [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil Ilya Chernyshov
2023-02-19 14:11 ` Ilya Chernyshov
2023-02-20 11:07 ` Ihor Radchenko
2023-02-20 16:36 ` Ilya Chernyshov
2023-02-22 11:21 ` Ihor Radchenko
2023-07-01 19:47 ` Ilya Chernyshov
2023-07-02 8:46 ` Ihor Radchenko
2023-07-07 7:24 ` Ilya Chernyshov
2023-07-08 8:35 ` Ihor Radchenko
2023-07-10 18:19 ` Ilya Chernyshov
2023-07-11 9:02 ` Ihor Radchenko
2023-07-11 13:16 ` Ilya Chernyshov [this message]
2023-07-12 8:16 ` Ihor Radchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87wmz6ziyl.fsf@gmail.com \
--to=ichernyshovvv@gmail.com \
--cc=emacs-orgmode@gnu.org \
--cc=yantar92@posteo.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).