* [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
@ 2023-02-19 12:25 Ilya Chernyshov
2023-02-19 14:11 ` Ilya Chernyshov
2023-02-20 11:07 ` Ihor Radchenko
0 siblings, 2 replies; 5+ messages in thread
From: Ilya Chernyshov @ 2023-02-19 12:25 UTC (permalink / raw)
To: emacs-orgmode
Hello, guys
`org-element-timestamp-interpreter' function returns string of the
form
"<2023-02-19 Sun 10:00>--<2023-02-19 Sun 10:30>" for a timestamp
object
passed to it. The better result would be "<2023-02-19 Sun
10:00-10:30>".
This function is also used for interpreting clock entries, which
only
have the format of "[2023-02-19 Sun 10:00]--[2023-02-19 Sun
10:30]".
So, an option is needed that controls whether to return a
daterange
(even it's possible to return a timerange) or a timerange (if the
dates
in the range are equal).
I wrote a patch that handles this problem, could you please review
the
code and give some advice to improve it?
--
Best,
Ilya
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
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
1 sibling, 0 replies; 5+ messages in thread
From: Ilya Chernyshov @ 2023-02-19 14:11 UTC (permalink / raw)
To: emacs-orgmode
[-- Attachment #1: Type: text/plain, Size: 34 bytes --]
I forgot to attach the patch :)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-element-timestamp-interpreter-Return-daterange-a.patch --]
[-- Type: text/x-patch, Size: 13338 bytes --]
From b47324bc804e64e6cef482ba4897a457252e803a Mon Sep 17 00:00:00 2001
From: Ilya Chernyshov <ichernyshovvv@gmail.com>
Date: Sat, 18 Feb 2023 14:55:39 +0700
Subject: [PATCH] org-element-timestamp-interpreter: Return daterange anyway,
if DATERANGE is non-nil
* lisp/org-element (org-element-timestamp-interpreter): Replace
silenced argument with optional argument DATERANGE which controls
whether to return daterange (even if dates in the range are equal) or
timerange (if it's possible). Refactor the code.
* lisp/org-element (org-element-planning-interpreter): Call
`org-element-timestamp-interpreter' without second argument.
* lisp/org-element (org-element-clock-interpreter): Call
`org-element-timestamp-interpreter' with DATERANGE set to t, because
clock entries only support daterange format.
* lisp/org-element (org-element-interpret-data): Call
`org-element-timestamp-interpreter' on timestamp object with DATERANGE
set to t, if it's inactive-range.
* testing/lisp/test-org-element
(test-org-element/timestamp-interpreter): Expect timerange returned
for timestamp of type active-range from
`org-element-timestamp-interpreter' and `org-test-parse-and-interpret'
calls. Add tests for `org-element-timestamp-interpreter' with
DATERANGE argument.
---
lisp/org-element.el | 180 ++++++++++++++-----------------
testing/lisp/test-org-element.el | 28 ++++-
2 files changed, 106 insertions(+), 102 deletions(-)
diff --git a/lisp/org-element.el b/lisp/org-element.el
index d7847a678..9649c6951 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -2042,7 +2042,7 @@ (defun org-element-clock-interpreter (clock _)
"Interpret CLOCK element as Org syntax."
(concat "CLOCK: "
(org-element-timestamp-interpreter
- (org-element-property :value clock) nil)
+ (org-element-property :value clock) t)
(let ((duration (org-element-property :duration clock)))
(and duration
(concat " => "
@@ -2673,15 +2673,15 @@ (defun org-element-planning-interpreter (planning _)
(list (let ((deadline (org-element-property :deadline planning)))
(when deadline
(concat org-element-deadline-keyword " "
- (org-element-timestamp-interpreter deadline nil))))
+ (org-element-timestamp-interpreter deadline))))
(let ((scheduled (org-element-property :scheduled planning)))
(when scheduled
(concat org-element-scheduled-keyword " "
- (org-element-timestamp-interpreter scheduled nil))))
+ (org-element-timestamp-interpreter scheduled))))
(let ((closed (org-element-property :closed planning)))
(when closed
(concat org-element-closed-keyword " "
- (org-element-timestamp-interpreter closed nil))))))
+ (org-element-timestamp-interpreter closed))))))
" "))
@@ -4020,100 +4020,79 @@ (defun org-element-timestamp-parser ()
repeater-props
warning-props))))))
-(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)))))
-
+(defun org-element-timestamp-interpreter (timestamp &optional daterange)
+ "Interpret TIMESTAMP object as Org syntax.
+
+If DATERANGE is non-nil, create daterange even if dates in the
+range are equal."
+ (if (member
+ (org-element-property :type timestamp)
+ '(active inactive inactive-range active-range))
+ (let((start-date
+ (format-time-string
+ (org-time-stamp-format nil 'no-brackets)
+ (org-encode-time
+ 0 0 0
+ (org-element-property :day-start timestamp)
+ (org-element-property :month-start timestamp)
+ (org-element-property :year-start timestamp)))))
+ (when start-date
+ (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"))))
+ (hour-start (org-element-property :hour-start timestamp))
+ (minute-start (org-element-property :minute-start timestamp))
+ (start-time
+ (and hour-start minute-start
+ (format "%02d:%02d" hour-start minute-start)))
+ (hour-end (org-element-property :hour-end timestamp))
+ (minute-end (org-element-property :minute-end timestamp))
+ (end-time (and hour-end minute-end
+ (format "%02d:%02d" hour-end minute-end)))
+ (day-end (org-element-property :day-end timestamp))
+ (month-end (org-element-property :month-end timestamp))
+ (year-end (org-element-property :year-end timestamp))
+ (time-range-p (and start-time end-time
+ (not (string= start-time end-time))))
+ (end-date
+ (and year-end month-end day-end
+ (format-time-string
+ (org-time-stamp-format nil 'no-brackets)
+ (org-encode-time
+ 0 0 0 day-end month-end year-end))))
+ (date-range-p (or (and daterange time-range-p)
+ (and end-date (not (string= end-date start-date)))))
+ (ts
+ (concat
+ "<" start-date (and start-time (concat " " start-time))
+ (if date-range-p
+ (concat ">--<" end-date (and end-time (concat " " end-time)))
+ (if time-range-p (concat "-" end-time)))
+ ">")))
+ (dolist (s (list repeat-string warning-string))
+ (when (org-string-nw-p s)
+ (setq ts (string-replace ">" (concat " " s ">") ts))))
+ (pcase (org-element-property :type timestamp)
+ ((or `active `active-range)
+ ts)
+ ((or `inactive `inactive-range)
+ (string-replace
+ "<" "["
+ (string-replace ">" "]" ts)))))))
+ (org-element-property :raw-value timestamp)))
;;;; Underline
@@ -5050,7 +5029,10 @@ (defun org-element-interpret-data (data)
((stringp data) data)
;; Element or object without contents.
((not (org-element-contents data))
- (funcall interpret data nil))
+ (cond ((eq type 'timestamp)
+ (funcall interpret data
+ (eq (org-element-property :type data) 'inactive-range)))
+ (t (funcall interpret data nil))))
;; Element or object with contents.
(t
(funcall
diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 43f1d860f..fd865f38b 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -3235,17 +3235,28 @@ (ert-deftest test-org-element/timestamp-interpreter ()
:hour-start 16 :minute-start 40)) nil)))
;; Active range.
(should
- (string-match "<2012-03-29 .* 16:40>--<2012-03-29 .* 16:41>"
+ (string-match "<2012-03-29 .* 16:40-16:41>"
(org-test-parse-and-interpret
"<2012-03-29 thu. 16:40>--<2012-03-29 thu. 16:41>")))
(should
(string-match
- "<2012-03-29 .* 16:40>--<2012-03-29 .* 16:41>"
+ "<2012-03-29 .* 16:40-16:41>"
(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 41)) nil)))
+
+ (should
+ (string-match
+ "<2012-03-29 .* 16:40>--<2012-03-29 .* 16:41>"
+ (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 41))
+ t)))
+
;; Inactive range.
(should
(string-match "\\[2012-03-29 .* 16:40\\]--\\[2012-03-29 .* 16:41\\]"
@@ -3258,7 +3269,18 @@ (ert-deftest test-org-element/timestamp-interpreter ()
'(timestamp
(: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)))
+ :day-end 29 :hour-end 16 :minute-end 41)) t)))
+
+ (should
+ (string-match
+ "\\[2012-03-29 .* 16:40-16:41\\]"
+ (org-element-timestamp-interpreter
+ '(timestamp
+ (: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)))
+
;; Diary.
(should (equal (org-test-parse-and-interpret "<%%diary-float t 4 2>")
"<%%diary-float t 4 2>\n"))
--
2.39.0
[-- Attachment #3: Type: text/plain, Size: 16 bytes --]
--
Best,
Ilya
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
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
1 sibling, 1 reply; 5+ messages in thread
From: Ihor Radchenko @ 2023-02-20 11:07 UTC (permalink / raw)
To: Ilya Chernyshov; +Cc: emacs-orgmode
Ilya Chernyshov <ichernyshovvv@gmail.com> writes:
> So, an option is needed that controls whether to return a
> daterange
> (even it's possible to return a timerange) or a timerange (if the
> dates
> in the range are equal).
>
> I wrote a patch that handles this problem, could you please review
> the
> code and give some advice to improve it?
What about recording the type of timestamp range in the parser?
Then, interpreter can simply examine the range type and emit the correct
timestamp string.
--
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
2023-02-20 11:07 ` Ihor Radchenko
@ 2023-02-20 16:36 ` Ilya Chernyshov
2023-02-22 11:21 ` Ihor Radchenko
0 siblings, 1 reply; 5+ messages in thread
From: Ilya Chernyshov @ 2023-02-20 16:36 UTC (permalink / raw)
To: Ihor Radchenko; +Cc: emacs-orgmode
[-- Attachment #1: Type: text/plain, Size: 982 bytes --]
You suggest to split timestamp types active/inactive-range to active/inactive-timerange, active/inactive-daterange?
On February 20, 2023 6:07:19 PM GMT+07:00, Ihor Radchenko <yantar92@posteo.net> wrote:
>Ilya Chernyshov <ichernyshovvv@gmail.com> writes:
>
>> So, an option is needed that controls whether to return a
>> daterange
>> (even it's possible to return a timerange) or a timerange (if the
>> dates
>> in the range are equal).
>>
>> I wrote a patch that handles this problem, could you please review
>> the
>> code and give some advice to improve it?
>
>What about recording the type of timestamp range in the parser?
>Then, interpreter can simply examine the range type and emit the correct
>timestamp string.
>
>--
>Ihor Radchenko // yantar92,
>Org mode contributor,
>Learn more about Org mode at <https://orgmode.org/>.
>Support Org development at <https://liberapay.com/org-mode>,
>or support my work at <https://liberapay.com/yantar92>
[-- Attachment #2: Type: text/html, Size: 1152 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] org-element-timestamp-interpreter: Return daterange anyway, if DATERANGE is non-nil
2023-02-20 16:36 ` Ilya Chernyshov
@ 2023-02-22 11:21 ` Ihor Radchenko
0 siblings, 0 replies; 5+ messages in thread
From: Ihor Radchenko @ 2023-02-22 11:21 UTC (permalink / raw)
To: Ilya Chernyshov; +Cc: emacs-orgmode
Ilya Chernyshov <ichernyshovvv@gmail.com> writes:
> You suggest to split timestamp types active/inactive-range to active/inactive-timerange, active/inactive-daterange?
I suggest introducing a new timestamp property :range-type. It can be
nil, timerange, or daterange.
Changing :type values will not be backwards-compatible.
--
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-02-22 11:21 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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).