mirror of
https://git.savannah.gnu.org/git/emacs/org-mode.git
synced 2025-01-15 17:00:45 +00:00
org-element: Improve timestamps parsing
* lisp/org-element.el (org-element-timestamp-parser): Modify timestamp objects properties. (org-element-headline-parser, org-element-inlinetask-parser): Remove `:timestamp' and `:clock' property. Add `:clockedp' property. Also, set `:closed', `:deadline' and `:scheduled' values to timestamp objects, not strings. Small refactoring. (org-element-clock-parser): Rename `:time' property into `:duration'. Also, set `:value' value as a timestamp object, not a string. (org-element-planning-parser): Set `:closed', `:deadline' and `:scheduled' values to timestamp objects, not strings. (org-element-clock-interpreter, org-element-planning-interpreter) (org-element-timestamp-interpreter): Update interpreters. (org-element--current-element): Tiny refactoring. * testing/lisp/test-org-element.el: Add tests.
This commit is contained in:
parent
2f2a80fe06
commit
c1e3aaece3
@ -116,6 +116,8 @@
|
||||
(eval-when-compile (require 'cl))
|
||||
(require 'org)
|
||||
|
||||
(declare-function org-clocking-buffer "org-clock" ())
|
||||
|
||||
|
||||
|
||||
;;; Definitions And Rules
|
||||
@ -711,9 +713,8 @@ Return a list whose CAR is `headline' and CDR is a plist
|
||||
containing `:raw-value', `:title', `:begin', `:end',
|
||||
`:pre-blank', `:hiddenp', `:contents-begin' and `:contents-end',
|
||||
`:level', `:priority', `:tags', `:todo-keyword',`:todo-type',
|
||||
`:scheduled', `:deadline', `:timestamp', `:clock', `:category',
|
||||
`:quotedp', `:archivedp', `:commentedp' and `:footnote-section-p'
|
||||
keywords.
|
||||
`:scheduled', `:deadline', `:closed', `:clockedp', `:quotedp',
|
||||
`:archivedp', `:commentedp' and `:footnote-section-p' keywords.
|
||||
|
||||
The plist also contains any property set in the property drawer,
|
||||
with its name in lowercase, the underscores replaced with hyphens
|
||||
@ -745,23 +746,36 @@ Assume point is at beginning of the headline."
|
||||
(string= org-footnote-section raw-value)))
|
||||
;; Normalize property names: ":SOME_PROP:" becomes
|
||||
;; ":some-prop".
|
||||
(standard-props (let (plist)
|
||||
(mapc
|
||||
(lambda (p)
|
||||
(let ((p-name (downcase (car p))))
|
||||
(while (string-match "_" p-name)
|
||||
(setq p-name
|
||||
(replace-match "-" nil nil p-name)))
|
||||
(setq p-name (intern (concat ":" p-name)))
|
||||
(setq plist
|
||||
(plist-put plist p-name (cdr p)))))
|
||||
(org-entry-properties nil 'standard))
|
||||
plist))
|
||||
(time-props (org-entry-properties nil 'special "CLOCK"))
|
||||
(scheduled (cdr (assoc "SCHEDULED" time-props)))
|
||||
(deadline (cdr (assoc "DEADLINE" time-props)))
|
||||
(clock (cdr (assoc "CLOCK" time-props)))
|
||||
(timestamp (cdr (assoc "TIMESTAMP" time-props)))
|
||||
(standard-props
|
||||
(let (plist)
|
||||
(mapc
|
||||
(lambda (p)
|
||||
(setq plist
|
||||
(plist-put plist
|
||||
(intern (concat ":"
|
||||
(replace-regexp-in-string
|
||||
"_" "-" (downcase (car p)))))
|
||||
(cdr p))))
|
||||
(org-entry-properties nil 'standard))
|
||||
plist))
|
||||
(time-props
|
||||
;; Read time properties on the line below the headline.
|
||||
(save-excursion
|
||||
(when (progn (forward-line)
|
||||
(looking-at org-planning-or-clock-line-re))
|
||||
(let ((end (line-end-position)) plist)
|
||||
(while (re-search-forward
|
||||
org-keyword-time-not-clock-regexp end t)
|
||||
(goto-char (match-end 1))
|
||||
(skip-chars-forward " \t")
|
||||
(let ((keyword (match-string 1))
|
||||
(time (org-element-timestamp-parser)))
|
||||
(cond ((equal keyword org-scheduled-string)
|
||||
(setq plist (plist-put plist :scheduled time)))
|
||||
((equal keyword org-deadline-string)
|
||||
(setq plist (plist-put plist :deadline time)))
|
||||
(t (setq plist (plist-put plist :closed time))))))
|
||||
plist))))
|
||||
(begin (point))
|
||||
(end (save-excursion (goto-char (org-end-of-subtree t t))))
|
||||
(pos-after-head (progn (forward-line) (point)))
|
||||
@ -773,7 +787,13 @@ Assume point is at beginning of the headline."
|
||||
(progn (goto-char end)
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(forward-line)
|
||||
(point)))))
|
||||
(point))))
|
||||
(clockedp (and (eq (org-clocking-buffer)
|
||||
(or (buffer-base-buffer) (current-buffer)))
|
||||
(save-excursion
|
||||
(goto-char (marker-position org-clock-marker))
|
||||
(org-back-to-heading t)
|
||||
(= (point) begin)))))
|
||||
;; Clean RAW-VALUE from any quote or comment string.
|
||||
(when (or quotedp commentedp)
|
||||
(let ((case-fold-search nil))
|
||||
@ -803,10 +823,6 @@ Assume point is at beginning of the headline."
|
||||
:tags tags
|
||||
:todo-keyword todo
|
||||
:todo-type todo-type
|
||||
:scheduled scheduled
|
||||
:deadline deadline
|
||||
:timestamp timestamp
|
||||
:clock clock
|
||||
:post-blank (count-lines
|
||||
(if (not contents-end) pos-after-head
|
||||
(goto-char contents-end)
|
||||
@ -815,8 +831,10 @@ Assume point is at beginning of the headline."
|
||||
end)
|
||||
:footnote-section-p footnote-section-p
|
||||
:archivedp archivedp
|
||||
:clockedp clockedp
|
||||
:commentedp commentedp
|
||||
:quotedp quotedp)
|
||||
time-props
|
||||
standard-props))))
|
||||
(org-element-put-property
|
||||
headline :title
|
||||
@ -880,7 +898,7 @@ Return a list whose CAR is `inlinetask' and CDR is a plist
|
||||
containing `:title', `:begin', `:end', `:hiddenp',
|
||||
`:contents-begin' and `:contents-end', `:level', `:priority',
|
||||
`:raw-value', `:tags', `:todo-keyword', `:todo-type',
|
||||
`:scheduled', `:deadline', `:timestamp', `:clock' and
|
||||
`:scheduled', `:deadline', `:clockedp', `:closed' and
|
||||
`:post-blank' keywords.
|
||||
|
||||
The plist also contains any property set in the property drawer,
|
||||
@ -904,27 +922,45 @@ Assume point is at beginning of the inline task."
|
||||
(raw-value (or (nth 4 components) ""))
|
||||
;; Normalize property names: ":SOME_PROP:" becomes
|
||||
;; ":some-prop".
|
||||
(standard-props (let (plist)
|
||||
(mapc
|
||||
(lambda (p)
|
||||
(let ((p-name (downcase (car p))))
|
||||
(while (string-match "_" p-name)
|
||||
(setq p-name
|
||||
(replace-match "-" nil nil p-name)))
|
||||
(setq p-name (intern (concat ":" p-name)))
|
||||
(setq plist
|
||||
(plist-put plist p-name (cdr p)))))
|
||||
(org-entry-properties nil 'standard))
|
||||
plist))
|
||||
(time-props (org-entry-properties nil 'special "CLOCK"))
|
||||
(scheduled (cdr (assoc "SCHEDULED" time-props)))
|
||||
(deadline (cdr (assoc "DEADLINE" time-props)))
|
||||
(clock (cdr (assoc "CLOCK" time-props)))
|
||||
(timestamp (cdr (assoc "TIMESTAMP" time-props)))
|
||||
(standard-props
|
||||
(let (plist)
|
||||
(mapc
|
||||
(lambda (p)
|
||||
(setq plist
|
||||
(plist-put plist
|
||||
(intern (concat ":"
|
||||
(replace-regexp-in-string
|
||||
"_" "-" (downcase (car p)))))
|
||||
(cdr p))))
|
||||
(org-entry-properties nil 'standard))
|
||||
plist))
|
||||
(time-props
|
||||
;; Read time properties on the line below the inlinetask
|
||||
;; opening string.
|
||||
(save-excursion
|
||||
(when (progn (forward-line)
|
||||
(looking-at org-planning-or-clock-line-re))
|
||||
(let ((end (line-end-position)) plist)
|
||||
(while (re-search-forward
|
||||
org-keyword-time-not-clock-regexp end t)
|
||||
(goto-char (match-end 1))
|
||||
(skip-chars-forward " \t")
|
||||
(let ((keyword (match-string 1))
|
||||
(time (org-element-timestamp-parser)))
|
||||
(cond ((equal keyword org-scheduled-string)
|
||||
(setq plist (plist-put plist :scheduled time)))
|
||||
((equal keyword org-deadline-string)
|
||||
(setq plist (plist-put plist :deadline time)))
|
||||
(t (setq plist (plist-put plist :closed time))))))
|
||||
plist))))
|
||||
(task-end (save-excursion
|
||||
(end-of-line)
|
||||
(and (re-search-forward "^\\*+ END" limit t)
|
||||
(match-beginning 0))))
|
||||
(clockedp (and (eq (org-clocking-buffer)
|
||||
(or (buffer-base-buffer) (current-buffer)))
|
||||
(let ((clock (marker-position org-clock-marker)))
|
||||
(and (> clock begin) (< clock task-end)))))
|
||||
(contents-begin (progn (forward-line)
|
||||
(and task-end (< (point) task-end) (point))))
|
||||
(hidden (and contents-begin (org-invisible-p2)))
|
||||
@ -950,11 +986,9 @@ Assume point is at beginning of the inline task."
|
||||
:tags tags
|
||||
:todo-keyword todo
|
||||
:todo-type todo-type
|
||||
:scheduled scheduled
|
||||
:deadline deadline
|
||||
:timestamp timestamp
|
||||
:clock clock
|
||||
:clockedp clockedp
|
||||
:post-blank (count-lines before-blank end))
|
||||
time-props
|
||||
standard-props
|
||||
(cadr keywords)))))
|
||||
(org-element-put-property
|
||||
@ -1427,13 +1461,13 @@ as keywords."
|
||||
(let* ((case-fold-search nil)
|
||||
(begin (point))
|
||||
(value (progn (search-forward org-clock-string (line-end-position) t)
|
||||
(org-skip-whitespace)
|
||||
(looking-at "\\[.*\\]")
|
||||
(org-match-string-no-properties 0)))
|
||||
(time (and (progn (goto-char (match-end 0))
|
||||
(looking-at " +=> +\\(\\S-+\\)[ \t]*$"))
|
||||
(org-match-string-no-properties 1)))
|
||||
(status (if time 'closed 'running))
|
||||
(skip-chars-forward " \t")
|
||||
(org-element-timestamp-parser)))
|
||||
(duration (and (search-forward " => " (line-end-position) t)
|
||||
(progn (skip-chars-forward " \t")
|
||||
(looking-at "\\(\\S-+\\)[ \t]*$"))
|
||||
(org-match-string-no-properties 1)))
|
||||
(status (if duration 'closed 'running))
|
||||
(post-blank (let ((before-blank (progn (forward-line) (point))))
|
||||
(skip-chars-forward " \r\t\n" limit)
|
||||
(skip-chars-backward " \t")
|
||||
@ -1443,7 +1477,7 @@ as keywords."
|
||||
(list 'clock
|
||||
(list :status status
|
||||
:value value
|
||||
:time time
|
||||
:duration duration
|
||||
:begin begin
|
||||
:end end
|
||||
:post-blank post-blank)))))
|
||||
@ -1452,13 +1486,14 @@ as keywords."
|
||||
"Interpret CLOCK element as Org syntax.
|
||||
CONTENTS is nil."
|
||||
(concat org-clock-string " "
|
||||
(org-element-property :value clock)
|
||||
(let ((time (org-element-property :time clock)))
|
||||
(and time
|
||||
(org-element-timestamp-interpreter
|
||||
(org-element-property :value clock) nil)
|
||||
(let ((duration (org-element-property :duration clock)))
|
||||
(and duration
|
||||
(concat " => "
|
||||
(apply 'format
|
||||
"%2s:%02s"
|
||||
(org-split-string time ":")))))))
|
||||
(org-split-string duration ":")))))))
|
||||
|
||||
|
||||
;;;; Comment
|
||||
@ -2049,13 +2084,11 @@ and `:post-blank' keywords."
|
||||
(end (point))
|
||||
closed deadline scheduled)
|
||||
(goto-char begin)
|
||||
(while (re-search-forward org-keyword-time-not-clock-regexp
|
||||
(line-end-position) t)
|
||||
(while (re-search-forward org-keyword-time-not-clock-regexp end t)
|
||||
(goto-char (match-end 1))
|
||||
(org-skip-whitespace)
|
||||
(let ((time (buffer-substring-no-properties
|
||||
(1+ (point)) (1- (match-end 0))))
|
||||
(keyword (match-string 1)))
|
||||
(skip-chars-forward " \t" end)
|
||||
(let ((keyword (match-string 1))
|
||||
(time (org-element-timestamp-parser)))
|
||||
(cond ((equal keyword org-closed-string) (setq closed time))
|
||||
((equal keyword org-deadline-string) (setq deadline time))
|
||||
(t (setq scheduled time)))))
|
||||
@ -2073,13 +2106,18 @@ CONTENTS is nil."
|
||||
(mapconcat
|
||||
'identity
|
||||
(delq nil
|
||||
(list (let ((closed (org-element-property :closed planning)))
|
||||
(when closed (concat org-closed-string " [" closed "]")))
|
||||
(let ((deadline (org-element-property :deadline planning)))
|
||||
(when deadline (concat org-deadline-string " <" deadline ">")))
|
||||
(list (let ((deadline (org-element-property :deadline planning)))
|
||||
(when deadline
|
||||
(concat org-deadline-string " "
|
||||
(org-element-timestamp-interpreter deadline nil))))
|
||||
(let ((scheduled (org-element-property :scheduled planning)))
|
||||
(when scheduled
|
||||
(concat org-scheduled-string " <" scheduled ">")))))
|
||||
(concat org-scheduled-string " "
|
||||
(org-element-timestamp-interpreter scheduled nil))))
|
||||
(let ((closed (org-element-property :closed planning)))
|
||||
(when closed
|
||||
(concat org-closed-string " "
|
||||
(org-element-timestamp-interpreter closed nil))))))
|
||||
" "))
|
||||
|
||||
|
||||
@ -3358,39 +3396,168 @@ Assume point is at the beginning of the timestamp."
|
||||
(save-excursion
|
||||
(let* ((begin (point))
|
||||
(activep (eq (char-after) ?<))
|
||||
(main-value
|
||||
(raw-value
|
||||
(progn
|
||||
(looking-at "[<[]\\(\\(%%\\)?.*?\\)[]>]\\(?:--[<[]\\(.*?\\)[]>]\\)?")
|
||||
(match-string-no-properties 1)))
|
||||
(range-end (match-string-no-properties 3))
|
||||
(type (cond ((match-string 2) 'diary)
|
||||
((and activep range-end) 'active-range)
|
||||
(looking-at "\\([<[]\\(%%\\)?.*?\\)[]>]\\(?:--\\([<[].*?[]>]\\)\\)?")
|
||||
(match-string-no-properties 0)))
|
||||
(date-start (match-string-no-properties 1))
|
||||
(date-end (match-string 3))
|
||||
(diaryp (match-beginning 2))
|
||||
(type (cond (diaryp 'diary)
|
||||
((and activep date-end) 'active-range)
|
||||
(activep 'active)
|
||||
(range-end 'inactive-range)
|
||||
(date-end 'inactive-range)
|
||||
(t 'inactive)))
|
||||
(post-blank (progn (goto-char (match-end 0))
|
||||
(skip-chars-forward " \t")))
|
||||
(end (point)))
|
||||
(end (point))
|
||||
(with-time-p (string-match "[012]?[0-9]:[0-5][0-9]" date-start))
|
||||
(repeater-props
|
||||
(and (not diaryp)
|
||||
(string-match "\\([.+]?\\+\\)\\([0-9]+\\)\\([hdwmy]\\)>"
|
||||
raw-value)
|
||||
(list
|
||||
:repeater-type
|
||||
(let ((type (match-string 1 raw-value)))
|
||||
(cond ((equal "++" type) 'catch-up)
|
||||
((equal ".+" type) 'restart)
|
||||
(t 'cumulate)))
|
||||
:repeater-value (string-to-number (match-string 2 raw-value))
|
||||
:repeater-unit
|
||||
(case (string-to-char (match-string 3 raw-value))
|
||||
(?h 'hour) (?d 'day) (?w 'week) (?m 'month) (t 'year)))))
|
||||
time-range year-start month-start day-start hour-start minute-start
|
||||
year-end month-end day-end hour-end minute-end)
|
||||
;; Extract time range, if any, and remove it from date start.
|
||||
(setq time-range
|
||||
(and (not diaryp)
|
||||
(string-match
|
||||
"[012]?[0-9]:[0-5][0-9]\\(-\\([012]?[0-9]\\):\\([0-5][0-9]\\)\\)"
|
||||
date-start)
|
||||
(cons (string-to-number (match-string 2 date-start))
|
||||
(string-to-number (match-string 3 date-start)))))
|
||||
(when time-range
|
||||
(setq date-start (replace-match "" nil nil date-start 1)))
|
||||
;; Parse date-start.
|
||||
(unless diaryp
|
||||
(let ((date (org-parse-time-string date-start)))
|
||||
(setq year-start (nth 5 date)
|
||||
month-start (nth 4 date)
|
||||
day-start (nth 3 date)
|
||||
hour-start (and with-time-p (nth 2 date))
|
||||
minute-start (and with-time-p (nth 1 date)))))
|
||||
;; Compute date-end. It can be provided directly in time-stamp,
|
||||
;; or extracted from time range. Otherwise, it defaults to the
|
||||
;; same values as date-start.
|
||||
(unless diaryp
|
||||
(let ((date (and date-end (org-parse-time-string date-end))))
|
||||
(setq year-end (or (nth 5 date) year-start)
|
||||
month-end (or (nth 4 date) month-start)
|
||||
day-end (or (nth 3 date) day-start)
|
||||
hour-end (or (nth 2 date) (car time-range) hour-start)
|
||||
minute-end (or (nth 1 date) (cdr time-range) minute-start))))
|
||||
(list 'timestamp
|
||||
(list :type type
|
||||
:value main-value
|
||||
:range-end range-end
|
||||
:begin begin
|
||||
:end end
|
||||
:post-blank post-blank)))))
|
||||
(nconc (list :type type
|
||||
:raw-value raw-value
|
||||
:year-start year-start
|
||||
:month-start month-start
|
||||
:day-start day-start
|
||||
:hour-start hour-start
|
||||
:minute-start minute-start
|
||||
:year-end year-end
|
||||
:month-end month-end
|
||||
:day-end day-end
|
||||
:hour-end hour-end
|
||||
:minute-end minute-end
|
||||
:begin begin
|
||||
:end end
|
||||
:post-blank post-blank)
|
||||
repeater-props)))))
|
||||
|
||||
(defun org-element-timestamp-interpreter (timestamp contents)
|
||||
"Interpret TIMESTAMP object as Org syntax.
|
||||
CONTENTS is nil."
|
||||
(let ((type (org-element-property :type timestamp) ))
|
||||
(concat
|
||||
(format (if (memq type '(inactive inactive-range)) "[%s]" "<%s>")
|
||||
(org-element-property :value timestamp))
|
||||
(let ((range-end (org-element-property :range-end timestamp)))
|
||||
(when range-end
|
||||
(concat "--"
|
||||
(format (if (eq type 'inactive-range) "[%s]" "<%s>")
|
||||
range-end)))))))
|
||||
;; Use `:raw-value' if specified.
|
||||
(or (org-element-property :raw-value timestamp)
|
||||
;; Otherwise, build timestamp string.
|
||||
(let ((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 repeat-string)
|
||||
(let ((ts (format-time-string
|
||||
(funcall (if with-time-p 'cdr 'car)
|
||||
org-time-stamp-formats)
|
||||
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))))
|
||||
(when (org-string-nw-p repeat-string)
|
||||
(setq ts (concat (substring ts 0 -1)
|
||||
" "
|
||||
repeat-string
|
||||
(substring ts -1))))
|
||||
;; Return value.
|
||||
ts)))
|
||||
(type (org-element-property :type timestamp)))
|
||||
(case type
|
||||
((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
|
||||
(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)
|
||||
(concat (case (org-element-property :repeater-type timestamp)
|
||||
(cumulate "+") (catch-up "++") (restart ".+"))
|
||||
(org-element-property :repeater-value timestamp)
|
||||
(org-element-property :repeater-unit timestamp)))))
|
||||
((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 (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
|
||||
(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)))))))))
|
||||
|
||||
(defun org-element-timestamp-successor (limit)
|
||||
"Search for the next timestamp object.
|
||||
@ -3539,7 +3706,7 @@ element it has to parse."
|
||||
;; a footnote definition: next item is always a paragraph.
|
||||
((not (bolp)) (org-element-paragraph-parser limit (list (point))))
|
||||
;; Planning and Clock.
|
||||
((and (looking-at org-planning-or-clock-line-re))
|
||||
((looking-at org-planning-or-clock-line-re)
|
||||
(if (equal (match-string 1) org-clock-string)
|
||||
(org-element-clock-parser limit)
|
||||
(org-element-planning-parser limit)))
|
||||
|
@ -278,22 +278,24 @@ Some other text
|
||||
;; Running clock.
|
||||
(let* ((org-clock-string "CLOCK:")
|
||||
(clock (org-test-with-temp-text "CLOCK: [2012-01-01 sun. 00:01]"
|
||||
(org-element-map
|
||||
(org-element-parse-buffer) 'clock 'identity nil t))))
|
||||
(org-element-at-point))))
|
||||
(should (eq (org-element-property :status clock) 'running))
|
||||
(should (equal (org-element-property :value clock)
|
||||
"[2012-01-01 sun. 00:01]"))
|
||||
(should-not (org-element-property :time clock)))
|
||||
(should
|
||||
(equal (org-element-property :raw-value
|
||||
(org-element-property :value clock))
|
||||
"[2012-01-01 sun. 00:01]"))
|
||||
(should-not (org-element-property :duration clock)))
|
||||
;; Closed clock.
|
||||
(let* ((org-clock-string "CLOCK:")
|
||||
(clock (org-test-with-temp-text "
|
||||
CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01"
|
||||
(org-element-map
|
||||
(org-element-parse-buffer) 'clock 'identity nil t))))
|
||||
(clock
|
||||
(org-test-with-temp-text
|
||||
"CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01"
|
||||
(org-element-at-point))))
|
||||
(should (eq (org-element-property :status clock) 'closed))
|
||||
(should (equal (org-element-property :value clock)
|
||||
(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 :time clock) "0:01"))))
|
||||
(should (equal (org-element-property :duration clock) "0:01"))))
|
||||
|
||||
|
||||
;;;; Code
|
||||
@ -1382,26 +1384,29 @@ Outside list"
|
||||
(ert-deftest test-org-element/planning-parser ()
|
||||
"Test `planning' parser."
|
||||
(should
|
||||
(equal
|
||||
(org-element-property
|
||||
:closed
|
||||
(org-test-with-temp-text "CLOSED: [2012-03-29 thu.]"
|
||||
(org-element-map (org-element-parse-buffer) 'planning 'identity nil t)))
|
||||
"2012-03-29 thu."))
|
||||
(equal "[2012-03-29 thu.]"
|
||||
(org-element-property
|
||||
:raw-value
|
||||
(org-element-property
|
||||
:closed
|
||||
(org-test-with-temp-text "CLOSED: [2012-03-29 thu.]"
|
||||
(org-element-at-point))))))
|
||||
(should
|
||||
(equal
|
||||
(org-element-property
|
||||
:deadline
|
||||
(org-test-with-temp-text "DEADLINE: <2012-03-29 thu.>"
|
||||
(org-element-map (org-element-parse-buffer) 'planning 'identity nil t)))
|
||||
"2012-03-29 thu."))
|
||||
(equal "<2012-03-29 thu.>"
|
||||
(org-element-property
|
||||
:raw-value
|
||||
(org-element-property
|
||||
:deadline
|
||||
(org-test-with-temp-text "DEADLINE: <2012-03-29 thu.>"
|
||||
(org-element-at-point))))))
|
||||
(should
|
||||
(equal
|
||||
(org-element-property
|
||||
:scheduled
|
||||
(org-test-with-temp-text "SCHEDULED: <2012-03-29 thu.>"
|
||||
(org-element-map (org-element-parse-buffer) 'planning 'identity nil t)))
|
||||
"2012-03-29 thu.")))
|
||||
(equal "<2012-03-29 thu.>"
|
||||
(org-element-property
|
||||
:raw-value
|
||||
(org-element-property
|
||||
:scheduled
|
||||
(org-test-with-temp-text "SCHEDULED: <2012-03-29 thu.>"
|
||||
(org-element-at-point)))))))
|
||||
|
||||
|
||||
;;;; Property Drawer
|
||||
@ -1707,27 +1712,41 @@ Outside list"
|
||||
;; Active timestamp.
|
||||
(should
|
||||
(org-test-with-temp-text "<2012-03-29 16:40>"
|
||||
(eq (org-element-property :type
|
||||
(org-element-map
|
||||
(org-element-parse-buffer)
|
||||
'timestamp 'identity nil t))
|
||||
'active)))
|
||||
(eq (org-element-property :type (org-element-context)) 'active)))
|
||||
(should
|
||||
(equal '(2012 3 29 16 40)
|
||||
(org-test-with-temp-text "<2012-03-29 16:40>"
|
||||
(let ((object (org-element-context)))
|
||||
(list (org-element-property :year-start object)
|
||||
(org-element-property :month-start object)
|
||||
(org-element-property :day-start object)
|
||||
(org-element-property :hour-start object)
|
||||
(org-element-property :minute-start object))))))
|
||||
;; Inactive timestamp.
|
||||
(should
|
||||
(org-test-with-temp-text "[2012-03-29 16:40]"
|
||||
(eq (org-element-property :type
|
||||
(org-element-map
|
||||
(org-element-parse-buffer)
|
||||
'timestamp 'identity nil t))
|
||||
'inactive)))
|
||||
(eq (org-element-property :type (org-element-context)) 'inactive)))
|
||||
;; Time range.
|
||||
(should
|
||||
(equal '(2012 3 29 16 40 7 30)
|
||||
(org-test-with-temp-text "<2012-03-29 7:30-16:40>"
|
||||
(let ((object (org-element-context)))
|
||||
(list (org-element-property :year-end object)
|
||||
(org-element-property :month-end object)
|
||||
(org-element-property :day-end object)
|
||||
(org-element-property :hour-end object)
|
||||
(org-element-property :minute-end object)
|
||||
(org-element-property :hour-start object)
|
||||
(org-element-property :minute-start object))))))
|
||||
;; Date range.
|
||||
(should
|
||||
(org-test-with-temp-text "[2012-03-29 16:40]--[2012-03-29 16:41]"
|
||||
(eq (org-element-property :type
|
||||
(org-element-map
|
||||
(org-element-parse-buffer)
|
||||
'timestamp 'identity nil t))
|
||||
'inactive-range)))
|
||||
(eq (org-element-property :type (org-element-context)) 'inactive-range)))
|
||||
;; With repeater.
|
||||
(should
|
||||
(eq 'catch-up
|
||||
(org-test-with-temp-text "<2012-03-29 ++1y>"
|
||||
(org-element-property :repeater-type (org-element-context)))))
|
||||
;; Timestamps are not planning elements.
|
||||
(should-not
|
||||
(org-test-with-temp-text "SCHEDULED: <2012-03-29 16:40>"
|
||||
@ -2102,9 +2121,9 @@ CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01"))
|
||||
(equal
|
||||
(org-test-parse-and-interpret
|
||||
"* Headline
|
||||
CLOSED: [2012-01-01] DEADLINE: <2012-01-01> SCHEDULED: <2012-01-01>")
|
||||
DEADLINE: <2012-01-01> SCHEDULED: <2012-01-01> CLOSED: [2012-01-01]")
|
||||
"* Headline
|
||||
CLOSED: [2012-01-01] DEADLINE: <2012-01-01> SCHEDULED: <2012-01-01>\n"))))
|
||||
DEADLINE: <2012-01-01> SCHEDULED: <2012-01-01> CLOSED: [2012-01-01]\n"))))
|
||||
|
||||
(ert-deftest test-org-element/property-drawer-interpreter ()
|
||||
"Test property drawer interpreter."
|
||||
@ -2159,25 +2178,61 @@ CLOSED: [2012-01-01] DEADLINE: <2012-01-01> SCHEDULED: <2012-01-01>\n"))))
|
||||
(ert-deftest test-org-element/timestamp-interpreter ()
|
||||
"Test timestamp interpreter."
|
||||
;; Active.
|
||||
(should (equal (org-test-parse-and-interpret "<2012-03-29 16:40>")
|
||||
"<2012-03-29 16:40>\n"))
|
||||
(should (equal (org-test-parse-and-interpret "<2012-03-29 thu. 16:40>")
|
||||
"<2012-03-29 thu. 16:40>\n"))
|
||||
(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)) nil)))
|
||||
;; Inactive.
|
||||
(should (equal (org-test-parse-and-interpret "[2012-03-29 16:40]")
|
||||
"[2012-03-29 16:40]\n"))
|
||||
(should (equal (org-test-parse-and-interpret "[2012-03-29 thu. 16:40]")
|
||||
"[2012-03-29 thu. 16:40]\n"))
|
||||
(should
|
||||
(string-match
|
||||
"\\[2012-03-29 .* 16:40\\]"
|
||||
(org-element-timestamp-interpreter
|
||||
'(timestamp
|
||||
(:type inactive :year-start 2012 :month-start 3 :day-start 29
|
||||
:hour-start 16 :minute-start 40)) nil)))
|
||||
;; Active range.
|
||||
(should (equal (org-test-parse-and-interpret
|
||||
"<2012-03-29 16:40>--<2012-03-29 16:41>")
|
||||
"<2012-03-29 16:40>--<2012-03-29 16:41>\n"))
|
||||
"<2012-03-29 thu. 16:40>--<2012-03-29 thu. 16:41>")
|
||||
"<2012-03-29 thu. 16:40>--<2012-03-29 thu. 16:41>\n"))
|
||||
(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)) nil)))
|
||||
;; Inactive range.
|
||||
(should (equal (org-test-parse-and-interpret
|
||||
"[2012-03-29 16:40]--[2012-03-29 16:41]")
|
||||
"[2012-03-29 16:40]--[2012-03-29 16:41]\n"))
|
||||
"[2012-03-29 thu. 16:40]--[2012-03-29 thu. 16:41]")
|
||||
"[2012-03-29 thu. 16:40]--[2012-03-29 thu. 16:41]\n"))
|
||||
(should
|
||||
(string-match
|
||||
"\\[2012-03-29 .* 16:40\\]--\\[2012-03-29 .* 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 "<%%org-float t 4 2>")
|
||||
"<%%org-float t 4 2>\n"))
|
||||
(should (equal (org-test-parse-and-interpret "<%%(org-float t 4 2)>")
|
||||
"<%%(org-float t 4 2)>\n"))
|
||||
;; Timestamp with repeater interval.
|
||||
(should (equal (org-test-parse-and-interpret "<2012-03-29 +1y>")
|
||||
"<2012-03-29 +1y>\n")))
|
||||
(should (equal (org-test-parse-and-interpret "<2012-03-29 thu. +1y>")
|
||||
"<2012-03-29 thu. +1y>\n"))
|
||||
(should
|
||||
(string-match
|
||||
"<2012-03-29 .* \\+1y>"
|
||||
(org-element-timestamp-interpreter
|
||||
'(timestamp
|
||||
(:type active :year-start 2012 :month-start 3 :day-start 29
|
||||
:repeater-type cumulate :repeater-value "1y")) nil))))
|
||||
|
||||
(ert-deftest test-org-element/verse-block-interpreter ()
|
||||
"Test verse block interpretation."
|
||||
|
Loading…
Reference in New Issue
Block a user