Browse Source

Merge branch 'master' into next

Gustav Wikström 5 years ago
parent
commit
cffe44ba94
3 changed files with 59 additions and 23 deletions
  1. 8 8
      doc/org-manual.org
  2. 8 2
      etc/ORG-NEWS
  3. 43 13
      lisp/org-attach.el

+ 8 - 8
doc/org-manual.org

@@ -8011,15 +8011,15 @@ mentioning.
   When attaching files to a heading it will be assigned a tag
   When attaching files to a heading it will be assigned a tag
   according to what is set here.
   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
   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~ ::
 - ~org-attach-expert~ ::
   #+vindex: org-attach-expert
   #+vindex: org-attach-expert

+ 8 - 2
etc/ORG-NEWS

@@ -188,8 +188,9 @@ precedence and will be used.
 One can now also choose to build attachment-directory-paths in a
 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
 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
 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
 If you've used ATTACH_DIR properties to manage attachments, use the
 following code to rename that property to DIR which supports the same
 following code to rename that property to DIR which supports the same
@@ -421,6 +422,11 @@ the attachment dispatcher.
 If one chooses, it is now possible to create ID's based on timestamp
 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.
 (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: ~org-id-locations-relative~
 New customization to make the persisting of org-id-locations between
 New customization to make the persisting of org-id-locations between
 sessions to store links to files as relative instead of absolute.  The
 sessions to store links to files as relative instead of absolute.  The

+ 43 - 13
lisp/org-attach.el

@@ -152,19 +152,33 @@ When set to `query', ask the user instead."
 	  (const :tag "Always delete attachments" t)
 	  (const :tag "Always delete attachments" t)
 	  (const :tag "Query the user" query)))
 	  (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
 Default format for how Org translates ID properties to a path for
-attachments."
+attachments.  Useful if ID is generated with UUID."
   (format "%s/%s"
   (format "%s/%s"
 	  (substring id 0 2)
 	  (substring id 0 2)
 	  (substring id 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
   :group 'org-attach
   :package-version '(Org . "9.3")
   :package-version '(Org . "9.3")
-  :type 'function)
+  :type '(repeat (function :tag "Function with ID as input")))
 
 
 (defvar org-attach-after-change-hook nil
 (defvar org-attach-after-change-hook nil
   "Hook to be called when files have been added or removed to the attachment folder.")
   "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
 to the attachment even if it has not yet been initialized in the
 filesystem.
 filesystem.
 
 
-If no attachment directory exist, return nil."
+If no attachment directory can be derived, return nil."
   (let (attach-dir id)
   (let (attach-dir id)
     (cond
     (cond
      (create-if-not-exists-p
      (create-if-not-exists-p
@@ -314,7 +328,7 @@ If no attachment directory exist, return nil."
       (org-attach-check-absolute-path attach-dir))
       (org-attach-check-absolute-path attach-dir))
      ((setq id (org-entry-get nil "ID" org-attach-use-inheritance))
      ((setq id (org-entry-get nil "ID" org-attach-use-inheritance))
       (org-attach-check-absolute-path nil)
       (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
     (if no-fs-check
 	attach-dir
 	attach-dir
       (when (and attach-dir (file-directory-p 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))
       (make-directory attach-dir t))
     attach-dir))
     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)
 (defun org-attach-check-absolute-path (dir)
   "Check if we have enough information to root the attachment directory.
   "Check if we have enough information to root the attachment directory.