From c1e3aaece33f8d603ece5709d5191fe780dd26cc Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Fri, 28 Sep 2012 14:50:21 +0200 Subject: [PATCH] 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. --- lisp/org-element.el | 355 ++++++++++++++++++++++++++++----------- testing/lisp/test-org-element.el | 171 ++++++++++++------- 2 files changed, 374 insertions(+), 152 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index c60d97997..44449d550 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -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))) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 18f78b007..768f3d33e 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -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." -- 2.11.4.GIT