forked from mirrors/org-mode
org-attach.el: ID to path functions may return nil
* lisp/org-attach.el (org-attach-dir-from-id): Ignore nil values returned by entries from `org-attach-id-to-path-function-list'. (org-attach-dir-get-create): Signal an error suggesting customization of `org-attach-id-to-path-function-list' if all ID-to-path functions return nil. (org-attach-id-to-path-function-list): Add to the docstring examples how to handle unusual IDs. (org-attach-id-uuid-folder-format, org-attach-id-ts-folder-format): Return nil if ID is too short. (org-attach-id-fallback-folder-format): New function that may be added as the last element of `org-attach-id-path-function-list' to handle unexpectedly short IDs. * etc/ORG-NEWS: Advertise the change. Earlier an obscure error like 'org-attach-id-ts-folder-format: Args out of range: "ftt", 0, 6' was signalled in the case of unexpectedly short ID. Reported-by: Janek F <xerusx@pm.me> Link: https://list.orgmode.org/KC8PcypJapBpJQtJxM0kX5N7Z0THL2Lq6EQjBMzpw1-vgQf72egZ2JOIlTbPYiqAVD4MdSBhrhBZr2Ykf5DN1mocm1ANvvuKKZShlkgzKYM=@pm.me
This commit is contained in:
parent
21413d3589
commit
08a8c9e678
39
etc/ORG-NEWS
39
etc/ORG-NEWS
|
@ -604,6 +604,45 @@ With the new customization option ~org-texinfo-with-latex~ set to (its
|
|||
default value) ~'detect~, if the system runs Texinfo 6.8 (3 July 2021)
|
||||
or newer, Org will export all LaTeX fragments and environments using
|
||||
Texinfo ~@math~ and ~@displaymath~ commands respectively.
|
||||
*** More flexible ~org-attach-id-to-path-function-list~
|
||||
|
||||
List entries may return nil if they are unable to handle the passed
|
||||
ID. So, responsibility is passed to the next item in the list.
|
||||
Default entries ~org-attach-id-uuid-folder-format~ and
|
||||
~org-attach-id-ts-folder-format~ now return nil for too short IDs.
|
||||
Earlier an obscure error has been thrown.
|
||||
|
||||
After the change, error text suggests adjusting
|
||||
~org-attach-id-to-path-function-list~ value. The
|
||||
~org-attach-dir-from-id~ function is adapted to ignore nil values and
|
||||
to take first non-nil value instead of the value returned by first
|
||||
~org-attach-id-to-path-function-list~ item.
|
||||
|
||||
New policy allows mixing different ID styles while keeping subfolder
|
||||
layout suited best for each one. For example, one can use the
|
||||
following snippet to allow multiple different ID formats in Org files.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq org-attach-id-to-path-function-list
|
||||
'(;; When ID looks like an UUIDs or Org internal ID, use
|
||||
;; `org-attach-id-uuid-folder-format'.
|
||||
(lambda (id)
|
||||
(and (or (org-uuidgen-p id)
|
||||
(string-match-p "[0-9a-z]\\{12\\}" id))
|
||||
(org-attach-id-uuid-folder-format id)))
|
||||
;; When ID looks like a timestap-based ID. Group by year-month
|
||||
;; folders.
|
||||
(lambda (id)
|
||||
(and (string-match-p "[0-9]\\{8\\}T[0-9]\\{6\\}\.[0-9]\\{6\\}" id)
|
||||
(org-attach-id-ts-folder-format id)))
|
||||
;; Any other ID goes into "important" folder.
|
||||
(lambda (id) (format "important/%s/%s" (substring id 0 1) id))
|
||||
;; Fallback to detect existing attachments for old defaults.
|
||||
;; All the above functions, even when return non-nil, would
|
||||
;; point to non-existing folders.
|
||||
org-attach-id-uuid-folder-format
|
||||
org-attach-id-ts-folder-format))
|
||||
#+end_src
|
||||
|
||||
* Version 9.5
|
||||
|
||||
|
|
|
@ -166,28 +166,57 @@ When set to `query', ask the user instead."
|
|||
"Translate an UUID ID into a folder-path.
|
||||
Default format for how Org translates ID properties to a path for
|
||||
attachments. Useful if ID is generated with UUID."
|
||||
(format "%s/%s"
|
||||
(substring id 0 2)
|
||||
(substring id 2)))
|
||||
(and (< 2 (length id))
|
||||
(format "%s/%s"
|
||||
(substring id 0 2)
|
||||
(substring id 2))))
|
||||
|
||||
(defun org-attach-id-ts-folder-format (id)
|
||||
"Translate an ID based on a timestamp to a folder-path.
|
||||
Useful way of translation if ID is generated based on ISO8601
|
||||
timestamp. Splits the attachment folder hierarchy into
|
||||
year-month, the rest."
|
||||
(format "%s/%s"
|
||||
(substring id 0 6)
|
||||
(substring id 6)))
|
||||
(and (< 6 (length id))
|
||||
(format "%s/%s"
|
||||
(substring id 0 6)
|
||||
(substring id 6))))
|
||||
|
||||
(defcustom org-attach-id-to-path-function-list '(org-attach-id-uuid-folder-format
|
||||
org-attach-id-ts-folder-format)
|
||||
"List of functions parsing an ID string into a folder-path.
|
||||
The first function in this list defines the preferred function
|
||||
which will be used when creating new attachment folders. All
|
||||
functions of this list will be tried when looking for existing
|
||||
attachment folders based on ID."
|
||||
(defun org-attach-id-fallback-folder-format (id)
|
||||
"Return \"__/X/ID\" folder path as a dumb fallback.
|
||||
X is the first character in the ID string.
|
||||
|
||||
This function may be appended to `org-attach-id-path-function-list' to
|
||||
provide a fallback for non-standard ID values that other functions in
|
||||
`org-attach-id-path-function-list' are unable to handle. For example,
|
||||
when the ID is too short for `org-attach-id-ts-folder-format'.
|
||||
|
||||
However, we recommend to define a more specific function spreading
|
||||
entries over multiple folders. This function may create a large
|
||||
number of entries in a single folder, which may cause issues on some
|
||||
systems."
|
||||
(format "__/%s/%s" (substring id 0 1) id))
|
||||
|
||||
(defcustom org-attach-id-to-path-function-list
|
||||
'(org-attach-id-uuid-folder-format
|
||||
org-attach-id-ts-folder-format
|
||||
org-attach-id-fallback-folder-format)
|
||||
"List of functions used to derive attachment path from an ID string.
|
||||
The functions are called with a single ID argument until the return
|
||||
value is an existing folder. If no folder has been created yet for
|
||||
the given ID, then the first non-nil value defines the attachment
|
||||
dir to be created.
|
||||
|
||||
Usually, the ID format passed to the functions is defined by
|
||||
`org-id-method'. It is advised that the first function in the list do
|
||||
not generate all the attachment dirs inside the same parent dir. Some
|
||||
file systems may have performance issues in such scenario.
|
||||
|
||||
Care should be taken when customizing this variable. Previously
|
||||
created attachment folders might not be correctly mapped upon removing
|
||||
functions from the list. Then, Org will not be able to detect the
|
||||
existing attachments."
|
||||
:group 'org-attach
|
||||
:package-version '(Org . "9.3")
|
||||
:package-version '(Org . "9.6")
|
||||
:type '(repeat (function :tag "Function with ID as input")))
|
||||
|
||||
(defvar org-attach-after-change-hook nil
|
||||
|
@ -360,7 +389,7 @@ If no attachment directory can be derived, return nil."
|
|||
(org-attach-check-absolute-path attach-dir))
|
||||
((setq id (org-entry-get nil "ID" org-attach-use-inheritance))
|
||||
(org-attach-check-absolute-path nil)
|
||||
(setq attach-dir (org-attach-dir-from-id id 'try-all))))
|
||||
(setq attach-dir (org-attach-dir-from-id id 'existing))))
|
||||
(if no-fs-check
|
||||
attach-dir
|
||||
(when (and attach-dir (file-directory-p attach-dir))
|
||||
|
@ -381,7 +410,11 @@ If the attachment by some reason cannot be created an error will be raised."
|
|||
(setq answer (read-char-exclusive)))
|
||||
(cond
|
||||
((or (eq org-attach-preferred-new-method 'id) (eq answer ?1))
|
||||
(setq attach-dir (org-attach-dir-from-id (org-id-get nil t))))
|
||||
(let ((id (org-id-get nil t)))
|
||||
(or (setq attach-dir (org-attach-dir-from-id id))
|
||||
(error "Failed to get folder for id %s, \
|
||||
adjust `org-attach-id-to-path-function-list'"
|
||||
id))))
|
||||
((or (eq org-attach-preferred-new-method 'dir) (eq answer ?2))
|
||||
(setq attach-dir (org-attach-set-directory)))
|
||||
((eq org-attach-preferred-new-method 'nil)
|
||||
|
@ -392,27 +425,25 @@ If the attachment by some reason cannot be created an error will be raised."
|
|||
(make-directory attach-dir t))
|
||||
attach-dir))
|
||||
|
||||
(defun org-attach-dir-from-id (id &optional try-all)
|
||||
(defun org-attach-dir-from-id (id &optional existing)
|
||||
"Return a folder path based on `org-attach-id-dir' and ID.
|
||||
If TRY-ALL is non-nil, try all id-to-path functions in
|
||||
`org-attach-id-to-path-function-list' and return the first path
|
||||
that exist in the filesystem, or the first one if none exist.
|
||||
Otherwise only use the first function in that list."
|
||||
(let ((attach-dir-preferred (expand-file-name
|
||||
(funcall (car org-attach-id-to-path-function-list) id)
|
||||
(expand-file-name org-attach-id-dir))))
|
||||
(if try-all
|
||||
(let ((attach-dir attach-dir-preferred)
|
||||
(fun-list (cdr org-attach-id-to-path-function-list)))
|
||||
(while (and fun-list (not (file-directory-p attach-dir)))
|
||||
(setq attach-dir (expand-file-name
|
||||
(funcall (car fun-list) id)
|
||||
(expand-file-name org-attach-id-dir)))
|
||||
(setq fun-list (cdr fun-list)))
|
||||
(if (file-directory-p attach-dir)
|
||||
attach-dir
|
||||
attach-dir-preferred))
|
||||
attach-dir-preferred)))
|
||||
Try id-to-path functions in `org-attach-id-to-path-function-list'
|
||||
ignoring nils. If EXISTING is non-nil, then return the first path
|
||||
found in the filesystem. Otherwise return the first non-nil value."
|
||||
(let ((fun-list org-attach-id-to-path-function-list)
|
||||
(base-dir (expand-file-name org-attach-id-dir))
|
||||
preferred first)
|
||||
(while (and fun-list
|
||||
(not preferred))
|
||||
(let* ((name (funcall (car fun-list) id))
|
||||
(candidate (and name (expand-file-name name base-dir))))
|
||||
(setq fun-list (cdr fun-list))
|
||||
(when candidate
|
||||
(if (or (not existing) (file-directory-p candidate))
|
||||
(setq preferred candidate)
|
||||
(unless first
|
||||
(setq first candidate))))))
|
||||
(or preferred first)))
|
||||
|
||||
(defun org-attach-check-absolute-path (dir)
|
||||
"Check if we have enough information to root the attachment directory.
|
||||
|
|
Loading…
Reference in New Issue