summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Wikström <gustav@whil.se>2019-10-20 02:49:48 +0200
committerGustav Wikström <gustav@whil.se>2019-10-20 02:49:48 +0200
commit42b8db0d349df6416fdc406b05015a2cef2aaaa8 (patch)
tree7e7ef411e8db4a22e690fb896aff18e373e205dc
parentaa8500505f607b9c94a0c01819dda678fcea224c (diff)
downloadorg-mode-42b8db0d349df6416fdc406b05015a2cef2aaaa8.tar.gz
Improve handling of org attach id to path functions
* doc/org-manual.org (Attachment options) * etc/ORG-NEWS (Org-Attach has been refactored and extended) (New ID method based on timestamp) * lisp/org-attach.el (org-attach-id-uuid-folder-format) (org-attach-id-ts-folder-format) (org-attach-id-to-path-function-list, org-attach-dir) (org-attach-dir-from-id): Better handling of id to path functionality. At the same time adding an id-to-path function for timestamp-based ID that easily can be promoted to the primary function by customization of the user.
-rw-r--r--doc/org-manual.org16
-rw-r--r--etc/ORG-NEWS10
-rw-r--r--lisp/org-attach.el56
3 files changed, 59 insertions, 23 deletions
diff --git a/doc/org-manual.org b/doc/org-manual.org
index 5959189..5e69ef0 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -8004,15 +8004,15 @@ mentioning.
When attaching files to a heading it will be assigned a tag
according to what is set here.
-- ~org-attach-id-to-path-function~ ::
- #+vindex: org-attach-id-to-path-function
+- ~org-attach-id-to-path-function-list~ ::
+ #+vindex: org-attach-id-to-path-function-list
When =ID= is used for attachments, the ID is parsed into a part of a
- directory-path. See ~org-attach-id-folder-format~ for the default
- function. Define a new one and add it to
- ~org-attach-id-to-path-function~ if you want the folder structure
- any other way. Note that modifying this makes org-attach dependent
- on your function also for opening attachments, not only setting
- them!
+ directory-path. See ~org-attach-id-uuid-folder-format~ for the
+ default function. Define a new one and add it as first element in
+ ~org-attach-id-to-path-function-list~ if you want the folder
+ structure in any other way. All functions in this list will be
+ tried when resolving existing ID's into paths, to maintain backward
+ compatability with existing folders in your system.
- ~org-attach-expert~ ::
#+vindex: org-attach-expert
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 0e07326..bdcfc24 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -178,8 +178,9 @@ precedence and will be used.
One can now also choose to build attachment-directory-paths in a
customized way. This is an advanced topic, but in some case it makes
sense to parse an ID in a different way than the default one. Create
-your own function and use it is ~org-attach-id-to-path-function~ if
-you want to customize the ID-based folder structure.
+your own function and add it to the beginning of
+~org-attach-id-to-path-function~list~ if you want to customize the ID
+based folder structure.
If you've used ATTACH_DIR properties to manage attachments, use the
following code to rename that property to DIR which supports the same
@@ -411,6 +412,11 @@ the attachment dispatcher.
If one chooses, it is now possible to create ID's based on timestamp
(ISO8601) instead of UUID by changing org-id-method to ts.
+For an improved folder structure when using timestamp as ID, make sure
+to promote ~org-attach-id-ts-folder-format~ to the first element of
+~org-attach-id-to-path-function-list~ in your configuration at the
+same time.
+
*** New customization: ~org-id-locations-relative~
New customization to make the persisting of org-id-locations between
sessions to store links to files as relative instead of absolute. The
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 2138a28..bc49be7 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -152,19 +152,33 @@ When set to `query', ask the user instead."
(const :tag "Always delete attachments" t)
(const :tag "Query the user" query)))
-(defun org-attach-id-folder-format (id)
- "Translate an ID into a folder-path.
+(defun org-attach-id-uuid-folder-format (id)
+ "Translate an UUID ID into a folder-path.
Default format for how Org translates ID properties to a path for
-attachments."
+attachments. Useful if ID is generated with UUID."
(format "%s/%s"
(substring id 0 2)
(substring id 2)))
-(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format
- "Function parsing the ID parameter into a folder-path."
+(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)))
+
+(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."
:group 'org-attach
:package-version '(Org . "9.3")
- :type 'function)
+ :type '(repeat (function :tag "Function with ID as input")))
(defvar org-attach-after-change-hook nil
"Hook to be called when files have been added or removed to the attachment folder.")
@@ -301,7 +315,7 @@ is run. If NO-FS-CHECK is non-nil, the function returns the path
to the attachment even if it has not yet been initialized in the
filesystem.
-If no attachment directory exist, return nil."
+If no attachment directory can be derived, return nil."
(let (attach-dir id)
(cond
(create-if-not-exists-p
@@ -314,7 +328,7 @@ If no attachment directory exist, 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))))
+ (setq attach-dir (org-attach-dir-from-id id 'try-all))))
(if no-fs-check
attach-dir
(when (and attach-dir (file-directory-p attach-dir))
@@ -346,11 +360,27 @@ 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)
- "Returns a file name based on `org-attach-id-dir' and ID."
- (expand-file-name
- (funcall org-attach-id-to-path-function id)
- (expand-file-name org-attach-id-dir)))
+(defun org-attach-dir-from-id (id &optional try-all)
+ "Returns 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)))
(defun org-attach-check-absolute-path (dir)
"Check if we have enough information to root the attachment directory.