lisp/org.el: Add org-property-separators option
* lisp/org.el (org-property-separators, org-property-get-separator): Created. (org-entry-get, org-entry-get-with-inheritance): Use new `org-property-get-separator' function. * testing/lisp/test-org.el (test-org/entry-get): Added tests for combining properties with custom separators `org-property-separators' is a customization option that allows for properties to be combined using a separator other than the default (a single space). It is an alist with the car of each element being a list of property names or regular expression and the cdr being the separator string, like '((("EXPORT_FILE_NAME") . "/")).
This commit is contained in:
parent
4f0f244477
commit
e268e47971
31
etc/ORG-NEWS
31
etc/ORG-NEWS
|
@ -141,6 +141,37 @@ discouraged when working with Org files.
|
|||
|
||||
** New features
|
||||
|
||||
*** New customization option =org-property-separators=
|
||||
A new alist variable to control how properties are combined.
|
||||
|
||||
If a property is specified multiple times with a =+=, like
|
||||
|
||||
#+begin_src org
|
||||
:PROPERTIES:
|
||||
:EXPORT_FILE_NAME: some/path
|
||||
:EXPORT_FILE_NAME+: to/file
|
||||
:END:
|
||||
#+end_src
|
||||
|
||||
the old behavior was to always combine them with a single space
|
||||
(=some/path to/file=). For the new variable, the car of each item in
|
||||
the alist should be either a list of property names or a regular
|
||||
expression, while the cdr should be the separator to use when
|
||||
combining that property.
|
||||
|
||||
The default value for the separator is a single space, if none of the
|
||||
provided items in the alist match a given property.
|
||||
|
||||
For example, in order to combine =EXPORT_FILE_NAME= properties with a
|
||||
forward slash =/=, one can use
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq org-property-separators '((("EXPORT_FILE_NAME") . "/")))
|
||||
#+end_src
|
||||
|
||||
The example above would then produce the property value
|
||||
=some/path/to/file=.
|
||||
|
||||
*** New library =org-persist.el= implements variable persistence across Emacs sessions
|
||||
|
||||
The library stores variable data in ~org-persist-directory~ (set to XDG
|
||||
|
|
47
lisp/org.el
47
lisp/org.el
|
@ -2850,6 +2850,34 @@ in this variable)."
|
|||
(member-ignore-case property org-use-property-inheritance))
|
||||
(t (error "Invalid setting of `org-use-property-inheritance'"))))
|
||||
|
||||
(defcustom org-property-separators nil
|
||||
"An alist to control how properties are combined.
|
||||
|
||||
The car of each item should be either a list of property names or
|
||||
a regular expression, while the cdr should be the separator to
|
||||
use when combining that property.
|
||||
|
||||
If an alist item cannot be found that matches a given property, a
|
||||
single space will be used as the separator."
|
||||
:group 'org-properties
|
||||
:type '(alist :key-type (choice (repeat :tag "Properties" string)
|
||||
(string :tag "Regular Expression"))
|
||||
:value-type (restricted-sexp :tag "Separator"
|
||||
:match-alternatives (stringp)
|
||||
:value " ")))
|
||||
|
||||
(defun org--property-get-separator (property)
|
||||
"Get the separator to use for combining PROPERTY."
|
||||
(or
|
||||
(catch 'separator
|
||||
(dolist (spec org-property-separators)
|
||||
(if (listp (car spec))
|
||||
(if (member property (car spec))
|
||||
(throw 'separator (cdr spec)))
|
||||
(if (string-match-p (car spec) property)
|
||||
(throw 'separator (cdr spec))))))
|
||||
" "))
|
||||
|
||||
(defcustom org-columns-default-format "%25ITEM %TODO %3PRIORITY %TAGS"
|
||||
"The default column format, if no other format has been defined.
|
||||
This variable can be set on the per-file basis by inserting a line
|
||||
|
@ -12358,7 +12386,9 @@ value higher up the hierarchy."
|
|||
(org-entry-get-with-inheritance property literal-nil))
|
||||
(t
|
||||
(let* ((local (org--property-local-values property literal-nil))
|
||||
(value (and local (mapconcat #'identity (delq nil local) " "))))
|
||||
(value (and local (mapconcat #'identity
|
||||
(delq nil local)
|
||||
(org--property-get-separator property)))))
|
||||
(if literal-nil value (org-not-nil value)))))))
|
||||
|
||||
(defun org-property-or-variable-value (var &optional inherit)
|
||||
|
@ -12467,7 +12497,8 @@ However, if LITERAL-NIL is set, return the string value \"nil\" instead."
|
|||
(catch 'exit
|
||||
(let ((element (or element
|
||||
(and (org-element--cache-active-p)
|
||||
(org-element-at-point nil 'cached)))))
|
||||
(org-element-at-point nil 'cached))))
|
||||
(separator (org--property-get-separator property)))
|
||||
(if element
|
||||
(let ((element (org-element-lineage element '(headline org-data inlinetask) 'with-self)))
|
||||
(while t
|
||||
|
@ -12475,8 +12506,8 @@ However, if LITERAL-NIL is set, return the string value \"nil\" instead."
|
|||
(v (if (listp v) v (list v))))
|
||||
(when v
|
||||
(setq value
|
||||
(concat (mapconcat #'identity (delq nil v) " ")
|
||||
(and value " ")
|
||||
(concat (mapconcat #'identity (delq nil v) separator)
|
||||
(and value separator)
|
||||
value)))
|
||||
(cond
|
||||
((car v)
|
||||
|
@ -12487,15 +12518,15 @@ However, if LITERAL-NIL is set, return the string value \"nil\" instead."
|
|||
(t
|
||||
(let ((global (org--property-global-or-keyword-value property literal-nil)))
|
||||
(cond ((not global))
|
||||
(value (setq value (concat global " " value)))
|
||||
(value (setq value (concat global separator value)))
|
||||
(t (setq value global))))
|
||||
(throw 'exit nil))))))
|
||||
(while t
|
||||
(let ((v (org--property-local-values property literal-nil)))
|
||||
(when v
|
||||
(setq value
|
||||
(concat (mapconcat #'identity (delq nil v) " ")
|
||||
(and value " ")
|
||||
(concat (mapconcat #'identity (delq nil v) separator)
|
||||
(and value separator)
|
||||
value)))
|
||||
(cond
|
||||
((car v)
|
||||
|
@ -12516,7 +12547,7 @@ However, if LITERAL-NIL is set, return the string value \"nil\" instead."
|
|||
(t
|
||||
(let ((global (org--property-global-or-keyword-value property literal-nil)))
|
||||
(cond ((not global))
|
||||
(value (setq value (concat global " " value)))
|
||||
(value (setq value (concat global separator value)))
|
||||
(t (setq value global))))
|
||||
(throw 'exit nil))))))))
|
||||
(if literal-nil value (org-not-nil value)))))
|
||||
|
|
|
@ -6014,7 +6014,35 @@ Paragraph<point>"
|
|||
(org-test-with-temp-text
|
||||
":PROPERTIES:\n:A: 0\n:END:\n#+PROPERTY: A 1\n* H\n:PROPERTIES:\n:A+: 2\n:END:"
|
||||
(org-mode-restart)
|
||||
(org-entry-get (point-max) "A" t)))))
|
||||
(org-entry-get (point-max) "A" t))))
|
||||
;; Use alternate separators
|
||||
(should
|
||||
(equal "0~2"
|
||||
(org-test-with-temp-text
|
||||
":PROPERTIES:\n:A: 0\n:A+: 2\n:END:"
|
||||
(let ((org-property-separators '((("A") . "~"))))
|
||||
(org-entry-get (point) "A")))))
|
||||
;; Default separator is single space
|
||||
(should
|
||||
(equal "0 2"
|
||||
(org-test-with-temp-text
|
||||
":PROPERTIES:\n:A: 0\n:B: 1\n:A+: 2\n:B+: 3\n:END:"
|
||||
(let ((org-property-separators '((("B") . "~"))))
|
||||
(org-entry-get (point) "A")))))
|
||||
;; Regular expression matching for separator
|
||||
(should
|
||||
(equal "0/2"
|
||||
(org-test-with-temp-text
|
||||
":PROPERTIES:\n:A: 0\n:A+: 2\n:END:"
|
||||
(let ((org-property-separators '((("B") . "~") ("[AC]" . "/"))))
|
||||
(org-entry-get (point) "A")))))
|
||||
;; Separator works with inheritance
|
||||
(should
|
||||
(equal "1~2"
|
||||
(org-test-with-temp-text
|
||||
"* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2\n:PROPERTIES:\n:A+: 2\n:END:"
|
||||
(let ((org-property-separators '((("A") . "~"))))
|
||||
(org-entry-get (point-max) "A" t))))))
|
||||
|
||||
(ert-deftest test-org/entry-properties ()
|
||||
"Test `org-entry-properties' specifications."
|
||||
|
|
Loading…
Reference in New Issue