org-duration: Read and write duration in compact form
* lisp/org-duration.el (org-duration-format): Add `compact' symbol. (org-duration-set-regexps): Make white space between duration parts optional (org-duration-from-minutes): Handle `compact' symbol. * testing/lisp/test-org-duration.el (test-org-duration/from-minutes): (test-org-duration/p): Add tests.
This commit is contained in:
parent
2fbbc23368
commit
2fde90aa2e
|
@ -42,6 +42,12 @@ possible via column view value edit or with =<C-c C-q>=.
|
|||
See [[*~org-columns-toggle-or-columns-quit~]]
|
||||
|
||||
** Miscellaneous
|
||||
*** Duration can be read and written in compact form
|
||||
|
||||
~org-duration-to-minutes~ understands =1d3h5min= as a duration,
|
||||
whereas ~org-duration-from-minutes~ can output this compact form if
|
||||
the duration format contains the symbol ~compact~.
|
||||
|
||||
*** Fontify whole TODO headlines
|
||||
|
||||
This feature is the same as ~org-fontify-done-headline~, but for TODO
|
||||
|
|
|
@ -28,14 +28,16 @@
|
|||
;; - 3:12
|
||||
;; - 1:23:45
|
||||
;; - 1y 3d 3h 4min
|
||||
;; - 1d3h5min
|
||||
;; - 3d 13:35
|
||||
;; - 2.35h
|
||||
;;
|
||||
;; More accurately, it consists of numbers and units, as defined in
|
||||
;; variable `org-duration-units', separated with white spaces, and
|
||||
;; a "H:MM" or "H:MM:SS" part. White spaces are tolerated between the
|
||||
;; number and its relative unit. Variable `org-duration-format'
|
||||
;; controls durations default representation.
|
||||
;; variable `org-duration-units', possibly separated with white
|
||||
;; spaces, and an optional "H:MM" or "H:MM:SS" part, which always
|
||||
;; comes last. White spaces are tolerated between the number and its
|
||||
;; relative unit. Variable `org-duration-format' controls durations
|
||||
;; default representation.
|
||||
;;
|
||||
;; The library provides functions allowing to convert a duration to,
|
||||
;; and from, a number of minutes: `org-duration-to-minutes' and
|
||||
|
@ -122,8 +124,7 @@ are specified here.
|
|||
Units with a zero value are skipped, unless REQUIRED? is non-nil.
|
||||
In that case, the unit is always used.
|
||||
|
||||
Eventually, the list can contain one of the following special
|
||||
entries:
|
||||
The list can also contain one of the following special entries:
|
||||
|
||||
(special . h:mm)
|
||||
(special . h:mm:ss)
|
||||
|
@ -139,6 +140,10 @@ entries:
|
|||
first one required or with a non-zero integer part. If there
|
||||
is no such unit, the smallest one is used.
|
||||
|
||||
Eventually, if the list contains the symbol `compact', the
|
||||
duration is expressed in a compact form, without any white space
|
||||
between units.
|
||||
|
||||
For example,
|
||||
|
||||
((\"d\" . nil) (\"h\" . t) (\"min\" . t))
|
||||
|
@ -172,7 +177,6 @@ a 2-digits fractional part, of \"d\" unit. A duration shorter
|
|||
than a day uses \"h\" unit instead."
|
||||
:group 'org-time
|
||||
:group 'org-clock
|
||||
:version "26.1"
|
||||
:package-version '(Org . "9.1")
|
||||
:type '(choice
|
||||
(const :tag "Use H:MM" h:mm)
|
||||
|
@ -191,7 +195,8 @@ than a day uses \"h\" unit instead."
|
|||
(const h:mm))
|
||||
(cons :tag "Use both units and H:MM:SS"
|
||||
(const special)
|
||||
(const h:mm:ss))))))
|
||||
(const h:mm:ss))
|
||||
(const :tag "Use compact form" compact)))))
|
||||
|
||||
|
||||
;;; Internal variables and functions
|
||||
|
@ -249,13 +254,10 @@ When optional argument CANONICAL is non-nil, refer to
|
|||
org-duration-units))
|
||||
t)))
|
||||
(setq org-duration--full-re
|
||||
(format "\\`[ \t]*%s\\(?:[ \t]+%s\\)*[ \t]*\\'"
|
||||
org-duration--unit-re
|
||||
org-duration--unit-re))
|
||||
(format "\\`\\(?:[ \t]*%s\\)+[ \t]*\\'" org-duration--unit-re))
|
||||
(setq org-duration--mixed-re
|
||||
(format "\\`[ \t]*\\(?1:%s\\(?:[ \t]+%s\\)*\\)[ \t]+\
|
||||
(format "\\`\\(?1:\\([ \t]*%s\\)+\\)[ \t]*\
|
||||
\\(?2:[0-9]+\\(?::[0-9][0-9]\\)\\{1,2\\}\\)[ \t]*\\'"
|
||||
org-duration--unit-re
|
||||
org-duration--unit-re)))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -353,10 +355,11 @@ Raise an error if expected format is unknown."
|
|||
;; Represent minutes above hour using provided units and H:MM
|
||||
;; or H:MM:SS below.
|
||||
(let* ((units-part (* min-modifier (/ (floor minutes) min-modifier)))
|
||||
(minutes-part (- minutes units-part)))
|
||||
(minutes-part (- minutes units-part))
|
||||
(compact (memq 'compact duration-format)))
|
||||
(concat
|
||||
(org-duration-from-minutes units-part truncated-format canonical)
|
||||
" "
|
||||
(and (not compact) " ")
|
||||
(org-duration-from-minutes minutes-part mode))))))
|
||||
;; Units format.
|
||||
(duration-format
|
||||
|
@ -368,12 +371,16 @@ Raise an error if expected format is unknown."
|
|||
(format "%%.%df" digits))))
|
||||
(selected-units
|
||||
(sort (cl-remove-if
|
||||
;; Ignore special format cells.
|
||||
(lambda (pair) (pcase pair (`(special . ,_) t) (_ nil)))
|
||||
;; Ignore special format cells and compact option.
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
((or `compact `(special . ,_)) t)
|
||||
(_ nil)))
|
||||
duration-format)
|
||||
(lambda (a b)
|
||||
(> (org-duration--modifier (car a) canonical)
|
||||
(org-duration--modifier (car b) canonical))))))
|
||||
(org-duration--modifier (car b) canonical)))))
|
||||
(separator (if (memq 'compact duration-format) "" " ")))
|
||||
(cond
|
||||
;; Fractional duration: use first unit that is either required
|
||||
;; or smaller than MINUTES.
|
||||
|
@ -402,8 +409,8 @@ Raise an error if expected format is unknown."
|
|||
(cond ((<= modifier minutes)
|
||||
(let ((value (floor minutes modifier)))
|
||||
(cl-decf minutes (* value modifier))
|
||||
(format " %d%s" value unit)))
|
||||
(required? (concat " 0" unit))
|
||||
(format "%s%d%s" separator value unit)))
|
||||
(required? (concat separator "0" unit))
|
||||
(t ""))))
|
||||
selected-units
|
||||
""))))
|
||||
|
|
|
@ -121,7 +121,15 @@
|
|||
(should (equal "0.5min"
|
||||
(let ((org-duration-format
|
||||
'(("h" . nil) ("min" . nil) (special . 1))))
|
||||
(org-duration-from-minutes 0.5)))))
|
||||
(org-duration-from-minutes 0.5))))
|
||||
;; Handle compact form.
|
||||
(should (equal "0h50min"
|
||||
(let ((org-duration-format '(("h" . t) ("min" . t) compact)))
|
||||
(org-duration-from-minutes 50))))
|
||||
(should (equal "1d0:10"
|
||||
(let ((org-duration-format
|
||||
'(("d" . nil) (special . h:mm) compact)))
|
||||
(org-duration-from-minutes (+ (* 24 60) 10))))))
|
||||
|
||||
(ert-deftest test-org-duration/p ()
|
||||
"Test `org-duration-p' specifications."
|
||||
|
@ -130,7 +138,9 @@
|
|||
(should (org-duration-p "123:12"))
|
||||
(should (org-duration-p "1:23:45"))
|
||||
(should (org-duration-p "3d 3h 4min"))
|
||||
(should (org-duration-p "3d3h4min"))
|
||||
(should (org-duration-p "3d 13:35"))
|
||||
(should (org-duration-p "3d13:35"))
|
||||
(should (org-duration-p "2.35h"))
|
||||
;; Handle custom units, but return nil for unknown units.
|
||||
(should-not (org-duration-p "1minute"))
|
||||
|
@ -146,7 +156,7 @@
|
|||
(should-not (org-duration-p "3::12"))
|
||||
(should-not (org-duration-p "3:2"))
|
||||
(should-not (org-duration-p "3:12:4"))
|
||||
;; Return nil in mixed mode if H:MM:SS part is not last.
|
||||
;; Return nil in mixed mode if H:MM:SS part is not the last one.
|
||||
(should-not (org-duration-p "3d 13:35 13h")))
|
||||
|
||||
(ert-deftest test-org-duration/h:mm-only-p ()
|
||||
|
|
Loading…
Reference in New Issue