emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* FW: [RFC] Link-type for attachments, more attach options
@ 2018-10-21  7:53 Gustav Wikström
  2018-11-01  1:45 ` tumashu
                   ` (8 more replies)
  0 siblings, 9 replies; 113+ messages in thread
From: Gustav Wikström @ 2018-10-21  7:53 UTC (permalink / raw)
  To: emacs-orgmode


[-- Attachment #1.1: Type: text/plain, Size: 1056 bytes --]

Hi,

I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review.

Kind regards
Gustav
___
Patch comments:
* Add new linktype "attached" for attachments

A new linktype "attached" is added in order to reduce link-duplication
when wanting to link to files in attached folders of nodes. This works
for both ID-based attachments and ATTACH_DIR.  Inline images will
trigger also for attachments, as well as search-decorations in the
links.  The goal is to make the functionality for attached-links
mirror file-links.

* Add further options for ATTACH_DIR

When working with ATTACH_DIR there are now a couple of new options available:
- org-attach-dir-inherit-by-default
- org-attach-dir-create-if-not-exist
- org-attach-dir-relative

Descriptions of them can be found in the commit for each new customization.

* Documentation in org-manual

Org-manual is updated with the new link-type as well as some minor
cleanup in the documentation related to external links and attachments.



[-- Attachment #1.2: Type: text/html, Size: 5038 bytes --]

[-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-more-attach-.patch --]
[-- Type: application/octet-stream, Size: 21974 bytes --]

From fe676033f871466493a9584972c3b110f4c55363 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com>
Date: Sun, 23 Sep 2018 02:43:16 +0200
Subject: [PATCH] org-attach, org-manual, org: New link-type, more attach
 options

* Add new linktype "attached" for attachments

A new linktype "attached" is added in order to reduce link-duplication
when wanting to link to files in attached folders of nodes. This works
for both ID-based attachments and ATTACH_DIR.  Inline images will
trigger also for attachments, as well as search-decorations in the
links.  The goal is to make the functionality for attached-links
mirror file-links.

* Add further options for ATTACH_DIR

When working with ATTACH_DIR there are now a couple of new options available:
- org-attach-dir-inherit-by-default
- org-attach-dir-create-if-not-exist
- org-attach-dir-relative

Descriptions of them can be found in the commit for each new customization.

* Documentation in org-manual

Org-manual is updated with the new link-type as well as some minor
cleanup in the documentation related to external links and attachments.
---
 doc/org-manual.org | 144 +++++++++++++++++++++++++++------------------
 lisp/org-attach.el | 138 +++++++++++++++++++++++++++++++++++--------
 lisp/org.el        |  17 ++++--
 3 files changed, 212 insertions(+), 87 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 7945b7333..144f5993e 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3137,6 +3137,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: attached links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3148,38 +3149,63 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
-
-| =http://www.astro.uva.nl/=dominik=        | on the web                     |
-| =doi:10.1000/182=                         | DOI for an electronic resource |
-| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
-| =/home/dominik/images/jupiter.jpg=        | same as above                  |
-| =file:papers/last.pdf=                    | file, relative path            |
-| =./papers/last.pdf=                       | same as above                  |
-| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
-| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
-| =file:sometextfile::NNN=                  | file, jump to line number      |
-| =file:projects.org=                       | another Org file               |
-| =file:projects.org::some words=           | text search in Org file[fn:28] |
-| =file:projects.org::*task title=          | heading search in Org file     |
-| =file+sys:/path/to/file=                  | open via OS, like double-click |
-| =file+emacs:/path/to/file=                | force opening by Emacs         |
-| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
-| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
-| =news:comp.emacs=                         | Usenet link                    |
-| =mailto:adent@galaxy.net=                 | mail link                      |
-| =mhe:folder=                              | MH-E folder link               |
-| =mhe:folder#id=                           | MH-E message link              |
-| =rmail:folder=                            | Rmail folder link              |
-| =rmail:folder#id=                         | Rmail message link             |
-| =gnus:group=                              | Gnus group link                |
-| =gnus:group#id=                           | Gnus article link              |
-| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
-| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
-| =info:org#External links=                 | Info node link                 |
-| =shell:ls *.org=                          | shell command                  |
-| =elisp:org-agenda=                        | interactive Elisp command      |
-| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
+the colon.
+
+This list shows the full set of built-in external link types:
+| http       | web                                 |
+| https      | secure web                          |
+| doi        | DOI for electronic resources        |
+| file       | file-links                          |
+| file+sys   | file-links forced to open via OS    |
+| file+emacs | file-links forced to open via emacs |
+| attached   | links to attachments for nodes      |
+| docview    | doc-view mode                       |
+| id         | Link to heading by id               |
+| news       | Usenet link                         |
+| mailto     | mail link                           |
+| mhe        | MH-E folder link                    |
+| rmail      | Rmail link                          |
+| gnus       | Gnus link                           |
+| bbdb       | BBDB link                           |
+| irc        | IRC link                            |
+| info       | Info link                           |
+| shell      | shell command                       |
+| elisp      | interactive elisp command link      |
+
+The following list shows examples for each link type.
+
+| =http://www.astro.uva.nl/=dominik=        | on the web                          |
+| =doi:10.1000/182=                         | DOI for an electronic resource      |
+| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path                 |
+| =/home/dominik/images/jupiter.jpg=        | same as above                       |
+| =file:papers/last.pdf=                    | file, relative path                 |
+| =./papers/last.pdf=                       | same as above                       |
+| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine        |
+| =/ssh:me@some.where:papers/last.pdf=      | same as above                       |
+| =file:sometextfile::NNN=                  | file, jump to line number           |
+| =file:projects.org=                       | another Org file                    |
+| =file:projects.org::some words=           | text search in Org file[fn:28]      |
+| =file:projects.org::*task title=          | heading search in Org file          |
+| =file+sys:/path/to/file=                  | open via OS, like double-click      |
+| =file+emacs:/path/to/file=                | force opening by Emacs              |
+| =attached:projects.org=                   | file in folder attached to headline |
+| =attached:projects.org::some words=       | text search in attached file        |
+| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page       |
+| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID               |
+| =news:comp.emacs=                         | Usenet link                         |
+| =mailto:adent@galaxy.net=                 | mail link                           |
+| =mhe:folder=                              | MH-E folder link                    |
+| =mhe:folder#id=                           | MH-E message link                   |
+| =rmail:folder=                            | Rmail folder link                   |
+| =rmail:folder#id=                         | Rmail message link                  |
+| =gnus:group=                              | Gnus group link                     |
+| =gnus:group#id=                           | Gnus article link                   |
+| =bbdb:R.*Stallman=                        | BBDB link (with regexp)             |
+| =irc:/irc.com/#emacs/bob=                 | IRC link                            |
+| =info:org#External links=                 | Info node link                      |
+| =shell:ls *.org=                          | shell command                       |
+| =elisp:org-agenda=                        | interactive Elisp command           |
+| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate              |
 
 #+cindex: VM links
 #+cindex: Wanderlust links
@@ -3532,24 +3558,26 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: attached links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:35].  For
-example, when the command ~org-store-link~ creates a link (see
-[[*Handling Links]]) to a file, it encodes the words in the current line
-as a search string that can be used to find this line back later when
-following the link with {{{kbd(C-c C-o)}}}.
+File links and attached file links can contain additional information
+to make Emacs jump to a particular location in the file when following
+a link.  This can be a line number or a search option after a double
+colon[fn:35].  For example, when the command ~org-store-link~ creates
+a link (see [[*Handling Links]]) to a file, it encodes the words in the
+current line as a search string that can be used to find this line
+back later when following the link with {{{kbd(C-c C-o)}}}.
 
 Here is the syntax of the different ways to attach a search to a file
 link, together with explanations for each:
 
 #+begin_example
-[[file:~/code/main.c::255]]
-[[file:~/xx.org::My Target]]
-[[file:~/xx.org::*My Target]]
-[[file:~/xx.org::#my-custom-id]]
-[[file:~/xx.org::/regexp/]]
+  [[file:~/code/main.c::255]]
+  [[file:~/xx.org::My Target]]
+  [[file:~/xx.org::*My Target]]
+  [[file:~/xx.org::#my-custom-id]]
+  [[file:~/xx.org::/regexp/]]
+  [[attached:~/code/main.c::255]]
 #+end_example
 
 - =255= ::
@@ -7527,18 +7555,22 @@ node/task.  Small chunks of plain text can simply be stored in the
 subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
 associations with files that live elsewhere on your computer or in the
 cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-~data~ directory which lives in the same directory where your Org file
-lives[fn:86].  If you initialize this directory with =git init=, Org
-automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by the unique ID of each entry, or by the =ATTACH_DIR= property.
+ID-based directories are by default located in the ~data~ directory
+which lives in the same directory where your Org file lives[fn:86].
+If you initialize this directory with =git init=, Org automatically
+commits changes when it sees them.  The attachment system has been
+contributed to Org by John Wiegley.
+
+In cases where =ATTACH_DIR= property is used to declare attachments,
+you can choose to either use absolute (default) or relative links.
+You can also make children inherit the attachment directory from a
+parent, so that an entire subtree uses the same attached directory.
+
+See customization group =Org Attach= if you want to change the default
+settings for attachments to fit your preferred style.
 
 The following commands deal with attachments:
 
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 53389f782..daf8cf2dd 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -57,6 +57,25 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
+(defcustom org-attach-dir-inherit-by-default nil
+  "Defines whether ATTACH_DIR-directories should be inherited by
+  subheadings by default when created. Defaults to not being
+  inherited."
+  :group 'org-attach
+  :type 'boolean)
+
+(defcustom org-attach-dir-create-if-not-exists t
+  "Choose whether ATTACH_DIR-directories should be created if
+they do not exist since before. Default is to create them."
+  :group 'org-attach
+  :type 'boolean)
+
+(defcustom org-attach-dir-relative nil
+  "Choose whether ATTACH_DIR-directories should be added as
+relative links or not. Defaults to not relative."
+  :group 'org-attach
+  :type 'boolean)
+
 (defcustom org-attach-commit t
   "If non-nil commit attachments with git.
 This is only done if the Org file is in a git repository."
@@ -280,20 +299,26 @@ Throw an error if we cannot root the directory."
   "Set the ATTACH_DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
 of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
+the directory to the default ID based one. Creates relative links
+if ORG-ATTACH-DIR-RELATIVE is t, and sets inheritance based on
+ORG-ATTACH-DIR-INHERIT-BY-DEFAULT"
   (interactive "P")
-  (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+  (let ((old (org-attach-dir nil))
+	(new
+	 (progn
+	   (if arg (org-entry-delete nil "ATTACH_DIR")
+	     (let* ((attach-dir (read-directory-name
+				 "Attachment directory: "
+				 (org-entry-get nil
+						"ATTACH_DIR")))
+		    (current-dir (file-name-directory (or load-file-name
+							  buffer-file-name)))
+		    (attach-dir-relative (file-relative-name attach-dir current-dir)))
+	       (if org-attach-dir-relative
+		   (org-entry-put nil "ATTACH_DIR" attach-dir-relative)
+		 (org-entry-put nil "ATTACH_DIR" attach-dir))))
+	   (org-attach-dir t))))
+    (when org-attach-dir-inherit-by-default (org-attach-set-inherit))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
@@ -527,14 +552,15 @@ This ignores files ending in \"~\"."
   "Show the attachment directory of the current task.
 This will attempt to use an external program to show the directory."
   (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
-    (and attach-dir (org-open-file attach-dir))))
+  (let* ((create-if-not-exist (if if-exists nil org-attach-dir-create-if-not-exists))
+	 (attach-dir (org-attach-dir create-if-not-exist)))
+    (when attach-dir (org-open-file attach-dir))))
 
 (defun org-attach-reveal-in-emacs ()
   "Show the attachment directory of the current task in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists)))
+    (when attach-dir (dired attach-dir))))
 
 (defun org-attach-open (&optional in-emacs)
   "Open an attachment of the current task.
@@ -543,15 +569,17 @@ This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists)))
+    (if attach-dir
+	(let* ((files (org-attach-file-list attach-dir))
+	       (file (if (= (length files) 1)
+			 (car files)
+		       (completing-read "Open attachment: "
+					(mapcar #'list files) nil t)))
+	       (path (expand-file-name file attach-dir)))
+	  (org-attach-annex-get-maybe path)
+	  (org-open-file path in-emacs))
+      (message "No attachment exists!"))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -570,6 +598,64 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(defun org-attach-open-link (link &optional in-emacs)
+  "LINK is expanded with the attached directory and opened the same
+way as file-links are."
+  (interactive "P")
+  (let (line search)
+    (if (string-match "::\\([0-9]+\\)\\'" link)
+        (setq line (string-to-number (match-string 1 link))
+              link (substring link 0 (match-beginning 0)))
+      (if (string-match "::\\(.+\\)\\'" link)
+          (setq search (match-string 1 link)
+                link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment
+directory."
+  (let (file link attached-dir)
+    (setq attached-dir (expand-file-name (org-attach-dir)))
+    (setq file (read-file-name "File: " attached-dir))
+    (let ((pwd (file-name-as-directory attached-dir))
+          (pwd1 (file-name-as-directory (abbreviate-file-name
+                                         attached-dir))))
+      (cond
+       ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
+        (setq link  (concat "attached:" (match-string 1 file))))
+       ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+                      (expand-file-name file))
+        (setq link  (concat
+                     "attached:" (match-string 1 (expand-file-name file)))))
+       (t (setq link (concat "attached:" file)))))
+    link))
+
+(defun org-attach-export-link (link description format)
+  "Export an \"attached\" link from Org files."
+  (save-excursion
+    (let (path desc)
+      (if (string-match "::\\([0-9]+\\)\\'" link)
+          (setq link (substring link 0 (match-beginning 0)))
+        (if (string-match "::\\(.+\\)\\'" link)
+            (setq link (substring link 0 (match-beginning 0)))))
+      (search-forward (concat "attached:" (org-link-escape link)))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
+(org-link-set-parameters "attached"
+                         :follow 'org-attach-open-link
+                         :export 'org-attach-export-link
+                         :complete 'org-attach-complete-link)
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
diff --git a/lisp/org.el b/lisp/org.el
index c0eaecdab..1eac53e0a 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -4427,6 +4427,7 @@ This is needed for font-lock setup.")
 		  (beg end))
 (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
 (declare-function org-agenda-skip "org-agenda" ())
+(declare-function org-attach-expand "org-attach" (&optional if-exists))
 (declare-function org-attach-reveal "org-attach" (&optional if-exists))
 (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
 (declare-function org-indent-mode "org-indent" (&optional arg))
@@ -18759,7 +18760,7 @@ boundaries."
 	    ;; Check absolute, relative file names and explicit
 	    ;; "file:" links.  Also check link abbreviations since
 	    ;; some might expand to "file" links.
-	    (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)"
+	    (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)"
 				   (if (not link-abbrevs) ""
 				     (format "\\|\\(?:%s:\\)"
 					     (regexp-opt link-abbrevs))))))
@@ -18768,14 +18769,20 @@ boundaries."
 	   ;; Check if we're at an inline image, i.e., an image file
 	   ;; link without a description (unless INCLUDE-LINKED is
 	   ;; non-nil).
-	   (when (and (equal "file" (org-element-property :type link))
+	   (when (and (or (equal "file" (org-element-property :type link))
+                          (equal "attached" (org-element-property :type link)))
 		      (or include-linked
 			  (null (org-element-contents link)))
 		      (string-match-p file-extension-re
 				      (org-element-property :path link)))
-	     (let ((file (expand-file-name
-			  (org-link-unescape
-			   (org-element-property :path link)))))
+	     (let ((file (if (equal "attached" (org-element-property :type link))
+			     (require 'org-attach)
+                             (org-attach-expand
+                              (org-link-unescape
+			       (org-element-property :path link)))
+			   (expand-file-name
+			    (org-link-unescape
+			     (org-element-property :path link))))))
 	       (when (file-exists-p file)
 		 (let ((width
 			;; Apply `org-image-actual-width' specifications.
-- 
2.19.1.windows.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
@ 2018-11-01  1:45 ` tumashu
  2018-11-02 22:40   ` Gustav Wikström
  2018-11-01 16:00 ` Marco Wahl
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: tumashu @ 2018-11-01  1:45 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 1210 bytes --]

Hello, this feature seem to be very useful, what is this patch status?






At 2018-10-21 15:53:38, "Gustav Wikström" <gustav@whil.se> wrote:


Hi,

 

I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review.

 

Kind regards

Gustav

___

Patch comments:

* Add new linktype "attached" for attachments

 

A new linktype "attached" is added in order to reduce link-duplication

when wanting to link to files in attached folders of nodes. This works

for both ID-based attachments and ATTACH_DIR.  Inline images will

trigger also for attachments, as well as search-decorations in the

links.  The goal is to make the functionality for attached-links

mirror file-links.

 

* Add further options for ATTACH_DIR

 

When working with ATTACH_DIR there are now a couple of new options available:

- org-attach-dir-inherit-by-default

- org-attach-dir-create-if-not-exist

- org-attach-dir-relative

 

Descriptions of them can be found in the commit for each new customization.

 

* Documentation in org-manual

 

Org-manual is updated with the new link-type as well as some minor

cleanup in the documentation related to external links and attachments.

 

 

[-- Attachment #2: Type: text/html, Size: 4683 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
  2018-11-01  1:45 ` tumashu
@ 2018-11-01 16:00 ` Marco Wahl
  2018-11-02 23:07   ` Gustav Wikström
  2018-11-04 22:37 ` Nicolas Goaziou
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: Marco Wahl @ 2018-11-01 16:00 UTC (permalink / raw)
  To: emacs-orgmode

Hi Gustav,

I played a bit with your proposition.  I like it; in particular the
completion function to insert links from the attachment directory with

    C-c C-l attached RET

It seems natural to me to have a more specific link type for attached
files.

In my opinion your patch should be applied to the 'next' branch.


My 2ct,
        Marco

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-01  1:45 ` tumashu
@ 2018-11-02 22:40   ` Gustav Wikström
  0 siblings, 0 replies; 113+ messages in thread
From: Gustav Wikström @ 2018-11-02 22:40 UTC (permalink / raw)
  To: tumashu; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 2043 bytes --]

Hi, nice to hear that you find it useful!

I don’t have access to apply the patch myself. So I’d be happy if one of the frequent maintainers could help out with that, and at the same time look a bit at the quality of it. I’ve used most of the functionality personally for well over a year in my local setup and just now took the time to repackage it into something reusable. Hopefully it’s seen as “good enough” to warrant a merge into one of the org-mode branches!

From my perspective the patch adds a lot of utility to the attachment-functionality.

Regards
Gustav

From: tumashu <tumashu@163.com>
Sent: den 1 november 2018 02:46
To: Gustav Wikström <gustav@whil.se>
Cc: emacs-orgmode <emacs-orgmode@gnu.org>
Subject: Re:[O] FW: [RFC] Link-type for attachments, more attach options

Hello, this feature seem to be very useful, what is this patch status?




At 2018-10-21 15:53:38, "Gustav Wikström" <gustav@whil.se<mailto:gustav@whil.se>> wrote:

Hi,

I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review.

Kind regards
Gustav
___
Patch comments:
* Add new linktype "attached" for attachments

A new linktype "attached" is added in order to reduce link-duplication
when wanting to link to files in attached folders of nodes. This works
for both ID-based attachments and ATTACH_DIR.  Inline images will
trigger also for attachments, as well as search-decorations in the
links.  The goal is to make the functionality for attached-links
mirror file-links.

* Add further options for ATTACH_DIR

When working with ATTACH_DIR there are now a couple of new options available:
- org-attach-dir-inherit-by-default
- org-attach-dir-create-if-not-exist
- org-attach-dir-relative

Descriptions of them can be found in the commit for each new customization.

* Documentation in org-manual

Org-manual is updated with the new link-type as well as some minor
cleanup in the documentation related to external links and attachments.



[-- Attachment #2: Type: text/html, Size: 9329 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-01 16:00 ` Marco Wahl
@ 2018-11-02 23:07   ` Gustav Wikström
  2018-11-03  3:37     ` Ihor Radchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-02 23:07 UTC (permalink / raw)
  To: Marco Wahl; +Cc: emacs-orgmode

Hi Marco,

Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it all the time to quickly add links to attached files.

One use case I have for this (as an example) is for projects and tasks. I have a 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the task is about some digital work, there are files involved with it. So I have a convention to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', and attach the folder to each task/project node. C-c C-l attached RET then makes it super-easy to refer to particular files within that folder, from within the node in the 'tasks.org' file!

Another use case is for my 'digital brain', where it's also fairly common for me to have attachment folders where I want to refer to files within them. Images for example, that then will be displayed in the org-mode file. Haven't settled on whether I should use auto-managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit of both...

I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. But if 'master' is to offensive to merge into straight away, 'next' sounds like a good option!

Kind regards
Gustav

-----Original Message-----
From: Marco Wahl <marcowahlsoft@gmail.com> 
Sent: den 1 november 2018 17:01
To: Gustav Wikström <gustav@whil.se>
Subject: Re: FW: [RFC] Link-type for attachments, more attach options

The following message is a courtesy copy of an article that has been posted to gmane.emacs.orgmode as well.

Hi Gustav,

I played a bit with your proposition.  I like it; in particular the completion function to insert links from the attachment directory with

    C-c C-l attached RET

It seems natural to me to have a more specific link type for attached files.

In my opinion your patch should be applied to the 'next' branch.


My 2ct,
        Marco


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-02 23:07   ` Gustav Wikström
@ 2018-11-03  3:37     ` Ihor Radchenko
  2018-11-17 12:13       ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Ihor Radchenko @ 2018-11-03  3:37 UTC (permalink / raw)
  To: Gustav Wikström, Marco Wahl; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 3393 bytes --]

Hi Gustav,

Thanks for the patch!
I am a heavy user of org attachments, so it is pleasant that someone
spent a time to implement this useful feature into org.

A comment regarding the code.
Your new link types appears to reimplement some of the code for the
"file:" links.
Would it make more sense to implement the "attachment:" link type as
abbreviation?
I mean something like the code below:

````
(defun yant/process-att-abbrev (arg)
  "Return `org-attach-dir' for the current entry."
  (s-concat (org-attach-dir 'CREATE) arg))

(add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)"))

(defun org-att-link-complete (&optional arg)
  "Completion function for att: link."
  (let* ((ref-dir (org-attach-dir 'CREATE))
	 (filelink (let ((default-directory ref-dir))
		     (org-file-complete-link)))
	 (filepath (apply #'s-concat (cdr (s-split ":" filelink)))))
    (format "att:%s" filepath)))

(org-link-set-parameters "att" 
			 :complete #'org-att-link-complete)
````

Also, is anyone interested in automatic placing of org attachments into
a folder structure, which mirrors the org path?
Something like in the following Stack Exchange question:
https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org-attach

Best,
Ihor

Gustav Wikström <gustav@whil.se> writes:

> Hi Marco,
>
> Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it all the time to quickly add links to attached files.
>
> One use case I have for this (as an example) is for projects and tasks. I have a 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the task is about some digital work, there are files involved with it. So I have a convention to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', and attach the folder to each task/project node. C-c C-l attached RET then makes it super-easy to refer to particular files within that folder, from within the node in the 'tasks.org' file!
>
> Another use case is for my 'digital brain', where it's also fairly common for me to have attachment folders where I want to refer to files within them. Images for example, that then will be displayed in the org-mode file. Haven't settled on whether I should use auto-managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit of both...
>
> I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. But if 'master' is to offensive to merge into straight away, 'next' sounds like a good option!
>
> Kind regards
> Gustav
>
> -----Original Message-----
> From: Marco Wahl <marcowahlsoft@gmail.com> 
> Sent: den 1 november 2018 17:01
> To: Gustav Wikström <gustav@whil.se>
> Subject: Re: FW: [RFC] Link-type for attachments, more attach options
>
> The following message is a courtesy copy of an article that has been posted to gmane.emacs.orgmode as well.
>
> Hi Gustav,
>
> I played a bit with your proposition.  I like it; in particular the completion function to insert links from the attachment directory with
>
>     C-c C-l attached RET
>
> It seems natural to me to have a more specific link type for attached files.
>
> In my opinion your patch should be applied to the 'next' branch.
>
>
> My 2ct,
>         Marco
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
  2018-11-01  1:45 ` tumashu
  2018-11-01 16:00 ` Marco Wahl
@ 2018-11-04 22:37 ` Nicolas Goaziou
  2018-11-17 11:58   ` Gustav Wikström
  2019-01-04 12:21 ` FW: " Feng Shu
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2018-11-04 22:37 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> I’ve attached a patch with some suggested additions to org-attach.
> Patch comments below. Please review.

Thank you. Some comments follow.

> * Add new linktype "attached" for attachments

This seem a bit long. Why not "att" links?

> * Add further options for ATTACH_DIR
>
> When working with ATTACH_DIR there are now a couple of new options available:
> - org-attach-dir-inherit-by-default

What is the difference between this and `org-attach-allow-inheritance'?

> - org-attach-dir-create-if-not-exist

What is the use-case for this one? It doesn't seem terribly useful at
first glance.

> - org-attach-dir-relative

I'm not sure to understand this one.
>
> +This list shows the full set of built-in external link types:
> +| http       | web                                 |
> +| https      | secure web                          |
> +| doi        | DOI for electronic resources        |
> +| file       | file-links                          |
> +| file+sys   | file-links forced to open via OS    |
> +| file+emacs | file-links forced to open via emacs |
> +| attached   | links to attachments for nodes      |
> +| docview    | doc-view mode                       |
> +| id         | Link to heading by id               |
> +| news       | Usenet link                         |
> +| mailto     | mail link                           |
> +| mhe        | MH-E folder link                    |
> +| rmail      | Rmail link                          |
> +| gnus       | Gnus link                           |
> +| bbdb       | BBDB link                           |
> +| irc        | IRC link                            |
> +| info       | Info link                           |
> +| shell      | shell command                       |
> +| elisp      | interactive elisp command link      |
> +
> +The following list shows examples for each link type.
> +
> +| =http://www.astro.uva.nl/=dominik=        | on the web                          |
> +| =doi:10.1000/182=                         | DOI for an electronic resource      |
> +| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path                 |
> +| =/home/dominik/images/jupiter.jpg=        | same as above                       |
> +| =file:papers/last.pdf=                    | file, relative path                 |
> +| =./papers/last.pdf=                       | same as above                       |
> +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine        |
> +| =/ssh:me@some.where:papers/last.pdf=      | same as above                       |
> +| =file:sometextfile::NNN=                  | file, jump to line number           |
> +| =file:projects.org=                       | another Org file                    |
> +| =file:projects.org::some words=           | text search in Org file[fn:28]      |
> +| =file:projects.org::*task title=          | heading search in Org file          |
> +| =file+sys:/path/to/file=                  | open via OS, like double-click      |
> +| =file+emacs:/path/to/file=                | force opening by Emacs              |
> +| =attached:projects.org=                   | file in folder attached to headline |
> +| =attached:projects.org::some words=       | text search in attached file        |
> +| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page       |
> +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID               |
> +| =news:comp.emacs=                         | Usenet link                         |
> +| =mailto:adent@galaxy.net=                 | mail link                           |
> +| =mhe:folder=                              | MH-E folder link                    |
> +| =mhe:folder#id=                           | MH-E message link                   |
> +| =rmail:folder=                            | Rmail folder link                   |
> +| =rmail:folder#id=                         | Rmail message link                  |
> +| =gnus:group=                              | Gnus group link                     |
> +| =gnus:group#id=                           | Gnus article link                   |
> +| =bbdb:R.*Stallman=                        | BBDB link (with regexp)             |
> +| =irc:/irc.com/#emacs/bob=                 | IRC link                            |
> +| =info:org#External links=                 | Info node link                      |
> +| =shell:ls *.org=                          | shell command                       |
> +| =elisp:org-agenda=                        | interactive Elisp command           |
> +| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate              |

I'm not sure to like the change above. It introduces a lot of
redundancy.

>  Here is the syntax of the different ways to attach a search to a file
>  link, together with explanations for each:
>  
>  #+begin_example
> -[[file:~/code/main.c::255]]
> -[[file:~/xx.org::My Target]]
> -[[file:~/xx.org::*My Target]]
> -[[file:~/xx.org::#my-custom-id]]
> -[[file:~/xx.org::/regexp/]]
> +  [[file:~/code/main.c::255]]
> +  [[file:~/xx.org::My Target]]
> +  [[file:~/xx.org::*My Target]]
> +  [[file:~/xx.org::#my-custom-id]]
> +  [[file:~/xx.org::/regexp/]]
> +  [[attached:~/code/main.c::255]]
>  #+end_example

Please discard this change.

> +Another method is /attachments/, which are files located in a
> +directory belonging to an outline node.  Org uses directories either
> +named by the unique ID of each entry, or by the =ATTACH_DIR= property.
> +ID-based directories are by default located in the ~data~ directory

... =data/= directory, which ...

> +(defcustom org-attach-dir-inherit-by-default nil
> +  "Defines whether ATTACH_DIR-directories should be inherited by
> +  subheadings by default when created. Defaults to not being
> +  inherited."
> +  :group 'org-attach
> +  :type 'boolean)

First line in a docstring must be a full sentence.  Indentation is wrong
in the subsequent lines.  Also, the `defcustom' is missing keywords,
e.g., :package-version and :safe.

> +(defcustom org-attach-dir-create-if-not-exists t
> +  "Choose whether ATTACH_DIR-directories should be created if
> +they do not exist since before. Default is to create them."
> +  :group 'org-attach
> +  :type 'boolean)
> +
> +(defcustom org-attach-dir-relative nil
> +  "Choose whether ATTACH_DIR-directories should be added as
> +relative links or not. Defaults to not relative."
> +  :group 'org-attach
> +  :type 'boolean)

Ditto.

>  (defcustom org-attach-commit t
>    "If non-nil commit attachments with git.
>  This is only done if the Org file is in a git repository."
> @@ -280,20 +299,26 @@ Throw an error if we cannot root the directory."
>    "Set the ATTACH_DIR node property and ask to move files there.
>  The property defines the directory that is used for attachments
>  of the entry.  When called with `\\[universal-argument]', reset \
> -the directory to
> -the default ID based one."
> +the directory to the default ID based one. Creates relative links

You need to use two spaces to separate sentences.

> +  (let ((old (org-attach-dir nil))
> +	(new
> +	 (progn
> +	   (if arg (org-entry-delete nil "ATTACH_DIR")
> +	     (let* ((attach-dir (read-directory-name
> +				 "Attachment directory: "
> +				 (org-entry-get nil
> +						"ATTACH_DIR")))
> +		    (current-dir (file-name-directory (or load-file-name
> +							  buffer-file-name)))

Why `load-file-name'? Why not using `default-directory'?

> +(defun org-attach-open-link (link &optional in-emacs)
> +  "LINK is expanded with the attached directory and opened the same
> +way as file-links are."

You need to expound the arguments in the docstring.

> +	    (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)"
>  				   (if (not link-abbrevs) ""
>  				     (format "\\|\\(?:%s:\\)"
>  					     (regexp-opt link-abbrevs))))))

Why is it needed? "attached" link type is already registered, so you
don't need to also hard-code it here.

> +	   (when (and (or (equal "file" (org-element-property :type link))
> +                          (equal "attached" (org-element-property :type link)))

Ditto.

> +	     (let ((file (if (equal "attached" (org-element-property :type link))
> +			     (require 'org-attach)
> +                             (org-attach-expand
> +                              (org-link-unescape
> +			       (org-element-property :path link)))
> +			   (expand-file-name
> +			    (org-link-unescape
> +			     (org-element-property :path link))))))

Ditto.

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-04 22:37 ` Nicolas Goaziou
@ 2018-11-17 11:58   ` Gustav Wikström
       [not found]     ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com>
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-17 11:58 UTC (permalink / raw)
  To: mail; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 11534 bytes --]

Hi Nicolas,

Thanks for your detailed comments. Much appreciated.

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 4 november 2018 23:37
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: FW: [RFC] Link-type for attachments, more attach options
> 
> Hello,
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > I’ve attached a patch with some suggested additions to org-attach.
> > Patch comments below. Please review.
> 
> Thank you. Some comments follow.
> 
> > * Add new linktype "attached" for attachments
> 
> This seem a bit long. Why not "att" links?

Yeah - I liked "attached" because I prefer clear keywords. But sure, we can keep it shorter. I'd suggest "@" instead in that case. Patch updated with that.

> 
> > * Add further options for ATTACH_DIR
> >
> > When working with ATTACH_DIR there are now a couple of new options available:
> > - org-attach-dir-inherit-by-default
> 
> What is the difference between this and `org-attach-allow-inheritance'?
> 
> > - org-attach-dir-create-if-not-exist
> 
> What is the use-case for this one? It doesn't seem terribly useful at
> first glance.

If you try to open attachments on a node where there is no ID or ATTACH_DIR, the default behavior is to add an ID and create a folder based on that ID. I would like Org-mode to not do that. This customization give the user the option to change that. Instead of providing this customization one could just change the default behavior of org-attach, since it's a bit offensive to create folders when I didn't ask for it. But instead of changing the default, I thought this way was more graceful. I wouldn't mind skipping this customization though, if the behavior was changed to what I implemented with org-attach-dir-create-if-not-exist set to nil.

> 
> > - org-attach-dir-relative
> 
> I'm not sure to understand this one.

When adding folders to nodes using option "s" in org-attach, the path is absolute. This makes attachment-directory paths relative to location of the file instead.

> >
> > +This list shows the full set of built-in external link types:
> > +| http       | web                                 |
> > +| https      | secure web                          |
> > +| doi        | DOI for electronic resources        |
> > +| file       | file-links                          |
> > +| file+sys   | file-links forced to open via OS    |
> > +| file+emacs | file-links forced to open via emacs |
> > +| attached   | links to attachments for nodes      |
> > +| docview    | doc-view mode                       |
> > +| id         | Link to heading by id               |
> > +| news       | Usenet link                         |
> > +| mailto     | mail link                           |
> > +| mhe        | MH-E folder link                    |
> > +| rmail      | Rmail link                          |
> > +| gnus       | Gnus link                           |
> > +| bbdb       | BBDB link                           |
> > +| irc        | IRC link                            |
> > +| info       | Info link                           |
> > +| shell      | shell command                       |
> > +| elisp      | interactive elisp command link      |
> > +
> > +The following list shows examples for each link type.
> > +
> > +| =http://www.astro.uva.nl/=dominik=        | on the web                          |
> > +| =doi:10.1000/182=                         | DOI for an electronic resource      |
> > +| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path                 |
> > +| =/home/dominik/images/jupiter.jpg=        | same as above                       |
> > +| =file:papers/last.pdf=                    | file, relative path                 |
> > +| =./papers/last.pdf=                       | same as above                       |
> > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine        |
> > +| =/ssh:me@some.where:papers/last.pdf=      | same as above                       |
> > +| =file:sometextfile::NNN=                  | file, jump to line number           |
> > +| =file:projects.org=                       | another Org file                    |
> > +| =file:projects.org::some words=           | text search in Org file[fn:28]      |
> > +| =file:projects.org::*task title=          | heading search in Org file          |
> > +| =file+sys:/path/to/file=                  | open via OS, like double-click      |
> > +| =file+emacs:/path/to/file=                | force opening by Emacs              |
> > +| =attached:projects.org=                   | file in folder attached to headline |
> > +| =attached:projects.org::some words=       | text search in attached file        |
> > +| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page       |
> > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID               |
> > +| =news:comp.emacs=                         | Usenet link                         |
> > +| =mailto:adent@galaxy.net=                 | mail link                           |
> > +| =mhe:folder=                              | MH-E folder link                    |
> > +| =mhe:folder#id=                           | MH-E message link                   |
> > +| =rmail:folder=                            | Rmail folder link                   |
> > +| =rmail:folder#id=                         | Rmail message link                  |
> > +| =gnus:group=                              | Gnus group link                     |
> > +| =gnus:group#id=                           | Gnus article link                   |
> > +| =bbdb:R.*Stallman=                        | BBDB link (with regexp)             |
> > +| =irc:/irc.com/#emacs/bob=                 | IRC link                            |
> > +| =info:org#External links=                 | Info node link                      |
> > +| =shell:ls *.org=                          | shell command                       |
> > +| =elisp:org-agenda=                        | interactive Elisp command           |
> > +| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate              |
> 
> I'm not sure to like the change above. It introduces a lot of
> redundancy.
> 

Currently the list in the documentation is just a bunch of examples. I've looked at it a couple of times asking myself "What is the complete list of built in link types?". This commit "fixes" that. I wouldn't say its redundant since all the rows in the second list are just examples.

> >  Here is the syntax of the different ways to attach a search to a file
> >  link, together with explanations for each:
> >
> >  #+begin_example
> > -[[file:~/code/main.c::255]]
> > -[[file:~/xx.org::My Target]]
> > -[[file:~/xx.org::*My Target]]
> > -[[file:~/xx.org::#my-custom-id]]
> > -[[file:~/xx.org::/regexp/]]
> > +  [[file:~/code/main.c::255]]
> > +  [[file:~/xx.org::My Target]]
> > +  [[file:~/xx.org::*My Target]]
> > +  [[file:~/xx.org::#my-custom-id]]
> > +  [[file:~/xx.org::/regexp/]]
> > +  [[attached:~/code/main.c::255]]
> >  #+end_example
> 
> Please discard this change.

Ofc, sorry for that.

> 
> > +Another method is /attachments/, which are files located in a
> > +directory belonging to an outline node.  Org uses directories either
> > +named by the unique ID of each entry, or by the =ATTACH_DIR= property.
> > +ID-based directories are by default located in the ~data~ directory
> 
> ... =data/= directory, which ...

Done.

> 
> > +(defcustom org-attach-dir-inherit-by-default nil
> > +  "Defines whether ATTACH_DIR-directories should be inherited by
> > +  subheadings by default when created. Defaults to not being
> > +  inherited."
> > +  :group 'org-attach
> > +  :type 'boolean)
> 
> First line in a docstring must be a full sentence.  Indentation is wrong
> in the subsequent lines.  Also, the `defcustom' is missing keywords,
> e.g., :package-version and :safe.

I can't say I understand the use of :safe here. But added it anyways. If you care, please explain why it's needed. Package-version is added. I set it to 9.2. Correct?

> 
> > +(defcustom org-attach-dir-create-if-not-exists t
> > +  "Choose whether ATTACH_DIR-directories should be created if
> > +they do not exist since before. Default is to create them."
> > +  :group 'org-attach
> > +  :type 'boolean)
> > +
> > +(defcustom org-attach-dir-relative nil
> > +  "Choose whether ATTACH_DIR-directories should be added as
> > +relative links or not. Defaults to not relative."
> > +  :group 'org-attach
> > +  :type 'boolean)
> 
> Ditto.

Ok

> 
> >  (defcustom org-attach-commit t
> >    "If non-nil commit attachments with git.
> >  This is only done if the Org file is in a git repository."
> > @@ -280,20 +299,26 @@ Throw an error if we cannot root the directory."
> >    "Set the ATTACH_DIR node property and ask to move files there.
> >  The property defines the directory that is used for attachments
> >  of the entry.  When called with `\\[universal-argument]', reset \
> > -the directory to
> > -the default ID based one."
> > +the directory to the default ID based one. Creates relative links
> 
> You need to use two spaces to separate sentences.

Ah, yes ofc. Fixed.

> 
> > +  (let ((old (org-attach-dir nil))
> > +	(new
> > +	 (progn
> > +	   (if arg (org-entry-delete nil "ATTACH_DIR")
> > +	     (let* ((attach-dir (read-directory-name
> > +				 "Attachment directory: "
> > +				 (org-entry-get nil
> > +						"ATTACH_DIR")))
> > +		    (current-dir (file-name-directory (or load-file-name
> > +							  buffer-file-name)))
> 
> Why `load-file-name'? Why not using `default-directory'?

Good question. I don't remember having any particular arguments for it. I'll change to your suggestion.
 
> 
> > +(defun org-attach-open-link (link &optional in-emacs)
> > +  "LINK is expanded with the attached directory and opened the same
> > +way as file-links are."
> 
> You need to expound the arguments in the docstring.

Sorry, I don't understand what I'm supposed to do here... I changed the comment to (maybe?) make it read better. Other than that, I'm at a loss.

> 
> > +	    (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)"
> >  				   (if (not link-abbrevs) ""
> >  				     (format "\\|\\(?:%s:\\)"
> >  					     (regexp-opt link-abbrevs))))))
> 
> Why is it needed? "attached" link type is already registered, so you
> don't need to also hard-code it here.

This is when parsing the buffer for images. I couldn't get org-mode to display images without this.

> 
> > +	   (when (and (or (equal "file" (org-element-property :type link))
> > +                          (equal "attached" (org-element-property :type link)))
> 
> Ditto.

Same comment as above.

> 
> > +	     (let ((file (if (equal "attached" (org-element-property :type link))
> > +			     (require 'org-attach)
> > +                             (org-attach-expand
> > +                              (org-link-unescape
> > +			       (org-element-property :path link)))
> > +			   (expand-file-name
> > +			    (org-link-unescape
> > +			     (org-element-property :path link))))))
> 
> Ditto.

Same comment as above.

> 
> Regards,
> 
> --
> Nicolas Goaziou

Thanks again for your comments. Updated patch is attached/att/@!

Kind regards,
Gustav

[-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-more-attach-.patch --]
[-- Type: application/octet-stream, Size: 17679 bytes --]

From f556e3e1dcfff6103e54aee244bbeacf13aeeb55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com>
Date: Sun, 23 Sep 2018 02:43:16 +0200
Subject: [PATCH] org-attach, org-manual, org: New link-type, more attach
 options

* Add new linktype "attached" for attachments

A new linktype "attached" is added in order to reduce link-duplication
when wanting to link to files in attached folders of nodes. This works
for both ID-based attachments and ATTACH_DIR.  Inline images will
trigger also for attachments, as well as search-decorations in the
links.  The goal is to make the functionality for attached-links
mirror file-links.

* Add further options for ATTACH_DIR

When working with ATTACH_DIR there are now a couple of new options available:
- org-attach-dir-inherit-by-default
- org-attach-dir-create-if-not-exist
- org-attach-dir-relative

Descriptions of them can be found in the commit for each new customization.

* Documentation in org-manual

Org-manual is updated with the new link-type as well as some minor
cleanup in the documentation related to external links and attachments.
---
 doc/org-manual.org |  72 ++++++++++++++++-------
 lisp/org-attach.el | 143 ++++++++++++++++++++++++++++++++++++---------
 lisp/org.el        |  17 ++++--
 3 files changed, 181 insertions(+), 51 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 5e4effb6f..960292ab2 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3141,6 +3141,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: @ links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3152,7 +3153,30 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
+the colon.
+
+This list shows the full set of built-in external link types:
+| http       | web                                 |
+| https      | secure web                          |
+| doi        | DOI for electronic resources        |
+| file       | file-links                          |
+| file+sys   | file-links forced to open via OS    |
+| file+emacs | file-links forced to open via emacs |
+| @          | links to attachments for nodes      |
+| docview    | doc-view mode                       |
+| id         | Link to heading by id               |
+| news       | Usenet link                         |
+| mailto     | mail link                           |
+| mhe        | MH-E folder link                    |
+| rmail      | Rmail link                          |
+| gnus       | Gnus link                           |
+| bbdb       | BBDB link                           |
+| irc        | IRC link                            |
+| info       | Info link                           |
+| shell      | shell command                       |
+| elisp      | interactive elisp command link      |
+
+The following list shows examples for each link type.
 
 | =http://www.astro.uva.nl/=dominik=        | on the web                     |
 | =doi:10.1000/182=                         | DOI for an electronic resource |
@@ -3168,6 +3192,8 @@ the colon.  The following list shows examples for each link type.
 | =file:projects.org::*task title=          | heading search in Org file     |
 | =file+sys:/path/to/file=                  | open via OS, like double-click |
 | =file+emacs:/path/to/file=                | force opening by Emacs         |
+| =@:projects.org=                          | file attached to headline      |
+| =@:projects.org::some words=              | text search in attached file   |
 | =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
 | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
 | =news:comp.emacs=                         | Usenet link                    |
@@ -3538,14 +3564,15 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: @ links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:35].  For
-example, when the command ~org-store-link~ creates a link (see
-[[*Handling Links]]) to a file, it encodes the words in the current line
-as a search string that can be used to find this line back later when
-following the link with {{{kbd(C-c C-o)}}}.
+File links and attached (@) links can contain additional information
+to make Emacs jump to a particular location in the file when following
+a link.  This can be a line number or a search option after a double
+colon[fn:35].  For example, when the command ~org-store-link~ creates
+a link (see [[*Handling Links]]) to a file, it encodes the words in the
+current line as a search string that can be used to find this line
+back later when following the link with {{{kbd(C-c C-o)}}}.
 
 Here is the syntax of the different ways to attach a search to a file
 link, together with explanations for each:
@@ -3556,6 +3583,7 @@ link, together with explanations for each:
 [[file:~/xx.org::*My Target]]
 [[file:~/xx.org::#my-custom-id]]
 [[file:~/xx.org::/regexp/]]
+[[@:~/code/main.c::255]]
 #+end_example
 
 - =255= ::
@@ -7533,18 +7561,22 @@ node/task.  Small chunks of plain text can simply be stored in the
 subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
 associations with files that live elsewhere on your computer or in the
 cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-~data~ directory which lives in the same directory where your Org file
-lives[fn:86].  If you initialize this directory with =git init=, Org
-automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by the unique ID of each entry, or by the =ATTACH_DIR= property.
+ID-based directories are by default located in the =data/= directory,
+which lives in the same directory where your Org file lives[fn:86].
+If you initialize this directory with =git init=, Org automatically
+commits changes when it sees them.  The attachment system has been
+contributed to Org by John Wiegley.
+
+In cases where =ATTACH_DIR= property is used to declare attachments,
+you can choose to either use absolute (default) or relative links.
+You can also make children inherit the attachment directory from a
+parent, so that an entire subtree uses the same attached directory.
+
+See customization group =Org Attach= if you want to change the default
+settings for attachments.
 
 The following commands deal with attachments:
 
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index e827d3721..bc7f02669 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -57,6 +57,30 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
+(defcustom org-attach-dir-inherit-by-default nil
+  "Defines whether ATTACH_DIR-directories should be inherited by subheadings by default when created.
+Defaults to not being inherited."
+  :group 'org-attach
+  :type 'boolean
+  :package-version '(Org . "9.2")
+  :safe #'booleanp)
+
+(defcustom org-attach-dir-create-if-not-exists t
+  "Choose whether ATTACH_DIR-directories should be created if they do not exist since before.
+Default is to create them."
+  :group 'org-attach
+  :type 'boolean
+  :package-version '(Org . "9.2")
+  :safe #'booleanp)
+
+(defcustom org-attach-dir-relative nil
+  "Choose whether ATTACH_DIR-directories should be added as relative links or not.
+Defaults to not relative."
+  :group 'org-attach
+  :type 'boolean
+  :package-version '(Org . "9.2")
+  :safe #'booleanp)
+
 (defcustom org-attach-commit t
   "If non-nil commit attachments with git.
 This is only done if the Org file is in a git repository."
@@ -280,20 +304,26 @@ Throw an error if we cannot root the directory."
   "Set the ATTACH_DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
 of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
+the directory to the default ID based one.  Creates relative
+links if ORG-ATTACH-DIR-RELATIVE is t, and sets inheritance based
+on ORG-ATTACH-DIR-INHERIT-BY-DEFAULT."
   (interactive "P")
-  (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+  (let ((old (org-attach-dir nil))
+	(new
+	 (progn
+	   (if arg (org-entry-delete nil "ATTACH_DIR")
+	     (let* ((attach-dir (read-directory-name
+				 "Attachment directory: "
+				 (org-entry-get nil
+						"ATTACH_DIR")))
+		    (current-dir (file-name-directory (or default-directory
+							  buffer-file-name)))
+		    (attach-dir-relative (file-relative-name attach-dir current-dir)))
+	       (if org-attach-dir-relative
+		   (org-entry-put nil "ATTACH_DIR" attach-dir-relative)
+		 (org-entry-put nil "ATTACH_DIR" attach-dir))))
+	   (org-attach-dir t))))
+    (when org-attach-dir-inherit-by-default (org-attach-set-inherit))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
@@ -527,14 +557,15 @@ This ignores files ending in \"~\"."
   "Show the attachment directory of the current task.
 This will attempt to use an external program to show the directory."
   (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
-    (and attach-dir (org-open-file attach-dir))))
+  (let* ((create-if-not-exist (if if-exists nil org-attach-dir-create-if-not-exists))
+	 (attach-dir (org-attach-dir create-if-not-exist)))
+    (when attach-dir (org-open-file attach-dir))))
 
 (defun org-attach-reveal-in-emacs ()
   "Show the attachment directory of the current task in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists)))
+    (when attach-dir (dired attach-dir))))
 
 (defun org-attach-open (&optional in-emacs)
   "Open an attachment of the current task.
@@ -543,15 +574,17 @@ This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists)))
+    (if attach-dir
+	(let* ((files (org-attach-file-list attach-dir))
+	       (file (if (= (length files) 1)
+			 (car files)
+		       (completing-read "Open attachment: "
+					(mapcar #'list files) nil t)))
+	       (path (expand-file-name file attach-dir)))
+	  (org-attach-annex-get-maybe path)
+	  (org-open-file path in-emacs))
+      (message "No attachment exists!"))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -570,6 +603,64 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(defun org-attach-open-link (link &optional in-emacs)
+  "Attach link type LINK is expanded with the attached directory and opened.
+This is done in the same way as file-links are opened."
+  (interactive "P")
+  (let (line search)
+    (if (string-match "::\\([0-9]+\\)\\'" link)
+        (setq line (string-to-number (match-string 1 link))
+              link (substring link 0 (match-beginning 0)))
+      (if (string-match "::\\(.+\\)\\'" link)
+          (setq search (match-string 1 link)
+                link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment directory."
+  (let (file link attached-dir)
+    (setq attached-dir (expand-file-name (org-attach-dir)))
+    (setq file (read-file-name "File: " attached-dir))
+    (let ((pwd (file-name-as-directory attached-dir))
+          (pwd1 (file-name-as-directory (abbreviate-file-name
+                                         attached-dir))))
+      (cond
+       ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
+        (setq link  (concat "@:" (match-string 1 file))))
+       ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+                      (expand-file-name file))
+        (setq link  (concat
+                     "@:" (match-string 1 (expand-file-name file)))))
+       (t (setq link (concat "@:" file)))))
+    link))
+
+(defun org-attach-export-link (link description format)
+  "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT.
+Also includes the DESCRIPTION of the link in the export."
+  (save-excursion
+    (let (path desc)
+      (if (string-match "::\\([0-9]+\\)\\'" link)
+          (setq link (substring link 0 (match-beginning 0)))
+        (if (string-match "::\\(.+\\)\\'" link)
+            (setq link (substring link 0 (match-beginning 0)))))
+      (search-forward (concat "@:" (org-link-escape link)))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
+(org-link-set-parameters "@"
+                         :follow 'org-attach-open-link
+                         :export 'org-attach-export-link
+                         :complete 'org-attach-complete-link)
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
diff --git a/lisp/org.el b/lisp/org.el
index eb1affbc7..9ed663bb9 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -4428,6 +4428,7 @@ This is needed for font-lock setup.")
 		  (beg end))
 (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
 (declare-function org-agenda-skip "org-agenda" ())
+(declare-function org-attach-expand "org-attach" (&optional if-exists))
 (declare-function org-attach-reveal "org-attach" (&optional if-exists))
 (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
 (declare-function org-indent-mode "org-indent" (&optional arg))
@@ -18721,7 +18722,7 @@ boundaries."
 	    ;; Check absolute, relative file names and explicit
 	    ;; "file:" links.  Also check link abbreviations since
 	    ;; some might expand to "file" links.
-	    (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)"
+	    (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)"
 				   (if (not link-abbrevs) ""
 				     (format "\\|\\(?:%s:\\)"
 					     (regexp-opt link-abbrevs))))))
@@ -18730,14 +18731,20 @@ boundaries."
 	   ;; Check if we're at an inline image, i.e., an image file
 	   ;; link without a description (unless INCLUDE-LINKED is
 	   ;; non-nil).
-	   (when (and (equal "file" (org-element-property :type link))
+	   (when (and (or (equal "file" (org-element-property :type link))
+                          (equal "@" (org-element-property :type link)))
 		      (or include-linked
 			  (null (org-element-contents link)))
 		      (string-match-p file-extension-re
 				      (org-element-property :path link)))
-	     (let ((file (expand-file-name
-			  (org-link-unescape
-			   (org-element-property :path link)))))
+	     (let ((file (if (equal "@" (org-element-property :type link))
+			     (require 'org-attach)
+                             (org-attach-expand
+                              (org-link-unescape
+			       (org-element-property :path link)))
+			   (expand-file-name
+			    (org-link-unescape
+			     (org-element-property :path link))))))
 	       (when (file-exists-p file)
 		 (let ((width
 			;; Apply `org-image-actual-width' specifications.
-- 
2.19.1.windows.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-03  3:37     ` Ihor Radchenko
@ 2018-11-17 12:13       ` Gustav Wikström
  2018-11-18  0:42         ` Ihor Radchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-17 12:13 UTC (permalink / raw)
  To: Ihor Radchenko, Marco Wahl; +Cc: emacs-orgmode

Hi Ihor,

I'm not sure I follow your suggestion regarding changing the implementation. But anyhow I don't think the implementation is heavy and at risk of cumbersome code duplication. My opinion ofc 😊

I like the idea of a function that would symbolically links folders from "ID"-folder structure to a hierarchy-folder structure, based on the name and path of the org-file  and its headings containing the links. I probably wouldn't use it much myself though. Not until org-mode starts working better with multiple files, allowing us to more easily define "org-mode libraries".

/G 

> -----Original Message-----
> From: Ihor Radchenko <yantar92@gmail.com>
> Sent: den 3 november 2018 04:38
> To: Gustav Wikström <gustav@whil.se>; Marco Wahl <marcowahlsoft@gmail.com>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> Hi Gustav,
> 
> Thanks for the patch!
> I am a heavy user of org attachments, so it is pleasant that someone
> spent a time to implement this useful feature into org.
> 
> A comment regarding the code.
> Your new link types appears to reimplement some of the code for the
> "file:" links.
> Would it make more sense to implement the "attachment:" link type as
> abbreviation?
> I mean something like the code below:
> 
> ````
> (defun yant/process-att-abbrev (arg)
>   "Return `org-attach-dir' for the current entry."
>   (s-concat (org-attach-dir 'CREATE) arg))
> 
> (add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)"))
> 
> (defun org-att-link-complete (&optional arg)
>   "Completion function for att: link."
>   (let* ((ref-dir (org-attach-dir 'CREATE))
> 	 (filelink (let ((default-directory ref-dir))
> 		     (org-file-complete-link)))
> 	 (filepath (apply #'s-concat (cdr (s-split ":" filelink)))))
>     (format "att:%s" filepath)))
> 
> (org-link-set-parameters "att"
> 			 :complete #'org-att-link-complete)
> ````
> 
> Also, is anyone interested in automatic placing of org attachments into
> a folder structure, which mirrors the org path?
> Something like in the following Stack Exchange question:
> https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org-
> attach
> 
> Best,
> Ihor
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Hi Marco,
> >
> > Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it
> all the time to quickly add links to attached files.
> >
> > One use case I have for this (as an example) is for projects and tasks. I have a
> 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the
> task is about some digital work, there are files involved with it. So I have a convention
> to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]',
> and attach the folder to each task/project node. C-c C-l attached RET then makes it super-
> easy to refer to particular files within that folder, from within the node in the
> 'tasks.org' file!
> >
> > Another use case is for my 'digital brain', where it's also fairly common for me to have
> attachment folders where I want to refer to files within them. Images for example, that
> then will be displayed in the org-mode file. Haven't settled on whether I should use auto-
> managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit
> of both...
> >
> > I'm not familiar with the 'next' branch and the plans for integrating it into 'master'.
> But if 'master' is to offensive to merge into straight away, 'next' sounds like a good
> option!
> >
> > Kind regards
> > Gustav
> >
> > -----Original Message-----
> > From: Marco Wahl <marcowahlsoft@gmail.com>
> > Sent: den 1 november 2018 17:01
> > To: Gustav Wikström <gustav@whil.se>
> > Subject: Re: FW: [RFC] Link-type for attachments, more attach options
> >
> > The following message is a courtesy copy of an article that has been posted to
> gmane.emacs.orgmode as well.
> >
> > Hi Gustav,
> >
> > I played a bit with your proposition.  I like it; in particular the completion function
> to insert links from the attachment directory with
> >
> >     C-c C-l attached RET
> >
> > It seems natural to me to have a more specific link type for attached files.
> >
> > In my opinion your patch should be applied to the 'next' branch.
> >
> >
> > My 2ct,
> >         Marco
> >

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-17 12:13       ` Gustav Wikström
@ 2018-11-18  0:42         ` Ihor Radchenko
  2018-11-18  8:57           ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Ihor Radchenko @ 2018-11-18  0:42 UTC (permalink / raw)
  To: Gustav Wikström, Marco Wahl; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 5690 bytes --]

Hi Gustav,

> I'm not sure I follow your suggestion regarding changing the
> implementation. But anyhow I don't think the implementation is heavy
> and at risk of cumbersome code duplication. My opinion ofc 😊 

Sure. The code is not that complicated.

> I like the idea of a function that would symbolically links folders
> from "ID"-folder structure to a hierarchy-folder structure, based on
> the name and path of the org-file  and its headings containing the
> links. I probably wouldn't use it much myself though. Not until
> org-mode starts working better with multiple files, allowing us to
> more easily define "org-mode libraries". 

I am wondering what you mean by "org-mode libraries". Can you explain
further? 

Also, another thought about the attachment: links.
It would be useful to implement links to attachments, which are not in
the current org entry.
For example, something like "attachment:ORG-ID:file-name", where ORG-ID
refers to ID of an arbitrary org entry.

Best,
Ihor


Gustav Wikström <gustav@whil.se> writes:

> Hi Ihor,
>
> I'm not sure I follow your suggestion regarding changing the implementation. But anyhow I don't think the implementation is heavy and at risk of cumbersome code duplication. My opinion ofc 😊
>
> I like the idea of a function that would symbolically links folders from "ID"-folder structure to a hierarchy-folder structure, based on the name and path of the org-file  and its headings containing the links. I probably wouldn't use it much myself though. Not until org-mode starts working better with multiple files, allowing us to more easily define "org-mode libraries".
>
> /G 
>
>> -----Original Message-----
>> From: Ihor Radchenko <yantar92@gmail.com>
>> Sent: den 3 november 2018 04:38
>> To: Gustav Wikström <gustav@whil.se>; Marco Wahl <marcowahlsoft@gmail.com>
>> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> Hi Gustav,
>> 
>> Thanks for the patch!
>> I am a heavy user of org attachments, so it is pleasant that someone
>> spent a time to implement this useful feature into org.
>> 
>> A comment regarding the code.
>> Your new link types appears to reimplement some of the code for the
>> "file:" links.
>> Would it make more sense to implement the "attachment:" link type as
>> abbreviation?
>> I mean something like the code below:
>> 
>> ````
>> (defun yant/process-att-abbrev (arg)
>>   "Return `org-attach-dir' for the current entry."
>>   (s-concat (org-attach-dir 'CREATE) arg))
>> 
>> (add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)"))
>> 
>> (defun org-att-link-complete (&optional arg)
>>   "Completion function for att: link."
>>   (let* ((ref-dir (org-attach-dir 'CREATE))
>> 	 (filelink (let ((default-directory ref-dir))
>> 		     (org-file-complete-link)))
>> 	 (filepath (apply #'s-concat (cdr (s-split ":" filelink)))))
>>     (format "att:%s" filepath)))
>> 
>> (org-link-set-parameters "att"
>> 			 :complete #'org-att-link-complete)
>> ````
>> 
>> Also, is anyone interested in automatic placing of org attachments into
>> a folder structure, which mirrors the org path?
>> Something like in the following Stack Exchange question:
>> https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org-
>> attach
>> 
>> Best,
>> Ihor
>> 
>> Gustav Wikström <gustav@whil.se> writes:
>> 
>> > Hi Marco,
>> >
>> > Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it
>> all the time to quickly add links to attached files.
>> >
>> > One use case I have for this (as an example) is for projects and tasks. I have a
>> 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the
>> task is about some digital work, there are files involved with it. So I have a convention
>> to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]',
>> and attach the folder to each task/project node. C-c C-l attached RET then makes it super-
>> easy to refer to particular files within that folder, from within the node in the
>> 'tasks.org' file!
>> >
>> > Another use case is for my 'digital brain', where it's also fairly common for me to have
>> attachment folders where I want to refer to files within them. Images for example, that
>> then will be displayed in the org-mode file. Haven't settled on whether I should use auto-
>> managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit
>> of both...
>> >
>> > I'm not familiar with the 'next' branch and the plans for integrating it into 'master'.
>> But if 'master' is to offensive to merge into straight away, 'next' sounds like a good
>> option!
>> >
>> > Kind regards
>> > Gustav
>> >
>> > -----Original Message-----
>> > From: Marco Wahl <marcowahlsoft@gmail.com>
>> > Sent: den 1 november 2018 17:01
>> > To: Gustav Wikström <gustav@whil.se>
>> > Subject: Re: FW: [RFC] Link-type for attachments, more attach options
>> >
>> > The following message is a courtesy copy of an article that has been posted to
>> gmane.emacs.orgmode as well.
>> >
>> > Hi Gustav,
>> >
>> > I played a bit with your proposition.  I like it; in particular the completion function
>> to insert links from the attachment directory with
>> >
>> >     C-c C-l attached RET
>> >
>> > It seems natural to me to have a more specific link type for attached files.
>> >
>> > In my opinion your patch should be applied to the 'next' branch.
>> >
>> >
>> > My 2ct,
>> >         Marco
>> >


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-18  0:42         ` Ihor Radchenko
@ 2018-11-18  8:57           ` Gustav Wikström
  2018-11-20 14:00             ` Ihor Radchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-18  8:57 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: Ihor Radchenko <yantar92@gmail.com>
> Sent: den 18 november 2018 01:42
> To: Gustav Wikström <gustav@whil.se>; Marco Wahl
> <marcowahlsoft@gmail.com>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> Hi Gustav,
> 
> > I like the idea of a function that would symbolically links folders
> > from "ID"-folder structure to a hierarchy-folder structure, based on
> > the name and path of the org-file  and its headings containing the
> > links. I probably wouldn't use it much myself though. Not until
> > org-mode starts working better with multiple files, allowing us to
> > more easily define "org-mode libraries".
> 
> I am wondering what you mean by "org-mode libraries". Can you explain
> further?

This goes a bit off topic; But what I mean is mainly two things: 
1) Generalize the org-agenda so that we can have multiple ones

   Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas.

2) Make files function as virtual "level-0 headings"

   If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well.

> 
> Also, another thought about the attachment: links.
> It would be useful to implement links to attachments, which are not in the
> current org entry.
> For example, something like "attachment:ORG-ID:file-name", where ORG-ID
> refers to ID of an arbitrary org entry.

I wouldn't call that attachment-links, but rather ID-based links (since attachments are local based on either headline ID or attach-dir of the current headline). ID links exist already but link to headlines. 

If you rather see ID-based attachments as some kind of global attachments for all your org-mode files, I'd think the link-type should reflect that and be called something like "ID-attachment:file-name", "ID-@:file-name", "@ID:file-name" and be a separate link-type.

> 
> Best,
> Ihor
> 
> 

Kind regards
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
       [not found]     ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com>
@ 2018-11-19 23:52       ` Nicolas Goaziou
  2018-11-25 21:13         ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2018-11-19 23:52 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: Org Mode List

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Yeah - I liked "attached" because I prefer clear keywords. But sure,
> we can keep it shorter. I'd suggest "@" instead in that case. Patch
> updated with that.

"@" syntax is a reserved syntax for citations in the "wip-cite" branch.
I'd rather not use it here. Also, years ago, "att" link type was used to
link to attachments, hence my proposal.

>> > When working with ATTACH_DIR there are now a couple of new options available:
>> > - org-attach-dir-inherit-by-default
>> 
>> What is the difference between this and
>> `org-attach-allow-inheritance'?

You didn't answer this question, did you?

Something is fishy here anyways. Why is "ATTACH_DIR_INHERIT" needed at
all? If `org-attach-allow-inheritance', "ATTACH_DIR" should be
inherited. Why depend on another property?

I'd rather not make these things more complex.

>> > - org-attach-dir-create-if-not-exist
>> 
>> What is the use-case for this one? It doesn't seem terribly useful at 
>> first glance.
>
> If you try to open attachments on a node where there is no ID or
>> ATTACH_DIR, the default behavior is to add an ID and create a folder
>> based on that ID. I would like Org-mode to not do that. This
>> customization give the user the option to change that. Instead of
>> providing this customization one could just change the default
>> behavior of org-attach, since it's a bit offensive to create folders
>> when I didn't ask for it. But instead of changing the default,
>> I thought this way was more graceful. I wouldn't mind skipping this
>> customization though, if the behavior was changed to what
>> I implemented with org-attach-dir-create-if-not-exist set to nil.

Considering attaching is about moving, or copying files somewhere,
creating a folder doesn't sound terribly offensive. You don't even have
to know the name of the folder.

Do you suggest to raise an error if there is no folder available for the
attached documents? If so, wouldn't it be better to ask the user first?

>> > - org-attach-dir-relative
>> 
>> I'm not sure to understand this one.
>
> When adding folders to nodes using option "s" in org-attach, the path
> is absolute. This makes attachment-directory paths relative to
> location of the file instead.

OK.

>> > +This list shows the full set of built-in external link types:
>> > +| http       | web                                 |
>> > +| https      | secure web                          |
>> > +| doi        | DOI for electronic resources        |
>> > +| file       | file-links                          |
>> > +| file+sys   | file-links forced to open via OS    |
>> > +| file+emacs | file-links forced to open via emacs |
>> > +| attached   | links to attachments for nodes      |
>> > +| docview    | doc-view mode                       |
>> > +| id         | Link to heading by id               |
>> > +| news       | Usenet link                         |
>> > +| mailto     | mail link                           |
>> > +| mhe        | MH-E folder link                    |
>> > +| rmail      | Rmail link                          |
>> > +| gnus       | Gnus link                           |
>> > +| bbdb       | BBDB link                           |
>> > +| irc        | IRC link                            |
>> > +| info       | Info link                           |
>> > +| shell      | shell command                       |
>> > +| elisp      | interactive elisp command link      |
>> > +
>> > +The following list shows examples for each link type.
>> > +
>> > +| =http://www.astro.uva.nl/=dominik=        | on the web                          |
>> > +| =doi:10.1000/182=                         | DOI for an electronic resource      |
>> > +| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path                 |
>> > +| =/home/dominik/images/jupiter.jpg=        | same as above                       |
>> > +| =file:papers/last.pdf=                    | file, relative path                 |
>> > +| =./papers/last.pdf=                       | same as above                       |
>> > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine        |
>> > +| =/ssh:me@some.where:papers/last.pdf=      | same as above                       |
>> > +| =file:sometextfile::NNN=                  | file, jump to line number           |
>> > +| =file:projects.org=                       | another Org file                    |
>> > +| =file:projects.org::some words=           | text search in Org file[fn:28]      |
>> > +| =file:projects.org::*task title=          | heading search in Org file          |
>> > +| =file+sys:/path/to/file=                  | open via OS, like double-click      |
>> > +| =file+emacs:/path/to/file=                | force opening by Emacs              |
>> > +| =attached:projects.org=                   | file in folder attached to headline |
>> > +| =attached:projects.org::some words=       | text search in attached file        |
>> > +| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page       |
>> > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID               |
>> > +| =news:comp.emacs=                         | Usenet link                         |
>> > +| =mailto:adent@galaxy.net=                 | mail link                           |
>> > +| =mhe:folder=                              | MH-E folder link                    |
>> > +| =mhe:folder#id=                           | MH-E message link                   |
>> > +| =rmail:folder=                            | Rmail folder link                   |
>> > +| =rmail:folder#id=                         | Rmail message link                  |
>> > +| =gnus:group=                              | Gnus group link                     |
>> > +| =gnus:group#id=                           | Gnus article link                   |
>> > +| =bbdb:R.*Stallman=                        | BBDB link (with regexp)             |
>> > +| =irc:/irc.com/#emacs/bob=                 | IRC link                            |
>> > +| =info:org#External links=                 | Info node link                      |
>> > +| =shell:ls *.org=                          | shell command                       |
>> > +| =elisp:org-agenda=                        | interactive Elisp command           |
>> > +| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate              |
>> 
>> I'm not sure to like the change above. It introduces a lot of 
>> redundancy.
>> 
>
> Currently the list in the documentation is just a bunch of examples.
>> I've looked at it a couple of times asking myself "What is the
>> complete list of built in link types?". This commit "fixes" that.
>> I wouldn't say its redundant since all the rows in the second list
>> are just examples.

It is still redundant. For example, the first table has

 | info | Info link |

whereas the second one tells us

 | info:org#External links | Info node link |

In this case,

 | Info link | info:org#External links |

would be sufficient enough. I have the feeling documentation can be
improved here.

Also, file+sys and file+emacs are deprecated. They can be removed.

> I can't say I understand the use of :safe here. But added it anyways.
> If you care, please explain why it's needed. Package-version is added.
> I set it to 9.2. Correct?

If :safe is not set, Emacs will warn every time the variable is set as
a local file variable.

It should be 9.3, not 9.2.

>> > +(defun org-attach-open-link (link &optional in-emacs)
>> > +  "LINK is expanded with the attached directory and opened the same 
>> > +way as file-links are."
>> 
>> You need to expound the arguments in the docstring.
>
> Sorry, I don't understand what I'm supposed to do here... I changed
> the comment to (maybe?) make it read better. Other than that, I'm at
> a loss.

Every argument needs to be documented in the docstring. What is LINK
type? What is IN-EMACS?

>> > +	    (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)"
>> >  				   (if (not link-abbrevs) ""
>> >  				     (format "\\|\\(?:%s:\\)"
>> >  					     (regexp-opt link-abbrevs))))))
>> 
>> Why is it needed? "attached" link type is already registered, so you 
>> don't need to also hard-code it here.
>
> This is when parsing the buffer for images. I couldn't get org-mode to
> display images without this.

This is still a hack, and clearly not the way to go, IMO. If not already
possible, we could add a new parameter in `org-link-parameters' or some
such. This is another issue, tho.

> +(defcustom org-attach-dir-create-if-not-exists t
> +  "Choose whether ATTACH_DIR-directories should be created if they do
> not exist since before.

Too long. Maybe:

When non-nil, ATTACH_DIR is created automatically if it doesn't exist.
Otherwise, ...

> +Default is to create them."
> +  :group 'org-attach
> +  :type 'boolean
> +  :package-version '(Org . "9.2")
> +  :safe #'booleanp)
> +
> +(defcustom org-attach-dir-relative nil
> +  "Choose whether ATTACH_DIR-directories should be added as relative links or not.

Too long. Maybe something like:

Non-nil means ATTACH_DIR is relative to the attachment node directory. 

> +Defaults to not relative."

Defaults to absolute location.

> +  (let ((old (org-attach-dir nil))
> +	(new
> +	 (progn
> +	   (if arg (org-entry-delete nil "ATTACH_DIR")
> +	     (let* ((attach-dir (read-directory-name
> +				 "Attachment directory: "
> +				 (org-entry-get nil
> +						"ATTACH_DIR")))
> +		    (current-dir (file-name-directory (or default-directory
> +							  buffer-file-name)))
> +		    (attach-dir-relative (file-relative-name attach-dir current-dir)))
> +	       (if org-attach-dir-relative
> +		   (org-entry-put nil "ATTACH_DIR" attach-dir-relative)
> +		 (org-entry-put nil "ATTACH_DIR" attach-dir))))

(org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative 
                                    attach-dir-relative
                                  attach-dir))

> +(defun org-attach-open-link (link &optional in-emacs)
> +  "Attach link type LINK is expanded with the attached directory and opened.
> +This is done in the same way as file-links are opened."
> +  (interactive "P")
> +  (let (line search)
> +    (if (string-match "::\\([0-9]+\\)\\'" link)
> +        (setq line (string-to-number (match-string 1 link))
> +              link (substring link 0 (match-beginning 0)))
> +      (if (string-match "::\\(.+\\)\\'" link)
> +          (setq search (match-string 1 link)
> +                link (substring link 0 (match-beginning 0)))))

Use `cond' instead.

> +    (if (string-match "[*?{]" (file-name-nondirectory link))
> +        (dired (org-attach-expand link))
> +      (org-open-file (org-attach-expand link) in-emacs line search))))
> +
> +(defun org-attach-complete-link ()
> +  "Advise the user with the available files in the attachment directory."
> +  (let (file link attached-dir)
> +    (setq attached-dir (expand-file-name (org-attach-dir)))
> +    (setq file (read-file-name "File: " attached-dir))
> +    (let ((pwd (file-name-as-directory attached-dir))
> +          (pwd1 (file-name-as-directory (abbreviate-file-name
> +                                         attached-dir))))
> +      (cond
> +       ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
> +        (setq link  (concat "@:" (match-string 1 file))))
> +       ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
> +                      (expand-file-name file))
> +        (setq link  (concat
> +                     "@:" (match-string 1 (expand-file-name file)))))
> +       (t (setq link (concat "@:" file)))))
> +    link))

I suggest:

  (let* ((attached-dir (expand-file-name (org-attach-dir)))
         (file (read-file-name "File: " attached-dir))
         (pwd (file-name-as-directory attached-dir))
         (pwd-relative (file-name-as-directory
                        (abbreviate-file-name attached-dir))))
   (cond
    ((string-match ...)
     (concat ...))
    ...
    (t (concat ...))))

> +(defun org-attach-export-link (link description format)
> +  "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT.
> +Also includes the DESCRIPTION of the link in the export."
> +  (save-excursion
> +    (let (path desc)
> +      (if (string-match "::\\([0-9]+\\)\\'" link)
> +          (setq link (substring link 0 (match-beginning 0)))
> +        (if (string-match "::\\(.+\\)\\'" link)
> +            (setq link (substring link 0 (match-beginning 0)))))

Use `cond' instead.

> +      (search-forward (concat "@:" (org-link-escape link)))

What is the use for the line above?

> diff --git a/lisp/org.el b/lisp/org.el
> index eb1affbc7..9ed663bb9 100644
> --- a/lisp/org.el
> +++ b/lisp/org.el
> @@ -4428,6 +4428,7 @@ This is needed for font-lock setup.")
>  		  (beg end))
>  (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
>  (declare-function org-agenda-skip "org-agenda" ())
> +(declare-function org-attach-expand "org-attach" (&optional if-exists))
>  (declare-function org-attach-reveal "org-attach" (&optional if-exists))
>  (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
>  (declare-function org-indent-mode "org-indent" (&optional arg))
> @@ -18721,7 +18722,7 @@ boundaries."
>  	    ;; Check absolute, relative file names and explicit
>  	    ;; "file:" links.  Also check link abbreviations since
>  	    ;; some might expand to "file" links.
> -	    (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)"
> +	    (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)"
>  				   (if (not link-abbrevs) ""
>  				     (format "\\|\\(?:%s:\\)"
>  					     (regexp-opt link-abbrevs))))))
> @@ -18730,14 +18731,20 @@ boundaries."
>  	   ;; Check if we're at an inline image, i.e., an image file
>  	   ;; link without a description (unless INCLUDE-LINKED is
>  	   ;; non-nil).
> -	   (when (and (equal "file" (org-element-property :type link))
> +	   (when (and (or (equal "file" (org-element-property :type link))
> +                          (equal "@" (org-element-property :type link)))
>  		      (or include-linked
>  			  (null (org-element-contents link)))
>  		      (string-match-p file-extension-re
>  				      (org-element-property :path link)))
> -	     (let ((file (expand-file-name
> -			  (org-link-unescape
> -			   (org-element-property :path link)))))
> +	     (let ((file (if (equal "@" (org-element-property :type link))
> +			     (require 'org-attach)
> +                             (org-attach-expand
> +                              (org-link-unescape
> +			       (org-element-property :path link)))
> +			   (expand-file-name
> +			    (org-link-unescape
> +			     (org-element-property :path link))))))
>  	       (when (file-exists-p file)
>  		 (let ((width
>  			;; Apply `org-image-actual-width' specifications.

This part can be omitted for now. Something better has to be found.

Thank you.

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-18  8:57           ` Gustav Wikström
@ 2018-11-20 14:00             ` Ihor Radchenko
  2018-11-24 13:56               ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Ihor Radchenko @ 2018-11-20 14:00 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 4798 bytes --]

Hi,

>    Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas.

Isn't this already in org? You can use custom agendas with multiple
"agendas" (custom commands) and set the files they operate on with
org-agenda-files within custom commands.

>    If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well.

You can do something like below. It is pretty much what you want, except
I am not sure how to update the headings from local org files. Current
org version does not allow `:results replace` on raw org output.

* Main heading

#+name: org-files-here
#+begin_src bash
ls *.org
#+end_src

#+begin_src emacs-lisp :var files=org-files-here()  :var stars=(make-string (car (org-heading-components)) ?*)  :results raw replace drawer
(let ((files (mapcar #'car files)))
  (cl-loop for file in files
	   concat (with-current-buffer (find-file-noselect file)
		    (concat (format "* %s\n" (buffer-file-name))
			    (replace-regexp-in-string "^\\*" (concat "*" stars) (buffer-string))))))
#+end_src

Best,
Ihor

Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: Ihor Radchenko <yantar92@gmail.com>
>> Sent: den 18 november 2018 01:42
>> To: Gustav Wikström <gustav@whil.se>; Marco Wahl
>> <marcowahlsoft@gmail.com>
>> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
>> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> Hi Gustav,
>> 
>> > I like the idea of a function that would symbolically links folders
>> > from "ID"-folder structure to a hierarchy-folder structure, based on
>> > the name and path of the org-file  and its headings containing the
>> > links. I probably wouldn't use it much myself though. Not until
>> > org-mode starts working better with multiple files, allowing us to
>> > more easily define "org-mode libraries".
>> 
>> I am wondering what you mean by "org-mode libraries". Can you explain
>> further?
>
> This goes a bit off topic; But what I mean is mainly two things: 
> 1) Generalize the org-agenda so that we can have multiple ones
>
>    Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas.
>
> 2) Make files function as virtual "level-0 headings"
>
>    If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well.
>
>> 
>> Also, another thought about the attachment: links.
>> It would be useful to implement links to attachments, which are not in the
>> current org entry.
>> For example, something like "attachment:ORG-ID:file-name", where ORG-ID
>> refers to ID of an arbitrary org entry.
>
> I wouldn't call that attachment-links, but rather ID-based links (since attachments are local based on either headline ID or attach-dir of the current headline). ID links exist already but link to headlines. 
>
> If you rather see ID-based attachments as some kind of global attachments for all your org-mode files, I'd think the link-type should reflect that and be called something like "ID-attachment:file-name", "ID-@:file-name", "@ID:file-name" and be a separate link-type.
>
>> 
>> Best,
>> Ihor
>> 
>> 
>
> Kind regards
> Gustav


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-20 14:00             ` Ihor Radchenko
@ 2018-11-24 13:56               ` Gustav Wikström
  2018-12-14  2:16                 ` Ihor Radchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-24 13:56 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: Ihor Radchenko <yantar92@gmail.com>
> Sent: den 20 november 2018 15:01
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> Hi,
> 
> >    Generalize org-agenda by allowing us to have multiple ones, and make
> them more general by thinking of them as a set of views that works on sets
> of files. Maybe this is not for all, but I would appreciate to create
> multiple "agendas" (even though I'd call them "libraries" in instead), and
> possibly also an aggregate agenda consisting of other agendas.
> 
> Isn't this already in org? You can use custom agendas with multiple
> "agendas" (custom commands) and set the files they operate on with org-
> agenda-files within custom commands.

No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. 

> 
> >    If two org-mode files exist in the same folder with different names, it
> would be awesome to think of (and work with) them as two top-level headings
> inside one org-mode buffer. Similar to two level-1 headings inside an org-
> mode file. For this to work all properties we can define for regular
> headings should be possible to define for these "level-0 headings". For
> example an attachment-folder or ID, a deadline, scheduled date, or TODO-
> keyword should in that case be configurable on the whole file. I guess some
> new conventions regarding syntax and existing properties would have to be
> created as well.
> 
> You can do something like below. It is pretty much what you want, except I
> am not sure how to update the headings from local org files. Current org
> version does not allow `:results replace` on raw org output.
> 
> * Main heading
> 
> #+name: org-files-here
> #+begin_src bash
> ls *.org
> #+end_src
> 
> #+begin_src emacs-lisp :var files=org-files-here()  :var stars=(make-string
> (car (org-heading-components)) ?*)  :results raw replace drawer (let ((files
> (mapcar #'car files)))
>   (cl-loop for file in files
> 	   concat (with-current-buffer (find-file-noselect file)
> 		    (concat (format "* %s\n" (buffer-file-name))
> 			    (replace-regexp-in-string "^\\*" (concat "*" stars)
> (buffer-string)))))) #+end_src

No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept.

Thanks for your idea and suggestion though!

> 
> Best,
> Ihor

Kind Regards,
Gustav


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2018-11-19 23:52       ` Nicolas Goaziou
@ 2018-11-25 21:13         ` Gustav Wikström
  2018-11-27  9:39           ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2018-11-25 21:13 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 18838 bytes --]

Hi again,

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 20 november 2018 00:52
> To: Gustav Wikström <gustav@whil.se>
> Cc: Org Mode List <emacs-orgmode@gnu.org>
> Subject: Re: [RFC] Link-type for attachments, more attach options
> 
> > Yeah - I liked "attached" because I prefer clear keywords. But sure,
> > we can keep it shorter. I'd suggest "@" instead in that case. Patch
> > updated with that.
> 
> "@" syntax is a reserved syntax for citations in the "wip-cite" branch.
> I'd rather not use it here. Also, years ago, "att" link type was used to
> link to attachments, hence my proposal.

Too bad, "@" was growing on me. @ is currently automatically set as a tag when attaching files to nodes. So it was fitting to use it also in links in my opinion. Is the cite-syntax the same as the regular link-pattern? [[@: ...]] ? Otherwise I'd suggest them to coexist. Or to change the cite-symbol to ... "c" maybe? @ is a pretty standard symbol for attachments. Just have a look at Gmail, Outlook etc.

I didn't change this in the attached patch. I'm hoping for second thoughts! :) The future ease of use (i.e. clarity and standardization of symbols in this case) should have precedence over current work in progress...

> >> > When working with ATTACH_DIR there are now a couple of new options available:
> >> > - org-attach-dir-inherit-by-default
> >>
> >> What is the difference between this and
> >> `org-attach-allow-inheritance'?
> 
> You didn't answer this question, did you?

No, seems I missed it. 

> Something is fishy here anyways. Why is "ATTACH_DIR_INHERIT" needed at
> all? If `org-attach-allow-inheritance', "ATTACH_DIR" should be
> inherited. Why depend on another property?

Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not sure of what way to go forward though. I can see at least two paths:

1) Rename `org-attach-allow-inheritance' to `org-attach-enable-inheritance' and always make attachments inherited when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd also change the precedence-logic between ATTACH_DIR & ID properties and make ID-based attachment inherit as well. The properties ATTACH_DIR and ID should be inherited from the closest node when resolving attachments, with ATTACH_DIR having precedence over ID if both exist for the same node.

2) remove `org-attach-allow-inheritance' and only rely on the "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if the "ATTACH_DIR" property should be inherited. This would be a smaller change from the user's perspective, where we're basically saying you cannot disable inheritance, but it's only active when a node has the ATTACH_DIR_INHERIT-property.

I prefer path (1). That would be a great default. But that change is bigger and should be separated from this patch anyways. To not increase the complexity I've removed the `org-attach-dir-inherit-by-default' customization.

> >> > - org-attach-dir-create-if-not-exist
> >>
> >> What is the use-case for this one? It doesn't seem terribly useful at
> >> first glance.
> >
> > If you try to open attachments on a node where there is no ID or
> >> ATTACH_DIR, the default behavior is to add an ID and create a folder
> >> based on that ID. I would like Org-mode to not do that. This
> >> customization give the user the option to change that. Instead of
> >> providing this customization one could just change the default
> >> behavior of org-attach, since it's a bit offensive to create folders
> >> when I didn't ask for it. But instead of changing the default,
> >> I thought this way was more graceful. I wouldn't mind skipping this
> >> customization though, if the behavior was changed to what
> >> I implemented with org-attach-dir-create-if-not-exist set to nil.
> 
> Considering attaching is about moving, or copying files somewhere,
> creating a folder doesn't sound terribly offensive. You don't even have
> to know the name of the folder.
> 
> Do you suggest to raise an error if there is no folder available for the
> attached documents? If so, wouldn't it be better to ask the user first?

Agreed, the parameter can be removed and a "do you want to create a folder?" question could be raised instead, when it's not intuitive for the program to create the folder by itself.

> >> > +This list shows the full set of built-in external link types:
> >> > +| http       | web                                 |
> >> > +| https      | secure web                          |
> >> > +| doi        | DOI for electronic resources        |
> >> > +| file       | file-links                          |
> >> > +| file+sys   | file-links forced to open via OS    |
> >> > +| file+emacs | file-links forced to open via emacs |
> >> > +| attached   | links to attachments for nodes      |
> >> > +| docview    | doc-view mode                       |
> >> > +| id         | Link to heading by id               |
> >> > +| news       | Usenet link                         |
> >> > +| mailto     | mail link                           |
> >> > +| mhe        | MH-E folder link                    |
> >> > +| rmail      | Rmail link                          |
> >> > +| gnus       | Gnus link                           |
> >> > +| bbdb       | BBDB link                           |
> >> > +| irc        | IRC link                            |
> >> > +| info       | Info link                           |
> >> > +| shell      | shell command                       |
> >> > +| elisp      | interactive elisp command link      |
> >> > +
> >> > +The following list shows examples for each link type.
> >> > +
> >> > +| =http://www.astro.uva.nl/=dominik=        | on the web                          |
> >> > +| =doi:10.1000/182=                         | DOI for an electronic resource      |
> >> > +| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path                 |
> >> > +| =/home/dominik/images/jupiter.jpg=        | same as above                       |
> >> > +| =file:papers/last.pdf=                    | file, relative path                 |
> >> > +| =./papers/last.pdf=                       | same as above                       |
> >> > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine        |
> >> > +| =/ssh:me@some.where:papers/last.pdf=      | same as above                       |
> >> > +| =file:sometextfile::NNN=                  | file, jump to line number           |
> >> > +| =file:projects.org=                       | another Org file                    |
> >> > +| =file:projects.org::some words=           | text search in Org file[fn:28]      |
> >> > +| =file:projects.org::*task title=          | heading search in Org file          |
> >> > +| =file+sys:/path/to/file=                  | open via OS, like double-click      |
> >> > +| =file+emacs:/path/to/file=                | force opening by Emacs              |
> >> > +| =attached:projects.org=                   | file in folder attached to headline |
> >> > +| =attached:projects.org::some words=       | text search in attached file        |
> >> > +| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page       |
> >> > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID               |
> >> > +| =news:comp.emacs=                         | Usenet link                         |
> >> > +| =mailto:adent@galaxy.net=                 | mail link                           |
> >> > +| =mhe:folder=                              | MH-E folder link                    |
> >> > +| =mhe:folder#id=                           | MH-E message link                   |
> >> > +| =rmail:folder=                            | Rmail folder link                   |
> >> > +| =rmail:folder#id=                         | Rmail message link                  |
> >> > +| =gnus:group=                              | Gnus group link                     |
> >> > +| =gnus:group#id=                           | Gnus article link                   |
> >> > +| =bbdb:R.*Stallman=                        | BBDB link (with regexp)             |
> >> > +| =irc:/irc.com/#emacs/bob=                 | IRC link                            |
> >> > +| =info:org#External links=                 | Info node link                      |
> >> > +| =shell:ls *.org=                          | shell command                       |
> >> > +| =elisp:org-agenda=                        | interactive Elisp command           |
> >> > +| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate              |
> >>
> >> I'm not sure to like the change above. It introduces a lot of
> >> redundancy.
> >>
> >
> > Currently the list in the documentation is just a bunch of examples.
> >> I've looked at it a couple of times asking myself "What is the
> >> complete list of built in link types?". This commit "fixes" that.
> >> I wouldn't say its redundant since all the rows in the second list
> >> are just examples.
> 
> It is still redundant. For example, the first table has
> 
>  | info | Info link |
> 
> whereas the second one tells us
> 
>  | info:org#External links | Info node link |
> 
> In this case,
> 
>  | Info link | info:org#External links |
> 
> would be sufficient enough. I have the feeling documentation can be
> improved here.

The problem I had with the second list is that it's just a list of examples. Nowhere does it say it's the complete list of commands. Anyways, I've tried to merge the two lists. Hope you'll find it more to your liking.

> 
> Also, file+sys and file+emacs are deprecated. They can be removed.

Ok, removed.

> 
> > I can't say I understand the use of :safe here. But added it anyways.
> > If you care, please explain why it's needed. Package-version is added.
> > I set it to 9.2. Correct?
> 
> If :safe is not set, Emacs will warn every time the variable is set as
> a local file variable.

Ok

> 
> It should be 9.3, not 9.2.

Ok, fixed

> 
> >> > +(defun org-attach-open-link (link &optional in-emacs)
> >> > +  "LINK is expanded with the attached directory and opened the same
> >> > +way as file-links are."
> >>
> >> You need to expound the arguments in the docstring.
> >
> > Sorry, I don't understand what I'm supposed to do here... I changed
> > the comment to (maybe?) make it read better. Other than that, I'm at
> > a loss.
> 
> Every argument needs to be documented in the docstring. What is LINK
> type? What is IN-EMACS?

Ok, got it.
> 
> >> > +	    (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)"
> >> >  				   (if (not link-abbrevs) ""
> >> >  				     (format "\\|\\(?:%s:\\)"
> >> >  					     (regexp-opt link-abbrevs))))))
> >>
> >> Why is it needed? "attached" link type is already registered, so you
> >> don't need to also hard-code it here.
> >
> > This is when parsing the buffer for images. I couldn't get org-mode to
> > display images without this.
> 
> This is still a hack, and clearly not the way to go, IMO. If not already
> possible, we could add a new parameter in `org-link-parameters' or some
> such. This is another issue, tho.

Ok, sure. Although to be fair it's an existing hack, which was expanded just a tiny bit. Removed anyways.
> 
> > +(defcustom org-attach-dir-create-if-not-exists t
> > +  "Choose whether ATTACH_DIR-directories should be created if they do
> > not exist since before.
> 
> Too long. Maybe:
> 
> When non-nil, ATTACH_DIR is created automatically if it doesn't exist.
> Otherwise, ...
> 
> > +Default is to create them."
> > +  :group 'org-attach
> > +  :type 'boolean
> > +  :package-version '(Org . "9.2")
> > +  :safe #'booleanp)
> > +
> > +(defcustom org-attach-dir-relative nil
> > +  "Choose whether ATTACH_DIR-directories should be added as relative links or not.
> 
> Too long. Maybe something like:
> 
> Non-nil means ATTACH_DIR is relative to the attachment node directory.
> 
> > +Defaults to not relative."
> 
> Defaults to absolute location.

Yeah, that's better. Fixed.

> 
> > +  (let ((old (org-attach-dir nil))
> > +	(new
> > +	 (progn
> > +	   (if arg (org-entry-delete nil "ATTACH_DIR")
> > +	     (let* ((attach-dir (read-directory-name
> > +				 "Attachment directory: "
> > +				 (org-entry-get nil
> > +						"ATTACH_DIR")))
> > +		    (current-dir (file-name-directory (or default-directory
> > +							  buffer-file-name)))
> > +		    (attach-dir-relative (file-relative-name attach-dir current-dir)))
> > +	       (if org-attach-dir-relative
> > +		   (org-entry-put nil "ATTACH_DIR" attach-dir-relative)
> > +		 (org-entry-put nil "ATTACH_DIR" attach-dir))))
> 
> (org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative
>                                     attach-dir-relative
>                                   attach-dir))

Yeah, that's nicer. Changed.

> 
> > +(defun org-attach-open-link (link &optional in-emacs)
> > +  "Attach link type LINK is expanded with the attached directory and opened.
> > +This is done in the same way as file-links are opened."
> > +  (interactive "P")
> > +  (let (line search)
> > +    (if (string-match "::\\([0-9]+\\)\\'" link)
> > +        (setq line (string-to-number (match-string 1 link))
> > +              link (substring link 0 (match-beginning 0)))
> > +      (if (string-match "::\\(.+\\)\\'" link)
> > +          (setq search (match-string 1 link)
> > +                link (substring link 0 (match-beginning 0)))))
> 
> Use `cond' instead.

Ok.

> 
> > +    (if (string-match "[*?{]" (file-name-nondirectory link))
> > +        (dired (org-attach-expand link))
> > +      (org-open-file (org-attach-expand link) in-emacs line search))))
> > +
> > +(defun org-attach-complete-link ()
> > +  "Advise the user with the available files in the attachment directory."
> > +  (let (file link attached-dir)
> > +    (setq attached-dir (expand-file-name (org-attach-dir)))
> > +    (setq file (read-file-name "File: " attached-dir))
> > +    (let ((pwd (file-name-as-directory attached-dir))
> > +          (pwd1 (file-name-as-directory (abbreviate-file-name
> > +                                         attached-dir))))
> > +      (cond
> > +       ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file)
> > +        (setq link  (concat "@:" (match-string 1 file))))
> > +       ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
> > +                      (expand-file-name file))
> > +        (setq link  (concat
> > +                     "@:" (match-string 1 (expand-file-name file)))))
> > +       (t (setq link (concat "@:" file)))))
> > +    link))
> 
> I suggest:
> 
>   (let* ((attached-dir (expand-file-name (org-attach-dir)))
>          (file (read-file-name "File: " attached-dir))
>          (pwd (file-name-as-directory attached-dir))
>          (pwd-relative (file-name-as-directory
>                         (abbreviate-file-name attached-dir))))
>    (cond
>     ((string-match ...)
>      (concat ...))
>     ...
>     (t (concat ...))))

Yeah, clearly an improvement.

> 
> > +(defun org-attach-export-link (link description format)
> > +  "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT.
> > +Also includes the DESCRIPTION of the link in the export."
> > +  (save-excursion
> > +    (let (path desc)
> > +      (if (string-match "::\\([0-9]+\\)\\'" link)
> > +          (setq link (substring link 0 (match-beginning 0)))
> > +        (if (string-match "::\\(.+\\)\\'" link)
> > +            (setq link (substring link 0 (match-beginning 0)))))
> 
> Use `cond' instead.

Ok.

> 
> > +      (search-forward (concat "@:" (org-link-escape link)))
> 
> What is the use for the line above?

Hmm, good question. Looking through my commit history I find no reason to justify it... I wonder how that got there. Effectively, I guess that row does nothing except stealing a few CPU-cycles... Removed. 

> > diff --git a/lisp/org.el b/lisp/org.el
> > index eb1affbc7..9ed663bb9 100644
> > --- a/lisp/org.el
> > +++ b/lisp/org.el
> > @@ -4428,6 +4428,7 @@ This is needed for font-lock setup.")
> >  		  (beg end))
> >  (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
> >  (declare-function org-agenda-skip "org-agenda" ())
> > +(declare-function org-attach-expand "org-attach" (&optional if-exists))
> >  (declare-function org-attach-reveal "org-attach" (&optional if-exists))
> >  (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
> >  (declare-function org-indent-mode "org-indent" (&optional arg))
> > @@ -18721,7 +18722,7 @@ boundaries."
> >  	    ;; Check absolute, relative file names and explicit
> >  	    ;; "file:" links.  Also check link abbreviations since
> >  	    ;; some might expand to "file" links.
> > -	    (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)"
> > +	    (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)"
> >  				   (if (not link-abbrevs) ""
> >  				     (format "\\|\\(?:%s:\\)"
> >  					     (regexp-opt link-abbrevs))))))
> > @@ -18730,14 +18731,20 @@ boundaries."
> >  	   ;; Check if we're at an inline image, i.e., an image file
> >  	   ;; link without a description (unless INCLUDE-LINKED is
> >  	   ;; non-nil).
> > -	   (when (and (equal "file" (org-element-property :type link))
> > +	   (when (and (or (equal "file" (org-element-property :type link))
> > +                          (equal "@" (org-element-property :type link)))
> >  		      (or include-linked
> >  			  (null (org-element-contents link)))
> >  		      (string-match-p file-extension-re
> >  				      (org-element-property :path link)))
> > -	     (let ((file (expand-file-name
> > -			  (org-link-unescape
> > -			   (org-element-property :path link)))))
> > +	     (let ((file (if (equal "@" (org-element-property :type link))
> > +			     (require 'org-attach)
> > +                             (org-attach-expand
> > +                              (org-link-unescape
> > +			       (org-element-property :path link)))
> > +			   (expand-file-name
> > +			    (org-link-unescape
> > +			     (org-element-property :path link))))))
> >  	       (when (file-exists-p file)
> >  		 (let ((width
> >  			;; Apply `org-image-actual-width' specifications.
> 
> This part can be omitted for now. Something better has to be found.

Ok, sure. I'll keep it on my local branch but it's omitted from the patch.

> 
> Thank you.
> 
> Regards,
> 
> --
> Nicolas Goaziou

New patch attached updated according to the comments.

Regards,
Gustav

[-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-new-option.patch --]
[-- Type: application/octet-stream, Size: 20080 bytes --]

From 88e23fd0d7bf8321dc5ea8e396a97500b1035b73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com>
Date: Sun, 25 Nov 2018 21:38:44 +0100
Subject: [PATCH] org-attach, org-manual, org: New link-type, new option

* Add new linktype "@" for attachments

A new linktype "@" is added in order to reduce link-duplication when
wanting to link to files in attached folders of nodes.  This works for
both ID-based attachments and ATTACH_DIR.  The goal is to make the
functionality for attached-links mirror file-links.

* Add further options for ATTACH_DIR

When working with ATTACH_DIR there are now a new option available:
- org-attach-dir-relative

With that option set to t ATTACH_DIR is stored as relative to the
file-location.

* Documentation in org-manual

Org-manual is updated with the new link-type as well as some minor
cleanup in the documentation related to external links and attachments.
---
 doc/org-manual.org | 114 ++++++++++++++++++++-----------------
 lisp/org-attach.el | 137 ++++++++++++++++++++++++++++++++++++---------
 2 files changed, 172 insertions(+), 79 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 5e4effb6f..0b626a1a8 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3141,6 +3141,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: @ links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3152,38 +3153,43 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
-
-| =http://www.astro.uva.nl/=dominik=        | on the web                     |
-| =doi:10.1000/182=                         | DOI for an electronic resource |
-| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
-| =/home/dominik/images/jupiter.jpg=        | same as above                  |
-| =file:papers/last.pdf=                    | file, relative path            |
-| =./papers/last.pdf=                       | same as above                  |
-| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
-| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
-| =file:sometextfile::NNN=                  | file, jump to line number      |
-| =file:projects.org=                       | another Org file               |
-| =file:projects.org::some words=           | text search in Org file[fn:28] |
-| =file:projects.org::*task title=          | heading search in Org file     |
-| =file+sys:/path/to/file=                  | open via OS, like double-click |
-| =file+emacs:/path/to/file=                | force opening by Emacs         |
-| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
-| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
-| =news:comp.emacs=                         | Usenet link                    |
-| =mailto:adent@galaxy.net=                 | mail link                      |
-| =mhe:folder=                              | MH-E folder link               |
-| =mhe:folder#id=                           | MH-E message link              |
-| =rmail:folder=                            | Rmail folder link              |
-| =rmail:folder#id=                         | Rmail message link             |
-| =gnus:group=                              | Gnus group link                |
-| =gnus:group#id=                           | Gnus article link              |
-| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
-| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
-| =info:org#External links=                 | Info node link                 |
-| =shell:ls *.org=                          | shell command                  |
-| =elisp:org-agenda=                        | interactive Elisp command      |
-| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
+the colon.
+
+This list shows the full set of built-in external link types,
+including examples for each:
+
+| Link Type | Description                  | Example                                               |
+|-----------+------------------------------+-------------------------------------------------------|
+| http      | web                          | =http://www.astro.uva.nl/=dominik=                    |
+| https     | secure web                   | =https://orgmode.org/=                                |
+| doi       | DOI for electronic resources | =doi:10.1000/182=                                     |
+| file      | file-links                   | =file:/home/dominik/images/jupiter.jpg=               |
+|           |                              | =/home/dominik/images/jupiter.jpg= (same as above)    |
+|           |                              | =file:papers/last.pdf=                                |
+|           |                              | =./papers/last.pdf= (same as above)                   |
+|           |                              | =file:/ssh:me@some.where:papers/last.pdf= (remote)    |
+|           |                              | =/ssh:me@some.where:papers/last.pdf= (same as above)  |
+|           |                              | =file:sometextfile::NNN= (jump to line number)        |
+|           |                              | =file:projects.org=                                   |
+|           |                              | =file:projects.org::some words= (text search) [fn:28] |
+|           |                              | =file:projects.org::*task title= (headline search)    |
+| @         | links to attachments         | =@:projects.org=                                      |
+|           |                              | =@:projects.org::some words= (text search)            |
+| docview   | doc-view mode                | =docview:papers/last.pdf::NNN=                        |
+| id        | Link to heading by id        | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=             |
+| news      | Usenet link                  | =news:comp.emacs=                                     |
+| mailto    | mail link                    | =mailto:adent@galaxy.net=                             |
+| mhe       | MH-E folder link             | =mhe:folder= (folder link)                            |
+|           |                              | =mhe:folder#id= (message link)                        |
+| rmail     | Rmail link                   | =rmail:folder= (folder link)                          |
+|           |                              | =rmail:folder#id= (message link)                      |
+| gnus      | Gnus link                    | =gnus:group= (group link)                             |
+|           |                              | =gnus:group#id= (article link)                        |
+| bbdb      | BBDB link                    | =bbdb:R.*Stallman= (link with regexp)                 |
+| irc       | IRC link                     | =irc:/irc.com/#emacs/bob=                             |
+| info      | Info link                    | =info:org#External links=                             |
+| shell     | shell command                | =shell:ls *.org=                                      |
+| elisp     | interactive elisp command    | =elisp:(find-file "Elisp.org")=                       |
 
 #+cindex: VM links
 #+cindex: Wanderlust links
@@ -3538,14 +3544,15 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: @ links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:35].  For
-example, when the command ~org-store-link~ creates a link (see
-[[*Handling Links]]) to a file, it encodes the words in the current line
-as a search string that can be used to find this line back later when
-following the link with {{{kbd(C-c C-o)}}}.
+File links and attached (@) links can contain additional information
+to make Emacs jump to a particular location in the file when following
+a link.  This can be a line number or a search option after a double
+colon[fn:35].  For example, when the command ~org-store-link~ creates
+a link (see [[*Handling Links]]) to a file, it encodes the words in the
+current line as a search string that can be used to find this line
+back later when following the link with {{{kbd(C-c C-o)}}}.
 
 Here is the syntax of the different ways to attach a search to a file
 link, together with explanations for each:
@@ -3556,6 +3563,7 @@ link, together with explanations for each:
 [[file:~/xx.org::*My Target]]
 [[file:~/xx.org::#my-custom-id]]
 [[file:~/xx.org::/regexp/]]
+[[@:~/code/main.c::255]]
 #+end_example
 
 - =255= ::
@@ -7533,18 +7541,22 @@ node/task.  Small chunks of plain text can simply be stored in the
 subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
 associations with files that live elsewhere on your computer or in the
 cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-~data~ directory which lives in the same directory where your Org file
-lives[fn:86].  If you initialize this directory with =git init=, Org
-automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by the unique ID of each entry, or by the =ATTACH_DIR= property.
+ID-based directories are by default located in the =data/= directory,
+which lives in the same directory where your Org file lives[fn:86].
+If you initialize this directory with =git init=, Org automatically
+commits changes when it sees them.  The attachment system has been
+contributed to Org by John Wiegley.
+
+In cases where =ATTACH_DIR= property is used to declare attachments,
+you can choose to either use absolute (default) or relative links.
+You can also make children inherit the attachment directory from a
+parent, so that an entire subtree uses the same attached directory.
+
+See customization group =Org Attach= if you want to change the default
+settings for attachments.
 
 The following commands deal with attachments:
 
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index e827d3721..4054a8044 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -57,6 +57,14 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
+(defcustom org-attach-dir-relative nil
+  "Choose whether ATTACH_DIR-directories should be added as relative links or not.
+Defaults to absolute location."
+  :group 'org-attach
+  :type 'boolean
+  :package-version '(Org . "9.3")
+  :safe #'booleanp)
+
 (defcustom org-attach-commit t
   "If non-nil commit attachments with git.
 This is only done if the Org file is in a git repository."
@@ -224,14 +232,18 @@ i       Make children of the current entry inherit its attachment directory.")))
 			      'org-attach-set-inherit))
        (t (error "No such attachment command %c" c))))))
 
-(defun org-attach-dir (&optional create-if-not-exists-p)
+(defun org-attach-dir (&optional create-if-not-exists-p verify-create-p)
   "Return the directory associated with the current entry.
 This first checks for a local property ATTACH_DIR, and then for an inherited
 property ATTACH_DIR_INHERIT.  If neither exists, the default mechanism
 using the entry ID will be invoked to access the unique directory for the
 current entry.
+
 If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil,
-the directory and (if necessary) the corresponding ID will be created."
+the directory and (if necessary) the corresponding ID will be created.
+
+If VERIFY-CREATE is non-nil, ask for verification from the user
+before directory is created."
   (let (attach-dir uuid)
     (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT"))
     (cond
@@ -245,7 +257,7 @@ the directory and (if necessary) the corresponding ID will be created."
 		 (goto-char org-entry-property-inherited-from)
 	       (org-back-to-heading t))
 	     (let (org-attach-allow-inheritance)
-	       (org-attach-dir create-if-not-exists-p))))
+	       (org-attach-dir create-if-not-exists-p verify-create-p))))
       (org-attach-check-absolute-path attach-dir)
       (setq org-attach-inherited t))
      (t					; use the ID
@@ -260,7 +272,10 @@ the directory and (if necessary) the corresponding ID will be created."
 			  (expand-file-name org-attach-directory))))))
     (when attach-dir
       (if (and create-if-not-exists-p
-	       (not (file-directory-p attach-dir)))
+	       (not (file-directory-p attach-dir))
+	       (if verify-create-p
+		   (yes-or-no-p "Create attachment directory?")
+		 t))
 	  (make-directory attach-dir t))
       (and (file-exists-p attach-dir)
 	   attach-dir))))
@@ -280,20 +295,24 @@ Throw an error if we cannot root the directory."
   "Set the ATTACH_DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
 of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
+the directory to the default ID based one.  Creates relative
+links if ORG-ATTACH-DIR-RELATIVE is t."
   (interactive "P")
   (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+	(new
+	 (progn
+	   (if arg (org-entry-delete nil "ATTACH_DIR")
+	     (let* ((attach-dir (read-directory-name
+				 "Attachment directory: "
+				 (org-entry-get nil
+						"ATTACH_DIR")))
+		    (current-dir (file-name-directory (or default-directory
+							  buffer-file-name)))
+		    (attach-dir-relative (file-relative-name attach-dir current-dir)))
+	       (org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative
+						   attach-dir-relative
+						 attach-dir))))
+	   (org-attach-dir t))))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
@@ -527,14 +546,14 @@ This ignores files ending in \"~\"."
   "Show the attachment directory of the current task.
 This will attempt to use an external program to show the directory."
   (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
+  (let ((attach-dir (org-attach-dir (not if-exists) t)))
     (and attach-dir (org-open-file attach-dir))))
 
 (defun org-attach-reveal-in-emacs ()
   "Show the attachment directory of the current task in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir t t)))
+    (when attach-dir (dired attach-dir))))
 
 (defun org-attach-open (&optional in-emacs)
   "Open an attachment of the current task.
@@ -543,15 +562,17 @@ This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir t t)))
+    (if attach-dir
+	(let* ((files (org-attach-file-list attach-dir))
+	       (file (if (= (length files) 1)
+			 (car files)
+		       (completing-read "Open attachment: "
+					(mapcar #'list files) nil t)))
+	       (path (expand-file-name file attach-dir)))
+	  (org-attach-annex-get-maybe path)
+	  (org-open-file path in-emacs))
+      (message "No attachment exist!"))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -570,6 +591,66 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(defun org-attach-open-link (link &optional in-emacs)
+  "Attach link type LINK is expanded with the attached directory and opened.
+
+With optional prefix argument IN-EMACS, Emacs will visit the file.
+With a double \\[universal-argument] \\[universal-argument] \
+prefix arg, Org tries to avoid opening in Emacs
+and to use an external application to visit the file."
+  (interactive "P")
+  (let (line search)
+    (cond
+     ((string-match "::\\([0-9]+\\)\\'" link)
+      (setq line (string-to-number (match-string 1 link))
+	    link (substring link 0 (match-beginning 0))))
+     ((string-match "::\\(.+\\)\\'" link)
+      (setq search (match-string 1 link)
+            link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment directory."
+  (let* ((attached-dir (expand-file-name (org-attach-dir)))
+	 (file (read-file-name "File: " attached-dir))
+	 (pwd (file-name-as-directory attached-dir))
+         (pwd-relative (file-name-as-directory
+			(abbreviate-file-name attached-dir))))
+    (cond
+     ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file)
+      (concat "@:" (match-string 1 file)))
+     ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+                    (expand-file-name file))
+      (concat "@:" (match-string 1 (expand-file-name file))))
+     (t (concat "@:" file)))))
+
+(defun org-attach-export-link (link description format)
+  "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT.
+Also includes the DESCRIPTION of the link in the export."
+  (save-excursion
+    (let (path desc)
+      (cond
+       ((string-match "::\\([0-9]+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0))))
+       ((string-match "::\\(.+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0)))))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
+(org-link-set-parameters "@"
+                         :follow 'org-attach-open-link
+                         :export 'org-attach-export-link
+                         :complete 'org-attach-complete-link)
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
-- 
2.19.1.windows.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2018-11-25 21:13         ` Gustav Wikström
@ 2018-11-27  9:39           ` Nicolas Goaziou
  2019-05-26 23:05             ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2018-11-27  9:39 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Too bad, "@" was growing on me. @ is currently automatically set as
> a tag when attaching files to nodes.

You probably customized `org-attach-auto-tag' because this is not the
default behaviour. It adds "ATTACH" tag automatically.

> So it was fitting to use it also
> in links in my opinion. Is the cite-syntax the same as the regular
> link-pattern? [[@: ...]] ?

It could be [@...], which is close enough to be confusing.

Moreover, all default link types currently use alphabetic characters.
Using a symbol here would be weird.

> Otherwise I'd suggest them to coexist. Or
> to change the cite-symbol to ... "c" maybe?

"@" is used for the citation key. Using a letter could interfere with
the key itself: @key vs. ckey.

> @ is a pretty standard symbol for attachments. Just have a look at
> Gmail, Outlook etc.

I prefer not to consider Gmail and Outlook as references, or even
standards. As another data point, Gnus uses "Attachment: " to list
attachments.

> I didn't change this in the attached patch. I'm hoping for second
> thoughts! :) The future ease of use (i.e. clarity and standardization
> of symbols in this case) should have precedence over current work in
> progress...

The citation syntax was discussed, and implemented, years ago. Also,
some external libraries apparently rely on it.

I still vote for "att", or "attachment".

> Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not sure of what way to go forward though. I can see at least two paths:
>
> 1) Rename `org-attach-allow-inheritance' to
> `org-attach-enable-inheritance' and always make attachments inherited
> when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd
> also change the precedence-logic between ATTACH_DIR & ID properties
> and make ID-based attachment inherit as well. The properties
> ATTACH_DIR and ID should be inherited from the closest node when
> resolving attachments, with ATTACH_DIR having precedence over ID if
> both exist for the same node.

Why defining `org-attach-enable-inheritance' at all? There is already
`org-use-property-inheritance' for this. We do not need another
conflicting variable.

I don't think we should inherit ID properties either. ID is defined
outside "org-attach.el", so this library shouldn't mess with its
meaning. Does inheriting ID properties give anything valuable?

> 2) remove `org-attach-allow-inheritance' and only rely on the
> "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if
> the "ATTACH_DIR" property should be inherited. This would be a smaller
> change from the user's perspective, where we're basically saying you
> cannot disable inheritance, but it's only active when a node has the
> ATTACH_DIR_INHERIT-property.
>
> I prefer path (1). 

So do I, with the remarks above.

> +This list shows the full set of built-in external link types,
> +including examples for each:
> +
> +| Link Type | Description                  | Example                                               |
> +|-----------+------------------------------+-------------------------------------------------------|
> +| http      | web                          | =http://www.astro.uva.nl/=dominik=                    |
> +| https     | secure web                   | =https://orgmode.org/=                                |
> +| doi       | DOI for electronic resources | =doi:10.1000/182=                                     |
> +| file      | file-links                   | =file:/home/dominik/images/jupiter.jpg=               |
> +|           |                              | =/home/dominik/images/jupiter.jpg= (same as above)    |
> +|           |                              | =file:papers/last.pdf=                                |
> +|           |                              | =./papers/last.pdf= (same as above)                   |
> +|           |                              | =file:/ssh:me@some.where:papers/last.pdf= (remote)    |
> +|           |                              | =/ssh:me@some.where:papers/last.pdf= (same as above)  |
> +|           |                              | =file:sometextfile::NNN= (jump to line number)        |
> +|           |                              | =file:projects.org=                                   |
> +|           |                              | =file:projects.org::some words= (text search) [fn:28] |
> +|           |                              | =file:projects.org::*task title= (headline search)    |
> +| @         | links to attachments         | =@:projects.org=                                      |
> +|           |                              | =@:projects.org::some words= (text search)            |
> +| docview   | doc-view mode                | =docview:papers/last.pdf::NNN=                        |
> +| id        | Link to heading by id        | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=             |
> +| news      | Usenet link                  | =news:comp.emacs=                                     |
> +| mailto    | mail link                    | =mailto:adent@galaxy.net=                             |
> +| mhe       | MH-E folder link             | =mhe:folder= (folder link)                            |
> +|           |                              | =mhe:folder#id= (message link)                        |
> +| rmail     | Rmail link                   | =rmail:folder= (folder link)                          |
> +|           |                              | =rmail:folder#id= (message link)                      |
> +| gnus      | Gnus link                    | =gnus:group= (group link)                             |
> +|           |                              | =gnus:group#id= (article link)                        |
> +| bbdb      | BBDB link                    | =bbdb:R.*Stallman= (link with regexp)                 |
> +| irc       | IRC link                     | =irc:/irc.com/#emacs/bob=                             |
> +| info      | Info link                    | =info:org#External links=                             |
> +| shell     | shell command                | =shell:ls *.org=                                      |
> +| elisp     | interactive elisp command    | =elisp:(find-file "Elisp.org")=                       |

The second column still doesn't bring much information compared to the
first one. Getting back to your first idea, we may try to do something
like the following:

--8<---------------cut here---------------start------------->8---
Here is the full set of built-in link types.

- =file= :: File links. File name may be remote, absolute, or relative.

  Additionally, you can specify a line number, or a text search.  In Org
  files, you may link to a headline name, a custom ID, or a code
  reference instead.

  As a special case, "file" prefix may be omitted if the file name is
  complete, e.g., it starts with =./=, or =/=.

- =att= :: Same as file links, but for attached documents to the current
  node (see [[*Attachments]]).

- =bbdb= :: Link to a BBDB record, with possible regexp completion.

- =docview= :: Link to a document opened with DocView mode.  You may
  specify a page number.

- =doi= :: Link to an electronic ressource, through its handle.

- =elisp= :: Execute an Elisp command upon activation.

- =gnus=, =rmail=, =mhe= :: Links to messages or folders from a given
  Emacs' MUA.

- =http=, =https= :: Web links.

- =id= :: Link to a specific headline by its ID property, in an Org
  file.

- =info= :: Link to an Info manual, or to a specific node.

- =irc= :: Link to an IRC channel.

- =mailto= :: Link to message composition.

- =news= :: Usenet links.

- =shell= :: Execute a shell command upon activation.

The following table illustrates the link types above, along with their
options:

| Link Type | Example                                               |
|-----------+-------------------------------------------------------|
| http      | =http://www.astro.uva.nl/=dominik=                    |
| https     | =https://orgmode.org/=                                |
| doi       | =doi:10.1000/182=                                     |
| file      | =file:/home/dominik/images/jupiter.jpg=               |
|           | =/home/dominik/images/jupiter.jpg= (same as above)    |
|           | =file:papers/last.pdf=                                |
|           | =./papers/last.pdf= (same as above)                   |
|           | =file:/ssh:me@some.where:papers/last.pdf= (remote)    |
|           | =/ssh:me@some.where:papers/last.pdf= (same as above)  |
|           | =file:sometextfile::NNN= (jump to line number)        |
|           | =file:projects.org=                                   |
|           | =file:projects.org::some words= (text search) [fn:28] |
|           | =file:projects.org::*task title= (headline search)    |
|           | =file:projects.org::#custom-id= (headline search)     |
| att       | =att:projects.org=                                    |
|           | =att:projects.org::some words= (text search)          |
| docview   | =docview:papers/last.pdf::NNN=                        |
| id        | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=             |
| news      | =news:comp.emacs=                                     |
| mailto    | =mailto:adent@galaxy.net=                             |
| mhe       | =mhe:folder= (folder link)                            |
|           | =mhe:folder#id= (message link)                        |
| rmail     | =rmail:folder= (folder link)                          |
|           | =rmail:folder#id= (message link)                      |
| gnus      | =gnus:group= (group link)                             |
|           | =gnus:group#id= (article link)                        |
| bbdb      | =bbdb:R.*Stallman= (record with regexp)               |
| irc       | =irc:/irc.com/#emacs/bob=                             |
| info      | =info:org::External links=                            |
| shell     | =shell:ls *.org=                                      |
| elisp     | =elisp:(find-file "Elisp.org")=                       |
--8<---------------cut here---------------end--------------->8---

WDYT?

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-11-24 13:56               ` Gustav Wikström
@ 2018-12-14  2:16                 ` Ihor Radchenko
  2019-05-26 22:24                   ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Ihor Radchenko @ 2018-12-14  2:16 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 4549 bytes --]

> No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. 

I just tried:

#+begin_src emacs-lisp
(setq org-agenda-custom-commands
      (quote (("v" "Test" tags-todo nil
	       ((org-agenda-files '("~/Org/inbox.org"))))
	      ("w" "Test 2" tags-todo nil
	       ((org-agenda-files '("~/Knowledge_base/2016/Private/Get_started_with_org_mode/get_started_org_mode.org")))))))
#+end_src

It works fine for me.

> No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept.

Yeah. But someone needs to volunteer with the patch.
It would be even better if these 0-level headings can be edited from the
referencing file.

Regards,
Ihor


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: Ihor Radchenko <yantar92@gmail.com>
>> Sent: den 20 november 2018 15:01
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
>> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> Hi,
>> 
>> >    Generalize org-agenda by allowing us to have multiple ones, and make
>> them more general by thinking of them as a set of views that works on sets
>> of files. Maybe this is not for all, but I would appreciate to create
>> multiple "agendas" (even though I'd call them "libraries" in instead), and
>> possibly also an aggregate agenda consisting of other agendas.
>> 
>> Isn't this already in org? You can use custom agendas with multiple
>> "agendas" (custom commands) and set the files they operate on with org-
>> agenda-files within custom commands.
>
> No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. 
>
>> 
>> >    If two org-mode files exist in the same folder with different names, it
>> would be awesome to think of (and work with) them as two top-level headings
>> inside one org-mode buffer. Similar to two level-1 headings inside an org-
>> mode file. For this to work all properties we can define for regular
>> headings should be possible to define for these "level-0 headings". For
>> example an attachment-folder or ID, a deadline, scheduled date, or TODO-
>> keyword should in that case be configurable on the whole file. I guess some
>> new conventions regarding syntax and existing properties would have to be
>> created as well.
>> 
>> You can do something like below. It is pretty much what you want, except I
>> am not sure how to update the headings from local org files. Current org
>> version does not allow `:results replace` on raw org output.
>> 
>> * Main heading
>> 
>> #+name: org-files-here
>> #+begin_src bash
>> ls *.org
>> #+end_src
>> 
>> #+begin_src emacs-lisp :var files=org-files-here()  :var stars=(make-string
>> (car (org-heading-components)) ?*)  :results raw replace drawer (let ((files
>> (mapcar #'car files)))
>>   (cl-loop for file in files
>> 	   concat (with-current-buffer (find-file-noselect file)
>> 		    (concat (format "* %s\n" (buffer-file-name))
>> 			    (replace-regexp-in-string "^\\*" (concat "*" stars)
>> (buffer-string)))))) #+end_src
>
> No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept.
>
> Thanks for your idea and suggestion though!
>
>> 
>> Best,
>> Ihor
>
> Kind Regards,
> Gustav
>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (2 preceding siblings ...)
  2018-11-04 22:37 ` Nicolas Goaziou
@ 2019-01-04 12:21 ` Feng Shu
  2019-05-26 23:15   ` Gustav Wikström
  2019-12-12  5:21 ` stardiviner
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: Feng Shu @ 2019-01-04 12:21 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Gustav Wikström <gustav@whil.se> writes:


I like this feature very much!




> Hi,
>
>  
>
> I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review.
>
>  
>
> Kind regards
>
> Gustav
>
> ___
>
> Patch comments:
>
> * Add new linktype "attached" for attachments
>
>  
>
> A new linktype "attached" is added in order to reduce link-duplication
>
> when wanting to link to files in attached folders of nodes. This works
>
> for both ID-based attachments and ATTACH_DIR.  Inline images will
>
> trigger also for attachments, as well as search-decorations in the
>
> links.  The goal is to make the functionality for attached-links
>
> mirror file-links.
>
>  
>
> * Add further options for ATTACH_DIR
>
>  
>
> When working with ATTACH_DIR there are now a couple of new options available:
>
> - org-attach-dir-inherit-by-default
>
> - org-attach-dir-create-if-not-exist
>
> - org-attach-dir-relative
>
>  
>
> Descriptions of them can be found in the commit for each new customization.
>
>  
>
> * Documentation in org-manual
>
>  
>
> Org-manual is updated with the new link-type as well as some minor
>
> cleanup in the documentation related to external links and attachments.
>

-- 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-12-14  2:16                 ` Ihor Radchenko
@ 2019-05-26 22:24                   ` Gustav Wikström
  0 siblings, 0 replies; 113+ messages in thread
From: Gustav Wikström @ 2019-05-26 22:24 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Hi again!

> -----Original Message-----
> From: Ihor Radchenko <yantar92@gmail.com>
> Sent: den 14 december 2018 03:16
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> > No, that's not what I want. What I'm talking about is extending org-mode conceptually
> > with the concept of 0-level headlines, where the body of that "headline" would be
> > everything before the first headline in a file, and where I could specify (for example) an
> > attachment-directory and be able to use it with this new syntax to link to attached files.
> > I guess I took it a bit far with the example of visualizing multiple files from a folder
> > as separate headlines inside a single emacs-buffer though. It would be cool to be able to
> > do that but my intention was more about introducing the 0-level headline concept.
> 
> Yeah. But someone needs to volunteer with the patch.

I just wanted to say I'm working on this. More info will come in a separate thread soon!

Kind regards,
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2018-11-27  9:39           ` Nicolas Goaziou
@ 2019-05-26 23:05             ` Gustav Wikström
  2019-06-15 13:29               ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-05-26 23:05 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 10736 bytes --]

Hi again,

Some updates, and a fresh patch...!

I won't say that much here since the patch speaks for itself (It 
contains a chapter to be added to ORG-NEWS). It's patch 0002 that is the 
important one. See sidenote below for a comment about patch 0001.

I have to mention that the patch has grown quite a lot. With the 
Additional changes, I've taken the liberty to promote attachments to a 
level-1 headline within the documentation!

Please review the new and improved" patch.

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 27 november 2018 10:40
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>
> Subject: Re: [RFC] Link-type for attachments, more attach options
> 
> Hello,
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Too bad, "@" was growing on me. @ is currently automatically set as
> > a tag when attaching files to nodes.
> 
> You probably customized `org-attach-auto-tag' because this is not the
> default behaviour. It adds "ATTACH" tag automatically.

Yeah, you're right. My bad!

> I prefer not to consider Gmail and Outlook as references, or even
> standards. As another data point, Gnus uses "Attachment: " to list
> attachments.

I won't argue any longer. And I'll do as you say. Attachment: it is!

> > Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not
> > sure of what way to go forward though. I can see at least two paths:
> >
> > 1) Rename `org-attach-allow-inheritance' to
> > `org-attach-enable-inheritance' and always make attachments inherited
> > when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd
> > also change the precedence-logic between ATTACH_DIR & ID properties
> > and make ID-based attachment inherit as well. The properties
> > ATTACH_DIR and ID should be inherited from the closest node when
> > resolving attachments, with ATTACH_DIR having precedence over ID if
> > both exist for the same node.
> 
> Why defining `org-attach-enable-inheritance' at all? There is already
> `org-use-property-inheritance' for this. We do not need another
> conflicting variable.
> 
> I don't think we should inherit ID properties either. ID is defined
> outside "org-attach.el", so this library shouldn't mess with its
> meaning. Does inheriting ID properties give anything valuable?

Inheriting ID's for attachments is actually valuable. It makes it possible, 
for example, to add attachment-links in subheadings to the node the  
attachment is defined on. After having used this for quite some time now it
feels quite natural to have inheritance switched on for attachments. No negative
side-effects at all.

> > 2) remove `org-attach-allow-inheritance' and only rely on the
> > "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if
> > the "ATTACH_DIR" property should be inherited. This would be a smaller
> > change from the user's perspective, where we're basically saying you
> > cannot disable inheritance, but it's only active when a node has the
> > ATTACH_DIR_INHERIT-property.
> >
> > I prefer path (1).
> 
> So do I, with the remarks above.

I went with path (1) and tried to fit it into the already existing property 
inheritance framework.

> > +This list shows the full set of built-in external link types,
> > +including examples for each:
> > +
> > +| Link Type | Description                  | Example|
> > +|-----------+------------------------------+-------------------------------------------------------|
> > +| http      | web                          | =http://www.astro.uva.nl/=dominik= |
> > +| https     | secure web                   | =https://orgmode.org/= |
> > +| doi       | DOI for electronic resources | =doi:10.1000/182= |
> > +| file      | file-links                   | =file:/home/dominik/images/jupiter.jpg= |
> > +|           |                              | =/home/dominik/images/jupiter.jpg= (same as above)    |
> > +|           |                              | =file:papers/last.pdf= |
> > +|           |                              | =./papers/last.pdf= (same as above) |
> > +|           |                              | =file:/ssh:me@some.where:papers/last.pdf= (remote)    |
> > +|           |                              | =/ssh:me@some.where:papers/last.pdf= (same as above)  |
> > +|           |                              | =file:sometextfile::NNN= (jump to line number)        |
> > +|           |                              | =file:projects.org= |
> > +|           |                              | =file:projects.org::some words= (text search) [fn:28] |
> > +|           |                              | =file:projects.org::*task title= (headline search)    |
> > +| @         | links to attachments         | =@:projects.org= |
> > +|           |                              | =@:projects.org::some words= (text search) |
> > +| docview   | doc-view mode                | =docview:papers/last.pdf::NNN= |
> > +| id        | Link to heading by id        | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= |
> > +| news      | Usenet link                  | =news:comp.emacs= |
> > +| mailto    | mail link                    | =mailto:adent@galaxy.net= |
> > +| mhe       | MH-E folder link             | =mhe:folder= (folder link) |
> > +|           |                              | =mhe:folder#id= (message link) |
> > +| rmail     | Rmail link                   | =rmail:folder= (folder link) |
> > +|           |                              | =rmail:folder#id= (message link) |
> > +| gnus      | Gnus link                    | =gnus:group= (group link) |
> > +|           |                              | =gnus:group#id= (article link) |
> > +| bbdb      | BBDB link                    | =bbdb:R.*Stallman= (link with regexp) |
> > +| irc       | IRC link                     | =irc:/irc.com/#emacs/bob= |
> > +| info      | Info link                    | =info:org#External links=|
> > +| shell     | shell command                | =shell:ls *.org= |
> > +| elisp     | interactive elisp command    | =elisp:(find-file "Elisp.org")= |
> 
> The second column still doesn't bring much information compared to the
> first one. Getting back to your first idea, we may try to do something
> like the following:
> 
> --8<---------------cut here---------------start------------->8---
> Here is the full set of built-in link types.
> 
> - =file= :: File links. File name may be remote, absolute, or relative.
> 
>   Additionally, you can specify a line number, or a text search.  In Org
>   files, you may link to a headline name, a custom ID, or a code
>   reference instead.
> 
>   As a special case, "file" prefix may be omitted if the file name is
>   complete, e.g., it starts with =./=, or =/=.
> 
> - =att= :: Same as file links, but for attached documents to the current
>   node (see [[*Attachments]]).
> 
> - =bbdb= :: Link to a BBDB record, with possible regexp completion.
> 
> - =docview= :: Link to a document opened with DocView mode.  You may
>   specify a page number.
> 
> - =doi= :: Link to an electronic ressource, through its handle.
> 
> - =elisp= :: Execute an Elisp command upon activation.
> 
> - =gnus=, =rmail=, =mhe= :: Links to messages or folders from a given
>   Emacs' MUA.
> 
> - =http=, =https= :: Web links.
> 
> - =id= :: Link to a specific headline by its ID property, in an Org
>   file.
> 
> - =info= :: Link to an Info manual, or to a specific node.
> 
> - =irc= :: Link to an IRC channel.
> 
> - =mailto= :: Link to message composition.
> 
> - =news= :: Usenet links.
> 
> - =shell= :: Execute a shell command upon activation.
> 
> The following table illustrates the link types above, along with their
> options:
> 
> | Link Type | Example                                               |
> |-----------+-------------------------------------------------------|
> | http      | =http://www.astro.uva.nl/=dominik=                    |
> | https     | =https://orgmode.org/=                                |
> | doi       | =doi:10.1000/182=                                     |
> | file      | =file:/home/dominik/images/jupiter.jpg=               |
> |           | =/home/dominik/images/jupiter.jpg= (same as above)    |
> |           | =file:papers/last.pdf=                                |
> |           | =./papers/last.pdf= (same as above)                   |
> |           | =file:/ssh:me@some.where:papers/last.pdf= (remote)    |
> |           | =/ssh:me@some.where:papers/last.pdf= (same as above)  |
> |           | =file:sometextfile::NNN= (jump to line number)        |
> |           | =file:projects.org=                                   |
> |           | =file:projects.org::some words= (text search) [fn:28] |
> |           | =file:projects.org::*task title= (headline search)    |
> |           | =file:projects.org::#custom-id= (headline search)     |
> | att       | =att:projects.org=                                    |
> |           | =att:projects.org::some words= (text search)          |
> | docview   | =docview:papers/last.pdf::NNN=                        |
> | id        | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=             |
> | news      | =news:comp.emacs=                                     |
> | mailto    | =mailto:adent@galaxy.net=                             |
> | mhe       | =mhe:folder= (folder link)                            |
> |           | =mhe:folder#id= (message link)                        |
> | rmail     | =rmail:folder= (folder link)                          |
> |           | =rmail:folder#id= (message link)                      |
> | gnus      | =gnus:group= (group link)                             |
> |           | =gnus:group#id= (article link)                        |
> | bbdb      | =bbdb:R.*Stallman= (record with regexp)               |
> | irc       | =irc:/irc.com/#emacs/bob=                             |
> | info      | =info:org::External links=                            |
> | shell     | =shell:ls *.org=                                      |
> | elisp     | =elisp:(find-file "Elisp.org")=                       |
> --8<---------------cut here---------------end--------------->8---
> 
> WDYT?

Thumbs up!

(Sidenote 1; what do I need to do to gain access to the official 
git-repository? Would be nice to be able to provide pull requests there!)

(Sidenote 2; The first patch is some minor unrelated fixups - it 
breaks test-org-export/expand-include as a side-effect. But that's probably 
because the test doesn't do what it should! 😲 )
 
Kind regards
Gustav

[-- Attachment #2: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --]
[-- Type: application/octet-stream, Size: 6293 bytes --]

From 91c01d90b1143cc4559cc886bcd176f1cd82576d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 26 May 2019 03:34:34 +0200
Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox,
 test-property-inheritance

* org-test.el:

Fix org-test-with-temp-text, make it work with <point>, as some
tests already expect it to do!

* testing/lisp/test-org-element.el

Fix a temp-text strings so that it doesn't have an initial newline.

* testing/lisp/test-org.el

Minor cleanup to align code-structure with other tests.  Nothing
changes in the test execpt style.

* testing/lisp/test-ox.el

Fix a couple of temp-text strings so that they don't have initial
newlines.

* testing/lisp/test-property-inheritance.el

Fix wrong file-header and file-ending.
---
 testing/lisp/test-org-element.el          |  4 ++--
 testing/lisp/test-org.el                  | 12 +++++-----
 testing/lisp/test-ox.el                   | 28 +++++++++++------------
 testing/lisp/test-property-inheritance.el |  4 ++--
 testing/org-test.el                       |  7 +++++-
 5 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 8b4081ee2..4c1e4d181 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -3250,8 +3250,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
 
 (ert-deftest test-org-element/granularity ()
   "Test granularity impact on buffer parsing."
-  (org-test-with-temp-text "
-* Head 1
+  (org-test-with-temp-text
+      "* Head 1
 ** Head 2
 #+BEGIN_CENTER
 Centered paragraph.
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index abc004689..d671b5c78 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -5060,18 +5060,18 @@ Paragraph<point>"
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
-      (org-entry-get (point) "A" t))))
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
+      (org-entry-get (point-max) "A" t))))
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
       (let ((org-use-property-inheritance t))
-	(org-entry-get (point) "A" 'selective)))))
+	(org-entry-get (point-max) "A" 'selective)))))
   (should-not
-   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
      (let ((org-use-property-inheritance nil))
-       (org-entry-get (point) "A" 'selective))))
+       (org-entry-get (point-max) "A" 'selective))))
   (should
    (equal
     "1 2"
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 43637b926..e5b4d3c92 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after
 comments removal."
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 
 # Comment
@@ -2012,15 +2012,15 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 
@@ -2029,8 +2029,8 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 
@@ -2040,24 +2040,24 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "- item 1\n\n- item 2\n"
-	  (org-test-with-temp-text "
-- item 1
+	  (org-test-with-temp-text
+	      "- item 1
 
   # Comment
 
diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el
index 0f803e5f7..1d0dcfbe1 100644
--- a/testing/lisp/test-property-inheritance.el
+++ b/testing/lisp/test-property-inheritance.el
@@ -1,4 +1,4 @@
-;;; test-ob-R.el --- tests for ob-R.el
+;;; test-property-inheritance.el --- tests for property-inheritance.el
 
 ;; Copyright (c) 2011-2014, 2019 Eric Schulte
 ;; Authors: Eric Schulte
@@ -47,4 +47,4 @@
 
 (provide 'test-ob-R)
 
-;;; test-ob-R.el ends here
+;;; test-property-inheritance.el ends here
diff --git a/testing/org-test.el b/testing/org-test.el
index 39c346410..6b218fc00 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -198,7 +198,10 @@ otherwise place the point at the beginning of the inserted text."
 (def-edebug-spec org-test-with-temp-text (form body))
 
 (defmacro org-test-with-temp-text-in-file (text &rest body)
-  "Run body in a temporary file buffer with Org mode as the active mode."
+  "Run body in a temporary file buffer with Org mode as the active mode.
+If the string \"<point>\" appears in TEXT then remove it and
+place the point there before running BODY, otherwise place the
+point at the beginning of the buffer."
   (declare (indent 1))
   (let ((results (cl-gensym)))
     `(let ((file (make-temp-file "org-test"))
@@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text."
 	   ,results)
        (with-temp-file file (insert inside-text))
        (find-file file)
+       (when (re-search-forward "<point>" nil t)
+	 (replace-match ""))
        (org-mode)
        (setq ,results (progn ,@body))
        (save-buffer) (kill-buffer (current-buffer))
-- 
2.17.1


[-- Attachment #3: 0002-org-attach-org-org-manual-org-news-testing-test-org-.patch --]
[-- Type: application/octet-stream, Size: 83011 bytes --]

From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 25 Nov 2018 21:38:44 +0100
Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news,
 testing/**/test-org-attach*

* org-attach.el

Changed the way attachments deal with property-inheritance.  It now
adheres to the =org-use-property-inheritance= setting by default but
it can be customized if needed (I recommend to enable it!).
The property ATTACH_DIR is depricated in favour of the shorter and simpler
property DIR.

Added an explicit option to =org-attach= for unsetting
attachment-directories (i.e. remove DIR property and deal with the
attachments by interaction).

Added attachment link type with the prefix "attachment:".

Added customizations:
- org-attach-dir-relative
- org-attach-preferred-new-method
- org-attach-use-inheritance
- org-attach-id-to-path-function

Hooks added:
- org-attach-after-change-hook
- org-attach-open-hook

* Add new linktype "attachment" for attachments

A new linktype "attachment" is added in order to reduce
link-duplication when wanting to link to files in attached folders of
nodes.  This works for both ID and DIR properties.  The goal is to
make the functionality for attached-links mirror file-links.

* org-attach-git.el

New file, existing functionality.  Code here has been factored out
from org-attach.el and if GIT-functionality is to be used this module
needs to be required sepatately.  It extends org-attach by use of its
hooks.

Activating git functionality in org-attach is done by loading
org-attach-git from now on, instead of customizing a variable.

Naming of both functions and tests has been modified to match the move
of functionality into its own module.

* org.el

Inline images are shown also using attachment-links, exactly the same
as it works for file-links today.

Make org-open-at-point respect ARG when opening attachment-dir

* org-compat.el

org-attach-directory has been deprecated in favour for
org-attach-id-dir.  The new name matches its purpose better.

* org-manual.org

Attachments have been promoted into its own top-level node!  There are
a lot of goodies to mention here that didn't fit naturally with
"capture" and "archive" before.

Nothing from the old documentation is deleted. It's just been
restructured and complemented with further information.

The manual is updated to include information about org-attach options.

The new attachment link type is mentioned both inside the
attachments-chapter and in the chapter dealing with links.

Documentation related to external links has been improved.

* testing/lisp/test-org-attach-annex.el

Require org-attach-git instead of org-attach, since this file tests
the GIT-functionality.

* testing/org-test.el

Define a symbol for a file to test attachments with.

* testing/examples/*

A bunch of new example files and folders are created and are used in
testing of org-attach to verify its functionality.
---
 doc/org-manual.org                            | 614 ++++++++++++------
 etc/ORG-NEWS                                  |  82 +++
 lisp/org-attach-git.el                        | 118 ++++
 lisp/org-attach.el                            | 564 ++++++++--------
 lisp/org-compat.el                            |   3 +
 lisp/org.el                                   |  23 +-
 testing/examples/att1/fileA                   |   1 +
 testing/examples/att1/fileB                   |   1 +
 testing/examples/att2/fileC                   |   1 +
 testing/examples/att2/fileD                   |   1 +
 testing/examples/attachments.org              |  32 +
 testing/examples/data/ab/cd123/fileE          |   1 +
 ...attach-annex.el => test-org-attach-git.el} |  12 +-
 testing/lisp/test-org-attach.el               |  50 ++
 testing/lisp/test-org.el                      |   6 +-
 testing/org-test.el                           |   3 +
 16 files changed, 1034 insertions(+), 478 deletions(-)
 create mode 100644 lisp/org-attach-git.el
 create mode 100644 testing/examples/att1/fileA
 create mode 100644 testing/examples/att1/fileB
 create mode 100644 testing/examples/att2/fileC
 create mode 100644 testing/examples/att2/fileD
 create mode 100644 testing/examples/attachments.org
 create mode 100644 testing/examples/data/ab/cd123/fileE
 rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index c519d310b..8f86c5228 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3068,6 +3068,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: attachment links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3079,38 +3080,112 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
-
-| =http://www.astro.uva.nl/=dominik=        | on the web                     |
-| =doi:10.1000/182=                         | DOI for an electronic resource |
-| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
-| =/home/dominik/images/jupiter.jpg=        | same as above                  |
-| =file:papers/last.pdf=                    | file, relative path            |
-| =./papers/last.pdf=                       | same as above                  |
-| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
-| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
-| =file:sometextfile::NNN=                  | file, jump to line number      |
-| =file:projects.org=                       | another Org file               |
-| =file:projects.org::some words=           | text search in Org file[fn:27] |
-| =file:projects.org::*task title=          | heading search in Org file     |
-| =file+sys:/path/to/file=                  | open via OS, like double-click |
-| =file+emacs:/path/to/file=                | force opening by Emacs         |
-| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
-| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
-| =news:comp.emacs=                         | Usenet link                    |
-| =mailto:adent@galaxy.net=                 | mail link                      |
-| =mhe:folder=                              | MH-E folder link               |
-| =mhe:folder#id=                           | MH-E message link              |
-| =rmail:folder=                            | Rmail folder link              |
-| =rmail:folder#id=                         | Rmail message link             |
-| =gnus:group=                              | Gnus group link                |
-| =gnus:group#id=                           | Gnus article link              |
-| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
-| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
-| =info:org#External links=                 | Info node link                 |
-| =shell:ls *.org=                          | shell command                  |
-| =elisp:org-agenda=                        | interactive Elisp command      |
-| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
+the colon.
+
+Here is the full set of built-in link types:
+
+- =file= ::
+
+     File links. File name may be remote, absolute, or relative.
+
+     Additionally, you can specify a line number, or a text search.
+     In Org files, you may link to a headline name, a custom ID, or a
+     code reference instead.
+
+     As a special case, "file" prefix may be omitted if the file name
+     is complete, e.g., it starts with =./=, or =/=.
+
+- =attachment= ::
+
+     Same as file links, but for attached documents to the current
+     node (see [[*Attachments]]).
+
+- =bbdb= ::
+
+     Link to a BBDB record, with possible regexp completion.
+
+- =docview= ::
+
+     Link to a document opened with DocView mode.  You may specify a
+     page number.
+
+- =doi= ::
+
+     Link to an electronic ressource, through its handle.
+
+- =elisp= ::
+
+     Execute an Elisp command upon activation.
+
+- =gnus=, =rmail=, =mhe= ::
+
+     Links to messages or folders from a given Emacs' MUA.
+
+- =http=, =https= ::
+
+     Web links.
+
+- =id= ::
+
+     Link to a specific headline by its ID property, in an Org file.
+
+- =info= ::
+
+     Link to an Info manual, or to a specific node.
+
+- =irc= ::
+
+     Link to an IRC channel.
+
+- =mailto= ::
+
+     Link to message composition.
+
+- =news= ::
+
+     Usenet links.
+
+- =shell= ::
+
+     Execute a shell command upon activation.
+
+The following table illustrates the link types above, along with their
+options:
+
+| Link Type  | Example                                                  |
+|------------+----------------------------------------------------------|
+| http       | =http://www.astro.uva.nl/=dominik=                       |
+| https      | =https://orgmode.org/=                                   |
+| doi        | =doi:10.1000/182=                                        |
+| file       | =file:/home/dominik/images/jupiter.jpg=                  |
+|            | =/home/dominik/images/jupiter.jpg= (same as above)       |
+|            | =file:papers/last.pdf=                                   |
+|            | =./papers/last.pdf= (same as above)                      |
+|            | =file:/ssh:me@some.where:papers/last.pdf= (remote)       |
+|            | =/ssh:me@some.where:papers/last.pdf= (same as above)     |
+|            | =file:sometextfile::NNN= (jump to line number)           |
+|            | =file:projects.org=                                      |
+|            | =file:projects.org::some words= (text search) [fn:28]    |
+|            | =file:projects.org::*task title= (headline search)       |
+|            | =file:projects.org::#custom-id= (headline search)        |
+| attachment | =attachment:projects.org=                                |
+|            | =attachment:projects.org::some words= (text search)      |
+| docview    | =docview:papers/last.pdf::NNN=                           |
+| id         | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=                |
+| news       | =news:comp.emacs=                                        |
+| mailto     | =mailto:adent@galaxy.net=                                |
+| mhe        | =mhe:folder= (folder link)                               |
+|            | =mhe:folder#id= (message link)                           |
+| rmail      | =rmail:folder= (folder link)                             |
+|            | =rmail:folder#id= (message link)                         |
+| gnus       | =gnus:group= (group link)                                |
+|            | =gnus:group#id= (article link)                           |
+| bbdb       | =bbdb:R.*Stallman= (record with regexp)                  |
+| irc        | =irc:/irc.com/#emacs/bob=                                |
+| info       | =info:org#External links=                                |
+| shell      | =shell:ls *.org=                                         |
+| elisp      | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) |
+|            | =elisp:org-agenda= (interactive Elisp command)           |
 
 #+cindex: VM links
 #+cindex: Wanderlust links
@@ -3462,20 +3537,22 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: attachment links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:34].  For
-example, when the command ~org-store-link~ creates a link (see
-[[*Handling Links]]) to a file, it encodes the words in the current line
-as a search string that can be used to find this line back later when
-following the link with {{{kbd(C-c C-o)}}}.
+File links and attachment links can contain additional information to
+make Emacs jump to a particular location in the file when following a
+link.  This can be a line number or a search option after a double
+colon[fn:34].  For example, when the command ~org-store-link~ creates
+a link (see [[*Handling Links]]) to a file, it encodes the words in the
+current line as a search string that can be used to find this line
+back later when following the link with {{{kbd(C-c C-o)}}}.
 
 Here is the syntax of the different ways to attach a search to a file
-link, together with explanations for each:
+link or attachment link, together with explanations for each:
 
 #+begin_example
 [[file:~/code/main.c::255]]
+[[attachment:main.c::255]]
 [[file:~/xx.org::My Target]]
 [[file:~/xx.org::*My Target]]
 [[file:~/xx.org::#my-custom-id]]
@@ -6901,11 +6978,9 @@ same commands.
 
 An important part of any organization system is the ability to quickly
 capture new ideas and tasks, and to associate reference material with
-them.  Org does this using a process called /capture/.  It also can
-store files related to a task (/attachments/) in a special directory.
-Once in the system, tasks and projects need to be moved around.
-Moving completed project trees to an archive file keeps the system
-compact and fast.
+them.  Org does this using a process called /capture/.  Once in the
+system, tasks and projects need to be moved around.  Moving completed
+project trees to an archive file keeps the system compact and fast.
 
 ** Capture
 :PROPERTIES:
@@ -7432,168 +7507,6 @@ another template.  In that case, add this command key like this:
 
 See the docstring of the variable for more information.
 
-** Attachments
-:PROPERTIES:
-:DESCRIPTION: Add files to tasks.
-:END:
-#+cindex: attachments
-#+vindex: org-attach-directory
-
-It is often useful to associate reference material with an outline
-node/task.  Small chunks of plain text can simply be stored in the
-subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
-associations with files that live elsewhere on your computer or in the
-cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-=data/= directory which lives in the same directory where your Org
-file lives[fn:87].  If you initialize this directory with =git init=,
-Org automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
-
-The following commands deal with attachments:
-
-- {{{kbd(C-c C-a)}}} (~org-attach~) ::
-
-  #+kindex: C-c C-a
-  #+findex: org-attach
-  The dispatcher for commands related to the attachment system.  After
-  these keys, a list of commands is displayed and you must press an
-  additional key to select a command:
-
-  - {{{kbd(a)}}} (~org-attach-attach~) ::
-
-    #+kindex: C-c C-a a
-    #+findex: org-attach-attach
-    #+vindex: org-attach-method
-    Select a file and move it into the task's attachment directory.
-    The file is copied, moved, or linked, depending on
-    ~org-attach-method~.  Note that hard links are not supported on
-    all systems.
-
-  - {{{kbd(c)}}}/{{{kbd(m)}}}/{{{kbd(l)}}} ::
-
-    #+kindex: C-c C-a c
-    #+kindex: C-c C-a m
-    #+kindex: C-c C-a l
-    Attach a file using the copy/move/link method.  Note that hard
-    links are not supported on all systems.
-
-  - {{{kbd(b)}}} (~org-attach-buffer~) ::
-
-    #+kindex: C-c C-a b
-    #+findex: org-attach-buffer
-    Select a buffer and save it as a file in the task's attachment
-    directory.
-
-  - {{{kbd(n)}}} (~org-attach-new~) ::
-
-    #+kindex: C-c C-a n
-    #+findex: org-attach-new
-    Create a new attachment as an Emacs buffer.
-
-  - {{{kbd(z)}}} (~org-attach-sync~) ::
-
-    #+kindex: C-c C-a z
-    #+findex: org-attach-sync
-    Synchronize the current task with its attachment directory, in
-    case you added attachments yourself.
-
-  - {{{kbd(o)}}} (~org-attach-open~) ::
-
-    #+kindex: C-c C-a o
-    #+findex: org-attach-open
-    #+vindex: org-file-apps
-    Open current task's attachment.  If there is more than one, prompt
-    for a file name first.  Opening follows the rules set by
-    ~org-file-apps~.  For more details, see the information on
-    following hyperlinks (see [[*Handling Links]]).
-
-  - {{{kbd(O)}}} (~org-attach-open-in-emacs~) ::
-
-    #+kindex: C-c C-a O
-    #+findex: org-attach-open-in-emacs
-    Also open the attachment, but force opening the file in Emacs.
-
-  - {{{kbd(f)}}} (~org-attach-reveal~) ::
-
-    #+kindex: C-c C-a f
-    #+findex: org-attach-reveal
-    Open the current task's attachment directory.
-
-  - {{{kbd(F)}}} (~org-attach-reveal-in-emacs~) ::
-
-    #+kindex: C-c C-a F
-    #+findex: org-attach-reveal-in-emacs
-    Also open the directory, but force using Dired in Emacs.
-
-  - {{{kbd(d)}}} (~org-attach-delete-one~) ::
-
-    #+kindex: C-c C-a d
-    Select and delete a single attachment.
-
-  - {{{kbd(D)}}} (~org-attach-delete-all~) ::
-
-    #+kindex: C-c C-a D
-    Delete all of a task's attachments.  A safer way is to open the
-    directory in Dired and delete from there.
-
-  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
-
-    #+kindex: C-c C-a s
-    #+cindex: @samp{ATTACH_DIR}, property
-    Set a specific directory as the entry's attachment directory.
-    This works by putting the directory path into the =ATTACH_DIR=
-    property.
-
-  - {{{kbd(i)}}} (~org-attach-set-inherit~) ::
-
-    #+kindex: C-c C-a i
-    #+cindex: @samp{ATTACH_DIR_INHERIT}, property
-    Set the =ATTACH_DIR_INHERIT= property, so that children use the
-    same directory for attachments as the parent does.
-
-#+cindex: attach from Dired
-#+findex: org-attach-dired-to-subtree
-It is possible to attach files to a subtree from a Dired buffer.  To
-use this feature, have one window in Dired mode containing the file(s)
-to be attached and another window with point in the subtree that shall
-get the attachments.  In the Dired window, with point on a file,
-{{{kbd(M-x org-attach-dired-to-subtree)}}} attaches the file to the
-subtree using the attachment method set by variable
-~org-attach-method~.  When files are marked in the Dired window then
-all marked files get attached.
-
-Add the following lines to the Emacs init file to have {{{kbd(C-c C-x
-a)}}} attach files in Dired buffers.
-
-#+begin_src emacs-lisp
-(add-hook 'dired-mode-hook
-          (lambda ()
-            (define-key dired-mode-map
-              (kbd "C-c C-x a")
-              #'org-attach-dired-to-subtree)))
-#+end_src
-
-The following code shows how to bind the previous command with
-a specific attachment method.
-
-#+begin_src emacs-lisp
-(add-hook 'dired-mode-hook
-          (lambda ()
-            (define-key dired-mode-map (kbd "C-c C-x c")
-              (lambda ()
-                (interactive)
-                (let ((org-attach-method 'cp))
-                  (call-interactively #'org-attach-dired-to-subtree))))))
-#+end_src
-
 ** RSS Feeds
 :PROPERTIES:
 :DESCRIPTION: Getting input from RSS feeds.
@@ -8072,6 +7985,291 @@ The following commands help manage the =ARCHIVE= tag:
   of its original context, including inherited tags and approximate
   position in the outline.
 
+* Attachments
+:PROPERTIES:
+:DESCRIPTION: Attach files to outlines.
+:END:
+#+cindex: attachments
+#+vindex: org-attach-id-dir
+
+It is often useful to associate reference material with an outline
+node/task.  Small chunks of plain text can simply be stored in the
+subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
+associations with files that live elsewhere on your computer or in the
+cloud, like emails or source code files belonging to a project.
+
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by a unique ID of each entry, or by a =DIR= property.
+
+The attachment system has been contributed to Org by John Wiegley.
+
+** Attachment defaults and dispatcher
+By default, org-attach will use ID properties when adding attachments
+to outline nodes.  This makes working with attachments fully
+automated.  There is no decision needed for folder-name or location.
+ID-based directories are by default located in the =data/= directory,
+which lives in the same directory where your Org file lives[fn:87].
+For more control over the setup, see [[*Attachment options]].
+
+When attachments are made using ~org-attach~ a default tag =ATTACH= is
+added to the node that gets the attachments.
+
+The following commands deal with attachments:
+
+- {{{kbd(C-c C-a)}}} (~org-attach~) ::
+
+  #+kindex: C-c C-a
+  #+findex: org-attach
+  The dispatcher for commands related to the attachment system.  After
+  these keys, a list of commands is displayed and you must press an
+  additional key to select a command:
+
+  - {{{kbd(a)}}} (~org-attach-attach~) ::
+
+    #+kindex: C-c C-a a
+    #+findex: org-attach-attach
+    #+vindex: org-attach-method
+    Select a file and move it into the task's attachment directory.
+    The file is copied, moved, or linked, depending on
+    ~org-attach-method~.  Note that hard links are not supported on
+    all systems.
+
+  - {{{kbd(c)}}}/{{{kbd(m)}}}/{{{kbd(l)}}} ::
+
+    #+kindex: C-c C-a c
+    #+kindex: C-c C-a m
+    #+kindex: C-c C-a l
+    Attach a file using the copy/move/link method.  Note that hard
+    links are not supported on all systems.
+
+  - {{{kbd(b)}}} (~org-attach-buffer~) ::
+
+    #+kindex: C-c C-a b
+    #+findex: org-attach-buffer
+    Select a buffer and save it as a file in the task's attachment
+    directory.
+
+  - {{{kbd(n)}}} (~org-attach-new~) ::
+
+    #+kindex: C-c C-a n
+    #+findex: org-attach-new
+    Create a new attachment as an Emacs buffer.
+
+  - {{{kbd(z)}}} (~org-attach-sync~) ::
+
+    #+kindex: C-c C-a z
+    #+findex: org-attach-sync
+    Synchronize the current task with its attachment directory, in
+    case you added attachments yourself.
+
+  - {{{kbd(o)}}} (~org-attach-open~) ::
+
+    #+kindex: C-c C-a o
+    #+findex: org-attach-open
+    #+vindex: org-file-apps
+    Open current task's attachment.  If there is more than one, prompt
+    for a file name first.  Opening follows the rules set by
+    ~org-file-apps~.  For more details, see the information on
+    following hyperlinks (see [[*Handling Links]]).
+
+  - {{{kbd(O)}}} (~org-attach-open-in-emacs~) ::
+
+    #+kindex: C-c C-a O
+    #+findex: org-attach-open-in-emacs
+    Also open the attachment, but force opening the file in Emacs.
+
+  - {{{kbd(f)}}} (~org-attach-reveal~) ::
+
+    #+kindex: C-c C-a f
+    #+findex: org-attach-reveal
+    Open the current task's attachment directory.
+
+  - {{{kbd(F)}}} (~org-attach-reveal-in-emacs~) ::
+
+    #+kindex: C-c C-a F
+    #+findex: org-attach-reveal-in-emacs
+    Also open the directory, but force using Dired in Emacs.
+
+  - {{{kbd(d)}}} (~org-attach-delete-one~) ::
+
+    #+kindex: C-c C-a d
+    Select and delete a single attachment.
+
+  - {{{kbd(D)}}} (~org-attach-delete-all~) ::
+
+    #+kindex: C-c C-a D
+    Delete all of a task's attachments.  A safer way is to open the
+    directory in Dired and delete from there.
+
+  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
+
+    #+kindex: C-c C-a s
+    #+cindex: @samp{DIR}, property
+    Set a specific directory as the entry's attachment directory.
+    This works by putting the directory path into the =DIR=
+    property.
+
+  - {{{kbd(S)}}} (~org-attach-unset-directory~) ::
+
+    #+kindex: C-c C-a S
+    #+cindex: @samp{DIR}, property
+    Remove the attachment-directory.  This command removes the =DIR=
+    property and asks the user to either move content inside that
+    folder, if an =ID= property is set, delete the content, or to
+    leave the attachment-directory as is but no longer attached to the
+    outline node.
+
+** Attachment options
+There are a couple of options for attachments that are worth
+mentioning.
+
+- ~org-attach-id-dir~ ::
+  #+vindex: org-attach-id-dir
+  The directory where attachments are stored when =ID= is used as
+  method.
+
+- ~org-attach-dir-relative~ ::
+  #+vindex: org-attach-dir-relative
+  When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}}
+  (~org-attach-set-directory~), absolute links are entered by default.
+  This option changes that to relative links.
+
+- ~org-attach-use-inheritance~ ::
+  #+vindex: org-attach-use-inheritance
+  By default folders attached to an outline node are inherited from
+  parents according to ~org-use-property-inheritance~.  If one instead
+  want to set inheritance specifically for org-attach that can be done
+  using ~org-attach-use-inheritance~.  Inheriting documents through
+  the node hierarchy makes a lot of sense in most cases. Especially
+  since the introduction of [[* Attachment links]].  The following example
+  shows one use case for attachment inheritance:
+
+  #+begin_example
+  ,* Chapter A ...
+    :PROPERTIES:
+    :DIR: Chapter A/
+    :END:
+  ,** Introduction
+  Some text
+
+  #+NAME: Image 1
+  [[Attachment:image 1.jpg]]
+  #+end_example
+
+  Without inheritance one would not be able to resolve the link to image
+  1.jpg, since the link is inside a sub-heading to Chapter A.
+
+  Inheritance works the same way for both =ID= and =DIR= property.  If
+  both properties are defined on the same headline then =DIR= takes
+  precedance.  This is also true if inheritance is enabled.  If =DIR= is
+  inherited from a parent node in the outline, that property still takes
+  precedence over an =ID= property defined on the node itself.
+
+- ~org-attach-method~ ::
+  #+vindex: org-attach-method
+  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
+  defaults to copying files.  The behaviour can be changed by
+  customizing ~org-attach-method~.  Options are =Copy=, =Move/Rename=,
+  =Hard link= or =Symbolic link=.
+
+- ~org-attach-preferred-new-method~ ::
+  #+vindex: org-attach-preferred-new-method
+  This customization lets you choose the default way to attach to
+  nodes without existing ID and DIR property.  It defaults to =id= but
+  can also be set to =dir=, =ask= or =nil=.
+
+- ~org-attach-archive-delete~ ::
+  #+vindex: org-attach-archive-delete
+  Configure this to determine if attachments should be deleted or not
+  when a subtree that has attachments is archived.
+
+- ~org-attach-auto-tag~ ::
+  #+vindex: org-attach-auto-tag
+  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
+  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!
+
+- ~org-attach-expert~ ::
+  #+vindex: org-attach-expert
+  Do not show the splash buffer with the attach dispatcher when
+  ~org-attach-expert~ is set to Non-nil.
+
+See customization group =Org Attach= if you want to change the
+default settings.
+
+** Attachment links
+Attached files and folders can be referenced using attachment-links.
+This makes it easy to refer to the material added to an outline node.
+Especially if it was attached using the unique ID of the entry!
+
+#+begin_example
+,* TODO Some task
+  :PROPERTIES:
+  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
+  :END:
+See attached document for more information: [[attachment:info.org]]
+#+end_example
+
+See [[* External Links]] for more information about these links.
+
+** Automatic version-control with git
+If the directory attached to an outline node is a git repository, Org
+can be configured to automatically commit changes to that repository
+when it sees them.
+
+To make org-mode take care of versioning of attachments for you, add
+the following to your Emacs config:
+
+#+begin_src emacs-lisp
+  (require 'org-attach-git)
+#+end_src
+
+** Attach from Dired
+#+cindex: attach from Dired
+#+findex: org-attach-dired-to-subtree
+It is possible to attach files to a subtree from a Dired buffer.  To
+use this feature, have one window in Dired mode containing the file(s)
+to be attached and another window with point in the subtree that shall
+get the attachments.  In the Dired window, with point on a file,
+{{{kbd(M-x org-attach-dired-to-subtree)}}} attaches the file to the
+subtree using the attachment method set by variable
+~org-attach-method~.  When files are marked in the Dired window then
+all marked files get attached.
+
+Add the following lines to the Emacs init file to have {{{kbd(C-c C-x
+a)}}} attach files in Dired buffers.
+
+#+begin_src emacs-lisp
+(add-hook 'dired-mode-hook
+          (lambda ()
+            (define-key dired-mode-map
+              (kbd "C-c C-x a")
+              #'org-attach-dired-to-subtree)))
+#+end_src
+
+The following code shows how to bind the previous command with
+a specific attachment method.
+
+#+begin_src emacs-lisp
+(add-hook 'dired-mode-hook
+          (lambda ()
+            (define-key dired-mode-map (kbd "C-c C-x c")
+              (lambda ()
+                (interactive)
+                (let ((org-attach-method 'cp))
+                  (call-interactively #'org-attach-dired-to-subtree))))))
+#+end_src
+
 * Agenda Views
 :PROPERTIES:
 :DESCRIPTION: Collecting information into views.
@@ -21225,7 +21423,7 @@ accessed in capture templates in a similar way.
 ~org-link-from-user-regexp~.
 
 [fn:87] If you move entries or Org files from one directory to
-another, you may want to configure ~org-attach-directory~ to contain
+another, you may want to configure ~org-attach-id-dir~ to contain
 an absolute path.
 
 [fn:88] Note the corresponding =STARTUP= options =logrefile=,
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 541559e64..5a868ca99 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -112,6 +112,84 @@ alternative was removed and there is no more a :use-xcolor options
 since now it's implicitly always true.
 
 ** New features
+*** Org-Attach has been refactored and extended
+Org attach has been refactored and the functionality extended.  It
+should now be easier to understand how it works.  A few improvements
+and extra options have been added as well.
+
+From the initial comment in org-attach source-code:
+
+- Attachments are managed either by using a custom property DIR or by
+  using property ID from org-id.  When DIR is defined, a location in
+  the filesystem is directly attached to the outline node.  When
+  org-id is used, attachments are stored in a folder named after the
+  ID, in a location defined by ~org-attach-id-dir~.  DIR has
+  precedence over ID when both parameters are defined for the current
+  outline node (also when inherited parameters are taken into
+  account).
+
+From now on inheritance requires no extra property and will adhere to
+~org-attach-use-inheritance~ by default.  Inheritance can be
+customized to always be activated or never be activated in
+~org-attach-use-inheritance~.
+
+The ATTACH_DIR property is depricated in favour of the shorter
+property DIR.  Links to folders inside the DIR property can now be
+declared as relative links.  This is not enabled by default, but can
+be set in ~org-attach-dir-relative~.
+
+When adding new attachment to the outline node the preferred way of
+doing so can be customized.  Take a look at
+~org-attach-preferred-new-method~.  It defaults to using ID since that
+was the behaviour before this change.
+
+If both DIR and ID properties are set on the same node, DIR has
+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.
+
+If you've used ATTACH_DIR properties to manage attachments, use the
+following code to rename that property to DIR which supports the same
+functionality.  ATTACH_DIR_INHERIT is no longer supported and is
+removed.
+
+#+begin_src emacs-lisp
+  (defun org-update-attach-properties ()
+      "Change properties for Org-Attach."
+      (interactive "P")
+      (org-with-point-at 1
+	(while (outline-next-heading)
+	  (let ((DIR (org--property-local-values "ATTACH_DIR" nil)))
+	    (when DIR
+	      (org-set-property "DIR" (car DIR))
+	      (org-delete-property "ATTACH_DIR"))))
+	(org-delete-property-globally "ATTACH_DIR_INHERIT")))
+#+end_src
+
+For those who hate breaking changes, even though the changes are made
+to clean things up; fear not.  ATTACH_DIR will still continue to work.
+It's just not documented any longer.  When you get the chance, run the
+code above to clean things up anyways!
+
+**** New hooks
+Two hooks are added to org-attach:
+- org-attach-after-change-hook
+- org-attach-open-hook
+
+They are added mostly for internal restructuring purposes, but can
+ofc. be used for other things as well.
+
+*** New link-type: Attachment
+Attachment-links are now first-class citizens.  They mimick file-links
+in everything they do but use the existing attachment-folder as a base
+when expanding the links. Both =DIR= and =ID= properties are used to
+try to resolve the links, in exactly the same way as Org-Attach uses
+those properties.
+
 *** Handle overlay specification for notes in Beamer export
 
 This aligns Beamer notes with slide overlays.
@@ -228,6 +306,10 @@ dynamic block in ~org-dynamic-block-alist~.
 *** ~org-babel-set-current-result-hash~
 
 It was unused throughout the code base.
+*** ~org-attach-directory~
+
+It has been deprecated in favour of ~org-attach-id-dir~ which is less
+ambigous given the restructured org-attach.
 
 ** Miscellaneous
 *** LaTeX preview is simplified
diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el
new file mode 100644
index 000000000..924d04157
--- /dev/null
+++ b/lisp/org-attach-git.el
@@ -0,0 +1,118 @@
+;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; Original Author: John Wiegley <johnw@newartisans.com>
+;; Restructurer: Gustav Wikström <gustav@whil.se>
+;; Keywords: org data git
+
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; An extention to org-attach.  If the attachment-directory to an
+;; outline node (using either DIR or ID) is initialized as a Git
+;; repository, then org-attach-git will automatically commit changes
+;; when it sees them.
+
+;;; Code:
+
+(require 'org-attach)
+(require 'vc-git)
+
+(defcustom org-attach-git-annex-cutoff (* 32 1024)
+  "If non-nil, files larger than this will be annexed instead of stored."
+  :group 'org-attach
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type '(choice
+	  (const :tag "None" nil)
+	  (integer :tag "Bytes")))
+
+(defcustom org-attach-git-annex-auto-get 'ask
+  "Confirmation preference for automatically getting annex files.
+If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+  :group 'org-attach
+  :package-version '(Org . "9.0")
+  :version "26.1"
+  :type '(choice
+	  (const :tag "confirm with `y-or-n-p'" ask)
+	  (const :tag "always get from annex if necessary" t)
+	  (const :tag "never get from annex" nil)))
+
+(defun org-attach-git-use-annex ()
+  "Return non-nil if git annex can be used."
+  (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir))))
+    (and org-attach-git-annex-cutoff
+         (or (file-exists-p (expand-file-name "annex" git-dir))
+             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
+
+(defun org-attach-git-annex-get-maybe (path)
+  "Call git annex get PATH (via shell) if using git annex.
+Signals an error if the file content is not available and it was not retrieved."
+  (let* ((default-directory (expand-file-name org-attach-id-dir))
+	 (path-relative (file-relative-name path)))
+    (when (and (org-attach-git-use-annex)
+	       (not
+		(string-equal
+		 "found"
+		 (shell-command-to-string
+		  (format "git annex find --format=found --in=here %s"
+			  (shell-quote-argument path-relative))))))
+      (let ((should-get
+	     (if (eq org-attach-git-annex-auto-get 'ask)
+		 (y-or-n-p (format "Run git annex get %s? " path-relative))
+	       org-attach-git-annex-auto-get)))
+	(if should-get
+	    (progn (message "Running git annex get \"%s\"." path-relative)
+		   (call-process "git" nil nil nil "annex" "get" path-relative))
+	  (error "File %s stored in git annex but it is not available, and was not retrieved"
+		 path))))))
+
+(defun org-attach-git-commit ()
+  "Commit changes to git if `org-attach-id-dir' is properly initialized.
+This checks for the existence of a \".git\" directory in that directory."
+  (let* ((dir (expand-file-name org-attach-id-dir))
+	 (git-dir (vc-git-root dir))
+	 (use-annex (org-attach-git-use-annex))
+	 (changes 0))
+    (when (and git-dir (executable-find "git"))
+      (with-temp-buffer
+	(cd dir)
+        (dolist (new-or-modified
+                 (split-string
+                  (shell-command-to-string
+                   "git ls-files -zmo --exclude-standard") "\0" t))
+          (if (and use-annex
+                   (>= (file-attribute-size (file-attributes new-or-modified))
+                       org-attach-git-annex-cutoff))
+              (call-process "git" nil nil nil "annex" "add" new-or-modified)
+            (call-process "git" nil nil nil "add" new-or-modified))
+	    (cl-incf changes))
+	(dolist (deleted
+		 (split-string
+		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
+	  (call-process "git" nil nil nil "rm" deleted)
+	  (cl-incf changes))
+	(when (> changes 0)
+	  (shell-command "git commit -m 'Synchronized attachments'"))))))
+
+(add-hook 'org-attach-after-change-hook 'org-attach-git-commit)
+(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe)
+
+(provide 'org-attach-git)
+
+;;; org-attach-git.el ends here
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index de8b2fc96..d863aa38b 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -1,9 +1,9 @@
-;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*-
+;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2008-2019 Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@newartisans.com>
-;; Keywords: org data task
+;; Keywords: org data attachment
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -24,32 +24,30 @@
 
 ;; See the Org manual for information on how to use it.
 ;;
-;; Attachments are managed in a special directory called "data", which
-;; lives in the same directory as the org file itself.  If this data
-;; directory is initialized as a Git repository, then org-attach will
-;; automatically commit changes when it sees them.
-;;
-;; Attachment directories are identified using a UUID generated for the
-;; task which has the attachments.  These are added as property to the
-;; task when necessary, and should not be deleted or changed by the
-;; user, ever.  UUIDs are generated by a mechanism defined in the variable
-;; `org-id-method'.
+;; Attachments are managed either by using a custom property DIR or by
+;; using property ID from org-id.  When DIR is defined, a location in
+;; the filesystem is directly attached to the outline node.  When
+;; org-id is used, attachments are stored in a folder named after the
+;; ID, in a location defined by `org-attach-id-dir'.  DIR has
+;; precedence over ID when both parameters are defined for the current
+;; outline node (also when inherited parameters are taken into
+;; account).
 
 ;;; Code:
 
 (require 'cl-lib)
 (require 'org)
+(require 'ol)
 (require 'org-id)
-(require 'vc-git)
 
 (declare-function dired-dwim-target-directory "dired-aux")
 
 (defgroup org-attach nil
-  "Options concerning entry attachments in Org mode."
+  "Options concerning attachments in Org mode."
   :tag "Org Attach"
   :group 'org)
 
-(defcustom org-attach-directory "data/"
+(defcustom org-attach-id-dir "data/"
   "The directory where attachments are stored.
 If this is a relative path, it will be interpreted relative to the directory
 where the Org file lives."
@@ -57,22 +55,13 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
-(defcustom org-attach-commit t
-  "If non-nil commit attachments with git.
-This is only done if the Org file is in a git repository."
+(defcustom org-attach-dir-relative nil
+  "Choose whether directories in DIR property should be added as relative links or not.
+Defaults to absolute location."
   :group 'org-attach
   :type 'boolean
-  :version "26.1"
-  :package-version '(Org . "9.0"))
-
-(defcustom org-attach-git-annex-cutoff (* 32 1024)
-  "If non-nil, files larger than this will be annexed instead of stored."
-  :group 'org-attach
-  :version "24.4"
-  :package-version '(Org . "8.0")
-  :type '(choice
-	  (const :tag "None" nil)
-	  (integer :tag "Bytes")))
+  :package-version '(Org . "9.3")
+  :safe #'booleanp)
 
 (defcustom org-attach-auto-tag "ATTACH"
   "Tag that will be triggered automatically when an entry has an attachment."
@@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository."
 	  (const :tag "None" nil)
 	  (string :tag "Tag")))
 
-(defcustom org-attach-file-list-property "Attachments"
-  "The property used to keep a list of attachment belonging to this entry.
-This is not really needed, so you may set this to nil if you don't want it.
-Also, for entries where children inherit the directory, the list of
-attachments is not kept in this property."
+(defcustom org-attach-preferred-new-method 'id
+  "Preferred way to attach to nodes without existing ID and DIR property.
+This choice is used when adding attachments to nodes without ID
+and DIR properties.
+
+Allowed values are:
+
+id         Create and use an ID parameter
+dir        Create and use a DIR parameter
+ask        Ask the user for input of which method to choose
+nil        Prefer to not create a new parameter
+
+           nil means that ID or DIR has to be created explicitly
+           before attaching files."
   :group 'org-attach
+  :package-version '(org . "9.3")
   :type '(choice
-	  (const :tag "None" nil)
-	  (string :tag "Tag")))
+	  (const :tag "ID parameter" id)
+	  (const :tag "DIR parameter" dir)
+	  (const :tag "Ask user" ask)
+	  (const :tag "Don't create" nil)))
 
 (defcustom org-attach-method 'cp
   "The preferred method to attach a file.
@@ -113,14 +114,22 @@ lns   create a symbol link.  Note that this is not supported
   :group 'org-attach
   :type 'boolean)
 
-(defcustom org-attach-allow-inheritance t
-  "Non-nil means allow attachment directories be inherited."
+(defcustom org-attach-use-inheritance 'selective
+  "Non-nil means allow attachments to be inherited from parent outline nodes.
+
+The implication of this is that (1) attachment links will look
+through all parent headings until it finds the linked attachment
+and (2) that running org-attach inside a node without attachments
+will make org-attach operate on the first parent heading it finds
+with attachments."
   :group 'org-attach
+  :type '(choice
+	  (const :tag "Don't use inheritance" nil)
+	  (const :tag "Inherit parent node attachments" t)
+	  (const :tag "Respect org-use-property-inheritance" selective)
+	  )
   :type 'boolean)
 
-(defvar org-attach-inherited nil
-  "Indicates if the last access to the attachment directory was inherited.")
-
 (defcustom org-attach-store-link-p nil
   "Non-nil means store a link to a file when attaching it."
   :group 'org-attach
@@ -141,16 +150,27 @@ When set to `query', ask the user instead."
 	  (const :tag "Always delete attachments" t)
 	  (const :tag "Query the user" query)))
 
-(defcustom org-attach-annex-auto-get 'ask
-  "Confirmation preference for automatically getting annex files.
-If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+(defun org-attach-id-folder-format (id)
+  (format "%s/%s"
+	  (substring id 0 2)
+	  (substring id 2))
+  )
+
+(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format
+  "The function parsing the ID parameter into a folder-path"
   :group 'org-attach
-  :package-version '(Org . "9.0")
-  :version "26.1"
-  :type '(choice
-	  (const :tag "confirm with `y-or-n-p'" ask)
-	  (const :tag "always get from annex if necessary" t)
-	  (const :tag "never get from annex" nil)))
+  :package-version '(Org . "9.3")
+  :type 'function
+  )
+
+(defvar org-attach-after-change-hook nil
+  "Hook to be called when files have been added or removed to the attachment folder.")
+
+(defvar org-attach-open-hook nil
+  "Hook that is invoked by `org-attach-open'.
+
+Created mostly to be compatible with org-attach-git after removing
+git-funtionality from this file.")
 
 (defcustom org-attach-commands
   '(((?a ?\C-a) org-attach-attach
@@ -186,9 +206,9 @@ you added attachments yourself.\n")
      "Delete all of a task's attachments.  A safer way is\n to open the \
 directory in dired and delete from there.\n")
     ((?s ?\C-s) org-attach-set-directory
-     "Set a specific attachment directory for this entry or reset to default.")
-    ((?i ?\C-i) org-attach-set-inherit
-     "Make children of the current entry inherit its attachment directory.\n")
+     "Set a specific attachment directory for this entry. Sets DIR property.")
+    ((?S ?\C-S) org-attach-unset-directory
+     "Unset the attachment directory for this entry.  Removes DIR property.")
     ((?q) (lambda () (interactive) (message "Abort")) "Abort."))
   "The list of commands for the attachment dispatcher.
 Each entry in this list is a list of three elements:
@@ -210,12 +230,14 @@ Each entry in this list is a list of three elements:
   "The dispatcher for attachment commands.
 Shows a list of commands and prompts for another key to execute a command."
   (interactive)
-  (let (c marker)
+  (let (c marker attachment)
     (when (eq major-mode 'org-agenda-mode)
       (setq marker (or (get-text-property (point) 'org-hd-marker)
 		       (get-text-property (point) 'org-marker)))
       (unless marker
-	(error "No task in current line")))
+	(error "No item in current line")))
+    (setq attachment (or (org-attach-dir)
+			 (quote  "No existing attachment-folder")))
     (save-excursion
       (when marker
 	(set-buffer (marker-buffer marker))
@@ -225,24 +247,25 @@ Shows a list of commands and prompts for another key to execute a command."
 	(save-window-excursion
 	  (unless org-attach-expert
 	    (with-output-to-temp-buffer "*Org Attach*"
-	      (princ
-	       (format "Select an Attachment Command:\n\n%s"
-		       (mapconcat
-			(lambda (entry)
-			  (pcase entry
-			    (`((,key . ,_) ,_ ,docstring)
-			     (format "%c       %s"
-				     key
-				     (replace-regexp-in-string "\n\\([\t ]*\\)"
-							       "        "
-							       docstring
-							       nil nil 1)))
-			    (_
-			     (user-error
-			      "Invalid `org-attach-commands' item: %S"
-			      entry))))
-			org-attach-commands
-			"\n")))))
+              (princ
+               (concat "Attachment folder:\n" attachment "\n\n"
+	               (format "Select an Attachment Command:\n\n%s"
+		               (mapconcat
+		                (lambda (entry)
+		                  (pcase entry
+		                    (`((,key . ,_) ,_ ,docstring)
+		                     (format "%c       %s"
+			                     key
+			                     (replace-regexp-in-string "\n\\([\t ]*\\)"
+							               "        "
+							               docstring
+							               nil nil 1)))
+		                    (_
+		                     (user-error
+			              "Invalid `org-attach-commands' item: %S"
+			              entry))))
+		                org-attach-commands
+		                "\n"))))))
 	  (org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
 	  (message "Select command: [%s]"
 		   (concat (mapcar #'caar org-attach-commands)))
@@ -256,148 +279,128 @@ Shows a list of commands and prompts for another key to execute a command."
 	  (error "No such attachment command: %c" c))))))
 
 (defun org-attach-dir (&optional create-if-not-exists-p)
-  "Return the directory associated with the current entry.
-This first checks for a local property ATTACH_DIR, and then for an inherited
-property ATTACH_DIR_INHERIT.  If neither exists, the default mechanism
-using the entry ID will be invoked to access the unique directory for the
-current entry.
-If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil,
-the directory and (if necessary) the corresponding ID will be created."
-  (let (attach-dir uuid)
-    (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT"))
-    (cond
-     ((setq attach-dir (org-entry-get nil "ATTACH_DIR"))
-      (org-attach-check-absolute-path attach-dir))
-     ((and org-attach-allow-inheritance
-	   (org-entry-get nil "ATTACH_DIR_INHERIT" t))
-      (setq attach-dir
-	    (org-with-wide-buffer
-	     (if (marker-position org-entry-property-inherited-from)
-		 (goto-char org-entry-property-inherited-from)
-	       (org-back-to-heading t))
-	     (let (org-attach-allow-inheritance)
-	       (org-attach-dir create-if-not-exists-p))))
-      (org-attach-check-absolute-path attach-dir)
-      (setq org-attach-inherited t))
-     (t					; use the ID
-      (org-attach-check-absolute-path nil)
-      (setq uuid (org-id-get (point) create-if-not-exists-p))
-      (when (or uuid create-if-not-exists-p)
-	(unless uuid (error "ID retrieval/creation failed"))
-	(setq attach-dir (expand-file-name
-			  (format "%s/%s"
-				  (substring uuid 0 2)
-				  (substring uuid 2))
-			  (expand-file-name org-attach-directory))))))
-    (when attach-dir
-      (if (and create-if-not-exists-p
-	       (not (file-directory-p attach-dir)))
-	  (make-directory attach-dir t))
-      (and (file-exists-p attach-dir)
-	   attach-dir))))
+  "Return the directory associated with the current outline node.
+First check for DIR property, then ID property.
+`org-attach-use-inheritance' determines whether inherited
+properties also will be considered.
+
+If an ID property is found the default mechanism using that ID
+will be invoked to access the directory for the current entry.
+
+If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
+is run."
+  (if create-if-not-exists-p
+      (org-attach-dir-get-create)
+    (let (attach-dir id)
+      (cond
+       ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
+	(org-attach-check-absolute-path attach-dir))
+       ;; Depricated and removed from documentation, but still
+       ;; works. Remove after major nr change...
+       ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance))
+	(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))))
+      attach-dir)))
+
+(defun org-attach-dir-get-create ()
+  "Return existing or new directory associated with the current outline node.
+
+`org-attach-preferred-new-method' decides how to attach
+new directory."
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (unless attach-dir
+      (let (answer)
+	(when (eq org-attach-preferred-new-method 'ask)
+	  (message "Create new ID [1] property or DIR [2] property for attachments?")
+	  (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))))
+	 ((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)
+	  (error "No existing directory. DIR or ID property has to be explicitly created.")))))
+    (if attach-dir
+	(progn (if (not (file-directory-p attach-dir))
+		   (make-directory attach-dir t))
+	       (if (file-exists-p attach-dir)
+		   attach-dir
+		 (error "Path does not exist: %s." attach-dir)))
+      (error "No attachment directory is associated with the current node."))))
+
+(defun org-attach-dir-from-id (id)
+  "Creates a path 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-check-absolute-path (dir)
   "Check if we have enough information to root the attachment directory.
 When DIR is given, check also if it is already absolute.  Otherwise,
-assume that it will be relative, and check if `org-attach-directory' is
+assume that it will be relative, and check if `org-attach-id-dir' is
 absolute, or if at least the current buffer has a file name.
 Throw an error if we cannot root the directory."
   (or (and dir (file-name-absolute-p dir))
-      (file-name-absolute-p org-attach-directory)
+      (file-name-absolute-p org-attach-id-dir)
       (buffer-file-name (buffer-base-buffer))
-      (error "Need absolute `org-attach-directory' to attach in buffers without filename")))
+      (error "Need absolute `org-attach-id-dir' to attach in buffers without filename")))
 
-(defun org-attach-set-directory (&optional arg)
-  "Set the ATTACH_DIR node property and ask to move files there.
+(defun org-attach-set-directory ()
+  "Set the DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
-of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
-  (interactive "P")
+of the entry.  Creates relative links if `org-attach-dir-relative'
+is t.
+
+Return the directory."
+  (interactive)
   (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+	(new
+	 (let* ((attach-dir (read-directory-name
+			     "Attachment directory: "
+			     (org-entry-get nil "DIR")))
+		(current-dir (file-name-directory (or default-directory
+						      buffer-file-name)))
+		(attach-dir-relative (file-relative-name attach-dir current-dir)))
+	   (org-entry-put nil "DIR" (if org-attach-dir-relative
+					attach-dir-relative
+				      attach-dir))
+           attach-dir)))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
+        (copy-directory old new t t t))
+      (when (yes-or-no-p (concat "Delete " old))
+        (delete-directory old t)))
+    new))
+
+(defun org-attach-unset-directory ()
+  "Removes DIR node property.
+If attachment folder is changed due to removal of DIR-property
+ask to move attachments to new location and ask to delete old
+attachment-folder.
+
+Change of attachment-folder due to unset might be if an ID
+property is set on the node, or if a separate inherited
+DIR-property exists (that is different than the unset one)."
+  (interactive)
+  (let ((old (org-attach-dir))
+	(new
+         (progn
+	   (org-entry-delete nil "DIR")
+	   ;; ATTACH-DIR is depricated and removed from documentation,
+	   ;; but still works. Remove code for it after major nr change.
+	   (org-entry-delete nil "ATTACH_DIR")
+	   (org-attach-dir))))
+    (unless (or (string= old new)
+                (not old))
+      (when (and new (yes-or-no-p "Copy over attachments from old directory? "))
         (copy-directory old new t nil t))
       (when (yes-or-no-p (concat "Delete " old))
         (delete-directory old t)))))
 
-(defun org-attach-set-inherit ()
-  "Set the ATTACH_DIR_INHERIT property of the current entry.
-The property defines the directory that is used for attachments
-of the entry and any children that do not explicitly define (by setting
-the ATTACH_DIR property) their own attachment directory."
-  (interactive)
-  (org-entry-put nil "ATTACH_DIR_INHERIT" "t")
-  (message "Children will inherit attachment directory"))
-
-(defun org-attach-use-annex ()
-  "Return non-nil if git annex can be used."
-  (let ((git-dir (vc-git-root (expand-file-name org-attach-directory))))
-    (and org-attach-git-annex-cutoff
-         (or (file-exists-p (expand-file-name "annex" git-dir))
-             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
-
-(defun org-attach-annex-get-maybe (path)
-  "Call git annex get PATH (via shell) if using git annex.
-Signals an error if the file content is not available and it was not retrieved."
-  (let* ((default-directory (expand-file-name org-attach-directory))
-	 (path-relative (file-relative-name path)))
-    (when (and (org-attach-use-annex)
-	       (not
-		(string-equal
-		 "found"
-		 (shell-command-to-string
-		  (format "git annex find --format=found --in=here %s"
-			  (shell-quote-argument path-relative))))))
-      (let ((should-get
-	     (if (eq org-attach-annex-auto-get 'ask)
-		 (y-or-n-p (format "Run git annex get %s? " path-relative))
-	       org-attach-annex-auto-get)))
-	(if should-get
-	    (progn (message "Running git annex get \"%s\"." path-relative)
-		   (call-process "git" nil nil nil "annex" "get" path-relative))
-	  (error "File %s stored in git annex but it is not available, and was not retrieved"
-		 path))))))
-
-(defun org-attach-commit ()
-  "Commit changes to git if `org-attach-directory' is properly initialized.
-This checks for the existence of a \".git\" directory in that directory."
-  (let* ((dir (expand-file-name org-attach-directory))
-	 (git-dir (vc-git-root dir))
-	 (use-annex (org-attach-use-annex))
-	 (changes 0))
-    (when (and git-dir (executable-find "git"))
-      (with-temp-buffer
-	(cd dir)
-        (dolist (new-or-modified
-                 (split-string
-                  (shell-command-to-string
-                   "git ls-files -zmo --exclude-standard") "\0" t))
-          (if (and use-annex
-                   (>= (file-attribute-size (file-attributes new-or-modified))
-                       org-attach-git-annex-cutoff))
-              (call-process "git" nil nil nil "annex" "add" new-or-modified)
-            (call-process "git" nil nil nil "add" new-or-modified))
-	    (cl-incf changes))
-	(dolist (deleted
-		 (split-string
-		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
-	  (call-process "git" nil nil nil "rm" deleted)
-	  (cl-incf changes))
-	(when (> changes 0)
-	  (shell-command "git commit -m 'Synchronized attachments'"))))))
-
 (defun org-attach-tag (&optional off)
   "Turn the autotag on or (if OFF is set) off."
   (when org-attach-auto-tag
@@ -422,22 +425,21 @@ Only do this when `org-attach-store-link-p' is non-nil."
   (org-attach-attach url))
 
 (defun org-attach-buffer (buffer-name)
-  "Attach BUFFER-NAME's contents to current task.
+  "Attach BUFFER-NAME's contents to current outline node.
 BUFFER-NAME is a string.  Signals a `file-already-exists' error
 if it would overwrite an existing filename."
   (interactive "bBuffer whose contents should be attached: ")
-  (let ((output (expand-file-name buffer-name (org-attach-dir t))))
+  (let* ((attach-dir (org-attach-dir 'get-create))
+	 (output (expand-file-name buffer-name attach-dir)))
     (when (file-exists-p output)
       (signal 'file-already-exists (list "File exists" output)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property buffer-name))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)
     (org-attach-tag)
     (with-temp-file output
       (insert-buffer-substring buffer-name))))
 
 (defun org-attach-attach (file &optional visit-dir method)
-  "Move/copy/link FILE into the attachment directory of the current task.
+  "Move/copy/link FILE into the attachment directory of the current outline node.
 If VISIT-DIR is non-nil, visit the directory with dired.
 METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
 `org-attach-method'."
@@ -452,10 +454,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
     nil))
   (setq method (or method org-attach-method))
   (let ((basename (file-name-nondirectory file)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property basename))
-    (let* ((attach-dir (org-attach-dir t))
+    (let* ((attach-dir (org-attach-dir 'get-create))
            (fname (expand-file-name basename attach-dir)))
       (cond
        ((eq method 'mv) (rename-file file fname))
@@ -463,8 +462,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
        ((eq method 'ln) (add-name-to-file file fname))
        ((eq method 'lns) (make-symbolic-link file fname))
        ((eq method 'url) (url-copy-file file fname)))
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-tag)
       (cond ((eq org-attach-store-link-p 'attached)
              (org-attach-store-link fname))
@@ -472,7 +470,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
              (org-attach-store-link file)))
       (if visit-dir
           (dired attach-dir)
-        (message "File %S is now a task attachment." basename)))))
+        (message "File %S is now an attachment." basename)))))
 
 (defun org-attach-attach-cp ()
   "Attach a file by copying it."
@@ -497,13 +495,10 @@ On some systems, this apparently does copy the file instead."
   (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach)))
 
 (defun org-attach-new (file)
-  "Create a new attachment FILE for the current task.
+  "Create a new attachment FILE for the current outline node.
 The attachment is created as an Emacs buffer."
   (interactive "sCreate attachment named: ")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-add-to-multivalued-property
-     (point) org-attach-file-list-property file))
-  (let ((attach-dir (org-attach-dir t)))
+  (let ((attach-dir (org-attach-dir 'get-create)))
     (org-attach-tag)
     (find-file (expand-file-name file attach-dir))
     (message "New attachment %s" file)))
@@ -511,7 +506,7 @@ The attachment is created as an Emacs buffer."
 (defun org-attach-delete-one (&optional file)
   "Delete a single attachment."
   (interactive)
-  (let* ((attach-dir (org-attach-dir t))
+  (let* ((attach-dir (org-attach-dir))
 	 (files (org-attach-file-list attach-dir))
 	 (file (or file
 		   (completing-read
@@ -523,44 +518,33 @@ The attachment is created as an Emacs buffer."
     (unless (file-exists-p file)
       (error "No such attachment: %s" file))
     (delete-file file)
-    (when org-attach-commit
-      (org-attach-commit))))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)))
 
 (defun org-attach-delete-all (&optional force)
-  "Delete all attachments from the current task.
+  "Delete all attachments from the current outline node.
 This actually deletes the entire attachment directory.
 A safer way is to open the directory in dired and delete from there."
   (interactive "P")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
-    (when
-	(and attach-dir
-	     (or force
-		 (y-or-n-p "Are you sure you want to remove all attachments of this entry? ")))
-      (shell-command (format "rm -fr %s" attach-dir))
+    (when (and attach-dir
+	       (or force
+		   (y-or-n-p "Are you sure you want to remove all attachments of this entry? ")))
+      (delete-directory attach-dir (yes-or-no-p "Recursive?") t)
       (message "Attachment directory removed")
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-untag))))
 
 (defun org-attach-sync ()
-  "Synchronize the current tasks with its attachments.
+  "Synchronize the current outline node with its attachments.
 This can be used after files have been added externally."
   (interactive)
-  (when org-attach-commit
-    (org-attach-commit))
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
     (when attach-dir
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (let ((files (org-attach-file-list attach-dir)))
-	(org-attach-tag (not files))
-	(when org-attach-file-list-property
-	  (dolist (file files)
-	    (unless (string-match "^\\.\\.?\\'" file)
-	      (org-entry-add-to-multivalued-property
-	       (point) org-attach-file-list-property file))))))))
+	(org-attach-tag (not files))))
+    (when (not attach-dir)
+      (org-attach-tag t))))
 
 (defun org-attach-file-list (dir)
   "Return a list of files in the attachment directory.
@@ -569,35 +553,41 @@ This ignores files ending in \"~\"."
 	(mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x))
 		(directory-files dir nil "[^~]\\'"))))
 
-(defun org-attach-reveal (&optional if-exists)
-  "Show the attachment directory of the current task.
+(defun org-attach-reveal ()
+  "Show the attachment directory of the current outline node.
 This will attempt to use an external program to show the directory."
-  (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
-    (and attach-dir (org-open-file attach-dir))))
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(org-open-file attach-dir)
+      (error "No attachment directory exist."))))
 
 (defun org-attach-reveal-in-emacs ()
-  "Show the attachment directory of the current task in dired."
+  "Show the attachment directory of the current outline node in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(dired attach-dir)
+      (error "No attachment directory exist."))))
 
 (defun org-attach-open (&optional in-emacs)
-  "Open an attachment of the current task.
+  "Open an attachment of the current outline node.
 If there are more than one attachment, you will be prompted for the file name.
 This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(let* ((files (org-attach-file-list attach-dir))
+	       (file (if (= (length files) 1)
+			 (car files)
+		       (completing-read "Open attachment: "
+					(mapcar #'list files) nil t)))
+	       (path (expand-file-name file attach-dir)))
+	  (run-hook-with-args 'org-attach-open-hook path)
+	  (org-open-file path in-emacs))
+      (error "No attachment directory exist."))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -616,6 +606,66 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(org-link-set-parameters "attachment"
+                         :follow #'org-attach-open-link
+                         :export #'org-attach-export-link
+                         :complete #'org-attach-complete-link)
+
+(defun org-attach-open-link (link &optional in-emacs)
+  "Attachment link type LINK is expanded with the attached directory and opened.
+
+With optional prefix argument IN-EMACS, Emacs will visit the file.
+With a double \\[universal-argument] \\[universal-argument] \
+prefix arg, Org tries to avoid opening in Emacs
+and to use an external application to visit the file."
+  (interactive "P")
+  (let (line search)
+    (cond
+     ((string-match "::\\([0-9]+\\)\\'" link)
+      (setq line (string-to-number (match-string 1 link))
+	    link (substring link 0 (match-beginning 0))))
+     ((string-match "::\\(.+\\)\\'" link)
+      (setq search (match-string 1 link)
+            link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment directory."
+  (let* ((attached-dir (expand-file-name (org-attach-dir)))
+	 (file (read-file-name "File: " attached-dir))
+	 (pwd (file-name-as-directory attached-dir))
+         (pwd-relative (file-name-as-directory
+			(abbreviate-file-name attached-dir))))
+    (cond
+     ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file)
+      (concat "attachment:" (match-string 1 file)))
+     ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+                    (expand-file-name file))
+      (concat "attachment:" (match-string 1 (expand-file-name file))))
+     (t (concat "attachment:" file)))))
+
+(defun org-attach-export-link (link description format)
+  "Translate attachment LINK from Org mode format to exported FORMAT.
+Also includes the DESCRIPTION of the link in the export."
+  (save-excursion
+    (let (path desc)
+      (cond
+       ((string-match "::\\([0-9]+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0))))
+       ((string-match "::\\(.+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0)))))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index 9cb396fe9..42fe64379 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -263,6 +263,9 @@ Counting starts at 1."
 (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays
   'org-clear-latex-preview "Org 9.3")
 
+(define-obsolete-variable-alias 'org-attach-directory
+  'org-attach-id-dir "Org 9.3")
+
 (defun org-in-fixed-width-region-p ()
   "Non-nil if point in a fixed-width region."
   (save-match-data
diff --git a/lisp/org.el b/lisp/org.el
index f0e7c3ab8..10b8babe5 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -3849,7 +3849,9 @@ This is needed for font-lock setup.")
 		  (beg end))
 (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
 (declare-function org-agenda-skip "org-agenda" ())
-(declare-function org-attach-reveal "org-attach" (&optional if-exists))
+(declare-function org-attach-expand "org-attach" (file))
+(declare-function org-attach-reveal "org-attach" ())
+(declare-function org-attach-reveal-in-emacs "org-attach" ())
 (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
 (declare-function org-indent-mode "org-indent" (&optional arg))
 (declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
@@ -8647,12 +8649,15 @@ a link."
 	  (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
 	    (`(nil . ,_)
 	     (require 'org-attach)
-	     (org-attach-reveal 'if-exists))
+	     (message "Opening attachment-dir")
+	     (if (equal arg '(4))
+		 (org-attach-reveal-in-emacs)
+	       (org-attach-reveal)))
 	    (`(,links . ,links-end)
 	     (dolist (link (if (stringp links) (list links) links))
 	       (search-forward link nil links-end)
 	       (goto-char (match-beginning 0))
-	       (org-open-at-point))))))
+	       (org-open-at-point arg))))))
        ;; On a footnote reference or at definition's label.
        ((or (eq type 'footnote-reference)
 	    (and (eq type 'footnote-definition)
@@ -16632,13 +16637,14 @@ boundaries."
 	     ;; "file:" links.  Also check link abbreviations since
 	     ;; some might expand to "file" links.
 	     (file-types-re
-	      (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
+	      (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
 		      (if (not link-abbrevs) ""
 			(concat "\\|" (regexp-opt link-abbrevs))))))
 	(while (re-search-forward file-types-re end t)
 	  (let* ((link (org-element-lineage
 			(save-match-data (org-element-context))
 			'(link) t))
+                 (linktype (org-element-property :type link))
 		 (inner-start (match-beginning 1))
 		 (path
 		  (cond
@@ -16652,7 +16658,8 @@ boundaries."
 		   ;; INCLUDE-LINKED is non-nil.
 		   ((or (not (org-element-property :contents-begin link))
 			include-linked)
-		    (and (equal "file" (org-element-property :type link))
+		    (and (or (equal "file" linktype)
+                             (equal "attachment" linktype))
 			 (org-element-property :path link)))
 		   ;; Link with a description.  Check if description
 		   ;; is a filename.  Even if Org doesn't have syntax
@@ -16671,7 +16678,11 @@ boundaries."
 			      (match-end 0))
 			   (match-string 2)))))))
 	    (when (and path (string-match-p file-extension-re path))
-	      (let ((file (expand-file-name path)))
+	      (let ((file (if (equal "attachment" linktype)
+                              (progn
+                                (require 'org-attach)
+                                (org-attach-expand path))
+                            (expand-file-name path))))
 		(when (file-exists-p file)
 		  (let ((width
 			 ;; Apply `org-image-actual-width' specifications.
diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA
new file mode 100644
index 000000000..9a0406c0d
--- /dev/null
+++ b/testing/examples/att1/fileA
@@ -0,0 +1 @@
+Text in fileA
diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB
new file mode 100644
index 000000000..dd2331824
--- /dev/null
+++ b/testing/examples/att1/fileB
@@ -0,0 +1 @@
+Text in fileB
diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC
new file mode 100644
index 000000000..2c9a92bfe
--- /dev/null
+++ b/testing/examples/att2/fileC
@@ -0,0 +1 @@
+Text in fileC
\ No newline at end of file
diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD
new file mode 100644
index 000000000..c706556c5
--- /dev/null
+++ b/testing/examples/att2/fileD
@@ -0,0 +1 @@
+text in fileD
diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org
new file mode 100644
index 000000000..ab4a4e548
--- /dev/null
+++ b/testing/examples/attachments.org
@@ -0,0 +1,32 @@
+#+TITLE: Org attach testfile
+Used to test and verify the functionality of org-attach.
+
+* H1
+ :PROPERTIES:
+ :DIR:      att1
+ :END:
+A link to one attachment: [[attachment:fileA]]
+
+** H1.1
+A link to another attachment: [[attachment:fileB]]
+
+** H1.2
+  :PROPERTIES:
+  :DIR:      att2
+  :END:
+
+* H2
+ :PROPERTIES:
+ :ID:       abcd123
+ :END:
+
+* H3
+ :PROPERTIES:
+ :DIR:      att1
+ :ID:       abcd1234
+ :END:
+
+** H3.1
+  :PROPERTIES:
+  :ID:       abcd12345
+  :END:
diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE
new file mode 100644
index 000000000..80d337772
--- /dev/null
+++ b/testing/examples/data/ab/cd123/fileE
@@ -0,0 +1 @@
+peek-a-boo
diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el
similarity index 93%
rename from testing/lisp/test-org-attach-annex.el
rename to testing/lisp/test-org-attach-git.el
index 7f2792696..8b826b72f 100644
--- a/testing/lisp/test-org-attach-annex.el
+++ b/testing/lisp/test-org-attach-git.el
@@ -20,19 +20,19 @@
 
 ;;; Code:
 (org-test-for-executable "git-annex")
-(require 'org-attach)
+(require 'org-attach-git)
 (require 'cl-lib)
 
-(defmacro test-org-attach-annex/with-annex (&rest body)
+(defmacro test-org-attach-git/with-annex (&rest body)
   `(let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (shell-command "git annex init")
 	   ,@body))))
 
-(ert-deftest test-org-attach/use-annex ()
+(ert-deftest test-org-attach-git/use-annex ()
   (test-org-attach-annex/with-annex
    (let ((org-attach-git-annex-cutoff 1))
      (should (org-attach-use-annex)))
@@ -44,12 +44,12 @@
   (let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (should-not (org-attach-use-annex)))
        (delete-directory tmpdir 'recursive))))
 
-(ert-deftest test-org-attach/get-maybe ()
+(ert-deftest test-org-attach-git/get-maybe ()
   (test-org-attach-annex/with-annex
    (let ((path (expand-file-name "test-file"))
 	 (annex-dup (make-temp-file "org-annex-test" t "/")))
diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el
index c2f2be356..02fd05032 100644
--- a/testing/lisp/test-org-attach.el
+++ b/testing/lisp/test-org-attach.el
@@ -28,6 +28,56 @@
 (require 'org-attach)
 (eval-and-compile (require 'cl-lib))
 
+(ert-deftest test-org-attach/dir ()
+  "Test `org-attach-get' specifications."
+  (org-test-in-example-file org-test-attachments-file
+    ;; Link inside H1
+    (org-next-link)
+    (save-excursion
+      (org-open-at-point)
+      (should (equal "Text in fileA\n" (buffer-string))))
+    ;; * H1.1
+    (org-next-visible-heading 1)
+    (let ((org-attach-use-inheritance nil))
+      (should-not (equal "att1" (org-attach-dir))))
+    (let ((org-attach-use-inheritance t))
+      (should (equal "att1" (org-attach-dir))))
+    ;; Link inside H1.1
+    (org-next-link)
+    (save-excursion
+      (let ((org-attach-use-inheritance nil))
+	(org-open-at-point)
+	(should-not (equal "Text in fileB\n" (buffer-string)))))
+    (save-excursion
+      (let ((org-attach-use-inheritance t))
+	(org-open-at-point)
+	(should (equal "Text in fileB\n" (buffer-string)))))
+    ;; * H1.2
+    (org-next-visible-heading 1)
+    (should (equal '("fileC" "fileD") (org-attach-file-list (org-attach-dir))))
+    ;; * H2
+    (org-next-visible-heading 1)
+    (let ((org-attach-id-dir "data/"))
+      (should (equal '("fileE") (org-attach-file-list (org-attach-dir))))
+      (save-excursion
+	(org-attach-open-in-emacs)
+	(should (equal "peek-a-boo\n" (buffer-string)))))
+    ;; * H3
+    (org-next-visible-heading 1)
+    ;; DIR has priority over ID
+    (should (equal '("fileA" "fileB") (org-attach-file-list (org-attach-dir))))
+    ;; * H3.1
+    (org-next-visible-heading 1)
+    (let ((org-attach-use-inheritance nil))
+      (should (equal "data/ab/cd12345" (file-relative-name (org-attach-dir)))))
+    (let ((org-attach-use-inheritance t))
+      ;; This is where it get's a bit sketchy...! DIR always has
+      ;; priority over ID, even if ID is declared "higher up" in the
+      ;; tree.  This can potentially be revised.  But it is also
+      ;; pretty clean.  DIR is always higher in priority than ID right
+      ;; now, no matter the depth in the tree.
+      (should (equal '("fileA" "fileB") (org-attach-file-list (org-attach-dir)))))))
+
 (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 ()
   "Attach file at point in dired to subtree."
   (should
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index d671b5c78..a618da479 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -2514,7 +2514,11 @@ Foo Bar
      (catch :result
        (cl-letf (((symbol-function 'org-tags-view)
 		  (lambda (&rest args) (throw :result t))))
-	 (org-open-at-point)
+	 ;; When point isn't on a tag it's going to try other things,
+	 ;; possibly trying to open attachments which will return an
+	 ;; error if there isn't an attachment. Supress that error.
+	 (ignore-errors
+	     (org-open-at-point))
 	 nil)))))
 
 \f
diff --git a/testing/org-test.el b/testing/org-test.el
index 6b218fc00..6d216bc28 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.")
 (defconst org-test-no-heading-file
   (expand-file-name "no-heading.org" org-test-example-dir))
 
+(defconst org-test-attachments-file
+  (expand-file-name "attachments.org" org-test-example-dir))
+
 (defconst org-test-link-in-heading-file
   (expand-file-name "link-in-heading.org" org-test-dir))
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-01-04 12:21 ` FW: " Feng Shu
@ 2019-05-26 23:15   ` Gustav Wikström
  0 siblings, 0 replies; 113+ messages in thread
From: Gustav Wikström @ 2019-05-26 23:15 UTC (permalink / raw)
  To: Feng Shu; +Cc: emacs-orgmode

Hi Feng Shu,

> -----Original Message-----
> From: Feng Shu <tumashu@163.com>
> Sent: den 4 januari 2019 13:22
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> I like this feature very much!

I'm glad! I've just now sent an updated patch to the mailing-list. 
It contains quite substantial changes. Maybe you care to review it 
as well? 

Best
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-05-26 23:05             ` Gustav Wikström
@ 2019-06-15 13:29               ` Nicolas Goaziou
  2019-06-15 15:38                 ` Bastien
  2019-06-30  6:03                 ` Gustav Wikström
  0 siblings, 2 replies; 113+ messages in thread
From: Nicolas Goaziou @ 2019-06-15 13:29 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: Bastien Guerry, emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Some updates, and a fresh patch...!

Thank you.
>
> I won't say that much here since the patch speaks for itself (It 
> contains a chapter to be added to ORG-NEWS). It's patch 0002 that is the 
> important one. See sidenote below for a comment about patch 0001.
>
> I have to mention that the patch has grown quite a lot. With the 
> Additional changes, I've taken the liberty to promote attachments to a 
> level-1 headline within the documentation!

Hmm. I don't think it should be a top-level information. More on this below.

> Inheriting ID's for attachments is actually valuable. It makes it possible, 
> for example, to add attachment-links in subheadings to the node the  
> attachment is defined on. After having used this for quite some time now it
> feels quite natural to have inheritance switched on for attachments. No negative
> side-effects at all.

OK.

> (Sidenote 1; what do I need to do to gain access to the official 
> git-repository? Would be nice to be able to provide pull requests there!)

Pull requests are not the preferred way to interact with the project.
However, I think you should have write access to the repository. I'm
Cc'ing Bastien about it, as I cannot do it myself.

> (Sidenote 2; The first patch is some minor unrelated fixups - it 
> breaks test-org-export/expand-include as a side-effect. But that's probably 
> because the test doesn't do what it should! 😲 )

Probably. Yet, we should do something about it. If you cannot fix it, at
least please comment it out somehow.

>    (should
>     (equal
>      "1"
> -    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> -      (org-entry-get (point) "A" t))))
> +    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
> +      (org-entry-get (point-max) "A" t))))

Not that it is wrong, but I don't see the benefit of this change.

>    (should
>     (equal
>      "1"
> -    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> +    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"

Ditto.

>        (let ((org-use-property-inheritance t))
> -	(org-entry-get (point) "A" 'selective)))))
> +	(org-entry-get (point-max) "A" 'selective)))))

Ditto.

>    (should-not
> -   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> +   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
>       (let ((org-use-property-inheritance nil))
> -       (org-entry-get (point) "A" 'selective))))
> +       (org-entry-get (point-max) "A" 'selective))))

Ditto.

>  (defmacro org-test-with-temp-text-in-file (text &rest body)
> -  "Run body in a temporary file buffer with Org mode as the active mode."
> +  "Run body in a temporary file buffer with Org mode as the active mode.
> +If the string \"<point>\" appears in TEXT then remove it and
> +place the point there before running BODY, otherwise place the
> +point at the beginning of the buffer."
>    (declare (indent 1))
>    (let ((results (cl-gensym)))
>      `(let ((file (make-temp-file "org-test"))
> @@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text."
>  	   ,results)
>         (with-temp-file file (insert inside-text))
>         (find-file file)
> +       (when (re-search-forward "<point>" nil t)
> +	 (replace-match ""))
>         (org-mode)
>         (setq ,results (progn ,@body))
>         (save-buffer) (kill-buffer (current-buffer))

While we're at fixing this macro, we may also wrap stuff within
`unwind-protect' so as to properly delete temporary files in any cases.

> From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
> Date: Sun, 25 Nov 2018 21:38:44 +0100
> Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news,
>  testing/**/test-org-attach*
>
> * org-attach.el
>
> Changed the way attachments deal with property-inheritance.  It now
> adheres to the =org-use-property-inheritance= setting by default but
> it can be customized if needed (I recommend to enable it!).
> The property ATTACH_DIR is depricated in favour of the shorter and simpler
> property DIR.

depricated -> deprecated

> * org-manual.org
>
> Attachments have been promoted into its own top-level node!  There are
> a lot of goodies to mention here that didn't fit naturally with
> "capture" and "archive" before.

This is true, but there is not enough information to require a top-level
node.

Here is a suggestion. Split "Capture, Refile, Archive" into two parts:

1. Refile, Copy and Archiving in one place, because they all relate to
   moving existing data around

2. Capture, Attachments, RSS Feeds, Protocols in another place, because
   they all insert external data to the system.

WDYT?

> +File links and attachment links can contain additional information to

Since attachment links are file links, it seems redundant to talk about
both everywhere. Just clarify clearly once that attachments links are
file links for all purposes.

> +It is often useful to associate reference material with an outline
> +node/task.

I would use "node" only: it is more generic.

> +The attachment system has been contributed to Org by John Wiegley.

I would drop this reference, since John Wiegley is already mentioned in
the Thanks entry.

> +** Attachment defaults and dispatcher
> +By default, org-attach will use ID properties when adding attachments
> +to outline nodes.  This makes working with attachments fully
> +automated.  There is no decision needed for folder-name or location.
> +ID-based directories are by default located in the =data/= directory,
> +which lives in the same directory where your Org file lives[fn:87].
> +For more control over the setup, see [[*Attachment options]].
> +
> +When attachments are made using ~org-attach~ a default tag =ATTACH= is
> +added to the node that gets the attachments.

Note overly important, but we prefer the active voice whenever possible.

> +  #+begin_example
> +  ,* Chapter A ...
> +    :PROPERTIES:
> +    :DIR: Chapter A/
> +    :END:
> +  ,** Introduction
> +  Some text
> +
> +  #+NAME: Image 1
> +  [[Attachment:image 1.jpg]]
> +  #+end_example
> +
> +  Without inheritance one would not be able to resolve the link to image
> +  1.jpg, since the link is inside a sub-heading to Chapter A.

=1.jpg=  ... =Chapter A=

> +  Inheritance works the same way for both =ID= and =DIR= property.  If
> +  both properties are defined on the same headline then =DIR= takes
> +  precedance.  This is also true if inheritance is enabled.  If =DIR= is
> +  inherited from a parent node in the outline, that property still takes
> +  precedence over an =ID= property defined on the node itself.
> +
> +- ~org-attach-method~ ::
> +  #+vindex: org-attach-method
> +  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
> +  defaults to copying files.  The behaviour can be changed by
> +  customizing ~org-attach-method~.  Options are =Copy=, =Move/Rename=,
> +  =Hard link= or =Symbolic link=.

I don't think =...= are warranted here.

> +- ~org-attach-preferred-new-method~ ::
> +  #+vindex: org-attach-preferred-new-method
> +  This customization lets you choose the default way to attach to
> +  nodes without existing ID and DIR property.  It defaults to =id= but
> +  can also be set to =dir=, =ask= or =nil=.

~id~, ~dir~ ~ask~ or ~nil~, since those are symbols.

> +  Do not show the splash buffer with the attach dispatcher when
> +  ~org-attach-expert~ is set to Non-nil.

non-~nil~

> +** Attachment links
> +Attached files and folders can be referenced using attachment-links.

Why the hyphen in "attachment-links"? I think "attachment links" is
perfectly clear.

> +This makes it easy to refer to the material added to an outline node.
> +Especially if it was attached using the unique ID of the entry!
> +
> +#+begin_example
> +,* TODO Some task
> +  :PROPERTIES:
> +  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
> +  :END:
> +See attached document for more information: [[attachment:info.org]]
> +#+end_example
> +
> +See [[* External Links]] for more information about these links.

No need for the space: [[*External Links]]

> +** Automatic version-control with git

Shouldn't it be "Git"?

> +If the directory attached to an outline node is a git repository, Org

Ditto.

> +can be configured to automatically commit changes to that repository
> +when it sees them.
> +
> +To make org-mode take care of versioning of attachments for you, add

To make Org mode...

> +(defcustom org-attach-dir-relative nil
> +  "Choose whether directories in DIR property should be added as relative links or not.
> +Defaults to absolute location."

First line is too long, maybe:

    Non-nil means directories in DIR property are added as relative links

> -(defcustom org-attach-annex-auto-get 'ask
> -  "Confirmation preference for automatically getting annex files.
> -If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
> +(defun org-attach-id-folder-format (id)
> +  (format "%s/%s"
> +	  (substring id 0 2)
> +	  (substring id 2))
> +  )

No dangling parens, please. Also, this function needs a docstring.

> +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format
> +  "The function parsing the ID parameter into a folder-path"

Missing full stop. Also: "Function parsing..."

>    :group 'org-attach
> -  :package-version '(Org . "9.0")
> -  :version "26.1"
> -  :type '(choice
> -	  (const :tag "confirm with `y-or-n-p'" ask)
> -	  (const :tag "always get from annex if necessary" t)
> -	  (const :tag "never get from annex" nil)))
> +  :package-version '(Org . "9.3")
> +  :type 'function
> +  )

See above.

> +  "Return the directory associated with the current outline node.
> +First check for DIR property, then ID property.
> +`org-attach-use-inheritance' determines whether inherited
> +properties also will be considered.
> +
> +If an ID property is found the default mechanism using that ID
> +will be invoked to access the directory for the current entry.
> +
> +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
> +is run."
> +  (if create-if-not-exists-p
> +      (org-attach-dir-get-create)

Could you merge the `if' within the `cond' below?

> +    (let (attach-dir id)
> +      (cond
> +       ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
> +	(org-attach-check-absolute-path attach-dir))
> +       ;; Depricated and removed from documentation, but still

Deprecated. Also, please add a FIXME.

> +    (if attach-dir
> +	(progn (if (not (file-directory-p attach-dir))
> +		   (make-directory attach-dir t))
> +	       (if (file-exists-p attach-dir)
> +		   attach-dir
> +		 (error "Path does not exist: %s." attach-dir)))
> +      (error "No attachment directory is associated with the current node."))))

    (unless attach-dir (error "No attachment ... current node"))
    (unless (file-directory-p attach-dir) (make-directory ...))
    attach-dir

Note that error messages never end with a full stop in Emacs. Also,
I don't see how the inner error could trigger since you create the
directory just before, and it would already have returned an error if
that wasn't possible.

> -      (shell-command (format "rm -fr %s" attach-dir))
> +    (when (and attach-dir
> +	       (or force
> +		   (y-or-n-p "Are you sure you want to remove all
> attachments of this entry? ")))

Maybe the less mouthful:

   "Really remove all attachments of this entry? "

Also, what about using `yes-or-no-p' since this looks a sensitive operation?

> +	(org-attach-tag (not files))))
> +    (when (not attach-dir)
> +      (org-attach-tag t))))

    (unless attach-dir (org-attach-tag t))

> +  (interactive)
> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(org-open-file attach-dir)
> +      (error "No attachment directory exist."))))

See above: no full stop at the end of error messages.

> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(dired attach-dir)
> +      (error "No attachment directory exist."))))

Ditto.
>  

> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(let* ((files (org-attach-file-list attach-dir))
> +	       (file (if (= (length files) 1)
> +			 (car files)
> +		       (completing-read "Open attachment: "
> +					(mapcar #'list files) nil t)))

I think a `pcase' is warranted here:

    (pcase (org-attach-file-list attach-dir)
      (`(,file) file)
      (files (completing-read ...)))

> +	       (path (expand-file-name file attach-dir)))
> +	  (run-hook-with-args 'org-attach-open-hook path)
> +	  (org-open-file path in-emacs))
> +      (error "No attachment directory exist."))))

Ahem. :)

> diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA

Would it be possible to use `org-test-with-temp-text-in file instead of
creating files?

> +(ert-deftest test-org-attach/dir ()
> +  "Test `org-attach-get' specifications."
> +  (org-test-in-example-file org-test-attachments-file
> +    ;; Link inside H1
> +    (org-next-link)
> +    (save-excursion
> +      (org-open-at-point)
> +      (should (equal "Text in fileA\n" (buffer-string))))

Please move `should' in the outermost part of the sexp, if possible. It
makes debugging easier (i.e., evaluating the sexp without getting
`should' in the way).

I probably missed a few things, but it keeps the ball rolling.

Thank you again for all the hard work.

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-06-15 13:29               ` Nicolas Goaziou
@ 2019-06-15 15:38                 ` Bastien
  2019-06-30  6:03                 ` Gustav Wikström
  1 sibling, 0 replies; 113+ messages in thread
From: Bastien @ 2019-06-15 15:38 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode

Hi Gustav,

thanks a lot for your contribution!

Please register as a user on https://code.orgmode.org then send me
your username in a private email, I'll then add you to the list of
people with push access.

Thanks,

-- 
 Bastien

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-06-15 13:29               ` Nicolas Goaziou
  2019-06-15 15:38                 ` Bastien
@ 2019-06-30  6:03                 ` Gustav Wikström
  2019-07-06 21:46                   ` Nicolas Goaziou
  1 sibling, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-06-30  6:03 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 15614 bytes --]

Hi,

Thanks!

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 15 juni 2019 15:29
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode <emacs-orgmode@gnu.org>; Bastien Guerry <bzg@gnu.org>
> Subject: Re: [RFC] Link-type for attachments, more attach options


> > (Sidenote 2; The first patch is some minor unrelated fixups - it
> > breaks test-org-export/expand-include as a side-effect. But that's probably
> > because the test doesn't do what it should! 😲 )
> 
> Probably. Yet, we should do something about it. If you cannot fix it, at
> least please comment it out somehow.

Looked at it a few more minutes. The error comes from the fix of
org-test-with-temp-text-in-file, where it previously didn't work with
point. It does now, which means the test-specification was wrong. The
test should compare to 2 instead of 1 since the inserted node will
be one level above the current headline.

> >    (should
> >     (equal
> >      "1"
> > -    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> > -      (org-entry-get (point) "A" t))))
> > +    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
> > +      (org-entry-get (point-max) "A" t))))
> 
> Not that it is wrong, but I don't see the benefit of this change.

No real benefit except that it now matches other tests that was also
defined. I spent a few minutes wondering why some was specified in one
way and the others another way. Realized there was no reason and
thought to save those minutes for the next person who might wonder the
same thing.

> >  (defmacro org-test-with-temp-text-in-file (text &rest body)
> > -  "Run body in a temporary file buffer with Org mode as the active mode."
> > +  "Run body in a temporary file buffer with Org mode as the active mode.
> > +If the string \"<point>\" appears in TEXT then remove it and
> > +place the point there before running BODY, otherwise place the
> > +point at the beginning of the buffer."
> >    (declare (indent 1))
> >    (let ((results (cl-gensym)))
> >      `(let ((file (make-temp-file "org-test"))
> > @@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text."
> >  	   ,results)
> >         (with-temp-file file (insert inside-text))
> >         (find-file file)
> > +       (when (re-search-forward "<point>" nil t)
> > +	 (replace-match ""))
> >         (org-mode)
> >         (setq ,results (progn ,@body))
> >         (save-buffer) (kill-buffer (current-buffer))
> 
> While we're at fixing this macro, we may also wrap stuff within
> `unwind-protect' so as to properly delete temporary files in any cases.

Ok, tried to do that. Maybe added a few to many guardrails but it
should work as intended.

> > From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001
> > From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
> > Date: Sun, 25 Nov 2018 21:38:44 +0100
> > Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news,
> >  testing/**/test-org-attach*
> >
> > * org-attach.el
> >
> > Changed the way attachments deal with property-inheritance.  It now
> > adheres to the =org-use-property-inheritance= setting by default but
> > it can be customized if needed (I recommend to enable it!).
> > The property ATTACH_DIR is depricated in favour of the shorter and simpler
> > property DIR.
> 
> depricated -> deprecated

Whops! Fixed

> > * org-manual.org
> >
> > Attachments have been promoted into its own top-level node!  There are
> > a lot of goodies to mention here that didn't fit naturally with
> > "capture" and "archive" before.
> 
> This is true, but there is not enough information to require a top-level
> node.
> 
> Here is a suggestion. Split "Capture, Refile, Archive" into two parts:
> 
> 1. Refile, Copy and Archiving in one place, because they all relate to
>    moving existing data around
> 
> 2. Capture, Attachments, RSS Feeds, Protocols in another place, because
>    they all insert external data to the system.
> 
> WDYT?

Fair enough. Modified the manual to match that suggestion.

> > +File links and attachment links can contain additional information to
> 
> Since attachment links are file links, it seems redundant to talk about
> both everywhere. Just clarify clearly once that attachments links are
> file links for all purposes.

Modified it a bit to make it read better. I do think it's worth having small 
notes that search options apply also for attachment links. But I agree that 
we don't need to mention it everywhere.

> > +It is often useful to associate reference material with an outline
> > +node/task.
> 
> I would use "node" only: it is more generic.

Agreed, fixed.
 
> > +The attachment system has been contributed to Org by John Wiegley.
> 
> I would drop this reference, since John Wiegley is already mentioned in
> the Thanks entry.

Ok, fixed.
 
> > +** Attachment defaults and dispatcher
> > +By default, org-attach will use ID properties when adding attachments
> > +to outline nodes.  This makes working with attachments fully
> > +automated.  There is no decision needed for folder-name or location.
> > +ID-based directories are by default located in the =data/= directory,
> > +which lives in the same directory where your Org file lives[fn:87].
> > +For more control over the setup, see [[*Attachment options]].
> > +
> > +When attachments are made using ~org-attach~ a default tag =ATTACH= is
> > +added to the node that gets the attachments.
> 
> Note overly important, but we prefer the active voice whenever possible.

Can't say I really understand what was meant with this.

> > +  #+begin_example
> > +  ,* Chapter A ...
> > +    :PROPERTIES:
> > +    :DIR: Chapter A/
> > +    :END:
> > +  ,** Introduction
> > +  Some text
> > +
> > +  #+NAME: Image 1
> > +  [[Attachment:image 1.jpg]]
> > +  #+end_example
> > +
> > +  Without inheritance one would not be able to resolve the link to image
> > +  1.jpg, since the link is inside a sub-heading to Chapter A.
> 
> =1.jpg=  ... =Chapter A=

Fixed.
 
> > +  Inheritance works the same way for both =ID= and =DIR= property.  If
> > +  both properties are defined on the same headline then =DIR= takes
> > +  precedance.  This is also true if inheritance is enabled.  If =DIR= is
> > +  inherited from a parent node in the outline, that property still takes
> > +  precedence over an =ID= property defined on the node itself.
> > +
> > +- ~org-attach-method~ ::
> > +  #+vindex: org-attach-method
> > +  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
> > +  defaults to copying files.  The behaviour can be changed by
> > +  customizing ~org-attach-method~.  Options are =Copy=, =Move/Rename=,
> > +  =Hard link= or =Symbolic link=.
> 
> I don't think =...= are warranted here.

Ok, fixed.

> 
> > +- ~org-attach-preferred-new-method~ ::
> > +  #+vindex: org-attach-preferred-new-method
> > +  This customization lets you choose the default way to attach to
> > +  nodes without existing ID and DIR property.  It defaults to =id= but
> > +  can also be set to =dir=, =ask= or =nil=.
> 
> ~id~, ~dir~ ~ask~ or ~nil~, since those are symbols.

Fixed.

> > +  Do not show the splash buffer with the attach dispatcher when
> > +  ~org-attach-expert~ is set to Non-nil.
> 
> non-~nil~

Fixed.

> > +** Attachment links
> > +Attached files and folders can be referenced using attachment-links.
> 
> Why the hyphen in "attachment-links"? I think "attachment links" is
> perfectly clear.

Fixed.
 
> > +This makes it easy to refer to the material added to an outline node.
> > +Especially if it was attached using the unique ID of the entry!
> > +
> > +#+begin_example
> > +,* TODO Some task
> > +  :PROPERTIES:
> > +  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
> > +  :END:
> > +See attached document for more information: [[attachment:info.org]]
> > +#+end_example
> > +
> > +See [[* External Links]] for more information about these links.
> 
> No need for the space: [[*External Links]]
> 
> > +** Automatic version-control with git
> 
> Shouldn't it be "Git"?

Maybe...? Changed now anyways.
 
> > +If the directory attached to an outline node is a git repository, Org
> 
> Ditto.

Changed.

> > +can be configured to automatically commit changes to that repository
> > +when it sees them.
> > +
> > +To make org-mode take care of versioning of attachments for you, add
> 
> To make Org mode...

Fixed.
 
> > +(defcustom org-attach-dir-relative nil
> > +  "Choose whether directories in DIR property should be added as relative links or not.
> > +Defaults to absolute location."
> 
> First line is too long, maybe:
> 
>     Non-nil means directories in DIR property are added as relative links
> 

Fixed.

> > -(defcustom org-attach-annex-auto-get 'ask
> > -  "Confirmation preference for automatically getting annex files.
> > -If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
> > +(defun org-attach-id-folder-format (id)
> > +  (format "%s/%s"
> > +	  (substring id 0 2)
> > +	  (substring id 2))
> > +  )
> 
> No dangling parens, please. Also, this function needs a docstring.

Ah, ofc.

> > +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format
> > +  "The function parsing the ID parameter into a folder-path"
> 
> Missing full stop. Also: "Function parsing..."
> 
> >    :group 'org-attach
> > -  :package-version '(Org . "9.0")
> > -  :version "26.1"
> > -  :type '(choice
> > -	  (const :tag "confirm with `y-or-n-p'" ask)
> > -	  (const :tag "always get from annex if necessary" t)
> > -	  (const :tag "never get from annex" nil)))
> > +  :package-version '(Org . "9.3")
> > +  :type 'function
> > +  )
> 
> See above.

Fixed.
 
> > +  "Return the directory associated with the current outline node.
> > +First check for DIR property, then ID property.
> > +`org-attach-use-inheritance' determines whether inherited
> > +properties also will be considered.
> > +
> > +If an ID property is found the default mechanism using that ID
> > +will be invoked to access the directory for the current entry.
> > +
> > +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
> > +is run."
> > +  (if create-if-not-exists-p
> > +      (org-attach-dir-get-create)
> 
> Could you merge the `if' within the `cond' below?

Done.
 
> > +    (let (attach-dir id)
> > +      (cond
> > +       ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
> > +	(org-attach-check-absolute-path attach-dir))
> > +       ;; Depricated and removed from documentation, but still
> 
> Deprecated. Also, please add a FIXME.

Fixed and added.
 
> > +    (if attach-dir
> > +	(progn (if (not (file-directory-p attach-dir))
> > +		   (make-directory attach-dir t))
> > +	       (if (file-exists-p attach-dir)
> > +		   attach-dir
> > +		 (error "Path does not exist: %s." attach-dir)))
> > +      (error "No attachment directory is associated with the current node."))))
> 
>     (unless attach-dir (error "No attachment ... current node"))
>     (unless (file-directory-p attach-dir) (make-directory ...))
>     attach-dir
> 
> Note that error messages never end with a full stop in Emacs. Also,
> I don't see how the inner error could trigger since you create the
> directory just before, and it would already have returned an error if
> that wasn't possible.

Ok, got it. Fixed. Removed inner error as well as I agree with your
conclusion. Tried to think of why it was added but couldn't remember
any reason.

> > -      (shell-command (format "rm -fr %s" attach-dir))
> > +    (when (and attach-dir
> > +	       (or force
> > +		   (y-or-n-p "Are you sure you want to remove all
> > attachments of this entry? ")))
> 
> Maybe the less mouthful:
> 
>    "Really remove all attachments of this entry? "
> 

Good suggestion, fixed.

> Also, what about using `yes-or-no-p' since this looks a sensitive operation?

Agreed! Didn't think of that.
 
> > +	(org-attach-tag (not files))))
> > +    (when (not attach-dir)
> > +      (org-attach-tag t))))
> 
>     (unless attach-dir (org-attach-tag t))

Fixed.
 
> > +  (interactive)
> > +  (let ((attach-dir (org-attach-dir)))
> > +    (if attach-dir
> > +	(org-open-file attach-dir)
> > +      (error "No attachment directory exist."))))
> 
> See above: no full stop at the end of error messages.

Fixed.

> > +  (let ((attach-dir (org-attach-dir)))
> > +    (if attach-dir
> > +	(dired attach-dir)
> > +      (error "No attachment directory exist."))))
> 
> Ditto.

Fixed
 
> > +  (let ((attach-dir (org-attach-dir)))
> > +    (if attach-dir
> > +	(let* ((files (org-attach-file-list attach-dir))
> > +	       (file (if (= (length files) 1)
> > +			 (car files)
> > +		       (completing-read "Open attachment: "
> > +					(mapcar #'list files) nil t)))
> 
> I think a `pcase' is warranted here:
> 
>     (pcase (org-attach-file-list attach-dir)
>       (`(,file) file)
>       (files (completing-read ...)))
> 

And so I learnt something new. Pattern matching in emacs, didn't think
of that. Changed. Can't really say that the code will be easier to
understand now. But for those familiar with pcase I'm sure it looks
nicer.

> > +	       (path (expand-file-name file attach-dir)))
> > +	  (run-hook-with-args 'org-attach-open-hook path)
> > +	  (org-open-file path in-emacs))
> > +      (error "No attachment directory exist."))))
> 
> Ahem. :)

Yeah. Fixed the full stop.

> 
> > diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA
> 
> Would it be possible to use `org-test-with-temp-text-in file instead of
> creating files?

I couldn't think of a good way since I wanted to test relations
between an org-mode document and it's attachments. I would need to
dynamically create both org-mode files and it's attachment and link
them in the filesystem somehow... That wasn't intuitive for me so I
chose this solution instead.
 
> > +(ert-deftest test-org-attach/dir ()
> > +  "Test `org-attach-get' specifications."
> > +  (org-test-in-example-file org-test-attachments-file
> > +    ;; Link inside H1
> > +    (org-next-link)
> > +    (save-excursion
> > +      (org-open-at-point)
> > +      (should (equal "Text in fileA\n" (buffer-string))))
> 
> Please move `should' in the outermost part of the sexp, if possible. It
> makes debugging easier (i.e., evaluating the sexp without getting
> `should' in the way).

Ok, did that. I agree - it reads better. To get this to work better I
made a slight change in org-test-in-example-file as well. Added to
patch 0001 since that change isn't really related to attachments but
rather a general improvement.

One might also argue that this particular test should be split up. I
Agree with that, but would like that to not be a stopper for this first 
patch.
 
> I probably missed a few things, but it keeps the ball rolling.

I've added a few fixes to the patch myself. I haven't kept track of
the changes though, since I'm trying to keep the patch together in one
commit (well... two in this case).
 
> Thank you again for all the hard work.

And thank you for the review. Bastien gave me access to the Git
repository. Let me know how you want to proceed with this patch.

Kind regards
Gustav Wikström

[-- Attachment #2: 0002-org-attach-org-org-manual-org-news-testing-test-org-.patch --]
[-- Type: application/octet-stream, Size: 106611 bytes --]

From ce40b082d106231a8306e60e9509b8be76a0189f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 25 Nov 2018 21:38:44 +0100
Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news,
 testing/**/test-org-attach*

* org-attach.el

Changed the way attachments deal with property-inheritance.  It now
adheres to the =org-use-property-inheritance= setting by default but
it can be customized if needed (I recommend to enable it!).
The property ATTACH_DIR is deprecated in favour of the shorter and simpler
property DIR.

Added an explicit option to =org-attach= for unsetting
attachment-directories (i.e. remove DIR property and deal with the
attachments by interaction).

Added attachment link type with the prefix "attachment:".

Added customizations:
- org-attach-dir-relative
- org-attach-preferred-new-method
- org-attach-use-inheritance
- org-attach-id-to-path-function

Hooks added:
- org-attach-after-change-hook
- org-attach-open-hook

* Add new linktype "attachment" for attachments

A new linktype "attachment" is added in order to reduce
link-duplication when wanting to link to files in attached folders of
nodes.  This works for both ID and DIR properties.  The goal is to
make the functionality for attachment links mirror the functionality
for file links.

* org-attach-git.el

New file, existing functionality.  Code here has been factored out
from org-attach.el and if GIT-functionality is to be used this module
needs to be required sepatately.  It extends org-attach by use of its
hooks.

Activating git functionality in org-attach is done by loading
org-attach-git from now on, instead of customizing a variable.

Naming of both functions and tests has been modified to match the move
of functionality into its own module.

* org.el

Inline images are shown also using attachment-links, exactly the same
as it works for file-links today.

Make org-open-at-point respect ARG when opening attachment-dir.

* org-compat.el

org-attach-directory has been deprecated in favour for
org-attach-id-dir.  The new name matches its purpose better.

* org-manual.org

The chapter "Refile, Copy, Archive" has been split into two separate
chapters.
- "Refile, Copy and Archiving" for information related to moving
  existing data around.

- "Capture, Attachments, RSS Feeds and Protocols" for information
  related to working with external data.

The attachment-part has been rewritten and extended to match the
changes in this patch.

The new attachment link type is mentioned both inside the attachments
chapter and in the chapter dealing with links.

Documentation related to external links has been improved.

* testing/lisp/test-org-attach-annex.el

Require org-attach-git instead of org-attach, since this file tests
the GIT-functionality.

* testing/org-test.el

Define a symbol for a file to test attachments with.

* testing/examples/*

A bunch of new example files and folders are created and are used in
testing of org-attach to verify its functionality.
---
 doc/org-manual.org                            | 1079 ++++++++++-------
 etc/ORG-NEWS                                  |   93 ++
 lisp/org-attach-git.el                        |  118 ++
 lisp/org-attach.el                            |  563 +++++----
 lisp/org-compat.el                            |    3 +
 lisp/org.el                                   |   23 +-
 testing/examples/att1/fileA                   |    1 +
 testing/examples/att1/fileB                   |    1 +
 testing/examples/att2/fileC                   |    1 +
 testing/examples/att2/fileD                   |    1 +
 testing/examples/attachments.org              |   32 +
 testing/examples/data/ab/cd123/fileE          |    1 +
 ...attach-annex.el => test-org-attach-git.el} |   12 +-
 testing/lisp/test-org-attach.el               |   69 ++
 testing/lisp/test-org.el                      |    6 +-
 testing/org-test.el                           |    3 +
 16 files changed, 1307 insertions(+), 699 deletions(-)
 create mode 100644 lisp/org-attach-git.el
 create mode 100644 testing/examples/att1/fileA
 create mode 100644 testing/examples/att1/fileB
 create mode 100644 testing/examples/att2/fileC
 create mode 100644 testing/examples/att2/fileD
 create mode 100644 testing/examples/attachments.org
 create mode 100644 testing/examples/data/ab/cd123/fileE
 rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 469e16402..801cca617 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3068,6 +3068,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: attachment links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3079,38 +3080,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
-
-| =http://www.astro.uva.nl/=dominik=        | on the web                     |
-| =doi:10.1000/182=                         | DOI for an electronic resource |
-| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
-| =/home/dominik/images/jupiter.jpg=        | same as above                  |
-| =file:papers/last.pdf=                    | file, relative path            |
-| =./papers/last.pdf=                       | same as above                  |
-| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
-| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
-| =file:sometextfile::NNN=                  | file, jump to line number      |
-| =file:projects.org=                       | another Org file               |
-| =file:projects.org::some words=           | text search in Org file[fn:27] |
-| =file:projects.org::*task title=          | heading search in Org file     |
-| =file+sys:/path/to/file=                  | open via OS, like double-click |
-| =file+emacs:/path/to/file=                | force opening by Emacs         |
-| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
-| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
-| =news:comp.emacs=                         | Usenet link                    |
-| =mailto:adent@galaxy.net=                 | mail link                      |
-| =mhe:folder=                              | MH-E folder link               |
-| =mhe:folder#id=                           | MH-E message link              |
-| =rmail:folder=                            | Rmail folder link              |
-| =rmail:folder#id=                         | Rmail message link             |
-| =gnus:group=                              | Gnus group link                |
-| =gnus:group#id=                           | Gnus article link              |
-| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
-| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
-| =info:org#External links=                 | Info node link                 |
-| =shell:ls *.org=                          | shell command                  |
-| =elisp:org-agenda=                        | interactive Elisp command      |
-| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
+the colon.
+
+Here is the full set of built-in link types:
+
+- =file= ::
+
+   File links.  File name may be remote, absolute, or relative.
+
+   Additionally, you can specify a line number, or a text search.
+   In Org files, you may link to a headline name, a custom ID, or a
+   code reference instead.
+
+   As a special case, "file" prefix may be omitted if the file name
+   is complete, e.g., it starts with =./=, or =/=.
+
+- =attachment= ::
+
+  Same as file links but for files and folders attached to the current
+  node (see [[*Attachments]]).  Attachment links are intended to behave
+  exactly as file links but for files relative to the attachment
+  directory.
+
+- =bbdb= ::
+
+  Link to a BBDB record, with possible regexp completion.
+
+- =docview= ::
+
+  Link to a document opened with DocView mode.  You may specify a page
+  number.
+
+- =doi= ::
+
+  Link to an electronic ressource, through its handle.
+
+- =elisp= ::
+
+  Execute an Elisp command upon activation.
+
+- =gnus=, =rmail=, =mhe= ::
+
+  Links to messages or folders from a given Emacs' MUA.
+
+- =http=, =https= ::
+
+  Web links.
+
+- =id= ::
+
+  Link to a specific headline by its ID property, in an Org file.
+
+- =info= ::
+
+  Link to an Info manual, or to a specific node.
+
+- =irc= ::
+
+  Link to an IRC channel.
+
+- =mailto= ::
+
+  Link to message composition.
+
+- =news= ::
+
+  Usenet links.
+
+- =shell= ::
+
+  Execute a shell command upon activation.
+
+The following table illustrates the link types above, along with their
+options:
+
+| Link Type  | Example                                                  |
+|------------+----------------------------------------------------------|
+| http       | =http://www.astro.uva.nl/=dominik=                       |
+| https      | =https://orgmode.org/=                                   |
+| doi        | =doi:10.1000/182=                                        |
+| file       | =file:/home/dominik/images/jupiter.jpg=                  |
+|            | =/home/dominik/images/jupiter.jpg= (same as above)       |
+|            | =file:papers/last.pdf=                                   |
+|            | =./papers/last.pdf= (same as above)                      |
+|            | =file:/ssh:me@some.where:papers/last.pdf= (remote)       |
+|            | =/ssh:me@some.where:papers/last.pdf= (same as above)     |
+|            | =file:sometextfile::NNN= (jump to line number)           |
+|            | =file:projects.org=                                      |
+|            | =file:projects.org::some words= (text search) [fn:28]    |
+|            | =file:projects.org::*task title= (headline search)       |
+|            | =file:projects.org::#custom-id= (headline search)        |
+| attachment | =attachment:projects.org=                                |
+|            | =attachment:projects.org::some words= (text search)      |
+| docview    | =docview:papers/last.pdf::NNN=                           |
+| id         | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=                |
+| news       | =news:comp.emacs=                                        |
+| mailto     | =mailto:adent@galaxy.net=                                |
+| mhe        | =mhe:folder= (folder link)                               |
+|            | =mhe:folder#id= (message link)                           |
+| rmail      | =rmail:folder= (folder link)                             |
+|            | =rmail:folder#id= (message link)                         |
+| gnus       | =gnus:group= (group link)                                |
+|            | =gnus:group#id= (article link)                           |
+| bbdb       | =bbdb:R.*Stallman= (record with regexp)                  |
+| irc        | =irc:/irc.com/#emacs/bob=                                |
+| info       | =info:org#External links=                                |
+| shell      | =shell:ls *.org=                                         |
+| elisp      | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) |
+|            | =elisp:org-agenda= (interactive Elisp command)           |
 
 #+cindex: VM links
 #+cindex: Wanderlust links
@@ -3462,15 +3539,19 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: attachment links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:34].  For
+File links can contain additional information to make Emacs jump to a
+particular location in the file when following a link.  This can be a
+line number or a search option after a double colon[fn:34].  For
 example, when the command ~org-store-link~ creates a link (see
 [[*Handling Links]]) to a file, it encodes the words in the current line
 as a search string that can be used to find this line back later when
 following the link with {{{kbd(C-c C-o)}}}.
 
+Note that all search options apply for Attachment links in the same
+way that they apply for File links.
+
 Here is the syntax of the different ways to attach a search to a file
 link, together with explanations for each:
 
@@ -3480,6 +3561,7 @@ link, together with explanations for each:
 [[file:~/xx.org::*My Target]]
 [[file:~/xx.org::#my-custom-id]]
 [[file:~/xx.org::/regexp/]]
+[[attachment:main.c::255]]
 #+end_example
 
 - =255= ::
@@ -6893,163 +6975,420 @@ same commands.
   continue the old one.  This command also removes the timer from the
   mode line.
 
-* Capture, Refile, Archive
-:PROPERTIES:
-:DESCRIPTION: The ins and outs for projects.
-:END:
-#+cindex: capture
-
-An important part of any organization system is the ability to quickly
-capture new ideas and tasks, and to associate reference material with
-them.  Org does this using a process called /capture/.  It also can
-store files related to a task (/attachments/) in a special directory.
-Once in the system, tasks and projects need to be moved around.
-Moving completed project trees to an archive file keeps the system
-compact and fast.
-
-** Capture
+* Refile, Copy and Archiving
 :PROPERTIES:
-:DESCRIPTION: Capturing new stuff.
+:DESCRIPTION: Moving and copying information with ease.
 :END:
-#+cindex: capture
+#+cindex: refiling notes
+#+cindex: copying notes
+#+cindex: archiving
 
-Capture lets you quickly store notes with little interruption of your
-work flow.  Org's method for capturing new items is heavily inspired
-by John Wiegley's excellent Remember package.
+Once information is in the system, it may need to be moved around.
+Org provides Refile, Copy and Archive commands for this.  Refile and
+Copy helps with moving and copying outlines.  Archiving helps to keep
+the system compact and fast.
 
-*** Setting up capture
+** Refile and Copy
 :PROPERTIES:
-:DESCRIPTION: Where notes will be stored.
+:DESCRIPTION: Moving/copying a tree from one place to another.
 :END:
+#+cindex: refiling notes
+#+cindex: copying notes
 
-The following customization sets a default target file for notes.
+When reviewing the captured data, you may want to refile or to copy
+some of the entries into a different list, for example into a project.
+Cutting, finding the right location, and then pasting the note is
+cumbersome.  To simplify this process, you can use the following
+special command:
 
-#+vindex: org-default-notes-file
-#+begin_src emacs-lisp
-(setq org-default-notes-file (concat org-directory "/notes.org"))
-#+end_src
+- {{{kbd(C-c C-w)}}} (~org-refile~) ::
 
-You may also define a global key for capturing new material (see
-[[*Activation]]).
+  #+kindex: C-c C-w
+  #+findex: org-refile
+  #+vindex: org-reverse-note-order
+  #+vindex: org-refile-targets
+  #+vindex: org-refile-use-outline-path
+  #+vindex: org-outline-path-complete-in-steps
+  #+vindex: org-refile-allow-creating-parent-nodes
+  #+vindex: org-log-refile
+  Refile the entry or region at point.  This command offers possible
+  locations for refiling the entry and lets you select one with
+  completion.  The item (or all items in the region) is filed below
+  the target heading as a subitem.  Depending on
+  ~org-reverse-note-order~, it is either the first or last subitem.
 
-*** Using capture
-:PROPERTIES:
-:DESCRIPTION: Commands to invoke and terminate capture.
-:END:
+  By default, all level 1 headlines in the current buffer are
+  considered to be targets, but you can have more complex definitions
+  across a number of files.  See the variable ~org-refile-targets~ for
+  details.  If you would like to select a location via
+  a file-path-like completion along the outline path, see the
+  variables ~org-refile-use-outline-path~ and
+  ~org-outline-path-complete-in-steps~.  If you would like to be able
+  to create new nodes as new parents for refiling on the fly, check
+  the variable ~org-refile-allow-creating-parent-nodes~.  When the
+  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
+  recorded whenever an entry is refiled.
 
-- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
+- {{{kbd(C-u C-c C-w)}}} ::
 
-  #+findex: org-capture
-  #+cindex: date tree
-  Display the capture templates menu.  If you have templates defined
-  (see [[*Capture templates]]), it offers these templates for selection or
-  use a new Org outline node as the default template.  It inserts the
-  template into the target file and switch to an indirect buffer
-  narrowed to this new node.  You may then insert the information you
-  want.
+  #+kindex: C-u C-c C-w
+  Use the refile interface to jump to a heading.
 
-- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
+- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
 
-  #+kindex: C-c C-c @r{(Capture buffer)}
-  #+findex: org-capture-finalize
-  Once you have finished entering information into the capture buffer,
-  {{{kbd(C-c C-c)}}} returns you to the window configuration before
-  the capture process, so that you can resume your work without
-  further distraction.  When called with a prefix argument, finalize
-  and then jump to the captured item.
+  #+kindex: C-u C-u C-c C-w
+  #+findex: org-refile-goto-last-stored
+  Jump to the location where ~org-refile~ last moved a tree to.
 
-- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
+- {{{kbd(C-2 C-c C-w)}}} ::
 
-  #+kindex: C-c C-w @r{(Capture buffer)}
-  #+findex: org-capture-refile
-  Finalize the capture process by refiling the note to a different
-  place (see [[*Refile and Copy]]).  Please realize that this is a normal
-  refiling command that will be executed---so point position at the
-  moment you run this command is important.  If you have inserted
-  a tree with a parent and children, first move point back to the
-  parent.  Any prefix argument given to this command is passed on to
-  the ~org-refile~ command.
+  #+kindex: C-2 C-c C-w
+  Refile as the child of the item currently being clocked.
 
-- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
+- {{{kbd(C-3 C-c C-w)}}} ::
 
-  #+kindex: C-c C-k @r{(Capture buffer)}
-  #+findex: org-capture-kill
-  Abort the capture process and return to the previous state.
+  #+kindex: C-3 C-c C-w
+  #+vindex: org-refile-keep
+  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
+  make this the default behavior, and beware that this may result in
+  duplicated =ID= properties.
 
-#+kindex: k c @r{(Agenda)}
-You can also call ~org-capture~ in a special way from the agenda,
-using the {{{kbd(k c)}}} key combination.  With this access, any
-timestamps inserted by the selected capture template defaults to the
-date at point in the agenda, rather than to the current date.
+- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
 
-To find the locations of the last stored capture, use ~org-capture~
-with prefix commands:
+  #+kindex: C-u C-u C-u C-c C-w
+  #+kindex: C-0 C-c C-w
+  #+findex: org-refile-cache-clear
+  #+vindex: org-refile-use-cache
+  Clear the target cache.  Caching of refile targets can be turned on
+  by setting ~org-refile-use-cache~.  To make the command see new
+  possible targets, you have to clear the cache with this command.
 
-- {{{kbd(C-u M-x org-capture)}}} ::
+- {{{kbd(C-c M-w)}}} (~org-copy~) ::
 
-  Visit the target location of a capture template.  You get to select
-  the template in the usual way.
+  #+kindex: C-c M-w
+  #+findex: org-copy
+  Copying works like refiling, except that the original note is not
+  deleted.
 
-- {{{kbd(C-u C-u M-x org-capture)}}} ::
+** Archiving
+:PROPERTIES:
+:DESCRIPTION: What to do with finished products.
+:END:
+#+cindex: archiving
 
-  Visit the last stored capture item in its buffer.
+When a project represented by a (sub)tree is finished, you may want to
+move the tree out of the way and to stop it from contributing to the
+agenda.  Archiving is important to keep your working files compact and
+global searches like the construction of agenda views fast.
 
-#+vindex: org-capture-bookmark
-#+vindex: org-capture-last-stored
-You can also jump to the bookmark ~org-capture-last-stored~, which is
-automatically created unless you set ~org-capture-bookmark~ to ~nil~.
+- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
 
-To insert the capture at point in an Org buffer, call ~org-capture~
-with a {{{kbd(C-0)}}} prefix argument.
+  #+kindex: C-c C-x C-a
+  #+findex: org-archive-subtree-default
+  #+vindex: org-archive-default-command
+  Archive the current entry using the command specified in the
+  variable ~org-archive-default-command~.
 
-*** Capture templates
+*** Moving a tree to an archive file
 :PROPERTIES:
-:DESCRIPTION: Define the outline of different note types.
+:DESCRIPTION: Moving a tree to an archive file.
+:ALT_TITLE: Moving subtrees
 :END:
-#+cindex: templates, for Capture
-
-You can use templates for different types of capture items, and for
-different target locations.  The easiest way to create such templates
-is through the customize interface.
+#+cindex: external archiving
 
-- {{{kbd(C)}}} ::
+The most common archiving action is to move a project tree to another
+file, the archive file.
 
-  #+kindex: C @r{(Capture menu}
-  #+vindex: org-capture-templates
-  Customize the variable ~org-capture-templates~.
+- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
 
-Before we give the formal description of template definitions, let's
-look at an example.  Say you would like to use one template to create
-general TODO entries, and you want to put these entries under the
-heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
-the file =journal.org= should capture journal entries.  A possible
-configuration would look like:
+  #+kindex: C-c C-x C-s
+  #+kindex: C-c $
+  #+findex: org-archive-subtree
+  #+vindex: org-archive-location
+  Archive the subtree starting at point position to the location given
+  by ~org-archive-location~.
 
-#+begin_src emacs-lisp
-(setq org-capture-templates
-      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
-         "* TODO %?\n  %i\n  %a")
-        ("j" "Journal" entry (file+datetree "~/org/journal.org")
-         "* %?\nEntered on %U\n  %i\n  %a")))
-#+end_src
+- {{{kbd(C-u C-c C-x C-s)}}} ::
 
-If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
-the template for you like this:
+  #+kindex: C-u C-c C-x C-s
+  Check if any direct children of the current headline could be moved
+  to the archive.  To do this, check each subtree for open TODO
+  entries.  If none is found, the command offers to move it to the
+  archive location.  If point is /not/ on a headline when this command
+  is invoked, check level 1 trees.
 
-#+begin_example
-,* TODO
-  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
-#+end_example
+- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
 
-#+texinfo: @noindent
-During expansion of the template, =%a= has been replaced by a link to
-the location from where you called the capture command.  This can be
-extremely useful for deriving tasks from emails, for example.  You
-fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
-you to the same place where you started the capture process.
+  #+kindex: C-u C-u C-c C-x C-s
+  As above, but check subtree for timestamps instead of TODO entries.
+  The command offers to archive the subtree if it /does/ contain
+  a timestamp, and that timestamp is in the past.
 
-To define special keys to capture to a particular template without
-going through the interactive template selection, you can create your
+#+cindex: archive locations
+The default archive location is a file in the same directory as the
+current file, with the name derived by appending =_archive= to the
+current file name.  You can also choose what heading to file archived
+items under, with the possibility to add them to a datetree in a file.
+For information and examples on how to specify the file and the
+heading, see the documentation string of the variable
+~org-archive-location~.
+
+There is also an in-buffer option for setting this variable, for
+example:
+
+#+cindex: @samp{ARCHIVE}, keyword
+: #+ARCHIVE: %s_done::
+
+#+cindex: ARCHIVE, property
+If you would like to have a special archive location for a single
+entry or a (sub)tree, give the entry an =ARCHIVE= property with the
+location as the value (see [[*Properties and Columns]]).
+
+#+vindex: org-archive-save-context-info
+When a subtree is moved, it receives a number of special properties
+that record context information like the file from where the entry
+came, its outline path the archiving time etc.  Configure the variable
+~org-archive-save-context-info~ to adjust the amount of information
+added.
+
+*** Internal archiving
+:PROPERTIES:
+:DESCRIPTION: Switch off a tree but keep it in the file.
+:END:
+
+#+cindex: @samp{ARCHIVE}, tag
+If you want to just switch off---for agenda views---certain subtrees
+without moving them to a different file, you can use the =ARCHIVE=
+tag.
+
+A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
+its location in the outline tree, but behaves in the following way:
+
+-
+  #+vindex: org-cycle-open-archived-trees
+  It does not open when you attempt to do so with a visibility cycling
+  command (see [[*Visibility Cycling]]).  You can force cycling archived
+  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
+  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
+  ~outline-show-all~, open archived subtrees.
+
+-
+  #+vindex: org-sparse-tree-open-archived-trees
+  During sparse tree construction (see [[*Sparse Trees]]), matches in
+  archived subtrees are not exposed, unless you configure the option
+  ~org-sparse-tree-open-archived-trees~.
+
+-
+  #+vindex: org-agenda-skip-archived-trees
+  During agenda view construction (see [[*Agenda Views]]), the content of
+  archived trees is ignored unless you configure the option
+  ~org-agenda-skip-archived-trees~, in which case these trees are
+  always included.  In the agenda you can press {{{kbd(v a)}}} to get
+  archives temporarily included.
+
+-
+  #+vindex: org-export-with-archived-trees
+  Archived trees are not exported (see [[*Exporting]]), only the headline
+  is.  Configure the details using the variable
+  ~org-export-with-archived-trees~.
+
+-
+  #+vindex: org-columns-skip-archived-trees
+  Archived trees are excluded from column view unless the variable
+  ~org-columns-skip-archived-trees~ is configured to ~nil~.
+
+The following commands help manage the =ARCHIVE= tag:
+
+- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
+
+  #+kindex: C-c C-x a
+  #+findex: org-toggle-archive-tag
+  Toggle the archive tag for the current headline.  When the tag is
+  set, the headline changes to a shadowed face, and the subtree below
+  it is hidden.
+
+- {{{kbd(C-u C-c C-x a)}}} ::
+
+  #+kindex: C-u C-c C-x a
+  Check if any direct children of the current headline should be
+  archived.  To do this, check each subtree for open TODO entries.  If
+  none is found, the command offers to set the =ARCHIVE= tag for the
+  child.  If point is /not/ on a headline when this command is
+  invoked, check the level 1 trees.
+
+- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
+
+  #+kindex: C-TAB
+  Cycle a tree even if it is tagged with =ARCHIVE=.
+
+- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
+
+  #+kindex: C-c C-x A
+  #+findex: org-archive-to-archive-sibling
+  Move the current entry to the /Archive Sibling/.  This is a sibling
+  of the entry with the heading =Archive= and the archive tag.  The
+  entry becomes a child of that sibling and in this way retains a lot
+  of its original context, including inherited tags and approximate
+  position in the outline.
+
+* Capture, Attachments, RSS Feeds and Protocols
+:PROPERTIES:
+:DESCRIPTION: Dealing with external data.
+:END:
+#+cindex: capture
+#+cindex: attachments
+#+cindex: RSS feeds
+#+cindex: Atom feeds
+#+cindex: protocols, for external access
+
+An important part of any organization system is the ability to quickly
+capture new ideas and tasks, and to associate reference material with
+them.  Org does this using a process called /capture/.  It also can
+store files related to a task (/attachments/) in a special directory.
+
+** Capture
+:PROPERTIES:
+:DESCRIPTION: Capturing new stuff.
+:END:
+#+cindex: capture
+
+Capture lets you quickly store notes with little interruption of your
+work flow.  Org's method for capturing new items is heavily inspired
+by John Wiegley's excellent Remember package.
+
+*** Setting up capture
+:PROPERTIES:
+:DESCRIPTION: Where notes will be stored.
+:END:
+
+The following customization sets a default target file for notes.
+
+#+vindex: org-default-notes-file
+#+begin_src emacs-lisp
+(setq org-default-notes-file (concat org-directory "/notes.org"))
+#+end_src
+
+You may also define a global key for capturing new material (see
+[[*Activation]]).
+
+*** Using capture
+:PROPERTIES:
+:DESCRIPTION: Commands to invoke and terminate capture.
+:END:
+
+- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
+
+  #+findex: org-capture
+  #+cindex: date tree
+  Display the capture templates menu.  If you have templates defined
+  (see [[*Capture templates]]), it offers these templates for selection or
+  use a new Org outline node as the default template.  It inserts the
+  template into the target file and switch to an indirect buffer
+  narrowed to this new node.  You may then insert the information you
+  want.
+
+- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
+
+  #+kindex: C-c C-c @r{(Capture buffer)}
+  #+findex: org-capture-finalize
+  Once you have finished entering information into the capture buffer,
+  {{{kbd(C-c C-c)}}} returns you to the window configuration before
+  the capture process, so that you can resume your work without
+  further distraction.  When called with a prefix argument, finalize
+  and then jump to the captured item.
+
+- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
+
+  #+kindex: C-c C-w @r{(Capture buffer)}
+  #+findex: org-capture-refile
+  Finalize the capture process by refiling the note to a different
+  place (see [[*Refile and Copy]]).  Please realize that this is a normal
+  refiling command that will be executed---so point position at the
+  moment you run this command is important.  If you have inserted
+  a tree with a parent and children, first move point back to the
+  parent.  Any prefix argument given to this command is passed on to
+  the ~org-refile~ command.
+
+- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
+
+  #+kindex: C-c C-k @r{(Capture buffer)}
+  #+findex: org-capture-kill
+  Abort the capture process and return to the previous state.
+
+#+kindex: k c @r{(Agenda)}
+You can also call ~org-capture~ in a special way from the agenda,
+using the {{{kbd(k c)}}} key combination.  With this access, any
+timestamps inserted by the selected capture template defaults to the
+date at point in the agenda, rather than to the current date.
+
+To find the locations of the last stored capture, use ~org-capture~
+with prefix commands:
+
+- {{{kbd(C-u M-x org-capture)}}} ::
+
+  Visit the target location of a capture template.  You get to select
+  the template in the usual way.
+
+- {{{kbd(C-u C-u M-x org-capture)}}} ::
+
+  Visit the last stored capture item in its buffer.
+
+#+vindex: org-capture-bookmark
+#+vindex: org-capture-last-stored
+You can also jump to the bookmark ~org-capture-last-stored~, which is
+automatically created unless you set ~org-capture-bookmark~ to ~nil~.
+
+To insert the capture at point in an Org buffer, call ~org-capture~
+with a {{{kbd(C-0)}}} prefix argument.
+
+*** Capture templates
+:PROPERTIES:
+:DESCRIPTION: Define the outline of different note types.
+:END:
+#+cindex: templates, for Capture
+
+You can use templates for different types of capture items, and for
+different target locations.  The easiest way to create such templates
+is through the customize interface.
+
+- {{{kbd(C)}}} ::
+
+  #+kindex: C @r{(Capture menu}
+  #+vindex: org-capture-templates
+  Customize the variable ~org-capture-templates~.
+
+Before we give the formal description of template definitions, let's
+look at an example.  Say you would like to use one template to create
+general TODO entries, and you want to put these entries under the
+heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
+the file =journal.org= should capture journal entries.  A possible
+configuration would look like:
+
+#+begin_src emacs-lisp
+(setq org-capture-templates
+      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
+         "* TODO %?\n  %i\n  %a")
+        ("j" "Journal" entry (file+datetree "~/org/journal.org")
+         "* %?\nEntered on %U\n  %i\n  %a")))
+#+end_src
+
+If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
+the template for you like this:
+
+#+begin_example
+,* TODO
+  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
+#+end_example
+
+#+texinfo: @noindent
+During expansion of the template, =%a= has been replaced by a link to
+the location from where you called the capture command.  This can be
+extremely useful for deriving tasks from emails, for example.  You
+fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
+you to the same place where you started the capture process.
+
+To define special keys to capture to a particular template without
+going through the interactive template selection, you can create your
 key binding like this:
 
 #+begin_src emacs-lisp
@@ -7434,28 +7773,30 @@ See the docstring of the variable for more information.
 
 ** Attachments
 :PROPERTIES:
-:DESCRIPTION: Add files to tasks.
+:DESCRIPTION: Attach files to outlines.
 :END:
 #+cindex: attachments
-#+vindex: org-attach-directory
 
 It is often useful to associate reference material with an outline
-node/task.  Small chunks of plain text can simply be stored in the
-subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
-associations with files that live elsewhere on your computer or in the
-cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-=data/= directory which lives in the same directory where your Org
-file lives[fn:87].  If you initialize this directory with =git init=,
-Org automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
+node.  Small chunks of plain text can simply be stored in the subtree
+of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish associations
+with files that live elsewhere on your computer or in the cloud, like
+emails or source code files belonging to a project.
+
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by a unique ID of each entry, or by a =DIR= property.
+
+*** Attachment defaults and dispatcher
+By default, org-attach will use ID properties when adding attachments
+to outline nodes.  This makes working with attachments fully
+automated.  There is no decision needed for folder-name or location.
+ID-based directories are by default located in the =data/= directory,
+which lives in the same directory where your Org file lives[fn:87].
+For more control over the setup, see [[*Attachment options]].
+
+When attachments are made using ~org-attach~ a default tag =ATTACH= is
+added to the node that gets the attachments.
 
 The following commands deal with attachments:
 
@@ -7540,25 +7881,144 @@ The following commands deal with attachments:
 
   - {{{kbd(D)}}} (~org-attach-delete-all~) ::
 
-    #+kindex: C-c C-a D
-    Delete all of a task's attachments.  A safer way is to open the
-    directory in Dired and delete from there.
+    #+kindex: C-c C-a D
+    Delete all of a task's attachments.  A safer way is to open the
+    directory in Dired and delete from there.
+
+  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
+
+    #+kindex: C-c C-a s
+    #+cindex: @samp{DIR}, property
+    Set a specific directory as the entry's attachment directory.
+    This works by putting the directory path into the =DIR=
+    property.
+
+  - {{{kbd(S)}}} (~org-attach-unset-directory~) ::
+
+    #+kindex: C-c C-a S
+    #+cindex: @samp{DIR}, property
+    Remove the attachment directory.  This command removes the =DIR=
+    property and asks the user to either move content inside that
+    folder, if an =ID= property is set, delete the content, or to
+    leave the attachment directory as is but no longer attached to the
+    outline node.
+
+*** Attachment options
+There are a couple of options for attachments that are worth
+mentioning.
+
+- ~org-attach-id-dir~ ::
+  #+vindex: org-attach-id-dir
+  The directory where attachments are stored when =ID= is used as
+  method.
+
+- ~org-attach-dir-relative~ ::
+  #+vindex: org-attach-dir-relative
+  When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}}
+  (~org-attach-set-directory~), absolute links are entered by default.
+  This option changes that to relative links.
+
+- ~org-attach-use-inheritance~ ::
+  #+vindex: org-attach-use-inheritance
+  By default folders attached to an outline node are inherited from
+  parents according to ~org-use-property-inheritance~.  If one instead
+  want to set inheritance specifically for org-attach that can be done
+  using ~org-attach-use-inheritance~.  Inheriting documents through
+  the node hierarchy makes a lot of sense in most cases. Especially
+  since the introduction of [[* Attachment links]].  The following example
+  shows one use case for attachment inheritance:
+
+  #+begin_example
+  ,* Chapter A ...
+    :PROPERTIES:
+    :DIR: Chapter A/
+    :END:
+  ,** Introduction
+  Some text
+
+  #+NAME: Image 1
+  [[Attachment:image 1.jpg]]
+  #+end_example
+
+  Without inheritance one would not be able to resolve the link to
+  image =1.jpg=, since the link is inside a sub-heading to =Chapter
+  A=.
+
+  Inheritance works the same way for both =ID= and =DIR= property.  If
+  both properties are defined on the same headline then =DIR= takes
+  precedance.  This is also true if inheritance is enabled.  If =DIR=
+  is inherited from a parent node in the outline, that property still
+  takes precedence over an =ID= property defined on the node itself.
+
+- ~org-attach-method~ ::
+  #+vindex: org-attach-method
+  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
+  defaults to copying files.  The behaviour can be changed by
+  customizing ~org-attach-method~.  Options are Copy, Move/Rename,
+  Hard link or Symbolic link.
+
+- ~org-attach-preferred-new-method~ ::
+  #+vindex: org-attach-preferred-new-method
+  This customization lets you choose the default way to attach to
+  nodes without existing =ID= and =DIR= property.  It defaults to ~id~
+  but can also be set to ~dir~, ~ask~ or ~nil~.
+
+- ~org-attach-archive-delete~ ::
+  #+vindex: org-attach-archive-delete
+  Configure this to determine if attachments should be deleted or not
+  when a subtree that has attachments is archived.
+
+- ~org-attach-auto-tag~ ::
+  #+vindex: org-attach-auto-tag
+  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
+  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!
+
+- ~org-attach-expert~ ::
+  #+vindex: org-attach-expert
+  Do not show the splash buffer with the attach dispatcher when
+  ~org-attach-expert~ is set to non-~nil~.
+
+See customization group =Org Attach= if you want to change the
+default settings.
+
+*** Attachment links
+Attached files and folders can be referenced using attachment links.
+This makes it easy to refer to the material added to an outline node.
+Especially if it was attached using the unique ID of the entry!
+
+#+begin_example
+,* TODO Some task
+  :PROPERTIES:
+  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
+  :END:
+See attached document for more information: [[attachment:info.org]]
+#+end_example
 
-  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
+See [[*External Links]] for more information about these links.
 
-    #+kindex: C-c C-a s
-    #+cindex: @samp{ATTACH_DIR}, property
-    Set a specific directory as the entry's attachment directory.
-    This works by putting the directory path into the =ATTACH_DIR=
-    property.
+*** Automatic version-control with Git
+If the directory attached to an outline node is a Git repository, Org
+can be configured to automatically commit changes to that repository
+when it sees them.
 
-  - {{{kbd(i)}}} (~org-attach-set-inherit~) ::
+To make Org mode take care of versioning of attachments for you, add
+the following to your Emacs config:
 
-    #+kindex: C-c C-a i
-    #+cindex: @samp{ATTACH_DIR_INHERIT}, property
-    Set the =ATTACH_DIR_INHERIT= property, so that children use the
-    same directory for attachments as the parent does.
+#+begin_src emacs-lisp
+  (require 'org-attach-git)
+#+end_src
 
+*** Attach from Dired
 #+cindex: attach from Dired
 #+findex: org-attach-dired-to-subtree
 It is possible to attach files to a subtree from a Dired buffer.  To
@@ -7829,249 +8289,6 @@ valid contents: ~org-protocol-create~ and
 ~org-protocol-create-for-org~.  The latter is of use if you're editing
 an Org file that is part of a publishing project.
 
-** Refile and Copy
-:PROPERTIES:
-:DESCRIPTION: Moving/copying a tree from one place to another.
-:END:
-#+cindex: refiling notes
-#+cindex: copying notes
-
-When reviewing the captured data, you may want to refile or to copy
-some of the entries into a different list, for example into a project.
-Cutting, finding the right location, and then pasting the note is
-cumbersome.  To simplify this process, you can use the following
-special command:
-
-- {{{kbd(C-c C-w)}}} (~org-refile~) ::
-
-  #+kindex: C-c C-w
-  #+findex: org-refile
-  #+vindex: org-reverse-note-order
-  #+vindex: org-refile-targets
-  #+vindex: org-refile-use-outline-path
-  #+vindex: org-outline-path-complete-in-steps
-  #+vindex: org-refile-allow-creating-parent-nodes
-  #+vindex: org-log-refile
-  Refile the entry or region at point.  This command offers possible
-  locations for refiling the entry and lets you select one with
-  completion.  The item (or all items in the region) is filed below
-  the target heading as a subitem.  Depending on
-  ~org-reverse-note-order~, it is either the first or last subitem.
-
-  By default, all level 1 headlines in the current buffer are
-  considered to be targets, but you can have more complex definitions
-  across a number of files.  See the variable ~org-refile-targets~ for
-  details.  If you would like to select a location via
-  a file-path-like completion along the outline path, see the
-  variables ~org-refile-use-outline-path~ and
-  ~org-outline-path-complete-in-steps~.  If you would like to be able
-  to create new nodes as new parents for refiling on the fly, check
-  the variable ~org-refile-allow-creating-parent-nodes~.  When the
-  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
-  recorded whenever an entry is refiled.
-
-- {{{kbd(C-u C-c C-w)}}} ::
-
-  #+kindex: C-u C-c C-w
-  Use the refile interface to jump to a heading.
-
-- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
-
-  #+kindex: C-u C-u C-c C-w
-  #+findex: org-refile-goto-last-stored
-  Jump to the location where ~org-refile~ last moved a tree to.
-
-- {{{kbd(C-2 C-c C-w)}}} ::
-
-  #+kindex: C-2 C-c C-w
-  Refile as the child of the item currently being clocked.
-
-- {{{kbd(C-3 C-c C-w)}}} ::
-
-  #+kindex: C-3 C-c C-w
-  #+vindex: org-refile-keep
-  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
-  make this the default behavior, and beware that this may result in
-  duplicated =ID= properties.
-
-- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
-
-  #+kindex: C-u C-u C-u C-c C-w
-  #+kindex: C-0 C-c C-w
-  #+findex: org-refile-cache-clear
-  #+vindex: org-refile-use-cache
-  Clear the target cache.  Caching of refile targets can be turned on
-  by setting ~org-refile-use-cache~.  To make the command see new
-  possible targets, you have to clear the cache with this command.
-
-- {{{kbd(C-c M-w)}}} (~org-copy~) ::
-
-  #+kindex: C-c M-w
-  #+findex: org-copy
-  Copying works like refiling, except that the original note is not
-  deleted.
-
-** Archiving
-:PROPERTIES:
-:DESCRIPTION: What to do with finished products.
-:END:
-#+cindex: archiving
-
-When a project represented by a (sub)tree is finished, you may want to
-move the tree out of the way and to stop it from contributing to the
-agenda.  Archiving is important to keep your working files compact and
-global searches like the construction of agenda views fast.
-
-- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
-
-  #+kindex: C-c C-x C-a
-  #+findex: org-archive-subtree-default
-  #+vindex: org-archive-default-command
-  Archive the current entry using the command specified in the
-  variable ~org-archive-default-command~.
-
-*** Moving a tree to an archive file
-:PROPERTIES:
-:DESCRIPTION: Moving a tree to an archive file.
-:ALT_TITLE: Moving subtrees
-:END:
-#+cindex: external archiving
-
-The most common archiving action is to move a project tree to another
-file, the archive file.
-
-- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
-
-  #+kindex: C-c C-x C-s
-  #+kindex: C-c $
-  #+findex: org-archive-subtree
-  #+vindex: org-archive-location
-  Archive the subtree starting at point position to the location given
-  by ~org-archive-location~.
-
-- {{{kbd(C-u C-c C-x C-s)}}} ::
-
-  #+kindex: C-u C-c C-x C-s
-  Check if any direct children of the current headline could be moved
-  to the archive.  To do this, check each subtree for open TODO
-  entries.  If none is found, the command offers to move it to the
-  archive location.  If point is /not/ on a headline when this command
-  is invoked, check level 1 trees.
-
-- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
-
-  #+kindex: C-u C-u C-c C-x C-s
-  As above, but check subtree for timestamps instead of TODO entries.
-  The command offers to archive the subtree if it /does/ contain
-  a timestamp, and that timestamp is in the past.
-
-#+cindex: archive locations
-The default archive location is a file in the same directory as the
-current file, with the name derived by appending =_archive= to the
-current file name.  You can also choose what heading to file archived
-items under, with the possibility to add them to a datetree in a file.
-For information and examples on how to specify the file and the
-heading, see the documentation string of the variable
-~org-archive-location~.
-
-There is also an in-buffer option for setting this variable, for
-example:
-
-#+cindex: @samp{ARCHIVE}, keyword
-: #+ARCHIVE: %s_done::
-
-#+cindex: ARCHIVE, property
-If you would like to have a special archive location for a single
-entry or a (sub)tree, give the entry an =ARCHIVE= property with the
-location as the value (see [[*Properties and Columns]]).
-
-#+vindex: org-archive-save-context-info
-When a subtree is moved, it receives a number of special properties
-that record context information like the file from where the entry
-came, its outline path the archiving time etc.  Configure the variable
-~org-archive-save-context-info~ to adjust the amount of information
-added.
-
-*** Internal archiving
-:PROPERTIES:
-:DESCRIPTION: Switch off a tree but keep it in the file.
-:END:
-
-#+cindex: @samp{ARCHIVE}, tag
-If you want to just switch off---for agenda views---certain subtrees
-without moving them to a different file, you can use the =ARCHIVE=
-tag.
-
-A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
-its location in the outline tree, but behaves in the following way:
-
--
-  #+vindex: org-cycle-open-archived-trees
-  It does not open when you attempt to do so with a visibility cycling
-  command (see [[*Visibility Cycling]]).  You can force cycling archived
-  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
-  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
-  ~outline-show-all~, open archived subtrees.
-
--
-  #+vindex: org-sparse-tree-open-archived-trees
-  During sparse tree construction (see [[*Sparse Trees]]), matches in
-  archived subtrees are not exposed, unless you configure the option
-  ~org-sparse-tree-open-archived-trees~.
-
--
-  #+vindex: org-agenda-skip-archived-trees
-  During agenda view construction (see [[*Agenda Views]]), the content of
-  archived trees is ignored unless you configure the option
-  ~org-agenda-skip-archived-trees~, in which case these trees are
-  always included.  In the agenda you can press {{{kbd(v a)}}} to get
-  archives temporarily included.
-
--
-  #+vindex: org-export-with-archived-trees
-  Archived trees are not exported (see [[*Exporting]]), only the headline
-  is.  Configure the details using the variable
-  ~org-export-with-archived-trees~.
-
--
-  #+vindex: org-columns-skip-archived-trees
-  Archived trees are excluded from column view unless the variable
-  ~org-columns-skip-archived-trees~ is configured to ~nil~.
-
-The following commands help manage the =ARCHIVE= tag:
-
-- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
-
-  #+kindex: C-c C-x a
-  #+findex: org-toggle-archive-tag
-  Toggle the archive tag for the current headline.  When the tag is
-  set, the headline changes to a shadowed face, and the subtree below
-  it is hidden.
-
-- {{{kbd(C-u C-c C-x a)}}} ::
-
-  #+kindex: C-u C-c C-x a
-  Check if any direct children of the current headline should be
-  archived.  To do this, check each subtree for open TODO entries.  If
-  none is found, the command offers to set the =ARCHIVE= tag for the
-  child.  If point is /not/ on a headline when this command is
-  invoked, check the level 1 trees.
-
-- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
-
-  #+kindex: C-TAB
-  Cycle a tree even if it is tagged with =ARCHIVE=.
-
-- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
-
-  #+kindex: C-c C-x A
-  #+findex: org-archive-to-archive-sibling
-  Move the current entry to the /Archive Sibling/.  This is a sibling
-  of the entry with the heading =Archive= and the archive tag.  The
-  entry becomes a child of that sibling and in this way retains a lot
-  of its original context, including inherited tags and approximate
-  position in the outline.
-
 * Agenda Views
 :PROPERTIES:
 :DESCRIPTION: Collecting information into views.
@@ -21241,7 +21458,7 @@ accessed in capture templates in a similar way.
 ~org-link-from-user-regexp~.
 
 [fn:87] If you move entries or Org files from one directory to
-another, you may want to configure ~org-attach-directory~ to contain
+another, you may want to configure ~org-attach-id-dir~ to contain
 an absolute path.
 
 [fn:88] Note the corresponding =STARTUP= options =logrefile=,
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 95358ca7b..4d5c11c3c 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI
 alternative was removed and there is no more a :use-xcolor options
 since now it's implicitly always true.
 
+*** Org-Attach Git commit
+[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality.  Not
+much, but the following changes are required if you still need to
+auto-commit attachments to git:
+
+- Customization of ~org-attach-annex-auto-get~ needs to be renamed to
+  ~org-attach-git-annex-auto-get~.
+
+- Customization of ~org-attach-commit~ is no longer needed.  Instead
+  one need to require the =org-attach-git= module in the startup.
+
 ** New features
+*** Org-Attach has been refactored and extended
+Org attach has been refactored and the functionality extended.  It
+should now be easier to understand how it works.  A few improvements
+and extra options have been added as well.
+
+From the initial comment in org-attach source-code:
+
+- Attachments are managed either by using a custom property DIR or by
+  using property ID from org-id.  When DIR is defined, a location in
+  the filesystem is directly attached to the outline node.  When
+  org-id is used, attachments are stored in a folder named after the
+  ID, in a location defined by ~org-attach-id-dir~.  DIR has
+  precedence over ID when both parameters are defined for the current
+  outline node (also when inherited parameters are taken into
+  account).
+
+From now on inheritance requires no extra property and will adhere to
+~org-attach-use-inheritance~ by default.  Inheritance can be
+customized to always be activated or never be activated in
+~org-attach-use-inheritance~.
+
+The ATTACH_DIR property is deprecated in favour of the shorter
+property DIR.  Links to folders inside the DIR property can now be
+declared as relative links.  This is not enabled by default, but can
+be set in ~org-attach-dir-relative~.
+
+When adding new attachment to the outline node the preferred way of
+doing so can be customized.  Take a look at
+~org-attach-preferred-new-method~.  It defaults to using ID since that
+was the behaviour before this change.
+
+If both DIR and ID properties are set on the same node, DIR has
+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.
+
+If you've used ATTACH_DIR properties to manage attachments, use the
+following code to rename that property to DIR which supports the same
+functionality.  ATTACH_DIR_INHERIT is no longer supported and is
+removed.
+
+#+begin_src emacs-lisp
+  (defun org-update-attach-properties ()
+      "Change properties for Org-Attach."
+      (interactive)
+      (org-with-point-at 1
+	(while (outline-next-heading)
+	  (let ((DIR (org--property-local-values "ATTACH_DIR" nil)))
+	    (when DIR
+	      (org-set-property "DIR" (car DIR))
+	      (org-delete-property "ATTACH_DIR"))))
+	(org-delete-property-globally "ATTACH_DIR_INHERIT")))
+#+end_src
+
+For those who hate breaking changes, even though the changes are made
+to clean things up; fear not.  ATTACH_DIR will still continue to work.
+It's just not documented any longer.  When you get the chance, run the
+code above to clean things up anyways!
+
+**** New hooks
+Two hooks are added to org-attach:
+- org-attach-after-change-hook
+- org-attach-open-hook
+
+They are added mostly for internal restructuring purposes, but can
+ofc. be used for other things as well.
+
+*** New link-type: Attachment
+Attachment-links are now first-class citizens.  They mimick file-links
+in everything they do but use the existing attachment-folder as a base
+when expanding the links. Both =DIR= and =ID= properties are used to
+try to resolve the links, in exactly the same way as Org-Attach uses
+those properties.
+
 *** Handle overlay specification for notes in Beamer export
 
 This aligns Beamer notes with slide overlays.
@@ -244,6 +333,10 @@ dynamic block in ~org-dynamic-block-alist~.
 *** ~org-babel-set-current-result-hash~
 
 It was unused throughout the code base.
+*** ~org-attach-directory~
+
+It has been deprecated in favour of ~org-attach-id-dir~ which is less
+ambigous given the restructured org-attach.
 
 ** Miscellaneous
 *** LaTeX preview is simplified
diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el
new file mode 100644
index 000000000..924d04157
--- /dev/null
+++ b/lisp/org-attach-git.el
@@ -0,0 +1,118 @@
+;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; Original Author: John Wiegley <johnw@newartisans.com>
+;; Restructurer: Gustav Wikström <gustav@whil.se>
+;; Keywords: org data git
+
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; An extention to org-attach.  If the attachment-directory to an
+;; outline node (using either DIR or ID) is initialized as a Git
+;; repository, then org-attach-git will automatically commit changes
+;; when it sees them.
+
+;;; Code:
+
+(require 'org-attach)
+(require 'vc-git)
+
+(defcustom org-attach-git-annex-cutoff (* 32 1024)
+  "If non-nil, files larger than this will be annexed instead of stored."
+  :group 'org-attach
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type '(choice
+	  (const :tag "None" nil)
+	  (integer :tag "Bytes")))
+
+(defcustom org-attach-git-annex-auto-get 'ask
+  "Confirmation preference for automatically getting annex files.
+If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+  :group 'org-attach
+  :package-version '(Org . "9.0")
+  :version "26.1"
+  :type '(choice
+	  (const :tag "confirm with `y-or-n-p'" ask)
+	  (const :tag "always get from annex if necessary" t)
+	  (const :tag "never get from annex" nil)))
+
+(defun org-attach-git-use-annex ()
+  "Return non-nil if git annex can be used."
+  (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir))))
+    (and org-attach-git-annex-cutoff
+         (or (file-exists-p (expand-file-name "annex" git-dir))
+             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
+
+(defun org-attach-git-annex-get-maybe (path)
+  "Call git annex get PATH (via shell) if using git annex.
+Signals an error if the file content is not available and it was not retrieved."
+  (let* ((default-directory (expand-file-name org-attach-id-dir))
+	 (path-relative (file-relative-name path)))
+    (when (and (org-attach-git-use-annex)
+	       (not
+		(string-equal
+		 "found"
+		 (shell-command-to-string
+		  (format "git annex find --format=found --in=here %s"
+			  (shell-quote-argument path-relative))))))
+      (let ((should-get
+	     (if (eq org-attach-git-annex-auto-get 'ask)
+		 (y-or-n-p (format "Run git annex get %s? " path-relative))
+	       org-attach-git-annex-auto-get)))
+	(if should-get
+	    (progn (message "Running git annex get \"%s\"." path-relative)
+		   (call-process "git" nil nil nil "annex" "get" path-relative))
+	  (error "File %s stored in git annex but it is not available, and was not retrieved"
+		 path))))))
+
+(defun org-attach-git-commit ()
+  "Commit changes to git if `org-attach-id-dir' is properly initialized.
+This checks for the existence of a \".git\" directory in that directory."
+  (let* ((dir (expand-file-name org-attach-id-dir))
+	 (git-dir (vc-git-root dir))
+	 (use-annex (org-attach-git-use-annex))
+	 (changes 0))
+    (when (and git-dir (executable-find "git"))
+      (with-temp-buffer
+	(cd dir)
+        (dolist (new-or-modified
+                 (split-string
+                  (shell-command-to-string
+                   "git ls-files -zmo --exclude-standard") "\0" t))
+          (if (and use-annex
+                   (>= (file-attribute-size (file-attributes new-or-modified))
+                       org-attach-git-annex-cutoff))
+              (call-process "git" nil nil nil "annex" "add" new-or-modified)
+            (call-process "git" nil nil nil "add" new-or-modified))
+	    (cl-incf changes))
+	(dolist (deleted
+		 (split-string
+		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
+	  (call-process "git" nil nil nil "rm" deleted)
+	  (cl-incf changes))
+	(when (> changes 0)
+	  (shell-command "git commit -m 'Synchronized attachments'"))))))
+
+(add-hook 'org-attach-after-change-hook 'org-attach-git-commit)
+(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe)
+
+(provide 'org-attach-git)
+
+;;; org-attach-git.el ends here
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index de8b2fc96..c4cdb161c 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -1,9 +1,9 @@
-;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*-
+;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2008-2019 Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@newartisans.com>
-;; Keywords: org data task
+;; Keywords: org data attachment
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -24,32 +24,30 @@
 
 ;; See the Org manual for information on how to use it.
 ;;
-;; Attachments are managed in a special directory called "data", which
-;; lives in the same directory as the org file itself.  If this data
-;; directory is initialized as a Git repository, then org-attach will
-;; automatically commit changes when it sees them.
-;;
-;; Attachment directories are identified using a UUID generated for the
-;; task which has the attachments.  These are added as property to the
-;; task when necessary, and should not be deleted or changed by the
-;; user, ever.  UUIDs are generated by a mechanism defined in the variable
-;; `org-id-method'.
+;; Attachments are managed either by using a custom property DIR or by
+;; using property ID from org-id.  When DIR is defined, a location in
+;; the filesystem is directly attached to the outline node.  When
+;; org-id is used, attachments are stored in a folder named after the
+;; ID, in a location defined by `org-attach-id-dir'.  DIR has
+;; precedence over ID when both parameters are defined for the current
+;; outline node (also when inherited parameters are taken into
+;; account).
 
 ;;; Code:
 
 (require 'cl-lib)
 (require 'org)
+(require 'ol)
 (require 'org-id)
-(require 'vc-git)
 
 (declare-function dired-dwim-target-directory "dired-aux")
 
 (defgroup org-attach nil
-  "Options concerning entry attachments in Org mode."
+  "Options concerning attachments in Org mode."
   :tag "Org Attach"
   :group 'org)
 
-(defcustom org-attach-directory "data/"
+(defcustom org-attach-id-dir "data/"
   "The directory where attachments are stored.
 If this is a relative path, it will be interpreted relative to the directory
 where the Org file lives."
@@ -57,22 +55,13 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
-(defcustom org-attach-commit t
-  "If non-nil commit attachments with git.
-This is only done if the Org file is in a git repository."
+(defcustom org-attach-dir-relative nil
+  "Non-nil means directories in DIR property are added as relative links.
+Defaults to absolute location."
   :group 'org-attach
   :type 'boolean
-  :version "26.1"
-  :package-version '(Org . "9.0"))
-
-(defcustom org-attach-git-annex-cutoff (* 32 1024)
-  "If non-nil, files larger than this will be annexed instead of stored."
-  :group 'org-attach
-  :version "24.4"
-  :package-version '(Org . "8.0")
-  :type '(choice
-	  (const :tag "None" nil)
-	  (integer :tag "Bytes")))
+  :package-version '(Org . "9.3")
+  :safe #'booleanp)
 
 (defcustom org-attach-auto-tag "ATTACH"
   "Tag that will be triggered automatically when an entry has an attachment."
@@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository."
 	  (const :tag "None" nil)
 	  (string :tag "Tag")))
 
-(defcustom org-attach-file-list-property "Attachments"
-  "The property used to keep a list of attachment belonging to this entry.
-This is not really needed, so you may set this to nil if you don't want it.
-Also, for entries where children inherit the directory, the list of
-attachments is not kept in this property."
+(defcustom org-attach-preferred-new-method 'id
+  "Preferred way to attach to nodes without existing ID and DIR property.
+This choice is used when adding attachments to nodes without ID
+and DIR properties.
+
+Allowed values are:
+
+id         Create and use an ID parameter
+dir        Create and use a DIR parameter
+ask        Ask the user for input of which method to choose
+nil        Prefer to not create a new parameter
+
+           nil means that ID or DIR has to be created explicitly
+           before attaching files."
   :group 'org-attach
+  :package-version '(org . "9.3")
   :type '(choice
-	  (const :tag "None" nil)
-	  (string :tag "Tag")))
+	  (const :tag "ID parameter" id)
+	  (const :tag "DIR parameter" dir)
+	  (const :tag "Ask user" ask)
+	  (const :tag "Don't create" nil)))
 
 (defcustom org-attach-method 'cp
   "The preferred method to attach a file.
@@ -113,14 +114,25 @@ lns   create a symbol link.  Note that this is not supported
   :group 'org-attach
   :type 'boolean)
 
-(defcustom org-attach-allow-inheritance t
-  "Non-nil means allow attachment directories be inherited."
+(defcustom org-attach-use-inheritance 'selective
+  "Attachment inheritance for the outline.
+
+Enabling inheritance for org-attach implies two things.  First,
+that attachment links will look through all parent headings until
+it finds the linked attachment.  Second, that running org-attach
+inside a node without attachments will make org-attach operate on
+the first parent heading it finds with an attachment.
+
+Selective means to respect the inheritance setting in
+`org-use-property-inheritance'."
   :group 'org-attach
+  :type '(choice
+	  (const :tag "Don't use inheritance" nil)
+	  (const :tag "Inherit parent node attachments" t)
+	  (const :tag "Respect org-use-property-inheritance" selective)
+	  )
   :type 'boolean)
 
-(defvar org-attach-inherited nil
-  "Indicates if the last access to the attachment directory was inherited.")
-
 (defcustom org-attach-store-link-p nil
   "Non-nil means store a link to a file when attaching it."
   :group 'org-attach
@@ -141,16 +153,28 @@ When set to `query', ask the user instead."
 	  (const :tag "Always delete attachments" t)
 	  (const :tag "Query the user" query)))
 
-(defcustom org-attach-annex-auto-get 'ask
-  "Confirmation preference for automatically getting annex files.
-If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+(defun org-attach-id-folder-format (id)
+  "Translate an ID into a folder-path.
+Default format for how Org translates ID properties to a path for
+attachments."
+  (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."
   :group 'org-attach
-  :package-version '(Org . "9.0")
-  :version "26.1"
-  :type '(choice
-	  (const :tag "confirm with `y-or-n-p'" ask)
-	  (const :tag "always get from annex if necessary" t)
-	  (const :tag "never get from annex" nil)))
+  :package-version '(Org . "9.3")
+  :type 'function)
+
+(defvar org-attach-after-change-hook nil
+  "Hook to be called when files have been added or removed to the attachment folder.")
+
+(defvar org-attach-open-hook nil
+  "Hook that is invoked by `org-attach-open'.
+
+Created mostly to be compatible with org-attach-git after removing
+git-funtionality from this file.")
 
 (defcustom org-attach-commands
   '(((?a ?\C-a) org-attach-attach
@@ -186,9 +210,9 @@ you added attachments yourself.\n")
      "Delete all of a task's attachments.  A safer way is\n to open the \
 directory in dired and delete from there.\n")
     ((?s ?\C-s) org-attach-set-directory
-     "Set a specific attachment directory for this entry or reset to default.")
-    ((?i ?\C-i) org-attach-set-inherit
-     "Make children of the current entry inherit its attachment directory.\n")
+     "Set a specific attachment directory for this entry. Sets DIR property.")
+    ((?S ?\C-S) org-attach-unset-directory
+     "Unset the attachment directory for this entry.  Removes DIR property.")
     ((?q) (lambda () (interactive) (message "Abort")) "Abort."))
   "The list of commands for the attachment dispatcher.
 Each entry in this list is a list of three elements:
@@ -210,39 +234,42 @@ Each entry in this list is a list of three elements:
   "The dispatcher for attachment commands.
 Shows a list of commands and prompts for another key to execute a command."
   (interactive)
-  (let (c marker)
+  (let (c marker attachment)
     (when (eq major-mode 'org-agenda-mode)
       (setq marker (or (get-text-property (point) 'org-hd-marker)
 		       (get-text-property (point) 'org-marker)))
       (unless marker
-	(error "No task in current line")))
+	(error "No item in current line")))
     (save-excursion
       (when marker
 	(set-buffer (marker-buffer marker))
 	(goto-char marker))
       (org-back-to-heading t)
+      (setq attachment (or (org-attach-dir)
+			   (quote  "Can't find an existing attachment-folder")))
       (save-excursion
 	(save-window-excursion
 	  (unless org-attach-expert
 	    (with-output-to-temp-buffer "*Org Attach*"
-	      (princ
-	       (format "Select an Attachment Command:\n\n%s"
-		       (mapconcat
-			(lambda (entry)
-			  (pcase entry
-			    (`((,key . ,_) ,_ ,docstring)
-			     (format "%c       %s"
-				     key
-				     (replace-regexp-in-string "\n\\([\t ]*\\)"
-							       "        "
-							       docstring
-							       nil nil 1)))
-			    (_
-			     (user-error
-			      "Invalid `org-attach-commands' item: %S"
-			      entry))))
-			org-attach-commands
-			"\n")))))
+              (princ
+               (concat "Attachment folder:\n" attachment "\n\n"
+	               (format "Select an Attachment Command:\n\n%s"
+		               (mapconcat
+		                (lambda (entry)
+		                  (pcase entry
+		                    (`((,key . ,_) ,_ ,docstring)
+		                     (format "%c       %s"
+			                     key
+			                     (replace-regexp-in-string "\n\\([\t ]*\\)"
+							               "        "
+							               docstring
+							               nil nil 1)))
+		                    (_
+		                     (user-error
+			              "Invalid `org-attach-commands' item: %S"
+			              entry))))
+		                org-attach-commands
+		                "\n"))))))
 	  (org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
 	  (message "Select command: [%s]"
 		   (concat (mapcar #'caar org-attach-commands)))
@@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command."
 	  (error "No such attachment command: %c" c))))))
 
 (defun org-attach-dir (&optional create-if-not-exists-p)
-  "Return the directory associated with the current entry.
-This first checks for a local property ATTACH_DIR, and then for an inherited
-property ATTACH_DIR_INHERIT.  If neither exists, the default mechanism
-using the entry ID will be invoked to access the unique directory for the
-current entry.
-If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil,
-the directory and (if necessary) the corresponding ID will be created."
-  (let (attach-dir uuid)
-    (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT"))
+  "Return the directory associated with the current outline node.
+First check for DIR property, then ID property.
+`org-attach-use-inheritance' determines whether inherited
+properties also will be considered.
+
+If an ID property is found the default mechanism using that ID
+will be invoked to access the directory for the current entry.
+
+If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
+is run."
+  (let (attach-dir id)
     (cond
-     ((setq attach-dir (org-entry-get nil "ATTACH_DIR"))
+     (create-if-not-exists-p
+      (setq attach-dir (org-attach-dir-get-create)))
+     ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
       (org-attach-check-absolute-path attach-dir))
-     ((and org-attach-allow-inheritance
-	   (org-entry-get nil "ATTACH_DIR_INHERIT" t))
-      (setq attach-dir
-	    (org-with-wide-buffer
-	     (if (marker-position org-entry-property-inherited-from)
-		 (goto-char org-entry-property-inherited-from)
-	       (org-back-to-heading t))
-	     (let (org-attach-allow-inheritance)
-	       (org-attach-dir create-if-not-exists-p))))
-      (org-attach-check-absolute-path attach-dir)
-      (setq org-attach-inherited t))
-     (t					; use the ID
+     ;; Deprecated and removed from documentation, but still
+     ;; works. FIXME: Remove after major nr change.
+     ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance))
+      (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 uuid (org-id-get (point) create-if-not-exists-p))
-      (when (or uuid create-if-not-exists-p)
-	(unless uuid (error "ID retrieval/creation failed"))
-	(setq attach-dir (expand-file-name
-			  (format "%s/%s"
-				  (substring uuid 0 2)
-				  (substring uuid 2))
-			  (expand-file-name org-attach-directory))))))
-    (when attach-dir
-      (if (and create-if-not-exists-p
-	       (not (file-directory-p attach-dir)))
-	  (make-directory attach-dir t))
-      (and (file-exists-p attach-dir)
-	   attach-dir))))
+      (setq attach-dir (org-attach-dir-from-id id))))
+    attach-dir))
+
+(defun org-attach-dir-get-create ()
+  "Return existing or new directory associated with the current outline node.
+
+`org-attach-preferred-new-method' decides how to attach
+new directory."
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (unless attach-dir
+      (let (answer)
+	(when (eq org-attach-preferred-new-method 'ask)
+	  (message "Create new ID [1] property or DIR [2] property for attachments?")
+	  (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))))
+	 ((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)
+	  (error "No existing directory. DIR or ID property has to be explicitly created")))))
+    (if attach-dir
+	(progn (if (not (file-directory-p attach-dir))
+		   (make-directory attach-dir t))
+	       attach-dir)
+      (error "No attachment directory is associated with the current node"))))
+
+(defun org-attach-dir-from-id (id)
+  "Creates a path 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-check-absolute-path (dir)
   "Check if we have enough information to root the attachment directory.
 When DIR is given, check also if it is already absolute.  Otherwise,
-assume that it will be relative, and check if `org-attach-directory' is
+assume that it will be relative, and check if `org-attach-id-dir' is
 absolute, or if at least the current buffer has a file name.
 Throw an error if we cannot root the directory."
   (or (and dir (file-name-absolute-p dir))
-      (file-name-absolute-p org-attach-directory)
+      (file-name-absolute-p org-attach-id-dir)
       (buffer-file-name (buffer-base-buffer))
-      (error "Need absolute `org-attach-directory' to attach in buffers without filename")))
+      (error "Need absolute `org-attach-id-dir' to attach in buffers without filename")))
 
-(defun org-attach-set-directory (&optional arg)
-  "Set the ATTACH_DIR node property and ask to move files there.
+(defun org-attach-set-directory ()
+  "Set the DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
-of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
-  (interactive "P")
+of the entry.  Creates relative links if `org-attach-dir-relative'
+is t.
+
+Return the directory."
+  (interactive)
   (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+	(new
+	 (let* ((attach-dir (read-directory-name
+			     "Attachment directory: "
+			     (org-entry-get nil "DIR")))
+		(current-dir (file-name-directory (or default-directory
+						      buffer-file-name)))
+		(attach-dir-relative (file-relative-name attach-dir current-dir)))
+	   (org-entry-put nil "DIR" (if org-attach-dir-relative
+					attach-dir-relative
+				      attach-dir))
+           attach-dir)))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
+        (copy-directory old new t t t))
+      (when (yes-or-no-p (concat "Delete " old))
+        (delete-directory old t)))
+    new))
+
+(defun org-attach-unset-directory ()
+  "Removes DIR node property.
+If attachment folder is changed due to removal of DIR-property
+ask to move attachments to new location and ask to delete old
+attachment-folder.
+
+Change of attachment-folder due to unset might be if an ID
+property is set on the node, or if a separate inherited
+DIR-property exists (that is different than the unset one)."
+  (interactive)
+  (let ((old (org-attach-dir))
+	(new
+         (progn
+	   (org-entry-delete nil "DIR")
+	   ;; ATTACH-DIR is deprecated and removed from documentation,
+	   ;; but still works. Remove code for it after major nr change.
+	   (org-entry-delete nil "ATTACH_DIR")
+	   (org-attach-dir))))
+    (unless (or (string= old new)
+                (not old))
+      (when (and new (yes-or-no-p "Copy over attachments from old directory? "))
         (copy-directory old new t nil t))
       (when (yes-or-no-p (concat "Delete " old))
         (delete-directory old t)))))
 
-(defun org-attach-set-inherit ()
-  "Set the ATTACH_DIR_INHERIT property of the current entry.
-The property defines the directory that is used for attachments
-of the entry and any children that do not explicitly define (by setting
-the ATTACH_DIR property) their own attachment directory."
-  (interactive)
-  (org-entry-put nil "ATTACH_DIR_INHERIT" "t")
-  (message "Children will inherit attachment directory"))
-
-(defun org-attach-use-annex ()
-  "Return non-nil if git annex can be used."
-  (let ((git-dir (vc-git-root (expand-file-name org-attach-directory))))
-    (and org-attach-git-annex-cutoff
-         (or (file-exists-p (expand-file-name "annex" git-dir))
-             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
-
-(defun org-attach-annex-get-maybe (path)
-  "Call git annex get PATH (via shell) if using git annex.
-Signals an error if the file content is not available and it was not retrieved."
-  (let* ((default-directory (expand-file-name org-attach-directory))
-	 (path-relative (file-relative-name path)))
-    (when (and (org-attach-use-annex)
-	       (not
-		(string-equal
-		 "found"
-		 (shell-command-to-string
-		  (format "git annex find --format=found --in=here %s"
-			  (shell-quote-argument path-relative))))))
-      (let ((should-get
-	     (if (eq org-attach-annex-auto-get 'ask)
-		 (y-or-n-p (format "Run git annex get %s? " path-relative))
-	       org-attach-annex-auto-get)))
-	(if should-get
-	    (progn (message "Running git annex get \"%s\"." path-relative)
-		   (call-process "git" nil nil nil "annex" "get" path-relative))
-	  (error "File %s stored in git annex but it is not available, and was not retrieved"
-		 path))))))
-
-(defun org-attach-commit ()
-  "Commit changes to git if `org-attach-directory' is properly initialized.
-This checks for the existence of a \".git\" directory in that directory."
-  (let* ((dir (expand-file-name org-attach-directory))
-	 (git-dir (vc-git-root dir))
-	 (use-annex (org-attach-use-annex))
-	 (changes 0))
-    (when (and git-dir (executable-find "git"))
-      (with-temp-buffer
-	(cd dir)
-        (dolist (new-or-modified
-                 (split-string
-                  (shell-command-to-string
-                   "git ls-files -zmo --exclude-standard") "\0" t))
-          (if (and use-annex
-                   (>= (file-attribute-size (file-attributes new-or-modified))
-                       org-attach-git-annex-cutoff))
-              (call-process "git" nil nil nil "annex" "add" new-or-modified)
-            (call-process "git" nil nil nil "add" new-or-modified))
-	    (cl-incf changes))
-	(dolist (deleted
-		 (split-string
-		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
-	  (call-process "git" nil nil nil "rm" deleted)
-	  (cl-incf changes))
-	(when (> changes 0)
-	  (shell-command "git commit -m 'Synchronized attachments'"))))))
-
 (defun org-attach-tag (&optional off)
   "Turn the autotag on or (if OFF is set) off."
   (when org-attach-auto-tag
@@ -422,22 +427,21 @@ Only do this when `org-attach-store-link-p' is non-nil."
   (org-attach-attach url))
 
 (defun org-attach-buffer (buffer-name)
-  "Attach BUFFER-NAME's contents to current task.
+  "Attach BUFFER-NAME's contents to current outline node.
 BUFFER-NAME is a string.  Signals a `file-already-exists' error
 if it would overwrite an existing filename."
   (interactive "bBuffer whose contents should be attached: ")
-  (let ((output (expand-file-name buffer-name (org-attach-dir t))))
+  (let* ((attach-dir (org-attach-dir 'get-create))
+	 (output (expand-file-name buffer-name attach-dir)))
     (when (file-exists-p output)
       (signal 'file-already-exists (list "File exists" output)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property buffer-name))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)
     (org-attach-tag)
     (with-temp-file output
       (insert-buffer-substring buffer-name))))
 
 (defun org-attach-attach (file &optional visit-dir method)
-  "Move/copy/link FILE into the attachment directory of the current task.
+  "Move/copy/link FILE into the attachment directory of the current outline node.
 If VISIT-DIR is non-nil, visit the directory with dired.
 METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
 `org-attach-method'."
@@ -452,10 +456,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
     nil))
   (setq method (or method org-attach-method))
   (let ((basename (file-name-nondirectory file)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property basename))
-    (let* ((attach-dir (org-attach-dir t))
+    (let* ((attach-dir (org-attach-dir 'get-create))
            (fname (expand-file-name basename attach-dir)))
       (cond
        ((eq method 'mv) (rename-file file fname))
@@ -463,8 +464,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
        ((eq method 'ln) (add-name-to-file file fname))
        ((eq method 'lns) (make-symbolic-link file fname))
        ((eq method 'url) (url-copy-file file fname)))
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-tag)
       (cond ((eq org-attach-store-link-p 'attached)
              (org-attach-store-link fname))
@@ -472,7 +472,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
              (org-attach-store-link file)))
       (if visit-dir
           (dired attach-dir)
-        (message "File %S is now a task attachment." basename)))))
+        (message "File %S is now an attachment." basename)))))
 
 (defun org-attach-attach-cp ()
   "Attach a file by copying it."
@@ -497,13 +497,10 @@ On some systems, this apparently does copy the file instead."
   (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach)))
 
 (defun org-attach-new (file)
-  "Create a new attachment FILE for the current task.
+  "Create a new attachment FILE for the current outline node.
 The attachment is created as an Emacs buffer."
   (interactive "sCreate attachment named: ")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-add-to-multivalued-property
-     (point) org-attach-file-list-property file))
-  (let ((attach-dir (org-attach-dir t)))
+  (let ((attach-dir (org-attach-dir 'get-create)))
     (org-attach-tag)
     (find-file (expand-file-name file attach-dir))
     (message "New attachment %s" file)))
@@ -511,7 +508,7 @@ The attachment is created as an Emacs buffer."
 (defun org-attach-delete-one (&optional file)
   "Delete a single attachment."
   (interactive)
-  (let* ((attach-dir (org-attach-dir t))
+  (let* ((attach-dir (org-attach-dir))
 	 (files (org-attach-file-list attach-dir))
 	 (file (or file
 		   (completing-read
@@ -523,44 +520,32 @@ The attachment is created as an Emacs buffer."
     (unless (file-exists-p file)
       (error "No such attachment: %s" file))
     (delete-file file)
-    (when org-attach-commit
-      (org-attach-commit))))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)))
 
 (defun org-attach-delete-all (&optional force)
-  "Delete all attachments from the current task.
+  "Delete all attachments from the current outline node.
 This actually deletes the entire attachment directory.
 A safer way is to open the directory in dired and delete from there."
   (interactive "P")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
-    (when
-	(and attach-dir
-	     (or force
-		 (y-or-n-p "Are you sure you want to remove all attachments of this entry? ")))
-      (shell-command (format "rm -fr %s" attach-dir))
+    (when (and attach-dir
+	       (or force
+		   (yes-or-no-p "Really remove all attachments of this entry? ")))
+      (delete-directory attach-dir (yes-or-no-p "Recursive?") t)
       (message "Attachment directory removed")
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-untag))))
 
 (defun org-attach-sync ()
-  "Synchronize the current tasks with its attachments.
+  "Synchronize the current outline node with its attachments.
 This can be used after files have been added externally."
   (interactive)
-  (when org-attach-commit
-    (org-attach-commit))
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
     (when attach-dir
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (let ((files (org-attach-file-list attach-dir)))
-	(org-attach-tag (not files))
-	(when org-attach-file-list-property
-	  (dolist (file files)
-	    (unless (string-match "^\\.\\.?\\'" file)
-	      (org-entry-add-to-multivalued-property
-	       (point) org-attach-file-list-property file))))))))
+	(org-attach-tag (not files))))
+    (unless attach-dir (org-attach-tag t))))
 
 (defun org-attach-file-list (dir)
   "Return a list of files in the attachment directory.
@@ -569,35 +554,40 @@ This ignores files ending in \"~\"."
 	(mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x))
 		(directory-files dir nil "[^~]\\'"))))
 
-(defun org-attach-reveal (&optional if-exists)
-  "Show the attachment directory of the current task.
+(defun org-attach-reveal ()
+  "Show the attachment directory of the current outline node.
 This will attempt to use an external program to show the directory."
-  (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
-    (and attach-dir (org-open-file attach-dir))))
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(org-open-file attach-dir)
+      (error "No attachment directory exist"))))
 
 (defun org-attach-reveal-in-emacs ()
-  "Show the attachment directory of the current task in dired."
+  "Show the attachment directory of the current outline node in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(dired attach-dir)
+      (error "No attachment directory exist"))))
 
 (defun org-attach-open (&optional in-emacs)
-  "Open an attachment of the current task.
+  "Open an attachment of the current outline node.
 If there are more than one attachment, you will be prompted for the file name.
 This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(let* ((file (pcase (org-attach-file-list attach-dir)
+		       (`(,file) file)
+		       (files (completing-read "Open attachment: "
+					       (mapcar #'list files) nil t))))
+	       (path (expand-file-name file attach-dir)))
+	  (run-hook-with-args 'org-attach-open-hook path)
+	  (org-open-file path in-emacs))
+      (error "No attachment directory exist"))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -616,6 +606,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(org-link-set-parameters "attachment"
+                         :follow #'org-attach-open-link
+                         :export #'org-attach-export-link
+                         :complete #'org-attach-complete-link)
+
+(defun org-attach-open-link (link &optional in-emacs)
+  "Attachment link type LINK is expanded with the attached directory and opened.
+
+With optional prefix argument IN-EMACS, Emacs will visit the file.
+With a double \\[universal-argument] \\[universal-argument] \
+prefix arg, Org tries to avoid opening in Emacs
+and to use an external application to visit the file."
+  (interactive "P")
+  (let (line search)
+    (cond
+     ((string-match "::\\([0-9]+\\)\\'" link)
+      (setq line (string-to-number (match-string 1 link))
+	    link (substring link 0 (match-beginning 0))))
+     ((string-match "::\\(.+\\)\\'" link)
+      (setq search (match-string 1 link)
+            link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment directory."
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(let* ((attached-dir (expand-file-name attach-dir))
+	       (file (read-file-name "File: " attached-dir))
+	       (pwd (file-name-as-directory attached-dir))
+               (pwd-relative (file-name-as-directory
+			      (abbreviate-file-name attached-dir))))
+	  (cond
+	   ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file)
+	    (concat "attachment:" (match-string 1 file)))
+	   ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+			  (expand-file-name file))
+	    (concat "attachment:" (match-string 1 (expand-file-name file))))
+	   (t (concat "attachment:" file))))
+      (error "No attachment directory exist"))))
+
+(defun org-attach-export-link (link description format)
+  "Translate attachment LINK from Org mode format to exported FORMAT.
+Also includes the DESCRIPTION of the link in the export."
+  (save-excursion
+    (let (path desc)
+      (cond
+       ((string-match "::\\([0-9]+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0))))
+       ((string-match "::\\(.+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0)))))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
@@ -643,7 +696,7 @@ Idea taken from `gnus-dired-attach'."
   (interactive
    (list (dired-get-marked-files)))
   (unless (eq major-mode 'dired-mode)
-    (user-error "This command must be triggered in a dired buffer."))
+    (user-error "This command must be triggered in a dired buffer"))
   (let ((start-win (selected-window))
         (other-win
          (get-window-with-predicate
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index 9cb396fe9..42fe64379 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -263,6 +263,9 @@ Counting starts at 1."
 (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays
   'org-clear-latex-preview "Org 9.3")
 
+(define-obsolete-variable-alias 'org-attach-directory
+  'org-attach-id-dir "Org 9.3")
+
 (defun org-in-fixed-width-region-p ()
   "Non-nil if point in a fixed-width region."
   (save-match-data
diff --git a/lisp/org.el b/lisp/org.el
index b19a30f38..255b94e8d 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -3849,7 +3849,9 @@ This is needed for font-lock setup.")
 		  (beg end))
 (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
 (declare-function org-agenda-skip "org-agenda" ())
-(declare-function org-attach-reveal "org-attach" (&optional if-exists))
+(declare-function org-attach-expand "org-attach" (file))
+(declare-function org-attach-reveal "org-attach" ())
+(declare-function org-attach-reveal-in-emacs "org-attach" ())
 (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
 (declare-function org-indent-mode "org-indent" (&optional arg))
 (declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
@@ -8647,12 +8649,15 @@ a link."
 	  (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
 	    (`(nil . ,_)
 	     (require 'org-attach)
-	     (org-attach-reveal 'if-exists))
+	     (message "Opening attachment-dir")
+	     (if (equal arg '(4))
+		 (org-attach-reveal-in-emacs)
+	       (org-attach-reveal)))
 	    (`(,links . ,links-end)
 	     (dolist (link (if (stringp links) (list links) links))
 	       (search-forward link nil links-end)
 	       (goto-char (match-beginning 0))
-	       (org-open-at-point))))))
+	       (org-open-at-point arg))))))
        ;; On a footnote reference or at definition's label.
        ((or (eq type 'footnote-reference)
 	    (and (eq type 'footnote-definition)
@@ -16632,13 +16637,14 @@ boundaries."
 	     ;; "file:" links.  Also check link abbreviations since
 	     ;; some might expand to "file" links.
 	     (file-types-re
-	      (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
+	      (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
 		      (if (not link-abbrevs) ""
 			(concat "\\|" (regexp-opt link-abbrevs))))))
 	(while (re-search-forward file-types-re end t)
 	  (let* ((link (org-element-lineage
 			(save-match-data (org-element-context))
 			'(link) t))
+                 (linktype (org-element-property :type link))
 		 (inner-start (match-beginning 1))
 		 (path
 		  (cond
@@ -16652,7 +16658,8 @@ boundaries."
 		   ;; INCLUDE-LINKED is non-nil.
 		   ((or (not (org-element-property :contents-begin link))
 			include-linked)
-		    (and (equal "file" (org-element-property :type link))
+		    (and (or (equal "file" linktype)
+                             (equal "attachment" linktype))
 			 (org-element-property :path link)))
 		   ;; Link with a description.  Check if description
 		   ;; is a filename.  Even if Org doesn't have syntax
@@ -16671,7 +16678,11 @@ boundaries."
 			      (match-end 0))
 			   (match-string 2)))))))
 	    (when (and path (string-match-p file-extension-re path))
-	      (let ((file (expand-file-name path)))
+	      (let ((file (if (equal "attachment" linktype)
+                              (progn
+                                (require 'org-attach)
+                                (org-attach-expand path))
+                            (expand-file-name path))))
 		(when (file-exists-p file)
 		  (let ((width
 			 ;; Apply `org-image-actual-width' specifications.
diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA
new file mode 100644
index 000000000..9a0406c0d
--- /dev/null
+++ b/testing/examples/att1/fileA
@@ -0,0 +1 @@
+Text in fileA
diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB
new file mode 100644
index 000000000..dd2331824
--- /dev/null
+++ b/testing/examples/att1/fileB
@@ -0,0 +1 @@
+Text in fileB
diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC
new file mode 100644
index 000000000..2c9a92bfe
--- /dev/null
+++ b/testing/examples/att2/fileC
@@ -0,0 +1 @@
+Text in fileC
\ No newline at end of file
diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD
new file mode 100644
index 000000000..c706556c5
--- /dev/null
+++ b/testing/examples/att2/fileD
@@ -0,0 +1 @@
+text in fileD
diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org
new file mode 100644
index 000000000..ab4a4e548
--- /dev/null
+++ b/testing/examples/attachments.org
@@ -0,0 +1,32 @@
+#+TITLE: Org attach testfile
+Used to test and verify the functionality of org-attach.
+
+* H1
+ :PROPERTIES:
+ :DIR:      att1
+ :END:
+A link to one attachment: [[attachment:fileA]]
+
+** H1.1
+A link to another attachment: [[attachment:fileB]]
+
+** H1.2
+  :PROPERTIES:
+  :DIR:      att2
+  :END:
+
+* H2
+ :PROPERTIES:
+ :ID:       abcd123
+ :END:
+
+* H3
+ :PROPERTIES:
+ :DIR:      att1
+ :ID:       abcd1234
+ :END:
+
+** H3.1
+  :PROPERTIES:
+  :ID:       abcd12345
+  :END:
diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE
new file mode 100644
index 000000000..80d337772
--- /dev/null
+++ b/testing/examples/data/ab/cd123/fileE
@@ -0,0 +1 @@
+peek-a-boo
diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el
similarity index 93%
rename from testing/lisp/test-org-attach-annex.el
rename to testing/lisp/test-org-attach-git.el
index 7f2792696..8b826b72f 100644
--- a/testing/lisp/test-org-attach-annex.el
+++ b/testing/lisp/test-org-attach-git.el
@@ -20,19 +20,19 @@
 
 ;;; Code:
 (org-test-for-executable "git-annex")
-(require 'org-attach)
+(require 'org-attach-git)
 (require 'cl-lib)
 
-(defmacro test-org-attach-annex/with-annex (&rest body)
+(defmacro test-org-attach-git/with-annex (&rest body)
   `(let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (shell-command "git annex init")
 	   ,@body))))
 
-(ert-deftest test-org-attach/use-annex ()
+(ert-deftest test-org-attach-git/use-annex ()
   (test-org-attach-annex/with-annex
    (let ((org-attach-git-annex-cutoff 1))
      (should (org-attach-use-annex)))
@@ -44,12 +44,12 @@
   (let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (should-not (org-attach-use-annex)))
        (delete-directory tmpdir 'recursive))))
 
-(ert-deftest test-org-attach/get-maybe ()
+(ert-deftest test-org-attach-git/get-maybe ()
   (test-org-attach-annex/with-annex
    (let ((path (expand-file-name "test-file"))
 	 (annex-dup (make-temp-file "org-annex-test" t "/")))
diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el
index c2f2be356..5bcfe86fd 100644
--- a/testing/lisp/test-org-attach.el
+++ b/testing/lisp/test-org-attach.el
@@ -28,6 +28,75 @@
 (require 'org-attach)
 (eval-and-compile (require 'cl-lib))
 
+(ert-deftest test-org-attach/dir ()
+  "Test `org-attach-get' specifications."
+  (should (equal "Text in fileA\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 157) ;; First attachment link
+		   (org-open-at-point)
+		   (buffer-string))))
+  (should-not (equal "Text in fileB\n"
+		     (org-test-in-example-file org-test-attachments-file
+		       (goto-char 219) ;; Second attachment link
+		       (let ((org-attach-use-inheritance nil))
+			 (org-open-at-point)
+			 (buffer-string)))))
+  (should (equal "Text in fileB\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 219) ;; Second attachment link
+		   (let ((org-attach-use-inheritance t))
+		     (org-open-at-point)
+		     (buffer-string)))))
+  (should-not (equal "att1"
+		     (org-test-in-example-file org-test-attachments-file
+		       (goto-char 179) ;; H1.1
+		       (let ((org-attach-use-inheritance nil))
+			 (org-attach-dir)))))
+  (should (equal "att1"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 179) ;; H1.1
+		   (let ((org-attach-use-inheritance t))
+		     (org-attach-dir)))))
+  (should (equal '("fileC" "fileD")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 239) ;; H1.2
+		   (org-attach-file-list (org-attach-dir)))))
+  (should (equal '("fileC" "fileD")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 239) ;; H1.2
+		   (org-attach-file-list (org-attach-dir)))))
+  (should (equal '("fileE")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 289) ;; H2
+		   (let ((org-attach-id-dir "data/"))
+		     (org-attach-file-list (org-attach-dir))))))
+  (should (equal "peek-a-boo\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 289) ;; H2
+		   (let ((org-attach-id-dir "data/"))
+		     (org-attach-open-in-emacs)
+		     (buffer-string)))))
+  (should (equal  '("fileA" "fileB")
+		  (org-test-in-example-file org-test-attachments-file
+		    (goto-char 336) ;; H3
+		    (org-attach-file-list (org-attach-dir)))))
+  (should (equal "data/ab/cd12345"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 401) ;; H3.1
+		   (let ((org-attach-use-inheritance nil)
+			 (org-attach-id-dir "data/"))
+		     (file-relative-name (org-attach-dir))))))
+  (should (equal '("fileA" "fileB")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 401) ;; H3.1
+		   (let ((org-attach-use-inheritance t))
+		     ;; This is where it get's a bit sketchy...! DIR always has
+		     ;; priority over ID, even if ID is declared "higher up" in the
+		     ;; tree.  This can potentially be revised.  But it is also
+		     ;; pretty clean.  DIR is always higher in priority than ID right
+		     ;; now, no matter the depth in the tree.
+		     (org-attach-file-list (org-attach-dir)))))))
+
 (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 ()
   "Attach file at point in dired to subtree."
   (should
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index d671b5c78..a618da479 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -2514,7 +2514,11 @@ Foo Bar
      (catch :result
        (cl-letf (((symbol-function 'org-tags-view)
 		  (lambda (&rest args) (throw :result t))))
-	 (org-open-at-point)
+	 ;; When point isn't on a tag it's going to try other things,
+	 ;; possibly trying to open attachments which will return an
+	 ;; error if there isn't an attachment. Supress that error.
+	 (ignore-errors
+	     (org-open-at-point))
 	 nil)))))
 
 \f
diff --git a/testing/org-test.el b/testing/org-test.el
index 295df1919..c3e21eb30 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.")
 (defconst org-test-no-heading-file
   (expand-file-name "no-heading.org" org-test-example-dir))
 
+(defconst org-test-attachments-file
+  (expand-file-name "attachments.org" org-test-example-dir))
+
 (defconst org-test-link-in-heading-file
   (expand-file-name "link-in-heading.org" org-test-dir))
 
-- 
2.17.1


[-- Attachment #3: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --]
[-- Type: application/octet-stream, Size: 8578 bytes --]

From 8bdf0c4d9e0308d32bee18613e530a2c497a4611 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 26 May 2019 03:34:34 +0200
Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox,
 test-property-inheritance

* org-test.el:

Fix org-test-with-temp-text-in-file.  Make it work with <point>, as
some tests already expect it to do!  Also make it fail more gracefully
by still removing temporary buffers and files.

Improve org-test-in-example-file.  Make it behave similar to
org-test-with-temp-text and org-test-with-temp-text-in-file, in that
it will return the last evaluated expression.

* testing/lisp/test-org-element.el

Fix a temp-text strings so that it doesn't have an initial newline.

* testing/lisp/test-org.el

Minor cleanup to align code-structure with other tests.  Nothing
changes in the test execpt style.

* testing/lisp/test-ox.el

Fix a couple of temp-text strings so that they don't have initial
newlines.

** test-org-export/expand-include

Test specification was wrong, due to org-test-with-temp-text-in-file
not previously working with <point>.  Since that is fixed in this
patch the test needed to be updated to match the expected outcome.

* testing/lisp/test-property-inheritance.el

Fix wrong file-header and file-ending.
---
 testing/lisp/test-org-element.el          |  4 +--
 testing/lisp/test-org.el                  | 12 +++----
 testing/lisp/test-ox.el                   | 30 ++++++++--------
 testing/lisp/test-property-inheritance.el |  4 +--
 testing/org-test.el                       | 44 ++++++++++++++---------
 5 files changed, 53 insertions(+), 41 deletions(-)

diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 8b4081ee2..4c1e4d181 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -3250,8 +3250,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
 
 (ert-deftest test-org-element/granularity ()
   "Test granularity impact on buffer parsing."
-  (org-test-with-temp-text "
-* Head 1
+  (org-test-with-temp-text
+      "* Head 1
 ** Head 2
 #+BEGIN_CENTER
 Centered paragraph.
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index abc004689..d671b5c78 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -5060,18 +5060,18 @@ Paragraph<point>"
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
-      (org-entry-get (point) "A" t))))
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
+      (org-entry-get (point-max) "A" t))))
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
       (let ((org-use-property-inheritance t))
-	(org-entry-get (point) "A" 'selective)))))
+	(org-entry-get (point-max) "A" 'selective)))))
   (should-not
-   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
      (let ((org-use-property-inheritance nil))
-       (org-entry-get (point) "A" 'selective))))
+       (org-entry-get (point-max) "A" 'selective))))
   (should
    (equal
     "1 2"
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 2c2778f82..b8c507e0b 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
 	       org-test-dir)
      (narrow-to-region (point) (point-max))
      (org-export-expand-include-keyword)
-     (eq 1 (org-current-level))))
+     (eq 2 (org-current-level))))
   ;; If :minlevel is present do not alter it.
   (should
    (org-test-with-temp-text
@@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after
 comments removal."
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 
 # Comment
@@ -2012,15 +2012,15 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 
@@ -2029,8 +2029,8 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 
@@ -2040,24 +2040,24 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "- item 1\n\n- item 2\n"
-	  (org-test-with-temp-text "
-- item 1
+	  (org-test-with-temp-text
+	      "- item 1
 
   # Comment
 
diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el
index 0f803e5f7..1d0dcfbe1 100644
--- a/testing/lisp/test-property-inheritance.el
+++ b/testing/lisp/test-property-inheritance.el
@@ -1,4 +1,4 @@
-;;; test-ob-R.el --- tests for ob-R.el
+;;; test-property-inheritance.el --- tests for property-inheritance.el
 
 ;; Copyright (c) 2011-2014, 2019 Eric Schulte
 ;; Authors: Eric Schulte
@@ -47,4 +47,4 @@
 
 (provide 'test-ob-R)
 
-;;; test-ob-R.el ends here
+;;; test-property-inheritance.el ends here
diff --git a/testing/org-test.el b/testing/org-test.el
index 39c346410..295df1919 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -146,7 +146,8 @@ currently executed.")
   (declare (indent 1))
   `(let* ((my-file (or ,file org-test-file))
 	  (visited-p (get-file-buffer my-file))
-	  to-be-removed)
+	  to-be-removed
+	  results)
      (save-window-excursion
        (save-match-data
 	 (find-file my-file)
@@ -160,9 +161,10 @@ currently executed.")
 	       (org-show-subtree)
 	       (org-show-all '(blocks)))
 	   (error nil))
-	 (save-restriction ,@body)))
+	 (setq results (save-restriction ,@body))))
      (unless visited-p
-       (kill-buffer to-be-removed))))
+       (kill-buffer to-be-removed))
+     results))
 (def-edebug-spec org-test-in-example-file (form body))
 
 (defmacro org-test-at-marker (file marker &rest body)
@@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text."
 (def-edebug-spec org-test-with-temp-text (form body))
 
 (defmacro org-test-with-temp-text-in-file (text &rest body)
-  "Run body in a temporary file buffer with Org mode as the active mode."
+  "Run body in a temporary file buffer with Org mode as the active mode.
+If the string \"<point>\" appears in TEXT then remove it and
+place the point there before running BODY, otherwise place the
+point at the beginning of the buffer."
   (declare (indent 1))
-  (let ((results (cl-gensym)))
-    `(let ((file (make-temp-file "org-test"))
-	   (kill-buffer-query-functions nil)
-	   (inside-text (if (stringp ,text) ,text (eval ,text)))
-	   ,results)
-       (with-temp-file file (insert inside-text))
-       (find-file file)
-       (org-mode)
-       (setq ,results (progn ,@body))
-       (save-buffer) (kill-buffer (current-buffer))
-       (delete-file file)
-       ,results)))
+  `(let ((file (make-temp-file "org-test"))
+	 (inside-text (if (stringp ,text) ,text (eval ,text)))
+	 buffer)
+     (with-temp-file file (insert inside-text))
+     (unwind-protect
+	 (progn
+	   (setq buffer (find-file file))
+	   (when (re-search-forward "<point>" nil t)
+	     (replace-match ""))
+	   (org-mode)
+	   (progn ,@body))
+       (let ((kill-buffer-query-functions nil))
+	 (when buffer
+	   (set-buffer buffer)
+	   ;; Ignore changes, we're deleting the file in the next step
+	   ;; anyways.
+	   (set-buffer-modified-p nil)
+	   (kill-buffer))
+	 (delete-file file)))))
 (def-edebug-spec org-test-with-temp-text-in-file (form body))
 
 (defun org-test-table-target-expect (target &optional expect laps
-- 
2.17.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-06-30  6:03                 ` Gustav Wikström
@ 2019-07-06 21:46                   ` Nicolas Goaziou
  2019-07-07 18:38                     ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2019-07-06 21:46 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> +	(if should-get
> +	    (progn (message "Running git annex get \"%s\"." path-relative)
> +		   (call-process "git" nil nil nil "annex" "get" path-relative))
> +	  (error "File %s stored in git annex but it is not available, and was not retrieved"
> +		 path))))))

Nitpick:

    (unless should-get 
     (error "File %S stored in git annex but unavailable" path))
    (message "Running git annex get %S." path-relative)
    (call-process ...)

> +Selective means to respect the inheritance setting in
> +`org-use-property-inheritance'."
>    :group 'org-attach
> +  :type '(choice
> +	  (const :tag "Don't use inheritance" nil)
> +	  (const :tag "Inherit parent node attachments" t)
> +	  (const :tag "Respect org-use-property-inheritance" selective)
> +	  )

Dangling paren spotted.

> +      (setq attachment (or (org-attach-dir)
> +			   (quote  "Can't find an existing attachment-folder")))

You forgot to remove that weird quote. Maybe you meant `error'?

> +    (if attach-dir
> +	(progn (if (not (file-directory-p attach-dir))
> +		   (make-directory attach-dir t))
> +	       attach-dir)
> +      (error "No attachment directory is associated with the current node"))))

Same nitpick as above:

    (unless attach-dir
     (error "No attachment ..."))
    (if (file-directory-p attach-dir) attach-dir
      (make-directory attach-dir))

> +(defun org-attach-dir-from-id (id)
> +  "Creates a path 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)))

Creates path -> Return a file name.

> +of the entry.  Creates relative links if `org-attach-dir-relative'
> +is t.

Nitpick:

  is t -> is non-nil.

If tests pass, feel free to apply the patches in master. Thank you!

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-06 21:46                   ` Nicolas Goaziou
@ 2019-07-07 18:38                     ` Gustav Wikström
  2019-07-08 10:47                       ` Marco Wahl
                                         ` (2 more replies)
  0 siblings, 3 replies; 113+ messages in thread
From: Gustav Wikström @ 2019-07-07 18:38 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 3167 bytes --]

Hi!

> > +	(if should-get
> > +	    (progn (message "Running git annex get \"%s\"." path-relative)
> > +		   (call-process "git" nil nil nil "annex" "get" path-relative))
> > +	  (error "File %s stored in git annex but it is not available, and was not
> retrieved"
> > +		 path))))))
> 
> Nitpick:
> 
>     (unless should-get
>      (error "File %S stored in git annex but unavailable" path))
>     (message "Running git annex get %S." path-relative)
>     (call-process ...)

Ok, fixed.

> > +Selective means to respect the inheritance setting in
> > +`org-use-property-inheritance'."
> >    :group 'org-attach
> > +  :type '(choice
> > +	  (const :tag "Don't use inheritance" nil)
> > +	  (const :tag "Inherit parent node attachments" t)
> > +	  (const :tag "Respect org-use-property-inheritance" selective)
> > +	  )
> 
> Dangling paren spotted.

Fixed.

> > +      (setq attachment (or (org-attach-dir)
> > +			   (quote  "Can't find an existing attachment-folder")))
> 
> You forgot to remove that weird quote. Maybe you meant `error'?

Hmm, actually no. But the code is pretty bad so I've refactored it a
bit. The purpose of the change is for org-attach to give an indication
of the active attachment path, or to signal that there is none. But
for that I don't really need a separate variable. Thus it's slightly
refactored for code-clarity.

> > +    (if attach-dir
> > +	(progn (if (not (file-directory-p attach-dir))
> > +		   (make-directory attach-dir t))
> > +	       attach-dir)
> > +      (error "No attachment directory is associated with the current node"))))
> 
> Same nitpick as above:
> 
>     (unless attach-dir
>      (error "No attachment ..."))
>     (if (file-directory-p attach-dir) attach-dir
>       (make-directory attach-dir))

Ok, fixed.

> > +(defun org-attach-dir-from-id (id)
> > +  "Creates a path 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)))
> 
> Creates path -> Return a file name.

Fixed.

> > +of the entry.  Creates relative links if `org-attach-dir-relative'
> > +is t.
> 
> Nitpick:
> 
>   is t -> is non-nil.

Ah, true. Fixed.

> If tests pass, feel free to apply the patches in master. Thank you!

Got it. Aaand one test failure. That test is unrelated to my changes
though, and fails also on master. Test-org-table/copy-down. So I'll
try to apply my patch asap regardless of that one test failing.

Just one more thing - a few days back I added a row to lisp/ox-html.el
regarding inline-images. I'm including that change as well since it
relates 100% to the new attachment link. I looked in the other
export-backends too but didn't add anything due to lack of time for
testing. Maybe the additions for other backends is as trivial as for
html. So someone who regularly export to those backends might want to
suggest patches for them to make attachment links to images actually
display as images? 😊

Final patches attached for full disclosure before applying them.

> 
> Regards,
> 
> --
> Nicolas Goaziou

[-- Attachment #2: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --]
[-- Type: application/octet-stream, Size: 8578 bytes --]

From 3cbe356b0a9d1a98848df0fa09ba306392995b88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 26 May 2019 03:34:34 +0200
Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox,
 test-property-inheritance

* org-test.el:

Fix org-test-with-temp-text-in-file.  Make it work with <point>, as
some tests already expect it to do!  Also make it fail more gracefully
by still removing temporary buffers and files.

Improve org-test-in-example-file.  Make it behave similar to
org-test-with-temp-text and org-test-with-temp-text-in-file, in that
it will return the last evaluated expression.

* testing/lisp/test-org-element.el

Fix a temp-text strings so that it doesn't have an initial newline.

* testing/lisp/test-org.el

Minor cleanup to align code-structure with other tests.  Nothing
changes in the test execpt style.

* testing/lisp/test-ox.el

Fix a couple of temp-text strings so that they don't have initial
newlines.

** test-org-export/expand-include

Test specification was wrong, due to org-test-with-temp-text-in-file
not previously working with <point>.  Since that is fixed in this
patch the test needed to be updated to match the expected outcome.

* testing/lisp/test-property-inheritance.el

Fix wrong file-header and file-ending.
---
 testing/lisp/test-org-element.el          |  4 +--
 testing/lisp/test-org.el                  | 12 +++----
 testing/lisp/test-ox.el                   | 30 ++++++++--------
 testing/lisp/test-property-inheritance.el |  4 +--
 testing/org-test.el                       | 44 ++++++++++++++---------
 5 files changed, 53 insertions(+), 41 deletions(-)

diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index 04f97f97a..f2ab38031 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -3264,8 +3264,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
 
 (ert-deftest test-org-element/granularity ()
   "Test granularity impact on buffer parsing."
-  (org-test-with-temp-text "
-* Head 1
+  (org-test-with-temp-text
+      "* Head 1
 ** Head 2
 #+BEGIN_CENTER
 Centered paragraph.
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index abc004689..d671b5c78 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -5060,18 +5060,18 @@ Paragraph<point>"
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
-      (org-entry-get (point) "A" t))))
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
+      (org-entry-get (point-max) "A" t))))
   (should
    (equal
     "1"
-    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
       (let ((org-use-property-inheritance t))
-	(org-entry-get (point) "A" 'selective)))))
+	(org-entry-get (point-max) "A" 'selective)))))
   (should-not
-   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
+   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
      (let ((org-use-property-inheritance nil))
-       (org-entry-get (point) "A" 'selective))))
+       (org-entry-get (point-max) "A" 'selective))))
   (should
    (equal
     "1 2"
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 2c2778f82..b8c507e0b 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
 	       org-test-dir)
      (narrow-to-region (point) (point-max))
      (org-export-expand-include-keyword)
-     (eq 1 (org-current-level))))
+     (eq 2 (org-current-level))))
   ;; If :minlevel is present do not alter it.
   (should
    (org-test-with-temp-text
@@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after
 comments removal."
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 
 # Comment
@@ -2012,15 +2012,15 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-Para1
+	  (org-test-with-temp-text
+	      "Para1
 # Comment
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 
@@ -2029,8 +2029,8 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 
@@ -2040,24 +2040,24 @@ Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 # Inside definition
 
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "[fn:1] Para1\n\nPara2\n"
-	  (org-test-with-temp-text "
-\[fn:1] Para1
+	  (org-test-with-temp-text
+	      "[fn:1] Para1
 
 # Inside definition
 Para2"
 	    (org-export-as (org-test-default-backend)))))
   (should
    (equal "- item 1\n\n- item 2\n"
-	  (org-test-with-temp-text "
-- item 1
+	  (org-test-with-temp-text
+	      "- item 1
 
   # Comment
 
diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el
index 0f803e5f7..1d0dcfbe1 100644
--- a/testing/lisp/test-property-inheritance.el
+++ b/testing/lisp/test-property-inheritance.el
@@ -1,4 +1,4 @@
-;;; test-ob-R.el --- tests for ob-R.el
+;;; test-property-inheritance.el --- tests for property-inheritance.el
 
 ;; Copyright (c) 2011-2014, 2019 Eric Schulte
 ;; Authors: Eric Schulte
@@ -47,4 +47,4 @@
 
 (provide 'test-ob-R)
 
-;;; test-ob-R.el ends here
+;;; test-property-inheritance.el ends here
diff --git a/testing/org-test.el b/testing/org-test.el
index 39c346410..295df1919 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -146,7 +146,8 @@ currently executed.")
   (declare (indent 1))
   `(let* ((my-file (or ,file org-test-file))
 	  (visited-p (get-file-buffer my-file))
-	  to-be-removed)
+	  to-be-removed
+	  results)
      (save-window-excursion
        (save-match-data
 	 (find-file my-file)
@@ -160,9 +161,10 @@ currently executed.")
 	       (org-show-subtree)
 	       (org-show-all '(blocks)))
 	   (error nil))
-	 (save-restriction ,@body)))
+	 (setq results (save-restriction ,@body))))
      (unless visited-p
-       (kill-buffer to-be-removed))))
+       (kill-buffer to-be-removed))
+     results))
 (def-edebug-spec org-test-in-example-file (form body))
 
 (defmacro org-test-at-marker (file marker &rest body)
@@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text."
 (def-edebug-spec org-test-with-temp-text (form body))
 
 (defmacro org-test-with-temp-text-in-file (text &rest body)
-  "Run body in a temporary file buffer with Org mode as the active mode."
+  "Run body in a temporary file buffer with Org mode as the active mode.
+If the string \"<point>\" appears in TEXT then remove it and
+place the point there before running BODY, otherwise place the
+point at the beginning of the buffer."
   (declare (indent 1))
-  (let ((results (cl-gensym)))
-    `(let ((file (make-temp-file "org-test"))
-	   (kill-buffer-query-functions nil)
-	   (inside-text (if (stringp ,text) ,text (eval ,text)))
-	   ,results)
-       (with-temp-file file (insert inside-text))
-       (find-file file)
-       (org-mode)
-       (setq ,results (progn ,@body))
-       (save-buffer) (kill-buffer (current-buffer))
-       (delete-file file)
-       ,results)))
+  `(let ((file (make-temp-file "org-test"))
+	 (inside-text (if (stringp ,text) ,text (eval ,text)))
+	 buffer)
+     (with-temp-file file (insert inside-text))
+     (unwind-protect
+	 (progn
+	   (setq buffer (find-file file))
+	   (when (re-search-forward "<point>" nil t)
+	     (replace-match ""))
+	   (org-mode)
+	   (progn ,@body))
+       (let ((kill-buffer-query-functions nil))
+	 (when buffer
+	   (set-buffer buffer)
+	   ;; Ignore changes, we're deleting the file in the next step
+	   ;; anyways.
+	   (set-buffer-modified-p nil)
+	   (kill-buffer))
+	 (delete-file file)))))
 (def-edebug-spec org-test-with-temp-text-in-file (form body))
 
 (defun org-test-table-target-expect (target &optional expect laps
-- 
2.17.1


[-- Attachment #3: 0002-org-attach-org-org-manual-org-news-ox-html-testing.patch --]
[-- Type: application/octet-stream, Size: 107223 bytes --]

From ae9cd4370b4daaaca7bc53923d5e438c08955e48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
Date: Sun, 25 Nov 2018 21:38:44 +0100
Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, ox-html,
 testing/*

* lisp/org-attach.el

Changed the way attachments deal with property-inheritance.  It now
adheres to the =org-use-property-inheritance= setting by default but
it can be customized if needed (I recommend to enable it!).
The property ATTACH_DIR is deprecated in favour of the shorter and simpler
property DIR.

Added an explicit option to =org-attach= for unsetting
attachment-directories (i.e. remove DIR property and deal with the
attachments by interaction).

Added attachment link type with the prefix "attachment:".

Added customizations:
- org-attach-dir-relative
- org-attach-preferred-new-method
- org-attach-use-inheritance
- org-attach-id-to-path-function

Hooks added:
- org-attach-after-change-hook
- org-attach-open-hook

A new linktype "attachment" is added in order to reduce
link-duplication when wanting to link to files in attached folders of
nodes.  This works for both ID and DIR properties.  The goal is to
make the functionality for attachment links mirror the functionality
for file links.

* lisp/org-attach-git.el

New file, existing functionality.  Code here has been factored out
from org-attach.el and if GIT-functionality is to be used this module
needs to be required sepatately.  It extends org-attach by use of its
hooks.

Activating git functionality in org-attach is done by loading
org-attach-git from now on, instead of customizing a variable.

Naming of both functions and tests has been modified to match the move
of functionality into its own module.

* lisp/org.el

Inline images are shown also using attachment-links, exactly the same
as it works for file-links today.

Make org-open-at-point respect ARG when opening attachment-dir.

* lisp/org-compat.el

org-attach-directory has been deprecated in favour for
org-attach-id-dir.  The new name matches its purpose better.

* lisp/ox-html.el

Export attachment links to images as inline images, in the same way as
file links work today.

* etc/ORG-NEWS

Mention the changes in this patch.

* doc/org-manual.org

The chapter "Refile, Copy, Archive" has been split into two separate
chapters.
- "Refile, Copy and Archiving" for information related to moving
  existing data around.

- "Capture, Attachments, RSS Feeds and Protocols" for information
  related to working with external data.

The attachment-part has been rewritten and extended to match the
changes in this patch.

The new attachment link type is mentioned both inside the attachments
chapter and in the chapter dealing with links.

Documentation related to external links has been improved.

* testing/lisp/test-org-attach-annex.el

Require org-attach-git instead of org-attach, since this file tests
the GIT-functionality.

* testing/lisp/test-org-attach.el

Add tests for org-attach.

* testing/org-test.el

Define a symbol for a file to test attachments with.

* testing/examples/*

A bunch of new example files and folders are created and are used in
testing of org-attach to verify its functionality.
---
 doc/org-manual.org                            | 1079 ++++++++++-------
 etc/ORG-NEWS                                  |   94 ++
 lisp/org-attach-git.el                        |  117 ++
 lisp/org-attach.el                            |  561 +++++----
 lisp/org-compat.el                            |    3 +
 lisp/org.el                                   |   23 +-
 lisp/ox-html.el                               |    1 +
 testing/examples/att1/fileA                   |    1 +
 testing/examples/att1/fileB                   |    1 +
 testing/examples/att2/fileC                   |    1 +
 testing/examples/att2/fileD                   |    1 +
 testing/examples/attachments.org              |   32 +
 testing/examples/data/ab/cd123/fileE          |    1 +
 ...attach-annex.el => test-org-attach-git.el} |   12 +-
 testing/lisp/test-org-attach.el               |   69 ++
 testing/lisp/test-org.el                      |    6 +-
 testing/org-test.el                           |    3 +
 17 files changed, 1307 insertions(+), 698 deletions(-)
 create mode 100644 lisp/org-attach-git.el
 create mode 100644 testing/examples/att1/fileA
 create mode 100644 testing/examples/att1/fileB
 create mode 100644 testing/examples/att2/fileC
 create mode 100644 testing/examples/att2/fileD
 create mode 100644 testing/examples/attachments.org
 create mode 100644 testing/examples/data/ab/cd123/fileE
 rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 8318e7cdc..e81b76f14 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -3071,6 +3071,7 @@ point on or at a target.
 #+cindex: irc links
 #+cindex: URL links
 #+cindex: file links
+#+cindex: attachment links
 #+cindex: Rmail links
 #+cindex: MH-E links
 #+cindex: Usenet links
@@ -3082,38 +3083,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB
 database entries and links to both IRC conversations and their logs.
 External links are URL-like locators.  They start with a short
 identifying string followed by a colon.  There can be no space after
-the colon.  The following list shows examples for each link type.
-
-| =https://staff.science.uva.nl/c.dominik/= | on the web                     |
-| =doi:10.1000/182=                         | DOI for an electronic resource |
-| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
-| =/home/dominik/images/jupiter.jpg=        | same as above                  |
-| =file:papers/last.pdf=                    | file, relative path            |
-| =./papers/last.pdf=                       | same as above                  |
-| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
-| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
-| =file:sometextfile::NNN=                  | file, jump to line number      |
-| =file:projects.org=                       | another Org file               |
-| =file:projects.org::some words=           | text search in Org file[fn:27] |
-| =file:projects.org::*task title=          | heading search in Org file     |
-| =file+sys:/path/to/file=                  | open via OS, like double-click |
-| =file+emacs:/path/to/file=                | force opening by Emacs         |
-| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
-| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
-| =news:comp.emacs=                         | Usenet link                    |
-| =mailto:adent@galaxy.net=                 | mail link                      |
-| =mhe:folder=                              | MH-E folder link               |
-| =mhe:folder#id=                           | MH-E message link              |
-| =rmail:folder=                            | Rmail folder link              |
-| =rmail:folder#id=                         | Rmail message link             |
-| =gnus:group=                              | Gnus group link                |
-| =gnus:group#id=                           | Gnus article link              |
-| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
-| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
-| =info:org#External links=                 | Info node link                 |
-| =shell:ls *.org=                          | shell command                  |
-| =elisp:org-agenda=                        | interactive Elisp command      |
-| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
+the colon.
+
+Here is the full set of built-in link types:
+
+- =file= ::
+
+   File links.  File name may be remote, absolute, or relative.
+
+   Additionally, you can specify a line number, or a text search.
+   In Org files, you may link to a headline name, a custom ID, or a
+   code reference instead.
+
+   As a special case, "file" prefix may be omitted if the file name
+   is complete, e.g., it starts with =./=, or =/=.
+
+- =attachment= ::
+
+  Same as file links but for files and folders attached to the current
+  node (see [[*Attachments]]).  Attachment links are intended to behave
+  exactly as file links but for files relative to the attachment
+  directory.
+
+- =bbdb= ::
+
+  Link to a BBDB record, with possible regexp completion.
+
+- =docview= ::
+
+  Link to a document opened with DocView mode.  You may specify a page
+  number.
+
+- =doi= ::
+
+  Link to an electronic ressource, through its handle.
+
+- =elisp= ::
+
+  Execute an Elisp command upon activation.
+
+- =gnus=, =rmail=, =mhe= ::
+
+  Links to messages or folders from a given Emacs' MUA.
+
+- =http=, =https= ::
+
+  Web links.
+
+- =id= ::
+
+  Link to a specific headline by its ID property, in an Org file.
+
+- =info= ::
+
+  Link to an Info manual, or to a specific node.
+
+- =irc= ::
+
+  Link to an IRC channel.
+
+- =mailto= ::
+
+  Link to message composition.
+
+- =news= ::
+
+  Usenet links.
+
+- =shell= ::
+
+  Execute a shell command upon activation.
+
+The following table illustrates the link types above, along with their
+options:
+
+| Link Type  | Example                                                  |
+|------------+----------------------------------------------------------|
+| http       | =http://staff.science.uva.nl/c.dominik/=                 |
+| https      | =https://orgmode.org/=                                   |
+| doi        | =doi:10.1000/182=                                        |
+| file       | =file:/home/dominik/images/jupiter.jpg=                  |
+|            | =/home/dominik/images/jupiter.jpg= (same as above)       |
+|            | =file:papers/last.pdf=                                   |
+|            | =./papers/last.pdf= (same as above)                      |
+|            | =file:/ssh:me@some.where:papers/last.pdf= (remote)       |
+|            | =/ssh:me@some.where:papers/last.pdf= (same as above)     |
+|            | =file:sometextfile::NNN= (jump to line number)           |
+|            | =file:projects.org=                                      |
+|            | =file:projects.org::some words= (text search) [fn:28]    |
+|            | =file:projects.org::*task title= (headline search)       |
+|            | =file:projects.org::#custom-id= (headline search)        |
+| attachment | =attachment:projects.org=                                |
+|            | =attachment:projects.org::some words= (text search)      |
+| docview    | =docview:papers/last.pdf::NNN=                           |
+| id         | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=                |
+| news       | =news:comp.emacs=                                        |
+| mailto     | =mailto:adent@galaxy.net=                                |
+| mhe        | =mhe:folder= (folder link)                               |
+|            | =mhe:folder#id= (message link)                           |
+| rmail      | =rmail:folder= (folder link)                             |
+|            | =rmail:folder#id= (message link)                         |
+| gnus       | =gnus:group= (group link)                                |
+|            | =gnus:group#id= (article link)                           |
+| bbdb       | =bbdb:R.*Stallman= (record with regexp)                  |
+| irc        | =irc:/irc.com/#emacs/bob=                                |
+| info       | =info:org#External links=                                |
+| shell      | =shell:ls *.org=                                         |
+| elisp      | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) |
+|            | =elisp:org-agenda= (interactive Elisp command)           |
 
 #+cindex: VM links
 #+cindex: Wanderlust links
@@ -3465,15 +3542,19 @@ the link completion function like this:
 :END:
 #+cindex: search option in file links
 #+cindex: file links, searching
+#+cindex: attachment links, searching
 
-File links can contain additional information to make Emacs jump to
-a particular location in the file when following a link.  This can be
-a line number or a search option after a double colon[fn:34].  For
+File links can contain additional information to make Emacs jump to a
+particular location in the file when following a link.  This can be a
+line number or a search option after a double colon[fn:34].  For
 example, when the command ~org-store-link~ creates a link (see
 [[*Handling Links]]) to a file, it encodes the words in the current line
 as a search string that can be used to find this line back later when
 following the link with {{{kbd(C-c C-o)}}}.
 
+Note that all search options apply for Attachment links in the same
+way that they apply for File links.
+
 Here is the syntax of the different ways to attach a search to a file
 link, together with explanations for each:
 
@@ -3483,6 +3564,7 @@ link, together with explanations for each:
 [[file:~/xx.org::*My Target]]
 [[file:~/xx.org::#my-custom-id]]
 [[file:~/xx.org::/regexp/]]
+[[attachment:main.c::255]]
 #+end_example
 
 - =255= ::
@@ -6896,163 +6978,420 @@ same commands.
   continue the old one.  This command also removes the timer from the
   mode line.
 
-* Capture, Refile, Archive
-:PROPERTIES:
-:DESCRIPTION: The ins and outs for projects.
-:END:
-#+cindex: capture
-
-An important part of any organization system is the ability to quickly
-capture new ideas and tasks, and to associate reference material with
-them.  Org does this using a process called /capture/.  It also can
-store files related to a task (/attachments/) in a special directory.
-Once in the system, tasks and projects need to be moved around.
-Moving completed project trees to an archive file keeps the system
-compact and fast.
-
-** Capture
+* Refile, Copy and Archiving
 :PROPERTIES:
-:DESCRIPTION: Capturing new stuff.
+:DESCRIPTION: Moving and copying information with ease.
 :END:
-#+cindex: capture
+#+cindex: refiling notes
+#+cindex: copying notes
+#+cindex: archiving
 
-Capture lets you quickly store notes with little interruption of your
-work flow.  Org's method for capturing new items is heavily inspired
-by John Wiegley's excellent Remember package.
+Once information is in the system, it may need to be moved around.
+Org provides Refile, Copy and Archive commands for this.  Refile and
+Copy helps with moving and copying outlines.  Archiving helps to keep
+the system compact and fast.
 
-*** Setting up capture
+** Refile and Copy
 :PROPERTIES:
-:DESCRIPTION: Where notes will be stored.
+:DESCRIPTION: Moving/copying a tree from one place to another.
 :END:
+#+cindex: refiling notes
+#+cindex: copying notes
 
-The following customization sets a default target file for notes.
+When reviewing the captured data, you may want to refile or to copy
+some of the entries into a different list, for example into a project.
+Cutting, finding the right location, and then pasting the note is
+cumbersome.  To simplify this process, you can use the following
+special command:
 
-#+vindex: org-default-notes-file
-#+begin_src emacs-lisp
-(setq org-default-notes-file (concat org-directory "/notes.org"))
-#+end_src
+- {{{kbd(C-c C-w)}}} (~org-refile~) ::
 
-You may also define a global key for capturing new material (see
-[[*Activation]]).
+  #+kindex: C-c C-w
+  #+findex: org-refile
+  #+vindex: org-reverse-note-order
+  #+vindex: org-refile-targets
+  #+vindex: org-refile-use-outline-path
+  #+vindex: org-outline-path-complete-in-steps
+  #+vindex: org-refile-allow-creating-parent-nodes
+  #+vindex: org-log-refile
+  Refile the entry or region at point.  This command offers possible
+  locations for refiling the entry and lets you select one with
+  completion.  The item (or all items in the region) is filed below
+  the target heading as a subitem.  Depending on
+  ~org-reverse-note-order~, it is either the first or last subitem.
 
-*** Using capture
-:PROPERTIES:
-:DESCRIPTION: Commands to invoke and terminate capture.
-:END:
+  By default, all level 1 headlines in the current buffer are
+  considered to be targets, but you can have more complex definitions
+  across a number of files.  See the variable ~org-refile-targets~ for
+  details.  If you would like to select a location via
+  a file-path-like completion along the outline path, see the
+  variables ~org-refile-use-outline-path~ and
+  ~org-outline-path-complete-in-steps~.  If you would like to be able
+  to create new nodes as new parents for refiling on the fly, check
+  the variable ~org-refile-allow-creating-parent-nodes~.  When the
+  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
+  recorded whenever an entry is refiled.
 
-- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
+- {{{kbd(C-u C-c C-w)}}} ::
 
-  #+findex: org-capture
-  #+cindex: date tree
-  Display the capture templates menu.  If you have templates defined
-  (see [[*Capture templates]]), it offers these templates for selection or
-  use a new Org outline node as the default template.  It inserts the
-  template into the target file and switch to an indirect buffer
-  narrowed to this new node.  You may then insert the information you
-  want.
+  #+kindex: C-u C-c C-w
+  Use the refile interface to jump to a heading.
 
-- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
+- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
 
-  #+kindex: C-c C-c @r{(Capture buffer)}
-  #+findex: org-capture-finalize
-  Once you have finished entering information into the capture buffer,
-  {{{kbd(C-c C-c)}}} returns you to the window configuration before
-  the capture process, so that you can resume your work without
-  further distraction.  When called with a prefix argument, finalize
-  and then jump to the captured item.
+  #+kindex: C-u C-u C-c C-w
+  #+findex: org-refile-goto-last-stored
+  Jump to the location where ~org-refile~ last moved a tree to.
 
-- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
+- {{{kbd(C-2 C-c C-w)}}} ::
 
-  #+kindex: C-c C-w @r{(Capture buffer)}
-  #+findex: org-capture-refile
-  Finalize the capture process by refiling the note to a different
-  place (see [[*Refile and Copy]]).  Please realize that this is a normal
-  refiling command that will be executed---so point position at the
-  moment you run this command is important.  If you have inserted
-  a tree with a parent and children, first move point back to the
-  parent.  Any prefix argument given to this command is passed on to
-  the ~org-refile~ command.
+  #+kindex: C-2 C-c C-w
+  Refile as the child of the item currently being clocked.
 
-- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
+- {{{kbd(C-3 C-c C-w)}}} ::
 
-  #+kindex: C-c C-k @r{(Capture buffer)}
-  #+findex: org-capture-kill
-  Abort the capture process and return to the previous state.
+  #+kindex: C-3 C-c C-w
+  #+vindex: org-refile-keep
+  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
+  make this the default behavior, and beware that this may result in
+  duplicated =ID= properties.
 
-#+kindex: k c @r{(Agenda)}
-You can also call ~org-capture~ in a special way from the agenda,
-using the {{{kbd(k c)}}} key combination.  With this access, any
-timestamps inserted by the selected capture template defaults to the
-date at point in the agenda, rather than to the current date.
+- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
 
-To find the locations of the last stored capture, use ~org-capture~
-with prefix commands:
+  #+kindex: C-u C-u C-u C-c C-w
+  #+kindex: C-0 C-c C-w
+  #+findex: org-refile-cache-clear
+  #+vindex: org-refile-use-cache
+  Clear the target cache.  Caching of refile targets can be turned on
+  by setting ~org-refile-use-cache~.  To make the command see new
+  possible targets, you have to clear the cache with this command.
 
-- {{{kbd(C-u M-x org-capture)}}} ::
+- {{{kbd(C-c M-w)}}} (~org-copy~) ::
 
-  Visit the target location of a capture template.  You get to select
-  the template in the usual way.
+  #+kindex: C-c M-w
+  #+findex: org-copy
+  Copying works like refiling, except that the original note is not
+  deleted.
 
-- {{{kbd(C-u C-u M-x org-capture)}}} ::
+** Archiving
+:PROPERTIES:
+:DESCRIPTION: What to do with finished products.
+:END:
+#+cindex: archiving
 
-  Visit the last stored capture item in its buffer.
+When a project represented by a (sub)tree is finished, you may want to
+move the tree out of the way and to stop it from contributing to the
+agenda.  Archiving is important to keep your working files compact and
+global searches like the construction of agenda views fast.
 
-#+vindex: org-capture-bookmark
-#+vindex: org-capture-last-stored
-You can also jump to the bookmark ~org-capture-last-stored~, which is
-automatically created unless you set ~org-capture-bookmark~ to ~nil~.
+- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
 
-To insert the capture at point in an Org buffer, call ~org-capture~
-with a {{{kbd(C-0)}}} prefix argument.
+  #+kindex: C-c C-x C-a
+  #+findex: org-archive-subtree-default
+  #+vindex: org-archive-default-command
+  Archive the current entry using the command specified in the
+  variable ~org-archive-default-command~.
 
-*** Capture templates
+*** Moving a tree to an archive file
 :PROPERTIES:
-:DESCRIPTION: Define the outline of different note types.
+:DESCRIPTION: Moving a tree to an archive file.
+:ALT_TITLE: Moving subtrees
 :END:
-#+cindex: templates, for Capture
-
-You can use templates for different types of capture items, and for
-different target locations.  The easiest way to create such templates
-is through the customize interface.
+#+cindex: external archiving
 
-- {{{kbd(C)}}} ::
+The most common archiving action is to move a project tree to another
+file, the archive file.
 
-  #+kindex: C @r{(Capture menu}
-  #+vindex: org-capture-templates
-  Customize the variable ~org-capture-templates~.
+- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
 
-Before we give the formal description of template definitions, let's
-look at an example.  Say you would like to use one template to create
-general TODO entries, and you want to put these entries under the
-heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
-the file =journal.org= should capture journal entries.  A possible
-configuration would look like:
+  #+kindex: C-c C-x C-s
+  #+kindex: C-c $
+  #+findex: org-archive-subtree
+  #+vindex: org-archive-location
+  Archive the subtree starting at point position to the location given
+  by ~org-archive-location~.
 
-#+begin_src emacs-lisp
-(setq org-capture-templates
-      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
-         "* TODO %?\n  %i\n  %a")
-        ("j" "Journal" entry (file+datetree "~/org/journal.org")
-         "* %?\nEntered on %U\n  %i\n  %a")))
-#+end_src
+- {{{kbd(C-u C-c C-x C-s)}}} ::
 
-If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
-the template for you like this:
+  #+kindex: C-u C-c C-x C-s
+  Check if any direct children of the current headline could be moved
+  to the archive.  To do this, check each subtree for open TODO
+  entries.  If none is found, the command offers to move it to the
+  archive location.  If point is /not/ on a headline when this command
+  is invoked, check level 1 trees.
 
-#+begin_example
-,* TODO
-  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
-#+end_example
+- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
 
-#+texinfo: @noindent
-During expansion of the template, =%a= has been replaced by a link to
-the location from where you called the capture command.  This can be
-extremely useful for deriving tasks from emails, for example.  You
-fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
-you to the same place where you started the capture process.
+  #+kindex: C-u C-u C-c C-x C-s
+  As above, but check subtree for timestamps instead of TODO entries.
+  The command offers to archive the subtree if it /does/ contain
+  a timestamp, and that timestamp is in the past.
 
-To define special keys to capture to a particular template without
-going through the interactive template selection, you can create your
+#+cindex: archive locations
+The default archive location is a file in the same directory as the
+current file, with the name derived by appending =_archive= to the
+current file name.  You can also choose what heading to file archived
+items under, with the possibility to add them to a datetree in a file.
+For information and examples on how to specify the file and the
+heading, see the documentation string of the variable
+~org-archive-location~.
+
+There is also an in-buffer option for setting this variable, for
+example:
+
+#+cindex: @samp{ARCHIVE}, keyword
+: #+ARCHIVE: %s_done::
+
+#+cindex: ARCHIVE, property
+If you would like to have a special archive location for a single
+entry or a (sub)tree, give the entry an =ARCHIVE= property with the
+location as the value (see [[*Properties and Columns]]).
+
+#+vindex: org-archive-save-context-info
+When a subtree is moved, it receives a number of special properties
+that record context information like the file from where the entry
+came, its outline path the archiving time etc.  Configure the variable
+~org-archive-save-context-info~ to adjust the amount of information
+added.
+
+*** Internal archiving
+:PROPERTIES:
+:DESCRIPTION: Switch off a tree but keep it in the file.
+:END:
+
+#+cindex: @samp{ARCHIVE}, tag
+If you want to just switch off---for agenda views---certain subtrees
+without moving them to a different file, you can use the =ARCHIVE=
+tag.
+
+A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
+its location in the outline tree, but behaves in the following way:
+
+-
+  #+vindex: org-cycle-open-archived-trees
+  It does not open when you attempt to do so with a visibility cycling
+  command (see [[*Visibility Cycling]]).  You can force cycling archived
+  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
+  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
+  ~outline-show-all~, open archived subtrees.
+
+-
+  #+vindex: org-sparse-tree-open-archived-trees
+  During sparse tree construction (see [[*Sparse Trees]]), matches in
+  archived subtrees are not exposed, unless you configure the option
+  ~org-sparse-tree-open-archived-trees~.
+
+-
+  #+vindex: org-agenda-skip-archived-trees
+  During agenda view construction (see [[*Agenda Views]]), the content of
+  archived trees is ignored unless you configure the option
+  ~org-agenda-skip-archived-trees~, in which case these trees are
+  always included.  In the agenda you can press {{{kbd(v a)}}} to get
+  archives temporarily included.
+
+-
+  #+vindex: org-export-with-archived-trees
+  Archived trees are not exported (see [[*Exporting]]), only the headline
+  is.  Configure the details using the variable
+  ~org-export-with-archived-trees~.
+
+-
+  #+vindex: org-columns-skip-archived-trees
+  Archived trees are excluded from column view unless the variable
+  ~org-columns-skip-archived-trees~ is configured to ~nil~.
+
+The following commands help manage the =ARCHIVE= tag:
+
+- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
+
+  #+kindex: C-c C-x a
+  #+findex: org-toggle-archive-tag
+  Toggle the archive tag for the current headline.  When the tag is
+  set, the headline changes to a shadowed face, and the subtree below
+  it is hidden.
+
+- {{{kbd(C-u C-c C-x a)}}} ::
+
+  #+kindex: C-u C-c C-x a
+  Check if any direct children of the current headline should be
+  archived.  To do this, check each subtree for open TODO entries.  If
+  none is found, the command offers to set the =ARCHIVE= tag for the
+  child.  If point is /not/ on a headline when this command is
+  invoked, check the level 1 trees.
+
+- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
+
+  #+kindex: C-TAB
+  Cycle a tree even if it is tagged with =ARCHIVE=.
+
+- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
+
+  #+kindex: C-c C-x A
+  #+findex: org-archive-to-archive-sibling
+  Move the current entry to the /Archive Sibling/.  This is a sibling
+  of the entry with the heading =Archive= and the archive tag.  The
+  entry becomes a child of that sibling and in this way retains a lot
+  of its original context, including inherited tags and approximate
+  position in the outline.
+
+* Capture, Attachments, RSS Feeds and Protocols
+:PROPERTIES:
+:DESCRIPTION: Dealing with external data.
+:END:
+#+cindex: capture
+#+cindex: attachments
+#+cindex: RSS feeds
+#+cindex: Atom feeds
+#+cindex: protocols, for external access
+
+An important part of any organization system is the ability to quickly
+capture new ideas and tasks, and to associate reference material with
+them.  Org does this using a process called /capture/.  It also can
+store files related to a task (/attachments/) in a special directory.
+
+** Capture
+:PROPERTIES:
+:DESCRIPTION: Capturing new stuff.
+:END:
+#+cindex: capture
+
+Capture lets you quickly store notes with little interruption of your
+work flow.  Org's method for capturing new items is heavily inspired
+by John Wiegley's excellent Remember package.
+
+*** Setting up capture
+:PROPERTIES:
+:DESCRIPTION: Where notes will be stored.
+:END:
+
+The following customization sets a default target file for notes.
+
+#+vindex: org-default-notes-file
+#+begin_src emacs-lisp
+(setq org-default-notes-file (concat org-directory "/notes.org"))
+#+end_src
+
+You may also define a global key for capturing new material (see
+[[*Activation]]).
+
+*** Using capture
+:PROPERTIES:
+:DESCRIPTION: Commands to invoke and terminate capture.
+:END:
+
+- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
+
+  #+findex: org-capture
+  #+cindex: date tree
+  Display the capture templates menu.  If you have templates defined
+  (see [[*Capture templates]]), it offers these templates for selection or
+  use a new Org outline node as the default template.  It inserts the
+  template into the target file and switch to an indirect buffer
+  narrowed to this new node.  You may then insert the information you
+  want.
+
+- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
+
+  #+kindex: C-c C-c @r{(Capture buffer)}
+  #+findex: org-capture-finalize
+  Once you have finished entering information into the capture buffer,
+  {{{kbd(C-c C-c)}}} returns you to the window configuration before
+  the capture process, so that you can resume your work without
+  further distraction.  When called with a prefix argument, finalize
+  and then jump to the captured item.
+
+- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
+
+  #+kindex: C-c C-w @r{(Capture buffer)}
+  #+findex: org-capture-refile
+  Finalize the capture process by refiling the note to a different
+  place (see [[*Refile and Copy]]).  Please realize that this is a normal
+  refiling command that will be executed---so point position at the
+  moment you run this command is important.  If you have inserted
+  a tree with a parent and children, first move point back to the
+  parent.  Any prefix argument given to this command is passed on to
+  the ~org-refile~ command.
+
+- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
+
+  #+kindex: C-c C-k @r{(Capture buffer)}
+  #+findex: org-capture-kill
+  Abort the capture process and return to the previous state.
+
+#+kindex: k c @r{(Agenda)}
+You can also call ~org-capture~ in a special way from the agenda,
+using the {{{kbd(k c)}}} key combination.  With this access, any
+timestamps inserted by the selected capture template defaults to the
+date at point in the agenda, rather than to the current date.
+
+To find the locations of the last stored capture, use ~org-capture~
+with prefix commands:
+
+- {{{kbd(C-u M-x org-capture)}}} ::
+
+  Visit the target location of a capture template.  You get to select
+  the template in the usual way.
+
+- {{{kbd(C-u C-u M-x org-capture)}}} ::
+
+  Visit the last stored capture item in its buffer.
+
+#+vindex: org-capture-bookmark
+#+vindex: org-capture-last-stored
+You can also jump to the bookmark ~org-capture-last-stored~, which is
+automatically created unless you set ~org-capture-bookmark~ to ~nil~.
+
+To insert the capture at point in an Org buffer, call ~org-capture~
+with a {{{kbd(C-0)}}} prefix argument.
+
+*** Capture templates
+:PROPERTIES:
+:DESCRIPTION: Define the outline of different note types.
+:END:
+#+cindex: templates, for Capture
+
+You can use templates for different types of capture items, and for
+different target locations.  The easiest way to create such templates
+is through the customize interface.
+
+- {{{kbd(C)}}} ::
+
+  #+kindex: C @r{(Capture menu}
+  #+vindex: org-capture-templates
+  Customize the variable ~org-capture-templates~.
+
+Before we give the formal description of template definitions, let's
+look at an example.  Say you would like to use one template to create
+general TODO entries, and you want to put these entries under the
+heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
+the file =journal.org= should capture journal entries.  A possible
+configuration would look like:
+
+#+begin_src emacs-lisp
+(setq org-capture-templates
+      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
+         "* TODO %?\n  %i\n  %a")
+        ("j" "Journal" entry (file+datetree "~/org/journal.org")
+         "* %?\nEntered on %U\n  %i\n  %a")))
+#+end_src
+
+If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
+the template for you like this:
+
+#+begin_example
+,* TODO
+  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
+#+end_example
+
+#+texinfo: @noindent
+During expansion of the template, =%a= has been replaced by a link to
+the location from where you called the capture command.  This can be
+extremely useful for deriving tasks from emails, for example.  You
+fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
+you to the same place where you started the capture process.
+
+To define special keys to capture to a particular template without
+going through the interactive template selection, you can create your
 key binding like this:
 
 #+begin_src emacs-lisp
@@ -7437,28 +7776,30 @@ See the docstring of the variable for more information.
 
 ** Attachments
 :PROPERTIES:
-:DESCRIPTION: Add files to tasks.
+:DESCRIPTION: Attach files to outlines.
 :END:
 #+cindex: attachments
-#+vindex: org-attach-directory
 
 It is often useful to associate reference material with an outline
-node/task.  Small chunks of plain text can simply be stored in the
-subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
-associations with files that live elsewhere on your computer or in the
-cloud, like emails or source code files belonging to a project.
-Another method is /attachments/, which are files located in
-a directory belonging to an outline node.  Org uses directories named
-by the unique ID of each entry.  These directories are located in the
-=data/= directory which lives in the same directory where your Org
-file lives[fn:87].  If you initialize this directory with =git init=,
-Org automatically commits changes when it sees them.  The attachment
-system has been contributed to Org by John Wiegley.
-
-In cases where it seems better to do so, you can attach a directory of
-your choice to an entry.  You can also make children inherit the
-attachment directory from a parent, so that an entire subtree uses the
-same attached directory.
+node.  Small chunks of plain text can simply be stored in the subtree
+of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish associations
+with files that live elsewhere on your computer or in the cloud, like
+emails or source code files belonging to a project.
+
+Another method is /attachments/, which are files located in a
+directory belonging to an outline node.  Org uses directories either
+named by a unique ID of each entry, or by a =DIR= property.
+
+*** Attachment defaults and dispatcher
+By default, org-attach will use ID properties when adding attachments
+to outline nodes.  This makes working with attachments fully
+automated.  There is no decision needed for folder-name or location.
+ID-based directories are by default located in the =data/= directory,
+which lives in the same directory where your Org file lives[fn:87].
+For more control over the setup, see [[*Attachment options]].
+
+When attachments are made using ~org-attach~ a default tag =ATTACH= is
+added to the node that gets the attachments.
 
 The following commands deal with attachments:
 
@@ -7543,25 +7884,144 @@ The following commands deal with attachments:
 
   - {{{kbd(D)}}} (~org-attach-delete-all~) ::
 
-    #+kindex: C-c C-a D
-    Delete all of a task's attachments.  A safer way is to open the
-    directory in Dired and delete from there.
+    #+kindex: C-c C-a D
+    Delete all of a task's attachments.  A safer way is to open the
+    directory in Dired and delete from there.
+
+  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
+
+    #+kindex: C-c C-a s
+    #+cindex: @samp{DIR}, property
+    Set a specific directory as the entry's attachment directory.
+    This works by putting the directory path into the =DIR=
+    property.
+
+  - {{{kbd(S)}}} (~org-attach-unset-directory~) ::
+
+    #+kindex: C-c C-a S
+    #+cindex: @samp{DIR}, property
+    Remove the attachment directory.  This command removes the =DIR=
+    property and asks the user to either move content inside that
+    folder, if an =ID= property is set, delete the content, or to
+    leave the attachment directory as is but no longer attached to the
+    outline node.
+
+*** Attachment options
+There are a couple of options for attachments that are worth
+mentioning.
+
+- ~org-attach-id-dir~ ::
+  #+vindex: org-attach-id-dir
+  The directory where attachments are stored when =ID= is used as
+  method.
+
+- ~org-attach-dir-relative~ ::
+  #+vindex: org-attach-dir-relative
+  When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}}
+  (~org-attach-set-directory~), absolute links are entered by default.
+  This option changes that to relative links.
+
+- ~org-attach-use-inheritance~ ::
+  #+vindex: org-attach-use-inheritance
+  By default folders attached to an outline node are inherited from
+  parents according to ~org-use-property-inheritance~.  If one instead
+  want to set inheritance specifically for org-attach that can be done
+  using ~org-attach-use-inheritance~.  Inheriting documents through
+  the node hierarchy makes a lot of sense in most cases. Especially
+  since the introduction of [[* Attachment links]].  The following example
+  shows one use case for attachment inheritance:
+
+  #+begin_example
+  ,* Chapter A ...
+    :PROPERTIES:
+    :DIR: Chapter A/
+    :END:
+  ,** Introduction
+  Some text
+
+  #+NAME: Image 1
+  [[Attachment:image 1.jpg]]
+  #+end_example
+
+  Without inheritance one would not be able to resolve the link to
+  image =1.jpg=, since the link is inside a sub-heading to =Chapter
+  A=.
+
+  Inheritance works the same way for both =ID= and =DIR= property.  If
+  both properties are defined on the same headline then =DIR= takes
+  precedance.  This is also true if inheritance is enabled.  If =DIR=
+  is inherited from a parent node in the outline, that property still
+  takes precedence over an =ID= property defined on the node itself.
+
+- ~org-attach-method~ ::
+  #+vindex: org-attach-method
+  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
+  defaults to copying files.  The behaviour can be changed by
+  customizing ~org-attach-method~.  Options are Copy, Move/Rename,
+  Hard link or Symbolic link.
+
+- ~org-attach-preferred-new-method~ ::
+  #+vindex: org-attach-preferred-new-method
+  This customization lets you choose the default way to attach to
+  nodes without existing =ID= and =DIR= property.  It defaults to ~id~
+  but can also be set to ~dir~, ~ask~ or ~nil~.
+
+- ~org-attach-archive-delete~ ::
+  #+vindex: org-attach-archive-delete
+  Configure this to determine if attachments should be deleted or not
+  when a subtree that has attachments is archived.
+
+- ~org-attach-auto-tag~ ::
+  #+vindex: org-attach-auto-tag
+  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
+  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!
+
+- ~org-attach-expert~ ::
+  #+vindex: org-attach-expert
+  Do not show the splash buffer with the attach dispatcher when
+  ~org-attach-expert~ is set to non-~nil~.
+
+See customization group =Org Attach= if you want to change the
+default settings.
+
+*** Attachment links
+Attached files and folders can be referenced using attachment links.
+This makes it easy to refer to the material added to an outline node.
+Especially if it was attached using the unique ID of the entry!
+
+#+begin_example
+,* TODO Some task
+  :PROPERTIES:
+  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
+  :END:
+See attached document for more information: [[attachment:info.org]]
+#+end_example
 
-  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
+See [[*External Links]] for more information about these links.
 
-    #+kindex: C-c C-a s
-    #+cindex: @samp{ATTACH_DIR}, property
-    Set a specific directory as the entry's attachment directory.
-    This works by putting the directory path into the =ATTACH_DIR=
-    property.
+*** Automatic version-control with Git
+If the directory attached to an outline node is a Git repository, Org
+can be configured to automatically commit changes to that repository
+when it sees them.
 
-  - {{{kbd(i)}}} (~org-attach-set-inherit~) ::
+To make Org mode take care of versioning of attachments for you, add
+the following to your Emacs config:
 
-    #+kindex: C-c C-a i
-    #+cindex: @samp{ATTACH_DIR_INHERIT}, property
-    Set the =ATTACH_DIR_INHERIT= property, so that children use the
-    same directory for attachments as the parent does.
+#+begin_src emacs-lisp
+  (require 'org-attach-git)
+#+end_src
 
+*** Attach from Dired
 #+cindex: attach from Dired
 #+findex: org-attach-dired-to-subtree
 It is possible to attach files to a subtree from a Dired buffer.  To
@@ -7832,249 +8292,6 @@ valid contents: ~org-protocol-create~ and
 ~org-protocol-create-for-org~.  The latter is of use if you're editing
 an Org file that is part of a publishing project.
 
-** Refile and Copy
-:PROPERTIES:
-:DESCRIPTION: Moving/copying a tree from one place to another.
-:END:
-#+cindex: refiling notes
-#+cindex: copying notes
-
-When reviewing the captured data, you may want to refile or to copy
-some of the entries into a different list, for example into a project.
-Cutting, finding the right location, and then pasting the note is
-cumbersome.  To simplify this process, you can use the following
-special command:
-
-- {{{kbd(C-c C-w)}}} (~org-refile~) ::
-
-  #+kindex: C-c C-w
-  #+findex: org-refile
-  #+vindex: org-reverse-note-order
-  #+vindex: org-refile-targets
-  #+vindex: org-refile-use-outline-path
-  #+vindex: org-outline-path-complete-in-steps
-  #+vindex: org-refile-allow-creating-parent-nodes
-  #+vindex: org-log-refile
-  Refile the entry or region at point.  This command offers possible
-  locations for refiling the entry and lets you select one with
-  completion.  The item (or all items in the region) is filed below
-  the target heading as a subitem.  Depending on
-  ~org-reverse-note-order~, it is either the first or last subitem.
-
-  By default, all level 1 headlines in the current buffer are
-  considered to be targets, but you can have more complex definitions
-  across a number of files.  See the variable ~org-refile-targets~ for
-  details.  If you would like to select a location via
-  a file-path-like completion along the outline path, see the
-  variables ~org-refile-use-outline-path~ and
-  ~org-outline-path-complete-in-steps~.  If you would like to be able
-  to create new nodes as new parents for refiling on the fly, check
-  the variable ~org-refile-allow-creating-parent-nodes~.  When the
-  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
-  recorded whenever an entry is refiled.
-
-- {{{kbd(C-u C-c C-w)}}} ::
-
-  #+kindex: C-u C-c C-w
-  Use the refile interface to jump to a heading.
-
-- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
-
-  #+kindex: C-u C-u C-c C-w
-  #+findex: org-refile-goto-last-stored
-  Jump to the location where ~org-refile~ last moved a tree to.
-
-- {{{kbd(C-2 C-c C-w)}}} ::
-
-  #+kindex: C-2 C-c C-w
-  Refile as the child of the item currently being clocked.
-
-- {{{kbd(C-3 C-c C-w)}}} ::
-
-  #+kindex: C-3 C-c C-w
-  #+vindex: org-refile-keep
-  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
-  make this the default behavior, and beware that this may result in
-  duplicated =ID= properties.
-
-- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
-
-  #+kindex: C-u C-u C-u C-c C-w
-  #+kindex: C-0 C-c C-w
-  #+findex: org-refile-cache-clear
-  #+vindex: org-refile-use-cache
-  Clear the target cache.  Caching of refile targets can be turned on
-  by setting ~org-refile-use-cache~.  To make the command see new
-  possible targets, you have to clear the cache with this command.
-
-- {{{kbd(C-c M-w)}}} (~org-copy~) ::
-
-  #+kindex: C-c M-w
-  #+findex: org-copy
-  Copying works like refiling, except that the original note is not
-  deleted.
-
-** Archiving
-:PROPERTIES:
-:DESCRIPTION: What to do with finished products.
-:END:
-#+cindex: archiving
-
-When a project represented by a (sub)tree is finished, you may want to
-move the tree out of the way and to stop it from contributing to the
-agenda.  Archiving is important to keep your working files compact and
-global searches like the construction of agenda views fast.
-
-- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
-
-  #+kindex: C-c C-x C-a
-  #+findex: org-archive-subtree-default
-  #+vindex: org-archive-default-command
-  Archive the current entry using the command specified in the
-  variable ~org-archive-default-command~.
-
-*** Moving a tree to an archive file
-:PROPERTIES:
-:DESCRIPTION: Moving a tree to an archive file.
-:ALT_TITLE: Moving subtrees
-:END:
-#+cindex: external archiving
-
-The most common archiving action is to move a project tree to another
-file, the archive file.
-
-- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
-
-  #+kindex: C-c C-x C-s
-  #+kindex: C-c $
-  #+findex: org-archive-subtree
-  #+vindex: org-archive-location
-  Archive the subtree starting at point position to the location given
-  by ~org-archive-location~.
-
-- {{{kbd(C-u C-c C-x C-s)}}} ::
-
-  #+kindex: C-u C-c C-x C-s
-  Check if any direct children of the current headline could be moved
-  to the archive.  To do this, check each subtree for open TODO
-  entries.  If none is found, the command offers to move it to the
-  archive location.  If point is /not/ on a headline when this command
-  is invoked, check level 1 trees.
-
-- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
-
-  #+kindex: C-u C-u C-c C-x C-s
-  As above, but check subtree for timestamps instead of TODO entries.
-  The command offers to archive the subtree if it /does/ contain
-  a timestamp, and that timestamp is in the past.
-
-#+cindex: archive locations
-The default archive location is a file in the same directory as the
-current file, with the name derived by appending =_archive= to the
-current file name.  You can also choose what heading to file archived
-items under, with the possibility to add them to a datetree in a file.
-For information and examples on how to specify the file and the
-heading, see the documentation string of the variable
-~org-archive-location~.
-
-There is also an in-buffer option for setting this variable, for
-example:
-
-#+cindex: @samp{ARCHIVE}, keyword
-: #+ARCHIVE: %s_done::
-
-#+cindex: ARCHIVE, property
-If you would like to have a special archive location for a single
-entry or a (sub)tree, give the entry an =ARCHIVE= property with the
-location as the value (see [[*Properties and Columns]]).
-
-#+vindex: org-archive-save-context-info
-When a subtree is moved, it receives a number of special properties
-that record context information like the file from where the entry
-came, its outline path the archiving time etc.  Configure the variable
-~org-archive-save-context-info~ to adjust the amount of information
-added.
-
-*** Internal archiving
-:PROPERTIES:
-:DESCRIPTION: Switch off a tree but keep it in the file.
-:END:
-
-#+cindex: @samp{ARCHIVE}, tag
-If you want to just switch off---for agenda views---certain subtrees
-without moving them to a different file, you can use the =ARCHIVE=
-tag.
-
-A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
-its location in the outline tree, but behaves in the following way:
-
--
-  #+vindex: org-cycle-open-archived-trees
-  It does not open when you attempt to do so with a visibility cycling
-  command (see [[*Visibility Cycling]]).  You can force cycling archived
-  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
-  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
-  ~outline-show-all~, open archived subtrees.
-
--
-  #+vindex: org-sparse-tree-open-archived-trees
-  During sparse tree construction (see [[*Sparse Trees]]), matches in
-  archived subtrees are not exposed, unless you configure the option
-  ~org-sparse-tree-open-archived-trees~.
-
--
-  #+vindex: org-agenda-skip-archived-trees
-  During agenda view construction (see [[*Agenda Views]]), the content of
-  archived trees is ignored unless you configure the option
-  ~org-agenda-skip-archived-trees~, in which case these trees are
-  always included.  In the agenda you can press {{{kbd(v a)}}} to get
-  archives temporarily included.
-
--
-  #+vindex: org-export-with-archived-trees
-  Archived trees are not exported (see [[*Exporting]]), only the headline
-  is.  Configure the details using the variable
-  ~org-export-with-archived-trees~.
-
--
-  #+vindex: org-columns-skip-archived-trees
-  Archived trees are excluded from column view unless the variable
-  ~org-columns-skip-archived-trees~ is configured to ~nil~.
-
-The following commands help manage the =ARCHIVE= tag:
-
-- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
-
-  #+kindex: C-c C-x a
-  #+findex: org-toggle-archive-tag
-  Toggle the archive tag for the current headline.  When the tag is
-  set, the headline changes to a shadowed face, and the subtree below
-  it is hidden.
-
-- {{{kbd(C-u C-c C-x a)}}} ::
-
-  #+kindex: C-u C-c C-x a
-  Check if any direct children of the current headline should be
-  archived.  To do this, check each subtree for open TODO entries.  If
-  none is found, the command offers to set the =ARCHIVE= tag for the
-  child.  If point is /not/ on a headline when this command is
-  invoked, check the level 1 trees.
-
-- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
-
-  #+kindex: C-TAB
-  Cycle a tree even if it is tagged with =ARCHIVE=.
-
-- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
-
-  #+kindex: C-c C-x A
-  #+findex: org-archive-to-archive-sibling
-  Move the current entry to the /Archive Sibling/.  This is a sibling
-  of the entry with the heading =Archive= and the archive tag.  The
-  entry becomes a child of that sibling and in this way retains a lot
-  of its original context, including inherited tags and approximate
-  position in the outline.
-
 * Agenda Views
 :PROPERTIES:
 :DESCRIPTION: Collecting information into views.
@@ -21244,7 +21461,7 @@ accessed in capture templates in a similar way.
 ~org-link-from-user-regexp~.
 
 [fn:87] If you move entries or Org files from one directory to
-another, you may want to configure ~org-attach-directory~ to contain
+another, you may want to configure ~org-attach-id-dir~ to contain
 an absolute path.
 
 [fn:88] Note the corresponding =STARTUP= options =logrefile=,
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 4abecdfbc..bbd9dc975 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI
 alternative was removed and there is no more a :use-xcolor options
 since now it's implicitly always true.
 
+*** Org-Attach Git commit
+[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality.  Not
+much, but the following changes are required if you still need to
+auto-commit attachments to git:
+
+- Customization of ~org-attach-annex-auto-get~ needs to be renamed to
+  ~org-attach-git-annex-auto-get~.
+
+- Customization of ~org-attach-commit~ is no longer needed.  Instead
+  one need to require the =org-attach-git= module in the startup.
+
 ** New features
+*** Org-Attach has been refactored and extended
+Org attach has been refactored and the functionality extended.  It
+should now be easier to understand how it works.  A few improvements
+and extra options have been added as well.
+
+From the initial comment in org-attach source-code:
+
+- Attachments are managed either by using a custom property DIR or by
+  using property ID from org-id.  When DIR is defined, a location in
+  the filesystem is directly attached to the outline node.  When
+  org-id is used, attachments are stored in a folder named after the
+  ID, in a location defined by ~org-attach-id-dir~.  DIR has
+  precedence over ID when both parameters are defined for the current
+  outline node (also when inherited parameters are taken into
+  account).
+
+From now on inheritance requires no extra property and will adhere to
+~org-attach-use-inheritance~ by default.  Inheritance can be
+customized to always be activated or never be activated in
+~org-attach-use-inheritance~.
+
+The ATTACH_DIR property is deprecated in favour of the shorter
+property DIR.  Links to folders inside the DIR property can now be
+declared as relative links.  This is not enabled by default, but can
+be set in ~org-attach-dir-relative~.
+
+When adding new attachment to the outline node the preferred way of
+doing so can be customized.  Take a look at
+~org-attach-preferred-new-method~.  It defaults to using ID since that
+was the behaviour before this change.
+
+If both DIR and ID properties are set on the same node, DIR has
+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.
+
+If you've used ATTACH_DIR properties to manage attachments, use the
+following code to rename that property to DIR which supports the same
+functionality.  ATTACH_DIR_INHERIT is no longer supported and is
+removed.
+
+#+begin_src emacs-lisp
+  (defun org-update-attach-properties ()
+      "Change properties for Org-Attach."
+      (interactive)
+      (org-with-point-at 1
+	(while (outline-next-heading)
+	  (let ((DIR (org--property-local-values "ATTACH_DIR" nil)))
+	    (when DIR
+	      (org-set-property "DIR" (car DIR))
+	      (org-delete-property "ATTACH_DIR"))))
+	(org-delete-property-globally "ATTACH_DIR_INHERIT")))
+#+end_src
+
+For those who hate breaking changes, even though the changes are made
+to clean things up; fear not.  ATTACH_DIR will still continue to work.
+It's just not documented any longer.  When you get the chance, run the
+code above to clean things up anyways!
+
+**** New hooks
+Two hooks are added to org-attach:
+- org-attach-after-change-hook
+- org-attach-open-hook
+
+They are added mostly for internal restructuring purposes, but can
+ofc. be used for other things as well.
+
+*** New link-type: Attachment
+Attachment-links are now first-class citizens.  They mimick file-links
+in everything they do but use the existing attachment-folder as a base
+when expanding the links. Both =DIR= and =ID= properties are used to
+try to resolve the links, in exactly the same way as Org-Attach uses
+those properties.
+
 *** Handle overlay specification for notes in Beamer export
 
 This aligns Beamer notes with slide overlays.
@@ -243,6 +332,11 @@ dynamic block in ~org-dynamic-block-alist~.
 ** Removed functions
 *** ~org-babel-set-current-result-hash~
 *** ~org-capture-insert-template-here~
+*** ~org-attach-directory~
+
+It has been deprecated in favour of ~org-attach-id-dir~ which is less
+ambigous given the restructured org-attach.
+
 ** Miscellaneous
 *** Change signature for ~org-list-to-subtree~
 The function now accepts the level of the subtree as an optional
diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el
new file mode 100644
index 000000000..f40eb966d
--- /dev/null
+++ b/lisp/org-attach-git.el
@@ -0,0 +1,117 @@
+;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; Original Author: John Wiegley <johnw@newartisans.com>
+;; Restructurer: Gustav Wikström <gustav@whil.se>
+;; Keywords: org data git
+
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; An extention to org-attach.  If the attachment-directory to an
+;; outline node (using either DIR or ID) is initialized as a Git
+;; repository, then org-attach-git will automatically commit changes
+;; when it sees them.
+
+;;; Code:
+
+(require 'org-attach)
+(require 'vc-git)
+
+(defcustom org-attach-git-annex-cutoff (* 32 1024)
+  "If non-nil, files larger than this will be annexed instead of stored."
+  :group 'org-attach
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type '(choice
+	  (const :tag "None" nil)
+	  (integer :tag "Bytes")))
+
+(defcustom org-attach-git-annex-auto-get 'ask
+  "Confirmation preference for automatically getting annex files.
+If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+  :group 'org-attach
+  :package-version '(Org . "9.0")
+  :version "26.1"
+  :type '(choice
+	  (const :tag "confirm with `y-or-n-p'" ask)
+	  (const :tag "always get from annex if necessary" t)
+	  (const :tag "never get from annex" nil)))
+
+(defun org-attach-git-use-annex ()
+  "Return non-nil if git annex can be used."
+  (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir))))
+    (and org-attach-git-annex-cutoff
+         (or (file-exists-p (expand-file-name "annex" git-dir))
+             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
+
+(defun org-attach-git-annex-get-maybe (path)
+  "Call git annex get PATH (via shell) if using git annex.
+Signals an error if the file content is not available and it was not retrieved."
+  (let* ((default-directory (expand-file-name org-attach-id-dir))
+	 (path-relative (file-relative-name path)))
+    (when (and (org-attach-git-use-annex)
+	       (not
+		(string-equal
+		 "found"
+		 (shell-command-to-string
+		  (format "git annex find --format=found --in=here %s"
+			  (shell-quote-argument path-relative))))))
+      (let ((should-get
+	     (if (eq org-attach-git-annex-auto-get 'ask)
+		 (y-or-n-p (format "Run git annex get %s? " path-relative))
+	       org-attach-git-annex-auto-get)))
+	(unless should-get
+	  (error "File %s stored in git annex but unavailable" path))
+	(message "Running git annex get \"%s\"." path-relative)
+	(call-process "git" nil nil nil "annex" "get" path-relative)))))
+
+(defun org-attach-git-commit ()
+  "Commit changes to git if `org-attach-id-dir' is properly initialized.
+This checks for the existence of a \".git\" directory in that directory."
+  (let* ((dir (expand-file-name org-attach-id-dir))
+	 (git-dir (vc-git-root dir))
+	 (use-annex (org-attach-git-use-annex))
+	 (changes 0))
+    (when (and git-dir (executable-find "git"))
+      (with-temp-buffer
+	(cd dir)
+        (dolist (new-or-modified
+                 (split-string
+                  (shell-command-to-string
+                   "git ls-files -zmo --exclude-standard") "\0" t))
+          (if (and use-annex
+                   (>= (file-attribute-size (file-attributes new-or-modified))
+                       org-attach-git-annex-cutoff))
+              (call-process "git" nil nil nil "annex" "add" new-or-modified)
+            (call-process "git" nil nil nil "add" new-or-modified))
+	    (cl-incf changes))
+	(dolist (deleted
+		 (split-string
+		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
+	  (call-process "git" nil nil nil "rm" deleted)
+	  (cl-incf changes))
+	(when (> changes 0)
+	  (shell-command "git commit -m 'Synchronized attachments'"))))))
+
+(add-hook 'org-attach-after-change-hook 'org-attach-git-commit)
+(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe)
+
+(provide 'org-attach-git)
+
+;;; org-attach-git.el ends here
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index a715c89e9..726085014 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -1,9 +1,9 @@
-;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*-
+;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2008-2019 Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@newartisans.com>
-;; Keywords: org data task
+;; Keywords: org data attachment
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -24,32 +24,30 @@
 
 ;; See the Org manual for information on how to use it.
 ;;
-;; Attachments are managed in a special directory called "data", which
-;; lives in the same directory as the org file itself.  If this data
-;; directory is initialized as a Git repository, then org-attach will
-;; automatically commit changes when it sees them.
-;;
-;; Attachment directories are identified using a UUID generated for the
-;; task which has the attachments.  These are added as property to the
-;; task when necessary, and should not be deleted or changed by the
-;; user, ever.  UUIDs are generated by a mechanism defined in the variable
-;; `org-id-method'.
+;; Attachments are managed either by using a custom property DIR or by
+;; using property ID from org-id.  When DIR is defined, a location in
+;; the filesystem is directly attached to the outline node.  When
+;; org-id is used, attachments are stored in a folder named after the
+;; ID, in a location defined by `org-attach-id-dir'.  DIR has
+;; precedence over ID when both parameters are defined for the current
+;; outline node (also when inherited parameters are taken into
+;; account).
 
 ;;; Code:
 
 (require 'cl-lib)
 (require 'org)
+(require 'ol)
 (require 'org-id)
-(require 'vc-git)
 
 (declare-function dired-dwim-target-directory "dired-aux")
 
 (defgroup org-attach nil
-  "Options concerning entry attachments in Org mode."
+  "Options concerning attachments in Org mode."
   :tag "Org Attach"
   :group 'org)
 
-(defcustom org-attach-directory "data/"
+(defcustom org-attach-id-dir "data/"
   "The directory where attachments are stored.
 If this is a relative path, it will be interpreted relative to the directory
 where the Org file lives."
@@ -57,22 +55,13 @@ where the Org file lives."
   :type 'directory
   :safe #'stringp)
 
-(defcustom org-attach-commit t
-  "If non-nil commit attachments with git.
-This is only done if the Org file is in a git repository."
+(defcustom org-attach-dir-relative nil
+  "Non-nil means directories in DIR property are added as relative links.
+Defaults to absolute location."
   :group 'org-attach
   :type 'boolean
-  :version "26.1"
-  :package-version '(Org . "9.0"))
-
-(defcustom org-attach-git-annex-cutoff (* 32 1024)
-  "If non-nil, files larger than this will be annexed instead of stored."
-  :group 'org-attach
-  :version "24.4"
-  :package-version '(Org . "8.0")
-  :type '(choice
-	  (const :tag "None" nil)
-	  (integer :tag "Bytes")))
+  :package-version '(Org . "9.3")
+  :safe #'booleanp)
 
 (defcustom org-attach-auto-tag "ATTACH"
   "Tag that will be triggered automatically when an entry has an attachment."
@@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository."
 	  (const :tag "None" nil)
 	  (string :tag "Tag")))
 
-(defcustom org-attach-file-list-property "Attachments"
-  "The property used to keep a list of attachment belonging to this entry.
-This is not really needed, so you may set this to nil if you don't want it.
-Also, for entries where children inherit the directory, the list of
-attachments is not kept in this property."
+(defcustom org-attach-preferred-new-method 'id
+  "Preferred way to attach to nodes without existing ID and DIR property.
+This choice is used when adding attachments to nodes without ID
+and DIR properties.
+
+Allowed values are:
+
+id         Create and use an ID parameter
+dir        Create and use a DIR parameter
+ask        Ask the user for input of which method to choose
+nil        Prefer to not create a new parameter
+
+           nil means that ID or DIR has to be created explicitly
+           before attaching files."
   :group 'org-attach
+  :package-version '(org . "9.3")
   :type '(choice
-	  (const :tag "None" nil)
-	  (string :tag "Tag")))
+	  (const :tag "ID parameter" id)
+	  (const :tag "DIR parameter" dir)
+	  (const :tag "Ask user" ask)
+	  (const :tag "Don't create" nil)))
 
 (defcustom org-attach-method 'cp
   "The preferred method to attach a file.
@@ -113,14 +114,24 @@ lns   create a symbol link.  Note that this is not supported
   :group 'org-attach
   :type 'boolean)
 
-(defcustom org-attach-allow-inheritance t
-  "Non-nil means allow attachment directories be inherited."
+(defcustom org-attach-use-inheritance 'selective
+  "Attachment inheritance for the outline.
+
+Enabling inheritance for org-attach implies two things.  First,
+that attachment links will look through all parent headings until
+it finds the linked attachment.  Second, that running org-attach
+inside a node without attachments will make org-attach operate on
+the first parent heading it finds with an attachment.
+
+Selective means to respect the inheritance setting in
+`org-use-property-inheritance'."
   :group 'org-attach
+  :type '(choice
+	  (const :tag "Don't use inheritance" nil)
+	  (const :tag "Inherit parent node attachments" t)
+	  (const :tag "Respect org-use-property-inheritance" selective))
   :type 'boolean)
 
-(defvar org-attach-inherited nil
-  "Indicates if the last access to the attachment directory was inherited.")
-
 (defcustom org-attach-store-link-p nil
   "Non-nil means store a link to a file when attaching it."
   :group 'org-attach
@@ -141,16 +152,28 @@ When set to `query', ask the user instead."
 	  (const :tag "Always delete attachments" t)
 	  (const :tag "Query the user" query)))
 
-(defcustom org-attach-annex-auto-get 'ask
-  "Confirmation preference for automatically getting annex files.
-If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
+(defun org-attach-id-folder-format (id)
+  "Translate an ID into a folder-path.
+Default format for how Org translates ID properties to a path for
+attachments."
+  (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."
   :group 'org-attach
-  :package-version '(Org . "9.0")
-  :version "26.1"
-  :type '(choice
-	  (const :tag "confirm with `y-or-n-p'" ask)
-	  (const :tag "always get from annex if necessary" t)
-	  (const :tag "never get from annex" nil)))
+  :package-version '(Org . "9.3")
+  :type 'function)
+
+(defvar org-attach-after-change-hook nil
+  "Hook to be called when files have been added or removed to the attachment folder.")
+
+(defvar org-attach-open-hook nil
+  "Hook that is invoked by `org-attach-open'.
+
+Created mostly to be compatible with org-attach-git after removing
+git-funtionality from this file.")
 
 (defcustom org-attach-commands
   '(((?a ?\C-a) org-attach-attach
@@ -186,9 +209,9 @@ you added attachments yourself.\n")
      "Delete all of a task's attachments.  A safer way is\n to open the \
 directory in dired and delete from there.\n")
     ((?s ?\C-s) org-attach-set-directory
-     "Set a specific attachment directory for this entry or reset to default.")
-    ((?i ?\C-i) org-attach-set-inherit
-     "Make children of the current entry inherit its attachment directory.\n")
+     "Set a specific attachment directory for this entry. Sets DIR property.")
+    ((?S ?\C-S) org-attach-unset-directory
+     "Unset the attachment directory for this entry.  Removes DIR property.")
     ((?q) (lambda () (interactive) (message "Abort")) "Abort."))
   "The list of commands for the attachment dispatcher.
 Each entry in this list is a list of three elements:
@@ -215,7 +238,7 @@ Shows a list of commands and prompts for another key to execute a command."
       (setq marker (or (get-text-property (point) 'org-hd-marker)
 		       (get-text-property (point) 'org-marker)))
       (unless marker
-	(error "No task in current line")))
+	(error "No item in current line")))
     (save-excursion
       (when marker
 	(set-buffer (marker-buffer marker))
@@ -225,24 +248,28 @@ Shows a list of commands and prompts for another key to execute a command."
 	(save-window-excursion
 	  (unless org-attach-expert
 	    (with-output-to-temp-buffer "*Org Attach*"
-	      (princ
-	       (format "Select an Attachment Command:\n\n%s"
-		       (mapconcat
-			(lambda (entry)
-			  (pcase entry
-			    (`((,key . ,_) ,_ ,docstring)
-			     (format "%c       %s"
-				     key
-				     (replace-regexp-in-string "\n\\([\t ]*\\)"
-							       "        "
-							       docstring
-							       nil nil 1)))
-			    (_
-			     (user-error
-			      "Invalid `org-attach-commands' item: %S"
-			      entry))))
-			org-attach-commands
-			"\n")))))
+              (princ
+               (concat "Attachment folder:\n"
+		       (or (org-attach-dir)
+			   "Can't find an existing attachment-folder")
+		       "\n\n"
+	               (format "Select an Attachment Command:\n\n%s"
+		               (mapconcat
+		                (lambda (entry)
+		                  (pcase entry
+		                    (`((,key . ,_) ,_ ,docstring)
+		                     (format "%c       %s"
+			                     key
+			                     (replace-regexp-in-string "\n\\([\t ]*\\)"
+							               "        "
+							               docstring
+							               nil nil 1)))
+		                    (_
+		                     (user-error
+			              "Invalid `org-attach-commands' item: %S"
+			              entry))))
+		                org-attach-commands
+		                "\n"))))))
 	  (org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
 	  (message "Select command: [%s]"
 		   (concat (mapcar #'caar org-attach-commands)))
@@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command."
 	  (error "No such attachment command: %c" c))))))
 
 (defun org-attach-dir (&optional create-if-not-exists-p)
-  "Return the directory associated with the current entry.
-This first checks for a local property ATTACH_DIR, and then for an inherited
-property ATTACH_DIR_INHERIT.  If neither exists, the default mechanism
-using the entry ID will be invoked to access the unique directory for the
-current entry.
-If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil,
-the directory and (if necessary) the corresponding ID will be created."
-  (let (attach-dir uuid)
-    (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT"))
+  "Return the directory associated with the current outline node.
+First check for DIR property, then ID property.
+`org-attach-use-inheritance' determines whether inherited
+properties also will be considered.
+
+If an ID property is found the default mechanism using that ID
+will be invoked to access the directory for the current entry.
+
+If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
+is run."
+  (let (attach-dir id)
     (cond
-     ((setq attach-dir (org-entry-get nil "ATTACH_DIR"))
+     (create-if-not-exists-p
+      (setq attach-dir (org-attach-dir-get-create)))
+     ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
       (org-attach-check-absolute-path attach-dir))
-     ((and org-attach-allow-inheritance
-	   (org-entry-get nil "ATTACH_DIR_INHERIT" t))
-      (setq attach-dir
-	    (org-with-wide-buffer
-	     (if (marker-position org-entry-property-inherited-from)
-		 (goto-char org-entry-property-inherited-from)
-	       (org-back-to-heading t))
-	     (let (org-attach-allow-inheritance)
-	       (org-attach-dir create-if-not-exists-p))))
-      (org-attach-check-absolute-path attach-dir)
-      (setq org-attach-inherited t))
-     (t					; use the ID
+     ;; Deprecated and removed from documentation, but still
+     ;; works. FIXME: Remove after major nr change.
+     ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance))
+      (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 uuid (org-id-get (point) create-if-not-exists-p))
-      (when (or uuid create-if-not-exists-p)
-	(unless uuid (error "ID retrieval/creation failed"))
-	(setq attach-dir (expand-file-name
-			  (format "%s/%s"
-				  (substring uuid 0 2)
-				  (substring uuid 2))
-			  (expand-file-name org-attach-directory))))))
-    (when attach-dir
-      (if (and create-if-not-exists-p
-	       (not (file-directory-p attach-dir)))
-	  (make-directory attach-dir t))
-      (and (file-exists-p attach-dir)
-	   attach-dir))))
+      (setq attach-dir (org-attach-dir-from-id id))))
+    attach-dir))
+
+(defun org-attach-dir-get-create ()
+  "Return existing or new directory associated with the current outline node.
+
+`org-attach-preferred-new-method' decides how to attach
+new directory."
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (unless attach-dir
+      (let (answer)
+	(when (eq org-attach-preferred-new-method 'ask)
+	  (message "Create new ID [1] property or DIR [2] property for attachments?")
+	  (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))))
+	 ((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)
+	  (error "No existing directory. DIR or ID property has to be explicitly created")))))
+    (unless attach-dir
+      (error "No attachment directory is associated with the current node"))
+    (unless (file-directory-p attach-dir)
+      (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-check-absolute-path (dir)
   "Check if we have enough information to root the attachment directory.
 When DIR is given, check also if it is already absolute.  Otherwise,
-assume that it will be relative, and check if `org-attach-directory' is
+assume that it will be relative, and check if `org-attach-id-dir' is
 absolute, or if at least the current buffer has a file name.
 Throw an error if we cannot root the directory."
   (or (and dir (file-name-absolute-p dir))
-      (file-name-absolute-p org-attach-directory)
+      (file-name-absolute-p org-attach-id-dir)
       (buffer-file-name (buffer-base-buffer))
-      (error "Need absolute `org-attach-directory' to attach in buffers without filename")))
+      (error "Need absolute `org-attach-id-dir' to attach in buffers without filename")))
 
-(defun org-attach-set-directory (&optional arg)
-  "Set the ATTACH_DIR node property and ask to move files there.
+(defun org-attach-set-directory ()
+  "Set the DIR node property and ask to move files there.
 The property defines the directory that is used for attachments
-of the entry.  When called with `\\[universal-argument]', reset \
-the directory to
-the default ID based one."
-  (interactive "P")
+of the entry.  Creates relative links if `org-attach-dir-relative'
+is non-nil.
+
+Return the directory."
+  (interactive)
   (let ((old (org-attach-dir))
-        (new
-         (progn
-           (if arg (org-entry-delete nil "ATTACH_DIR")
-             (let ((dir (read-directory-name
-                         "Attachment directory: "
-                         (org-entry-get nil
-                                        "ATTACH_DIR"
-                                        (and org-attach-allow-inheritance t)))))
-               (org-entry-put nil "ATTACH_DIR" dir)))
-           (org-attach-dir t))))
+	(new
+	 (let* ((attach-dir (read-directory-name
+			     "Attachment directory: "
+			     (org-entry-get nil "DIR")))
+		(current-dir (file-name-directory (or default-directory
+						      buffer-file-name)))
+		(attach-dir-relative (file-relative-name attach-dir current-dir)))
+	   (org-entry-put nil "DIR" (if org-attach-dir-relative
+					attach-dir-relative
+				      attach-dir))
+           attach-dir)))
     (unless (or (string= old new)
                 (not old))
       (when (yes-or-no-p "Copy over attachments from old directory? ")
+        (copy-directory old new t t t))
+      (when (yes-or-no-p (concat "Delete " old))
+        (delete-directory old t)))
+    new))
+
+(defun org-attach-unset-directory ()
+  "Removes DIR node property.
+If attachment folder is changed due to removal of DIR-property
+ask to move attachments to new location and ask to delete old
+attachment-folder.
+
+Change of attachment-folder due to unset might be if an ID
+property is set on the node, or if a separate inherited
+DIR-property exists (that is different than the unset one)."
+  (interactive)
+  (let ((old (org-attach-dir))
+	(new
+         (progn
+	   (org-entry-delete nil "DIR")
+	   ;; ATTACH-DIR is deprecated and removed from documentation,
+	   ;; but still works. Remove code for it after major nr change.
+	   (org-entry-delete nil "ATTACH_DIR")
+	   (org-attach-dir))))
+    (unless (or (string= old new)
+                (not old))
+      (when (and new (yes-or-no-p "Copy over attachments from old directory? "))
         (copy-directory old new t nil t))
       (when (yes-or-no-p (concat "Delete " old))
         (delete-directory old t)))))
 
-(defun org-attach-set-inherit ()
-  "Set the ATTACH_DIR_INHERIT property of the current entry.
-The property defines the directory that is used for attachments
-of the entry and any children that do not explicitly define (by setting
-the ATTACH_DIR property) their own attachment directory."
-  (interactive)
-  (org-entry-put nil "ATTACH_DIR_INHERIT" "t")
-  (message "Children will inherit attachment directory"))
-
-(defun org-attach-use-annex ()
-  "Return non-nil if git annex can be used."
-  (let ((git-dir (vc-git-root (expand-file-name org-attach-directory))))
-    (and org-attach-git-annex-cutoff
-         (or (file-exists-p (expand-file-name "annex" git-dir))
-             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
-
-(defun org-attach-annex-get-maybe (path)
-  "Call git annex get PATH (via shell) if using git annex.
-Signals an error if the file content is not available and it was not retrieved."
-  (let* ((default-directory (expand-file-name org-attach-directory))
-	 (path-relative (file-relative-name path)))
-    (when (and (org-attach-use-annex)
-	       (not
-		(string-equal
-		 "found"
-		 (shell-command-to-string
-		  (format "git annex find --format=found --in=here %s"
-			  (shell-quote-argument path-relative))))))
-      (let ((should-get
-	     (if (eq org-attach-annex-auto-get 'ask)
-		 (y-or-n-p (format "Run git annex get %s? " path-relative))
-	       org-attach-annex-auto-get)))
-	(if should-get
-	    (progn (message "Running git annex get \"%s\"." path-relative)
-		   (call-process "git" nil nil nil "annex" "get" path-relative))
-	  (error "File %s stored in git annex but it is not available, and was not retrieved"
-		 path))))))
-
-(defun org-attach-commit ()
-  "Commit changes to git if `org-attach-directory' is properly initialized.
-This checks for the existence of a \".git\" directory in that directory."
-  (let* ((dir (expand-file-name org-attach-directory))
-	 (git-dir (vc-git-root dir))
-	 (use-annex (org-attach-use-annex))
-	 (changes 0))
-    (when (and git-dir (executable-find "git"))
-      (with-temp-buffer
-	(cd dir)
-        (dolist (new-or-modified
-                 (split-string
-                  (shell-command-to-string
-                   "git ls-files -zmo --exclude-standard") "\0" t))
-          (if (and use-annex
-                   (>= (file-attribute-size (file-attributes new-or-modified))
-                       org-attach-git-annex-cutoff))
-              (call-process "git" nil nil nil "annex" "add" new-or-modified)
-            (call-process "git" nil nil nil "add" new-or-modified))
-	    (cl-incf changes))
-	(dolist (deleted
-		 (split-string
-		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
-	  (call-process "git" nil nil nil "rm" deleted)
-	  (cl-incf changes))
-	(when (> changes 0)
-	  (shell-command "git commit -m 'Synchronized attachments'"))))))
-
 (defun org-attach-tag (&optional off)
   "Turn the autotag on or (if OFF is set) off."
   (when org-attach-auto-tag
@@ -423,22 +428,21 @@ Only do this when `org-attach-store-link-p' is non-nil."
     (org-attach-attach url)))
 
 (defun org-attach-buffer (buffer-name)
-  "Attach BUFFER-NAME's contents to current task.
+  "Attach BUFFER-NAME's contents to current outline node.
 BUFFER-NAME is a string.  Signals a `file-already-exists' error
 if it would overwrite an existing filename."
   (interactive "bBuffer whose contents should be attached: ")
-  (let ((output (expand-file-name buffer-name (org-attach-dir t))))
+  (let* ((attach-dir (org-attach-dir 'get-create))
+	 (output (expand-file-name buffer-name attach-dir)))
     (when (file-exists-p output)
       (signal 'file-already-exists (list "File exists" output)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property buffer-name))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)
     (org-attach-tag)
     (with-temp-file output
       (insert-buffer-substring buffer-name))))
 
 (defun org-attach-attach (file &optional visit-dir method)
-  "Move/copy/link FILE into the attachment directory of the current task.
+  "Move/copy/link FILE into the attachment directory of the current outline node.
 If VISIT-DIR is non-nil, visit the directory with dired.
 METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
 `org-attach-method'."
@@ -453,10 +457,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
     nil))
   (setq method (or method org-attach-method))
   (let ((basename (file-name-nondirectory file)))
-    (when (and org-attach-file-list-property (not org-attach-inherited))
-      (org-entry-add-to-multivalued-property
-       (point) org-attach-file-list-property basename))
-    (let* ((attach-dir (org-attach-dir t))
+    (let* ((attach-dir (org-attach-dir 'get-create))
            (fname (expand-file-name basename attach-dir)))
       (cond
        ((eq method 'mv) (rename-file file fname))
@@ -464,8 +465,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
        ((eq method 'ln) (add-name-to-file file fname))
        ((eq method 'lns) (make-symbolic-link file fname))
        ((eq method 'url) (url-copy-file file fname)))
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-tag)
       (cond ((eq org-attach-store-link-p 'attached)
              (org-attach-store-link fname))
@@ -473,7 +473,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
              (org-attach-store-link file)))
       (if visit-dir
           (dired attach-dir)
-        (message "File %S is now a task attachment." basename)))))
+        (message "File %S is now an attachment." basename)))))
 
 (defun org-attach-attach-cp ()
   "Attach a file by copying it."
@@ -498,13 +498,10 @@ On some systems, this apparently does copy the file instead."
   (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach)))
 
 (defun org-attach-new (file)
-  "Create a new attachment FILE for the current task.
+  "Create a new attachment FILE for the current outline node.
 The attachment is created as an Emacs buffer."
   (interactive "sCreate attachment named: ")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-add-to-multivalued-property
-     (point) org-attach-file-list-property file))
-  (let ((attach-dir (org-attach-dir t)))
+  (let ((attach-dir (org-attach-dir 'get-create)))
     (org-attach-tag)
     (find-file (expand-file-name file attach-dir))
     (message "New attachment %s" file)))
@@ -512,7 +509,7 @@ The attachment is created as an Emacs buffer."
 (defun org-attach-delete-one (&optional file)
   "Delete a single attachment."
   (interactive)
-  (let* ((attach-dir (org-attach-dir t))
+  (let* ((attach-dir (org-attach-dir))
 	 (files (org-attach-file-list attach-dir))
 	 (file (or file
 		   (completing-read
@@ -524,44 +521,32 @@ The attachment is created as an Emacs buffer."
     (unless (file-exists-p file)
       (error "No such attachment: %s" file))
     (delete-file file)
-    (when org-attach-commit
-      (org-attach-commit))))
+    (run-hook-with-args 'org-attach-after-change-hook attach-dir)))
 
 (defun org-attach-delete-all (&optional force)
-  "Delete all attachments from the current task.
+  "Delete all attachments from the current outline node.
 This actually deletes the entire attachment directory.
 A safer way is to open the directory in dired and delete from there."
   (interactive "P")
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
-    (when
-	(and attach-dir
-	     (or force
-		 (y-or-n-p "Are you sure you want to remove all attachments of this entry? ")))
-      (shell-command (format "rm -fr %s" attach-dir))
+    (when (and attach-dir
+	       (or force
+		   (yes-or-no-p "Really remove all attachments of this entry? ")))
+      (delete-directory attach-dir (yes-or-no-p "Recursive?") t)
       (message "Attachment directory removed")
-      (when org-attach-commit
-        (org-attach-commit))
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-untag))))
 
 (defun org-attach-sync ()
-  "Synchronize the current tasks with its attachments.
+  "Synchronize the current outline node with its attachments.
 This can be used after files have been added externally."
   (interactive)
-  (when org-attach-commit
-    (org-attach-commit))
-  (when (and org-attach-file-list-property (not org-attach-inherited))
-    (org-entry-delete (point) org-attach-file-list-property))
   (let ((attach-dir (org-attach-dir)))
     (when attach-dir
+      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (let ((files (org-attach-file-list attach-dir)))
-	(org-attach-tag (not files))
-	(when org-attach-file-list-property
-	  (dolist (file files)
-	    (unless (string-match "^\\.\\.?\\'" file)
-	      (org-entry-add-to-multivalued-property
-	       (point) org-attach-file-list-property file))))))))
+	(org-attach-tag (not files))))
+    (unless attach-dir (org-attach-tag t))))
 
 (defun org-attach-file-list (dir)
   "Return a list of files in the attachment directory.
@@ -570,35 +555,40 @@ This ignores files ending in \"~\"."
 	(mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x))
 		(directory-files dir nil "[^~]\\'"))))
 
-(defun org-attach-reveal (&optional if-exists)
-  "Show the attachment directory of the current task.
+(defun org-attach-reveal ()
+  "Show the attachment directory of the current outline node.
 This will attempt to use an external program to show the directory."
-  (interactive "P")
-  (let ((attach-dir (org-attach-dir (not if-exists))))
-    (and attach-dir (org-open-file attach-dir))))
+  (interactive)
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(org-open-file attach-dir)
+      (error "No attachment directory exist"))))
 
 (defun org-attach-reveal-in-emacs ()
-  "Show the attachment directory of the current task in dired."
+  "Show the attachment directory of the current outline node in dired."
   (interactive)
-  (let ((attach-dir (org-attach-dir t)))
-    (dired attach-dir)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(dired attach-dir)
+      (error "No attachment directory exist"))))
 
 (defun org-attach-open (&optional in-emacs)
-  "Open an attachment of the current task.
+  "Open an attachment of the current outline node.
 If there are more than one attachment, you will be prompted for the file name.
 This command will open the file using the settings in `org-file-apps'
 and in the system-specific variants of this variable.
 If IN-EMACS is non-nil, force opening in Emacs."
   (interactive "P")
-  (let* ((attach-dir (org-attach-dir t))
-	 (files (org-attach-file-list attach-dir))
-	 (file (if (= (length files) 1)
-		   (car files)
-		 (completing-read "Open attachment: "
-				  (mapcar #'list files) nil t)))
-         (path (expand-file-name file attach-dir)))
-    (org-attach-annex-get-maybe path)
-    (org-open-file path in-emacs)))
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(let* ((file (pcase (org-attach-file-list attach-dir)
+		       (`(,file) file)
+		       (files (completing-read "Open attachment: "
+					       (mapcar #'list files) nil t))))
+	       (path (expand-file-name file attach-dir)))
+	  (run-hook-with-args 'org-attach-open-hook path)
+	  (org-open-file path in-emacs))
+      (error "No attachment directory exist"))))
 
 (defun org-attach-open-in-emacs ()
   "Open attachment, force opening in Emacs.
@@ -617,6 +607,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
 prefix."
   (concat "file:" (org-attach-expand file)))
 
+(org-link-set-parameters "attachment"
+                         :follow #'org-attach-open-link
+                         :export #'org-attach-export-link
+                         :complete #'org-attach-complete-link)
+
+(defun org-attach-open-link (link &optional in-emacs)
+  "Attachment link type LINK is expanded with the attached directory and opened.
+
+With optional prefix argument IN-EMACS, Emacs will visit the file.
+With a double \\[universal-argument] \\[universal-argument] \
+prefix arg, Org tries to avoid opening in Emacs
+and to use an external application to visit the file."
+  (interactive "P")
+  (let (line search)
+    (cond
+     ((string-match "::\\([0-9]+\\)\\'" link)
+      (setq line (string-to-number (match-string 1 link))
+	    link (substring link 0 (match-beginning 0))))
+     ((string-match "::\\(.+\\)\\'" link)
+      (setq search (match-string 1 link)
+            link (substring link 0 (match-beginning 0)))))
+    (if (string-match "[*?{]" (file-name-nondirectory link))
+        (dired (org-attach-expand link))
+      (org-open-file (org-attach-expand link) in-emacs line search))))
+
+(defun org-attach-complete-link ()
+  "Advise the user with the available files in the attachment directory."
+  (let ((attach-dir (org-attach-dir)))
+    (if attach-dir
+	(let* ((attached-dir (expand-file-name attach-dir))
+	       (file (read-file-name "File: " attached-dir))
+	       (pwd (file-name-as-directory attached-dir))
+               (pwd-relative (file-name-as-directory
+			      (abbreviate-file-name attached-dir))))
+	  (cond
+	   ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file)
+	    (concat "attachment:" (match-string 1 file)))
+	   ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
+			  (expand-file-name file))
+	    (concat "attachment:" (match-string 1 (expand-file-name file))))
+	   (t (concat "attachment:" file))))
+      (error "No attachment directory exist"))))
+
+(defun org-attach-export-link (link description format)
+  "Translate attachment LINK from Org mode format to exported FORMAT.
+Also includes the DESCRIPTION of the link in the export."
+  (save-excursion
+    (let (path desc)
+      (cond
+       ((string-match "::\\([0-9]+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0))))
+       ((string-match "::\\(.+\\)\\'" link)
+        (setq link (substring link 0 (match-beginning 0)))))
+      (setq path (file-relative-name (org-attach-expand link))
+            desc (or description link))
+      (pcase format
+        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+        (`latex (format "\\href{%s}{%s}" path desc))
+        (`texinfo (format "@uref{%s,%s}" path desc))
+        (`ascii (format "%s (%s)" desc path))
+        (`md (format "[%s](%s)" desc path))
+        (_ path)))))
+
 (defun org-attach-archive-delete-maybe ()
   "Maybe delete subtree attachments when archiving.
 This function is called by `org-archive-hook'.  The option
@@ -644,7 +697,7 @@ Idea taken from `gnus-dired-attach'."
   (interactive
    (list (dired-get-marked-files)))
   (unless (eq major-mode 'dired-mode)
-    (user-error "This command must be triggered in a dired buffer."))
+    (user-error "This command must be triggered in a dired buffer"))
   (let ((start-win (selected-window))
         (other-win
          (get-window-with-predicate
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index 9cb396fe9..42fe64379 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -263,6 +263,9 @@ Counting starts at 1."
 (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays
   'org-clear-latex-preview "Org 9.3")
 
+(define-obsolete-variable-alias 'org-attach-directory
+  'org-attach-id-dir "Org 9.3")
+
 (defun org-in-fixed-width-region-p ()
   "Non-nil if point in a fixed-width region."
   (save-match-data
diff --git a/lisp/org.el b/lisp/org.el
index 9601ecf2e..5d6cc757d 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -3847,7 +3847,9 @@ This is needed for font-lock setup.")
 		  (beg end))
 (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
 (declare-function org-agenda-skip "org-agenda" ())
-(declare-function org-attach-reveal "org-attach" (&optional if-exists))
+(declare-function org-attach-expand "org-attach" (file))
+(declare-function org-attach-reveal "org-attach" ())
+(declare-function org-attach-reveal-in-emacs "org-attach" ())
 (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
 (declare-function org-indent-mode "org-indent" (&optional arg))
 (declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
@@ -8645,12 +8647,15 @@ a link."
 	  (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
 	    (`(nil . ,_)
 	     (require 'org-attach)
-	     (org-attach-reveal 'if-exists))
+	     (message "Opening attachment-dir")
+	     (if (equal arg '(4))
+		 (org-attach-reveal-in-emacs)
+	       (org-attach-reveal)))
 	    (`(,links . ,links-end)
 	     (dolist (link (if (stringp links) (list links) links))
 	       (search-forward link nil links-end)
 	       (goto-char (match-beginning 0))
-	       (org-open-at-point))))))
+	       (org-open-at-point arg))))))
        ;; On a footnote reference or at definition's label.
        ((or (eq type 'footnote-reference)
 	    (and (eq type 'footnote-definition)
@@ -16630,13 +16635,14 @@ boundaries."
 	     ;; "file:" links.  Also check link abbreviations since
 	     ;; some might expand to "file" links.
 	     (file-types-re
-	      (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
+	      (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
 		      (if (not link-abbrevs) ""
 			(concat "\\|" (regexp-opt link-abbrevs))))))
 	(while (re-search-forward file-types-re end t)
 	  (let* ((link (org-element-lineage
 			(save-match-data (org-element-context))
 			'(link) t))
+                 (linktype (org-element-property :type link))
 		 (inner-start (match-beginning 1))
 		 (path
 		  (cond
@@ -16650,7 +16656,8 @@ boundaries."
 		   ;; INCLUDE-LINKED is non-nil.
 		   ((or (not (org-element-property :contents-begin link))
 			include-linked)
-		    (and (equal "file" (org-element-property :type link))
+		    (and (or (equal "file" linktype)
+                             (equal "attachment" linktype))
 			 (org-element-property :path link)))
 		   ;; Link with a description.  Check if description
 		   ;; is a filename.  Even if Org doesn't have syntax
@@ -16669,7 +16676,11 @@ boundaries."
 			      (match-end 0))
 			   (match-string 2)))))))
 	    (when (and path (string-match-p file-extension-re path))
-	      (let ((file (expand-file-name path)))
+	      (let ((file (if (equal "attachment" linktype)
+                              (progn
+                                (require 'org-attach)
+                                (org-attach-expand path))
+                            (expand-file-name path))))
 		(when (file-exists-p file)
 		  (let ((width
 			 ;; Apply `org-image-actual-width' specifications.
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index f1c06e069..757006321 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -884,6 +884,7 @@ link to the image."
 
 (defcustom org-html-inline-image-rules
   '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
+    ("attachment" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
     ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
     ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'"))
   "Rules characterizing image files that can be inlined into HTML.
diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA
new file mode 100644
index 000000000..9a0406c0d
--- /dev/null
+++ b/testing/examples/att1/fileA
@@ -0,0 +1 @@
+Text in fileA
diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB
new file mode 100644
index 000000000..dd2331824
--- /dev/null
+++ b/testing/examples/att1/fileB
@@ -0,0 +1 @@
+Text in fileB
diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC
new file mode 100644
index 000000000..2c9a92bfe
--- /dev/null
+++ b/testing/examples/att2/fileC
@@ -0,0 +1 @@
+Text in fileC
\ No newline at end of file
diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD
new file mode 100644
index 000000000..c706556c5
--- /dev/null
+++ b/testing/examples/att2/fileD
@@ -0,0 +1 @@
+text in fileD
diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org
new file mode 100644
index 000000000..ab4a4e548
--- /dev/null
+++ b/testing/examples/attachments.org
@@ -0,0 +1,32 @@
+#+TITLE: Org attach testfile
+Used to test and verify the functionality of org-attach.
+
+* H1
+ :PROPERTIES:
+ :DIR:      att1
+ :END:
+A link to one attachment: [[attachment:fileA]]
+
+** H1.1
+A link to another attachment: [[attachment:fileB]]
+
+** H1.2
+  :PROPERTIES:
+  :DIR:      att2
+  :END:
+
+* H2
+ :PROPERTIES:
+ :ID:       abcd123
+ :END:
+
+* H3
+ :PROPERTIES:
+ :DIR:      att1
+ :ID:       abcd1234
+ :END:
+
+** H3.1
+  :PROPERTIES:
+  :ID:       abcd12345
+  :END:
diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE
new file mode 100644
index 000000000..80d337772
--- /dev/null
+++ b/testing/examples/data/ab/cd123/fileE
@@ -0,0 +1 @@
+peek-a-boo
diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el
similarity index 93%
rename from testing/lisp/test-org-attach-annex.el
rename to testing/lisp/test-org-attach-git.el
index 7f2792696..8b826b72f 100644
--- a/testing/lisp/test-org-attach-annex.el
+++ b/testing/lisp/test-org-attach-git.el
@@ -20,19 +20,19 @@
 
 ;;; Code:
 (org-test-for-executable "git-annex")
-(require 'org-attach)
+(require 'org-attach-git)
 (require 'cl-lib)
 
-(defmacro test-org-attach-annex/with-annex (&rest body)
+(defmacro test-org-attach-git/with-annex (&rest body)
   `(let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (shell-command "git annex init")
 	   ,@body))))
 
-(ert-deftest test-org-attach/use-annex ()
+(ert-deftest test-org-attach-git/use-annex ()
   (test-org-attach-annex/with-annex
    (let ((org-attach-git-annex-cutoff 1))
      (should (org-attach-use-annex)))
@@ -44,12 +44,12 @@
   (let ((tmpdir (make-temp-file "org-annex-test" t "/")))
      (unwind-protect
 	 (let ((default-directory tmpdir)
-	       (org-attach-directory tmpdir))
+	       (org-attach-id-dir tmpdir))
 	   (shell-command "git init")
 	   (should-not (org-attach-use-annex)))
        (delete-directory tmpdir 'recursive))))
 
-(ert-deftest test-org-attach/get-maybe ()
+(ert-deftest test-org-attach-git/get-maybe ()
   (test-org-attach-annex/with-annex
    (let ((path (expand-file-name "test-file"))
 	 (annex-dup (make-temp-file "org-annex-test" t "/")))
diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el
index c2f2be356..5bcfe86fd 100644
--- a/testing/lisp/test-org-attach.el
+++ b/testing/lisp/test-org-attach.el
@@ -28,6 +28,75 @@
 (require 'org-attach)
 (eval-and-compile (require 'cl-lib))
 
+(ert-deftest test-org-attach/dir ()
+  "Test `org-attach-get' specifications."
+  (should (equal "Text in fileA\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 157) ;; First attachment link
+		   (org-open-at-point)
+		   (buffer-string))))
+  (should-not (equal "Text in fileB\n"
+		     (org-test-in-example-file org-test-attachments-file
+		       (goto-char 219) ;; Second attachment link
+		       (let ((org-attach-use-inheritance nil))
+			 (org-open-at-point)
+			 (buffer-string)))))
+  (should (equal "Text in fileB\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 219) ;; Second attachment link
+		   (let ((org-attach-use-inheritance t))
+		     (org-open-at-point)
+		     (buffer-string)))))
+  (should-not (equal "att1"
+		     (org-test-in-example-file org-test-attachments-file
+		       (goto-char 179) ;; H1.1
+		       (let ((org-attach-use-inheritance nil))
+			 (org-attach-dir)))))
+  (should (equal "att1"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 179) ;; H1.1
+		   (let ((org-attach-use-inheritance t))
+		     (org-attach-dir)))))
+  (should (equal '("fileC" "fileD")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 239) ;; H1.2
+		   (org-attach-file-list (org-attach-dir)))))
+  (should (equal '("fileC" "fileD")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 239) ;; H1.2
+		   (org-attach-file-list (org-attach-dir)))))
+  (should (equal '("fileE")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 289) ;; H2
+		   (let ((org-attach-id-dir "data/"))
+		     (org-attach-file-list (org-attach-dir))))))
+  (should (equal "peek-a-boo\n"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 289) ;; H2
+		   (let ((org-attach-id-dir "data/"))
+		     (org-attach-open-in-emacs)
+		     (buffer-string)))))
+  (should (equal  '("fileA" "fileB")
+		  (org-test-in-example-file org-test-attachments-file
+		    (goto-char 336) ;; H3
+		    (org-attach-file-list (org-attach-dir)))))
+  (should (equal "data/ab/cd12345"
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 401) ;; H3.1
+		   (let ((org-attach-use-inheritance nil)
+			 (org-attach-id-dir "data/"))
+		     (file-relative-name (org-attach-dir))))))
+  (should (equal '("fileA" "fileB")
+		 (org-test-in-example-file org-test-attachments-file
+		   (goto-char 401) ;; H3.1
+		   (let ((org-attach-use-inheritance t))
+		     ;; This is where it get's a bit sketchy...! DIR always has
+		     ;; priority over ID, even if ID is declared "higher up" in the
+		     ;; tree.  This can potentially be revised.  But it is also
+		     ;; pretty clean.  DIR is always higher in priority than ID right
+		     ;; now, no matter the depth in the tree.
+		     (org-attach-file-list (org-attach-dir)))))))
+
 (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 ()
   "Attach file at point in dired to subtree."
   (should
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index d671b5c78..a618da479 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -2514,7 +2514,11 @@ Foo Bar
      (catch :result
        (cl-letf (((symbol-function 'org-tags-view)
 		  (lambda (&rest args) (throw :result t))))
-	 (org-open-at-point)
+	 ;; When point isn't on a tag it's going to try other things,
+	 ;; possibly trying to open attachments which will return an
+	 ;; error if there isn't an attachment. Supress that error.
+	 (ignore-errors
+	     (org-open-at-point))
 	 nil)))))
 
 \f
diff --git a/testing/org-test.el b/testing/org-test.el
index 295df1919..c3e21eb30 100644
--- a/testing/org-test.el
+++ b/testing/org-test.el
@@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.")
 (defconst org-test-no-heading-file
   (expand-file-name "no-heading.org" org-test-example-dir))
 
+(defconst org-test-attachments-file
+  (expand-file-name "attachments.org" org-test-example-dir))
+
 (defconst org-test-link-in-heading-file
   (expand-file-name "link-in-heading.org" org-test-dir))
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-07 18:38                     ` Gustav Wikström
@ 2019-07-08 10:47                       ` Marco Wahl
  2019-07-09 10:16                       ` Nicolas Goaziou
  2019-07-27 14:56                       ` Ihor Radchenko
  2 siblings, 0 replies; 113+ messages in thread
From: Marco Wahl @ 2019-07-08 10:47 UTC (permalink / raw)
  To: emacs-orgmode

Hi Gustav and all,

Thanks for the refreshment of the org attach universe.

In particular I like the new attachment type for links.  I'd like to
express my favorability to use the name "att" opposed to "attachment" to
specify that type.


Thanks for reading, best regards,  Marco

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-07 18:38                     ` Gustav Wikström
  2019-07-08 10:47                       ` Marco Wahl
@ 2019-07-09 10:16                       ` Nicolas Goaziou
  2019-07-27 14:56                       ` Ihor Radchenko
  2 siblings, 0 replies; 113+ messages in thread
From: Nicolas Goaziou @ 2019-07-09 10:16 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Final patches attached for full disclosure before applying them.

I see you applied your patches. Thank you.

Just some remarks:

- "Capture, Attachments, RSS Feeds and Protocols" is too long: we ought
  to find a shorter title,
- Sub-nodes behind "Attachments" have no description. The should have
  one, unless they are not meant to appear in the toc, in which case,
  you should set "UNNUMBERED" property to "notoc".

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-07 18:38                     ` Gustav Wikström
  2019-07-08 10:47                       ` Marco Wahl
  2019-07-09 10:16                       ` Nicolas Goaziou
@ 2019-07-27 14:56                       ` Ihor Radchenko
  2019-07-28 20:39                         ` Gustav Wikström
  2 siblings, 1 reply; 113+ messages in thread
From: Ihor Radchenko @ 2019-07-27 14:56 UTC (permalink / raw)
  To: Gustav Wikström, Nicolas Goaziou; +Cc: emacs-orgmode

Hi,

> ATTACH_DIR_INHERIT is no longer supported and is +removed.

I just found that removing ATTACH_DIR_INHERIT broke my current
configuration. I do not use ATTACH_DIR property - all the attachment
folders are created using ID. Also, I use ID property to store links to
entries. Therefore, inheriting ATTACH_DIR does nothing for me and
inheriting ID always gives the current entry's id value. At the end, I
cannot make a common attachment directory for the whole subtree, like I
was able to do with ATTACH_DIR_INHERIT.

Regards,
Ihor


Gustav Wikström <gustav@whil.se> writes:

> Hi!
>
>> > +	(if should-get
>> > +	    (progn (message "Running git annex get \"%s\"." path-relative)
>> > +		   (call-process "git" nil nil nil "annex" "get" path-relative))
>> > +	  (error "File %s stored in git annex but it is not available, and was not
>> retrieved"
>> > +		 path))))))
>> 
>> Nitpick:
>> 
>>     (unless should-get
>>      (error "File %S stored in git annex but unavailable" path))
>>     (message "Running git annex get %S." path-relative)
>>     (call-process ...)
>
> Ok, fixed.
>
>> > +Selective means to respect the inheritance setting in
>> > +`org-use-property-inheritance'."
>> >    :group 'org-attach
>> > +  :type '(choice
>> > +	  (const :tag "Don't use inheritance" nil)
>> > +	  (const :tag "Inherit parent node attachments" t)
>> > +	  (const :tag "Respect org-use-property-inheritance" selective)
>> > +	  )
>> 
>> Dangling paren spotted.
>
> Fixed.
>
>> > +      (setq attachment (or (org-attach-dir)
>> > +			   (quote  "Can't find an existing attachment-folder")))
>> 
>> You forgot to remove that weird quote. Maybe you meant `error'?
>
> Hmm, actually no. But the code is pretty bad so I've refactored it a
> bit. The purpose of the change is for org-attach to give an indication
> of the active attachment path, or to signal that there is none. But
> for that I don't really need a separate variable. Thus it's slightly
> refactored for code-clarity.
>
>> > +    (if attach-dir
>> > +	(progn (if (not (file-directory-p attach-dir))
>> > +		   (make-directory attach-dir t))
>> > +	       attach-dir)
>> > +      (error "No attachment directory is associated with the current node"))))
>> 
>> Same nitpick as above:
>> 
>>     (unless attach-dir
>>      (error "No attachment ..."))
>>     (if (file-directory-p attach-dir) attach-dir
>>       (make-directory attach-dir))
>
> Ok, fixed.
>
>> > +(defun org-attach-dir-from-id (id)
>> > +  "Creates a path 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)))
>> 
>> Creates path -> Return a file name.
>
> Fixed.
>
>> > +of the entry.  Creates relative links if `org-attach-dir-relative'
>> > +is t.
>> 
>> Nitpick:
>> 
>>   is t -> is non-nil.
>
> Ah, true. Fixed.
>
>> If tests pass, feel free to apply the patches in master. Thank you!
>
> Got it. Aaand one test failure. That test is unrelated to my changes
> though, and fails also on master. Test-org-table/copy-down. So I'll
> try to apply my patch asap regardless of that one test failing.
>
> Just one more thing - a few days back I added a row to lisp/ox-html.el
> regarding inline-images. I'm including that change as well since it
> relates 100% to the new attachment link. I looked in the other
> export-backends too but didn't add anything due to lack of time for
> testing. Maybe the additions for other backends is as trivial as for
> html. So someone who regularly export to those backends might want to
> suggest patches for them to make attachment links to images actually
> display as images? 

>
> Final patches attached for full disclosure before applying them.
>
>> 
>> Regards,
>> 
>> --
>> Nicolas Goaziou
> From 3cbe356b0a9d1a98848df0fa09ba306392995b88 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
> Date: Sun, 26 May 2019 03:34:34 +0200
> Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox,
>  test-property-inheritance
>
> * org-test.el:
>
> Fix org-test-with-temp-text-in-file.  Make it work with <point>, as
> some tests already expect it to do!  Also make it fail more gracefully
> by still removing temporary buffers and files.
>
> Improve org-test-in-example-file.  Make it behave similar to
> org-test-with-temp-text and org-test-with-temp-text-in-file, in that
> it will return the last evaluated expression.
>
> * testing/lisp/test-org-element.el
>
> Fix a temp-text strings so that it doesn't have an initial newline.
>
> * testing/lisp/test-org.el
>
> Minor cleanup to align code-structure with other tests.  Nothing
> changes in the test execpt style.
>
> * testing/lisp/test-ox.el
>
> Fix a couple of temp-text strings so that they don't have initial
> newlines.
>
> ** test-org-export/expand-include
>
> Test specification was wrong, due to org-test-with-temp-text-in-file
> not previously working with <point>.  Since that is fixed in this
> patch the test needed to be updated to match the expected outcome.
>
> * testing/lisp/test-property-inheritance.el
>
> Fix wrong file-header and file-ending.
> ---
>  testing/lisp/test-org-element.el          |  4 +--
>  testing/lisp/test-org.el                  | 12 +++----
>  testing/lisp/test-ox.el                   | 30 ++++++++--------
>  testing/lisp/test-property-inheritance.el |  4 +--
>  testing/org-test.el                       | 44 ++++++++++++++---------
>  5 files changed, 53 insertions(+), 41 deletions(-)
>
> diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
> index 04f97f97a..f2ab38031 100644
> --- a/testing/lisp/test-org-element.el
> +++ b/testing/lisp/test-org-element.el
> @@ -3264,8 +3264,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
>  
>  (ert-deftest test-org-element/granularity ()
>    "Test granularity impact on buffer parsing."
> -  (org-test-with-temp-text "
> -* Head 1
> +  (org-test-with-temp-text
> +      "* Head 1
>  ** Head 2
>  #+BEGIN_CENTER
>  Centered paragraph.
> diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
> index abc004689..d671b5c78 100644
> --- a/testing/lisp/test-org.el
> +++ b/testing/lisp/test-org.el
> @@ -5060,18 +5060,18 @@ Paragraph<point>"
>    (should
>     (equal
>      "1"
> -    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> -      (org-entry-get (point) "A" t))))
> +    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
> +      (org-entry-get (point-max) "A" t))))
>    (should
>     (equal
>      "1"
> -    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> +    (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
>        (let ((org-use-property-inheritance t))
> -	(org-entry-get (point) "A" 'selective)))))
> +	(org-entry-get (point-max) "A" 'selective)))))
>    (should-not
> -   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2"
> +   (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2"
>       (let ((org-use-property-inheritance nil))
> -       (org-entry-get (point) "A" 'selective))))
> +       (org-entry-get (point-max) "A" 'selective))))
>    (should
>     (equal
>      "1 2"
> diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
> index 2c2778f82..b8c507e0b 100644
> --- a/testing/lisp/test-ox.el
> +++ b/testing/lisp/test-ox.el
> @@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
>  	       org-test-dir)
>       (narrow-to-region (point) (point-max))
>       (org-export-expand-include-keyword)
> -     (eq 1 (org-current-level))))
> +     (eq 2 (org-current-level))))
>    ;; If :minlevel is present do not alter it.
>    (should
>     (org-test-with-temp-text
> @@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after
>  comments removal."
>    (should
>     (equal "Para1\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -Para1
> +	  (org-test-with-temp-text
> +	      "Para1
>  # Comment
>  
>  # Comment
> @@ -2012,15 +2012,15 @@ Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "Para1\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -Para1
> +	  (org-test-with-temp-text
> +	      "Para1
>  # Comment
>  Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "[fn:1] Para1\n\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -\[fn:1] Para1
> +	  (org-test-with-temp-text
> +	      "[fn:1] Para1
>  # Inside definition
>  
>  
> @@ -2029,8 +2029,8 @@ Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "[fn:1] Para1\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -\[fn:1] Para1
> +	  (org-test-with-temp-text
> +	      "[fn:1] Para1
>  
>  # Inside definition
>  
> @@ -2040,24 +2040,24 @@ Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "[fn:1] Para1\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -\[fn:1] Para1
> +	  (org-test-with-temp-text
> +	      "[fn:1] Para1
>  # Inside definition
>  
>  Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "[fn:1] Para1\n\nPara2\n"
> -	  (org-test-with-temp-text "
> -\[fn:1] Para1
> +	  (org-test-with-temp-text
> +	      "[fn:1] Para1
>  
>  # Inside definition
>  Para2"
>  	    (org-export-as (org-test-default-backend)))))
>    (should
>     (equal "- item 1\n\n- item 2\n"
> -	  (org-test-with-temp-text "
> -- item 1
> +	  (org-test-with-temp-text
> +	      "- item 1
>  
>    # Comment
>  
> diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el
> index 0f803e5f7..1d0dcfbe1 100644
> --- a/testing/lisp/test-property-inheritance.el
> +++ b/testing/lisp/test-property-inheritance.el
> @@ -1,4 +1,4 @@
> -;;; test-ob-R.el --- tests for ob-R.el
> +;;; test-property-inheritance.el --- tests for property-inheritance.el
>  
>  ;; Copyright (c) 2011-2014, 2019 Eric Schulte
>  ;; Authors: Eric Schulte
> @@ -47,4 +47,4 @@
>  
>  (provide 'test-ob-R)
>  
> -;;; test-ob-R.el ends here
> +;;; test-property-inheritance.el ends here
> diff --git a/testing/org-test.el b/testing/org-test.el
> index 39c346410..295df1919 100644
> --- a/testing/org-test.el
> +++ b/testing/org-test.el
> @@ -146,7 +146,8 @@ currently executed.")
>    (declare (indent 1))
>    `(let* ((my-file (or ,file org-test-file))
>  	  (visited-p (get-file-buffer my-file))
> -	  to-be-removed)
> +	  to-be-removed
> +	  results)
>       (save-window-excursion
>         (save-match-data
>  	 (find-file my-file)
> @@ -160,9 +161,10 @@ currently executed.")
>  	       (org-show-subtree)
>  	       (org-show-all '(blocks)))
>  	   (error nil))
> -	 (save-restriction ,@body)))
> +	 (setq results (save-restriction ,@body))))
>       (unless visited-p
> -       (kill-buffer to-be-removed))))
> +       (kill-buffer to-be-removed))
> +     results))
>  (def-edebug-spec org-test-in-example-file (form body))
>  
>  (defmacro org-test-at-marker (file marker &rest body)
> @@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text."
>  (def-edebug-spec org-test-with-temp-text (form body))
>  
>  (defmacro org-test-with-temp-text-in-file (text &rest body)
> -  "Run body in a temporary file buffer with Org mode as the active mode."
> +  "Run body in a temporary file buffer with Org mode as the active mode.
> +If the string \"<point>\" appears in TEXT then remove it and
> +place the point there before running BODY, otherwise place the
> +point at the beginning of the buffer."
>    (declare (indent 1))
> -  (let ((results (cl-gensym)))
> -    `(let ((file (make-temp-file "org-test"))
> -	   (kill-buffer-query-functions nil)
> -	   (inside-text (if (stringp ,text) ,text (eval ,text)))
> -	   ,results)
> -       (with-temp-file file (insert inside-text))
> -       (find-file file)
> -       (org-mode)
> -       (setq ,results (progn ,@body))
> -       (save-buffer) (kill-buffer (current-buffer))
> -       (delete-file file)
> -       ,results)))
> +  `(let ((file (make-temp-file "org-test"))
> +	 (inside-text (if (stringp ,text) ,text (eval ,text)))
> +	 buffer)
> +     (with-temp-file file (insert inside-text))
> +     (unwind-protect
> +	 (progn
> +	   (setq buffer (find-file file))
> +	   (when (re-search-forward "<point>" nil t)
> +	     (replace-match ""))
> +	   (org-mode)
> +	   (progn ,@body))
> +       (let ((kill-buffer-query-functions nil))
> +	 (when buffer
> +	   (set-buffer buffer)
> +	   ;; Ignore changes, we're deleting the file in the next step
> +	   ;; anyways.
> +	   (set-buffer-modified-p nil)
> +	   (kill-buffer))
> +	 (delete-file file)))))
>  (def-edebug-spec org-test-with-temp-text-in-file (form body))
>  
>  (defun org-test-table-target-expect (target &optional expect laps
> -- 
> 2.17.1
>
> From ae9cd4370b4daaaca7bc53923d5e438c08955e48 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se>
> Date: Sun, 25 Nov 2018 21:38:44 +0100
> Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, ox-html,
>  testing/*
>
> * lisp/org-attach.el
>
> Changed the way attachments deal with property-inheritance.  It now
> adheres to the =org-use-property-inheritance= setting by default but
> it can be customized if needed (I recommend to enable it!).
> The property ATTACH_DIR is deprecated in favour of the shorter and simpler
> property DIR.
>
> Added an explicit option to =org-attach= for unsetting
> attachment-directories (i.e. remove DIR property and deal with the
> attachments by interaction).
>
> Added attachment link type with the prefix "attachment:".
>
> Added customizations:
> - org-attach-dir-relative
> - org-attach-preferred-new-method
> - org-attach-use-inheritance
> - org-attach-id-to-path-function
>
> Hooks added:
> - org-attach-after-change-hook
> - org-attach-open-hook
>
> A new linktype "attachment" is added in order to reduce
> link-duplication when wanting to link to files in attached folders of
> nodes.  This works for both ID and DIR properties.  The goal is to
> make the functionality for attachment links mirror the functionality
> for file links.
>
> * lisp/org-attach-git.el
>
> New file, existing functionality.  Code here has been factored out
> from org-attach.el and if GIT-functionality is to be used this module
> needs to be required sepatately.  It extends org-attach by use of its
> hooks.
>
> Activating git functionality in org-attach is done by loading
> org-attach-git from now on, instead of customizing a variable.
>
> Naming of both functions and tests has been modified to match the move
> of functionality into its own module.
>
> * lisp/org.el
>
> Inline images are shown also using attachment-links, exactly the same
> as it works for file-links today.
>
> Make org-open-at-point respect ARG when opening attachment-dir.
>
> * lisp/org-compat.el
>
> org-attach-directory has been deprecated in favour for
> org-attach-id-dir.  The new name matches its purpose better.
>
> * lisp/ox-html.el
>
> Export attachment links to images as inline images, in the same way as
> file links work today.
>
> * etc/ORG-NEWS
>
> Mention the changes in this patch.
>
> * doc/org-manual.org
>
> The chapter "Refile, Copy, Archive" has been split into two separate
> chapters.
> - "Refile, Copy and Archiving" for information related to moving
>   existing data around.
>
> - "Capture, Attachments, RSS Feeds and Protocols" for information
>   related to working with external data.
>
> The attachment-part has been rewritten and extended to match the
> changes in this patch.
>
> The new attachment link type is mentioned both inside the attachments
> chapter and in the chapter dealing with links.
>
> Documentation related to external links has been improved.
>
> * testing/lisp/test-org-attach-annex.el
>
> Require org-attach-git instead of org-attach, since this file tests
> the GIT-functionality.
>
> * testing/lisp/test-org-attach.el
>
> Add tests for org-attach.
>
> * testing/org-test.el
>
> Define a symbol for a file to test attachments with.
>
> * testing/examples/*
>
> A bunch of new example files and folders are created and are used in
> testing of org-attach to verify its functionality.
> ---
>  doc/org-manual.org                            | 1079 ++++++++++-------
>  etc/ORG-NEWS                                  |   94 ++
>  lisp/org-attach-git.el                        |  117 ++
>  lisp/org-attach.el                            |  561 +++++----
>  lisp/org-compat.el                            |    3 +
>  lisp/org.el                                   |   23 +-
>  lisp/ox-html.el                               |    1 +
>  testing/examples/att1/fileA                   |    1 +
>  testing/examples/att1/fileB                   |    1 +
>  testing/examples/att2/fileC                   |    1 +
>  testing/examples/att2/fileD                   |    1 +
>  testing/examples/attachments.org              |   32 +
>  testing/examples/data/ab/cd123/fileE          |    1 +
>  ...attach-annex.el => test-org-attach-git.el} |   12 +-
>  testing/lisp/test-org-attach.el               |   69 ++
>  testing/lisp/test-org.el                      |    6 +-
>  testing/org-test.el                           |    3 +
>  17 files changed, 1307 insertions(+), 698 deletions(-)
>  create mode 100644 lisp/org-attach-git.el
>  create mode 100644 testing/examples/att1/fileA
>  create mode 100644 testing/examples/att1/fileB
>  create mode 100644 testing/examples/att2/fileC
>  create mode 100644 testing/examples/att2/fileD
>  create mode 100644 testing/examples/attachments.org
>  create mode 100644 testing/examples/data/ab/cd123/fileE
>  rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%)
>
> diff --git a/doc/org-manual.org b/doc/org-manual.org
> index 8318e7cdc..e81b76f14 100644
> --- a/doc/org-manual.org
> +++ b/doc/org-manual.org
> @@ -3071,6 +3071,7 @@ point on or at a target.
>  #+cindex: irc links
>  #+cindex: URL links
>  #+cindex: file links
> +#+cindex: attachment links
>  #+cindex: Rmail links
>  #+cindex: MH-E links
>  #+cindex: Usenet links
> @@ -3082,38 +3083,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB
>  database entries and links to both IRC conversations and their logs.
>  External links are URL-like locators.  They start with a short
>  identifying string followed by a colon.  There can be no space after
> -the colon.  The following list shows examples for each link type.
> -
> -| =https://staff.science.uva.nl/c.dominik/= | on the web                     |
> -| =doi:10.1000/182=                         | DOI for an electronic resource |
> -| =file:/home/dominik/images/jupiter.jpg=   | file, absolute path            |
> -| =/home/dominik/images/jupiter.jpg=        | same as above                  |
> -| =file:papers/last.pdf=                    | file, relative path            |
> -| =./papers/last.pdf=                       | same as above                  |
> -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine   |
> -| =/ssh:me@some.where:papers/last.pdf=      | same as above                  |
> -| =file:sometextfile::NNN=                  | file, jump to line number      |
> -| =file:projects.org=                       | another Org file               |
> -| =file:projects.org::some words=           | text search in Org file[fn:27] |
> -| =file:projects.org::*task title=          | heading search in Org file     |
> -| =file+sys:/path/to/file=                  | open via OS, like double-click |
> -| =file+emacs:/path/to/file=                | force opening by Emacs         |
> -| =docview:papers/last.pdf::NNN=            | open in doc-view mode at page  |
> -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID          |
> -| =news:comp.emacs=                         | Usenet link                    |
> -| =mailto:adent@galaxy.net=                 | mail link                      |
> -| =mhe:folder=                              | MH-E folder link               |
> -| =mhe:folder#id=                           | MH-E message link              |
> -| =rmail:folder=                            | Rmail folder link              |
> -| =rmail:folder#id=                         | Rmail message link             |
> -| =gnus:group=                              | Gnus group link                |
> -| =gnus:group#id=                           | Gnus article link              |
> -| =bbdb:R.*Stallman=                        | BBDB link (with regexp)        |
> -| =irc:/irc.com/#emacs/bob=                 | IRC link                       |
> -| =info:org#External links=                 | Info node link                 |
> -| =shell:ls *.org=                          | shell command                  |
> -| =elisp:org-agenda=                        | interactive Elisp command      |
> -| =elisp:(find-file "Elisp.org")=           | Elisp form to evaluate         |
> +the colon.
> +
> +Here is the full set of built-in link types:
> +
> +- =file= ::
> +
> +   File links.  File name may be remote, absolute, or relative.
> +
> +   Additionally, you can specify a line number, or a text search.
> +   In Org files, you may link to a headline name, a custom ID, or a
> +   code reference instead.
> +
> +   As a special case, "file" prefix may be omitted if the file name
> +   is complete, e.g., it starts with =./=, or =/=.
> +
> +- =attachment= ::
> +
> +  Same as file links but for files and folders attached to the current
> +  node (see [[*Attachments]]).  Attachment links are intended to behave
> +  exactly as file links but for files relative to the attachment
> +  directory.
> +
> +- =bbdb= ::
> +
> +  Link to a BBDB record, with possible regexp completion.
> +
> +- =docview= ::
> +
> +  Link to a document opened with DocView mode.  You may specify a page
> +  number.
> +
> +- =doi= ::
> +
> +  Link to an electronic ressource, through its handle.
> +
> +- =elisp= ::
> +
> +  Execute an Elisp command upon activation.
> +
> +- =gnus=, =rmail=, =mhe= ::
> +
> +  Links to messages or folders from a given Emacs' MUA.
> +
> +- =http=, =https= ::
> +
> +  Web links.
> +
> +- =id= ::
> +
> +  Link to a specific headline by its ID property, in an Org file.
> +
> +- =info= ::
> +
> +  Link to an Info manual, or to a specific node.
> +
> +- =irc= ::
> +
> +  Link to an IRC channel.
> +
> +- =mailto= ::
> +
> +  Link to message composition.
> +
> +- =news= ::
> +
> +  Usenet links.
> +
> +- =shell= ::
> +
> +  Execute a shell command upon activation.
> +
> +The following table illustrates the link types above, along with their
> +options:
> +
> +| Link Type  | Example                                                  |
> +|------------+----------------------------------------------------------|
> +| http       | =http://staff.science.uva.nl/c.dominik/=                 |
> +| https      | =https://orgmode.org/=                                   |
> +| doi        | =doi:10.1000/182=                                        |
> +| file       | =file:/home/dominik/images/jupiter.jpg=                  |
> +|            | =/home/dominik/images/jupiter.jpg= (same as above)       |
> +|            | =file:papers/last.pdf=                                   |
> +|            | =./papers/last.pdf= (same as above)                      |
> +|            | =file:/ssh:me@some.where:papers/last.pdf= (remote)       |
> +|            | =/ssh:me@some.where:papers/last.pdf= (same as above)     |
> +|            | =file:sometextfile::NNN= (jump to line number)           |
> +|            | =file:projects.org=                                      |
> +|            | =file:projects.org::some words= (text search) [fn:28]    |
> +|            | =file:projects.org::*task title= (headline search)       |
> +|            | =file:projects.org::#custom-id= (headline search)        |
> +| attachment | =attachment:projects.org=                                |
> +|            | =attachment:projects.org::some words= (text search)      |
> +| docview    | =docview:papers/last.pdf::NNN=                           |
> +| id         | =id:B7423F4D-2E8A-471B-8810-C40F074717E9=                |
> +| news       | =news:comp.emacs=                                        |
> +| mailto     | =mailto:adent@galaxy.net=                                |
> +| mhe        | =mhe:folder= (folder link)                               |
> +|            | =mhe:folder#id= (message link)                           |
> +| rmail      | =rmail:folder= (folder link)                             |
> +|            | =rmail:folder#id= (message link)                         |
> +| gnus       | =gnus:group= (group link)                                |
> +|            | =gnus:group#id= (article link)                           |
> +| bbdb       | =bbdb:R.*Stallman= (record with regexp)                  |
> +| irc        | =irc:/irc.com/#emacs/bob=                                |
> +| info       | =info:org#External links=                                |
> +| shell      | =shell:ls *.org=                                         |
> +| elisp      | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) |
> +|            | =elisp:org-agenda= (interactive Elisp command)           |
>  
>  #+cindex: VM links
>  #+cindex: Wanderlust links
> @@ -3465,15 +3542,19 @@ the link completion function like this:
>  :END:
>  #+cindex: search option in file links
>  #+cindex: file links, searching
> +#+cindex: attachment links, searching
>  
> -File links can contain additional information to make Emacs jump to
> -a particular location in the file when following a link.  This can be
> -a line number or a search option after a double colon[fn:34].  For
> +File links can contain additional information to make Emacs jump to a
> +particular location in the file when following a link.  This can be a
> +line number or a search option after a double colon[fn:34].  For
>  example, when the command ~org-store-link~ creates a link (see
>  [[*Handling Links]]) to a file, it encodes the words in the current line
>  as a search string that can be used to find this line back later when
>  following the link with {{{kbd(C-c C-o)}}}.
>  
> +Note that all search options apply for Attachment links in the same
> +way that they apply for File links.
> +
>  Here is the syntax of the different ways to attach a search to a file
>  link, together with explanations for each:
>  
> @@ -3483,6 +3564,7 @@ link, together with explanations for each:
>  [[file:~/xx.org::*My Target]]
>  [[file:~/xx.org::#my-custom-id]]
>  [[file:~/xx.org::/regexp/]]
> +[[attachment:main.c::255]]
>  #+end_example
>  
>  - =255= ::
> @@ -6896,163 +6978,420 @@ same commands.
>    continue the old one.  This command also removes the timer from the
>    mode line.
>  
> -* Capture, Refile, Archive
> -:PROPERTIES:
> -:DESCRIPTION: The ins and outs for projects.
> -:END:
> -#+cindex: capture
> -
> -An important part of any organization system is the ability to quickly
> -capture new ideas and tasks, and to associate reference material with
> -them.  Org does this using a process called /capture/.  It also can
> -store files related to a task (/attachments/) in a special directory.
> -Once in the system, tasks and projects need to be moved around.
> -Moving completed project trees to an archive file keeps the system
> -compact and fast.
> -
> -** Capture
> +* Refile, Copy and Archiving
>  :PROPERTIES:
> -:DESCRIPTION: Capturing new stuff.
> +:DESCRIPTION: Moving and copying information with ease.
>  :END:
> -#+cindex: capture
> +#+cindex: refiling notes
> +#+cindex: copying notes
> +#+cindex: archiving
>  
> -Capture lets you quickly store notes with little interruption of your
> -work flow.  Org's method for capturing new items is heavily inspired
> -by John Wiegley's excellent Remember package.
> +Once information is in the system, it may need to be moved around.
> +Org provides Refile, Copy and Archive commands for this.  Refile and
> +Copy helps with moving and copying outlines.  Archiving helps to keep
> +the system compact and fast.
>  
> -*** Setting up capture
> +** Refile and Copy
>  :PROPERTIES:
> -:DESCRIPTION: Where notes will be stored.
> +:DESCRIPTION: Moving/copying a tree from one place to another.
>  :END:
> +#+cindex: refiling notes
> +#+cindex: copying notes
>  
> -The following customization sets a default target file for notes.
> +When reviewing the captured data, you may want to refile or to copy
> +some of the entries into a different list, for example into a project.
> +Cutting, finding the right location, and then pasting the note is
> +cumbersome.  To simplify this process, you can use the following
> +special command:
>  
> -#+vindex: org-default-notes-file
> -#+begin_src emacs-lisp
> -(setq org-default-notes-file (concat org-directory "/notes.org"))
> -#+end_src
> +- {{{kbd(C-c C-w)}}} (~org-refile~) ::
>  
> -You may also define a global key for capturing new material (see
> -[[*Activation]]).
> +  #+kindex: C-c C-w
> +  #+findex: org-refile
> +  #+vindex: org-reverse-note-order
> +  #+vindex: org-refile-targets
> +  #+vindex: org-refile-use-outline-path
> +  #+vindex: org-outline-path-complete-in-steps
> +  #+vindex: org-refile-allow-creating-parent-nodes
> +  #+vindex: org-log-refile
> +  Refile the entry or region at point.  This command offers possible
> +  locations for refiling the entry and lets you select one with
> +  completion.  The item (or all items in the region) is filed below
> +  the target heading as a subitem.  Depending on
> +  ~org-reverse-note-order~, it is either the first or last subitem.
>  
> -*** Using capture
> -:PROPERTIES:
> -:DESCRIPTION: Commands to invoke and terminate capture.
> -:END:
> +  By default, all level 1 headlines in the current buffer are
> +  considered to be targets, but you can have more complex definitions
> +  across a number of files.  See the variable ~org-refile-targets~ for
> +  details.  If you would like to select a location via
> +  a file-path-like completion along the outline path, see the
> +  variables ~org-refile-use-outline-path~ and
> +  ~org-outline-path-complete-in-steps~.  If you would like to be able
> +  to create new nodes as new parents for refiling on the fly, check
> +  the variable ~org-refile-allow-creating-parent-nodes~.  When the
> +  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
> +  recorded whenever an entry is refiled.
>  
> -- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
> +- {{{kbd(C-u C-c C-w)}}} ::
>  
> -  #+findex: org-capture
> -  #+cindex: date tree
> -  Display the capture templates menu.  If you have templates defined
> -  (see [[*Capture templates]]), it offers these templates for selection or
> -  use a new Org outline node as the default template.  It inserts the
> -  template into the target file and switch to an indirect buffer
> -  narrowed to this new node.  You may then insert the information you
> -  want.
> +  #+kindex: C-u C-c C-w
> +  Use the refile interface to jump to a heading.
>  
> -- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
> +- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
>  
> -  #+kindex: C-c C-c @r{(Capture buffer)}
> -  #+findex: org-capture-finalize
> -  Once you have finished entering information into the capture buffer,
> -  {{{kbd(C-c C-c)}}} returns you to the window configuration before
> -  the capture process, so that you can resume your work without
> -  further distraction.  When called with a prefix argument, finalize
> -  and then jump to the captured item.
> +  #+kindex: C-u C-u C-c C-w
> +  #+findex: org-refile-goto-last-stored
> +  Jump to the location where ~org-refile~ last moved a tree to.
>  
> -- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
> +- {{{kbd(C-2 C-c C-w)}}} ::
>  
> -  #+kindex: C-c C-w @r{(Capture buffer)}
> -  #+findex: org-capture-refile
> -  Finalize the capture process by refiling the note to a different
> -  place (see [[*Refile and Copy]]).  Please realize that this is a normal
> -  refiling command that will be executed---so point position at the
> -  moment you run this command is important.  If you have inserted
> -  a tree with a parent and children, first move point back to the
> -  parent.  Any prefix argument given to this command is passed on to
> -  the ~org-refile~ command.
> +  #+kindex: C-2 C-c C-w
> +  Refile as the child of the item currently being clocked.
>  
> -- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
> +- {{{kbd(C-3 C-c C-w)}}} ::
>  
> -  #+kindex: C-c C-k @r{(Capture buffer)}
> -  #+findex: org-capture-kill
> -  Abort the capture process and return to the previous state.
> +  #+kindex: C-3 C-c C-w
> +  #+vindex: org-refile-keep
> +  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
> +  make this the default behavior, and beware that this may result in
> +  duplicated =ID= properties.
>  
> -#+kindex: k c @r{(Agenda)}
> -You can also call ~org-capture~ in a special way from the agenda,
> -using the {{{kbd(k c)}}} key combination.  With this access, any
> -timestamps inserted by the selected capture template defaults to the
> -date at point in the agenda, rather than to the current date.
> +- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
>  
> -To find the locations of the last stored capture, use ~org-capture~
> -with prefix commands:
> +  #+kindex: C-u C-u C-u C-c C-w
> +  #+kindex: C-0 C-c C-w
> +  #+findex: org-refile-cache-clear
> +  #+vindex: org-refile-use-cache
> +  Clear the target cache.  Caching of refile targets can be turned on
> +  by setting ~org-refile-use-cache~.  To make the command see new
> +  possible targets, you have to clear the cache with this command.
>  
> -- {{{kbd(C-u M-x org-capture)}}} ::
> +- {{{kbd(C-c M-w)}}} (~org-copy~) ::
>  
> -  Visit the target location of a capture template.  You get to select
> -  the template in the usual way.
> +  #+kindex: C-c M-w
> +  #+findex: org-copy
> +  Copying works like refiling, except that the original note is not
> +  deleted.
>  
> -- {{{kbd(C-u C-u M-x org-capture)}}} ::
> +** Archiving
> +:PROPERTIES:
> +:DESCRIPTION: What to do with finished products.
> +:END:
> +#+cindex: archiving
>  
> -  Visit the last stored capture item in its buffer.
> +When a project represented by a (sub)tree is finished, you may want to
> +move the tree out of the way and to stop it from contributing to the
> +agenda.  Archiving is important to keep your working files compact and
> +global searches like the construction of agenda views fast.
>  
> -#+vindex: org-capture-bookmark
> -#+vindex: org-capture-last-stored
> -You can also jump to the bookmark ~org-capture-last-stored~, which is
> -automatically created unless you set ~org-capture-bookmark~ to ~nil~.
> +- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
>  
> -To insert the capture at point in an Org buffer, call ~org-capture~
> -with a {{{kbd(C-0)}}} prefix argument.
> +  #+kindex: C-c C-x C-a
> +  #+findex: org-archive-subtree-default
> +  #+vindex: org-archive-default-command
> +  Archive the current entry using the command specified in the
> +  variable ~org-archive-default-command~.
>  
> -*** Capture templates
> +*** Moving a tree to an archive file
>  :PROPERTIES:
> -:DESCRIPTION: Define the outline of different note types.
> +:DESCRIPTION: Moving a tree to an archive file.
> +:ALT_TITLE: Moving subtrees
>  :END:
> -#+cindex: templates, for Capture
> -
> -You can use templates for different types of capture items, and for
> -different target locations.  The easiest way to create such templates
> -is through the customize interface.
> +#+cindex: external archiving
>  
> -- {{{kbd(C)}}} ::
> +The most common archiving action is to move a project tree to another
> +file, the archive file.
>  
> -  #+kindex: C @r{(Capture menu}
> -  #+vindex: org-capture-templates
> -  Customize the variable ~org-capture-templates~.
> +- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
>  
> -Before we give the formal description of template definitions, let's
> -look at an example.  Say you would like to use one template to create
> -general TODO entries, and you want to put these entries under the
> -heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
> -the file =journal.org= should capture journal entries.  A possible
> -configuration would look like:
> +  #+kindex: C-c C-x C-s
> +  #+kindex: C-c $
> +  #+findex: org-archive-subtree
> +  #+vindex: org-archive-location
> +  Archive the subtree starting at point position to the location given
> +  by ~org-archive-location~.
>  
> -#+begin_src emacs-lisp
> -(setq org-capture-templates
> -      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
> -         "* TODO %?\n  %i\n  %a")
> -        ("j" "Journal" entry (file+datetree "~/org/journal.org")
> -         "* %?\nEntered on %U\n  %i\n  %a")))
> -#+end_src
> +- {{{kbd(C-u C-c C-x C-s)}}} ::
>  
> -If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
> -the template for you like this:
> +  #+kindex: C-u C-c C-x C-s
> +  Check if any direct children of the current headline could be moved
> +  to the archive.  To do this, check each subtree for open TODO
> +  entries.  If none is found, the command offers to move it to the
> +  archive location.  If point is /not/ on a headline when this command
> +  is invoked, check level 1 trees.
>  
> -#+begin_example
> -,* TODO
> -  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
> -#+end_example
> +- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
>  
> -#+texinfo: @noindent
> -During expansion of the template, =%a= has been replaced by a link to
> -the location from where you called the capture command.  This can be
> -extremely useful for deriving tasks from emails, for example.  You
> -fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
> -you to the same place where you started the capture process.
> +  #+kindex: C-u C-u C-c C-x C-s
> +  As above, but check subtree for timestamps instead of TODO entries.
> +  The command offers to archive the subtree if it /does/ contain
> +  a timestamp, and that timestamp is in the past.
>  
> -To define special keys to capture to a particular template without
> -going through the interactive template selection, you can create your
> +#+cindex: archive locations
> +The default archive location is a file in the same directory as the
> +current file, with the name derived by appending =_archive= to the
> +current file name.  You can also choose what heading to file archived
> +items under, with the possibility to add them to a datetree in a file.
> +For information and examples on how to specify the file and the
> +heading, see the documentation string of the variable
> +~org-archive-location~.
> +
> +There is also an in-buffer option for setting this variable, for
> +example:
> +
> +#+cindex: @samp{ARCHIVE}, keyword
> +: #+ARCHIVE: %s_done::
> +
> +#+cindex: ARCHIVE, property
> +If you would like to have a special archive location for a single
> +entry or a (sub)tree, give the entry an =ARCHIVE= property with the
> +location as the value (see [[*Properties and Columns]]).
> +
> +#+vindex: org-archive-save-context-info
> +When a subtree is moved, it receives a number of special properties
> +that record context information like the file from where the entry
> +came, its outline path the archiving time etc.  Configure the variable
> +~org-archive-save-context-info~ to adjust the amount of information
> +added.
> +
> +*** Internal archiving
> +:PROPERTIES:
> +:DESCRIPTION: Switch off a tree but keep it in the file.
> +:END:
> +
> +#+cindex: @samp{ARCHIVE}, tag
> +If you want to just switch off---for agenda views---certain subtrees
> +without moving them to a different file, you can use the =ARCHIVE=
> +tag.
> +
> +A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
> +its location in the outline tree, but behaves in the following way:
> +
> +-
> +  #+vindex: org-cycle-open-archived-trees
> +  It does not open when you attempt to do so with a visibility cycling
> +  command (see [[*Visibility Cycling]]).  You can force cycling archived
> +  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
> +  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
> +  ~outline-show-all~, open archived subtrees.
> +
> +-
> +  #+vindex: org-sparse-tree-open-archived-trees
> +  During sparse tree construction (see [[*Sparse Trees]]), matches in
> +  archived subtrees are not exposed, unless you configure the option
> +  ~org-sparse-tree-open-archived-trees~.
> +
> +-
> +  #+vindex: org-agenda-skip-archived-trees
> +  During agenda view construction (see [[*Agenda Views]]), the content of
> +  archived trees is ignored unless you configure the option
> +  ~org-agenda-skip-archived-trees~, in which case these trees are
> +  always included.  In the agenda you can press {{{kbd(v a)}}} to get
> +  archives temporarily included.
> +
> +-
> +  #+vindex: org-export-with-archived-trees
> +  Archived trees are not exported (see [[*Exporting]]), only the headline
> +  is.  Configure the details using the variable
> +  ~org-export-with-archived-trees~.
> +
> +-
> +  #+vindex: org-columns-skip-archived-trees
> +  Archived trees are excluded from column view unless the variable
> +  ~org-columns-skip-archived-trees~ is configured to ~nil~.
> +
> +The following commands help manage the =ARCHIVE= tag:
> +
> +- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
> +
> +  #+kindex: C-c C-x a
> +  #+findex: org-toggle-archive-tag
> +  Toggle the archive tag for the current headline.  When the tag is
> +  set, the headline changes to a shadowed face, and the subtree below
> +  it is hidden.
> +
> +- {{{kbd(C-u C-c C-x a)}}} ::
> +
> +  #+kindex: C-u C-c C-x a
> +  Check if any direct children of the current headline should be
> +  archived.  To do this, check each subtree for open TODO entries.  If
> +  none is found, the command offers to set the =ARCHIVE= tag for the
> +  child.  If point is /not/ on a headline when this command is
> +  invoked, check the level 1 trees.
> +
> +- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
> +
> +  #+kindex: C-TAB
> +  Cycle a tree even if it is tagged with =ARCHIVE=.
> +
> +- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
> +
> +  #+kindex: C-c C-x A
> +  #+findex: org-archive-to-archive-sibling
> +  Move the current entry to the /Archive Sibling/.  This is a sibling
> +  of the entry with the heading =Archive= and the archive tag.  The
> +  entry becomes a child of that sibling and in this way retains a lot
> +  of its original context, including inherited tags and approximate
> +  position in the outline.
> +
> +* Capture, Attachments, RSS Feeds and Protocols
> +:PROPERTIES:
> +:DESCRIPTION: Dealing with external data.
> +:END:
> +#+cindex: capture
> +#+cindex: attachments
> +#+cindex: RSS feeds
> +#+cindex: Atom feeds
> +#+cindex: protocols, for external access
> +
> +An important part of any organization system is the ability to quickly
> +capture new ideas and tasks, and to associate reference material with
> +them.  Org does this using a process called /capture/.  It also can
> +store files related to a task (/attachments/) in a special directory.
> +
> +** Capture
> +:PROPERTIES:
> +:DESCRIPTION: Capturing new stuff.
> +:END:
> +#+cindex: capture
> +
> +Capture lets you quickly store notes with little interruption of your
> +work flow.  Org's method for capturing new items is heavily inspired
> +by John Wiegley's excellent Remember package.
> +
> +*** Setting up capture
> +:PROPERTIES:
> +:DESCRIPTION: Where notes will be stored.
> +:END:
> +
> +The following customization sets a default target file for notes.
> +
> +#+vindex: org-default-notes-file
> +#+begin_src emacs-lisp
> +(setq org-default-notes-file (concat org-directory "/notes.org"))
> +#+end_src
> +
> +You may also define a global key for capturing new material (see
> +[[*Activation]]).
> +
> +*** Using capture
> +:PROPERTIES:
> +:DESCRIPTION: Commands to invoke and terminate capture.
> +:END:
> +
> +- {{{kbd(M-x org-capture)}}} (~org-capture~) ::
> +
> +  #+findex: org-capture
> +  #+cindex: date tree
> +  Display the capture templates menu.  If you have templates defined
> +  (see [[*Capture templates]]), it offers these templates for selection or
> +  use a new Org outline node as the default template.  It inserts the
> +  template into the target file and switch to an indirect buffer
> +  narrowed to this new node.  You may then insert the information you
> +  want.
> +
> +- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) ::
> +
> +  #+kindex: C-c C-c @r{(Capture buffer)}
> +  #+findex: org-capture-finalize
> +  Once you have finished entering information into the capture buffer,
> +  {{{kbd(C-c C-c)}}} returns you to the window configuration before
> +  the capture process, so that you can resume your work without
> +  further distraction.  When called with a prefix argument, finalize
> +  and then jump to the captured item.
> +
> +- {{{kbd(C-c C-w)}}} (~org-capture-refile~) ::
> +
> +  #+kindex: C-c C-w @r{(Capture buffer)}
> +  #+findex: org-capture-refile
> +  Finalize the capture process by refiling the note to a different
> +  place (see [[*Refile and Copy]]).  Please realize that this is a normal
> +  refiling command that will be executed---so point position at the
> +  moment you run this command is important.  If you have inserted
> +  a tree with a parent and children, first move point back to the
> +  parent.  Any prefix argument given to this command is passed on to
> +  the ~org-refile~ command.
> +
> +- {{{kbd(C-c C-k)}}} (~org-capture-kill~) ::
> +
> +  #+kindex: C-c C-k @r{(Capture buffer)}
> +  #+findex: org-capture-kill
> +  Abort the capture process and return to the previous state.
> +
> +#+kindex: k c @r{(Agenda)}
> +You can also call ~org-capture~ in a special way from the agenda,
> +using the {{{kbd(k c)}}} key combination.  With this access, any
> +timestamps inserted by the selected capture template defaults to the
> +date at point in the agenda, rather than to the current date.
> +
> +To find the locations of the last stored capture, use ~org-capture~
> +with prefix commands:
> +
> +- {{{kbd(C-u M-x org-capture)}}} ::
> +
> +  Visit the target location of a capture template.  You get to select
> +  the template in the usual way.
> +
> +- {{{kbd(C-u C-u M-x org-capture)}}} ::
> +
> +  Visit the last stored capture item in its buffer.
> +
> +#+vindex: org-capture-bookmark
> +#+vindex: org-capture-last-stored
> +You can also jump to the bookmark ~org-capture-last-stored~, which is
> +automatically created unless you set ~org-capture-bookmark~ to ~nil~.
> +
> +To insert the capture at point in an Org buffer, call ~org-capture~
> +with a {{{kbd(C-0)}}} prefix argument.
> +
> +*** Capture templates
> +:PROPERTIES:
> +:DESCRIPTION: Define the outline of different note types.
> +:END:
> +#+cindex: templates, for Capture
> +
> +You can use templates for different types of capture items, and for
> +different target locations.  The easiest way to create such templates
> +is through the customize interface.
> +
> +- {{{kbd(C)}}} ::
> +
> +  #+kindex: C @r{(Capture menu}
> +  #+vindex: org-capture-templates
> +  Customize the variable ~org-capture-templates~.
> +
> +Before we give the formal description of template definitions, let's
> +look at an example.  Say you would like to use one template to create
> +general TODO entries, and you want to put these entries under the
> +heading =Tasks= in your file =~/org/gtd.org=.  Also, a date tree in
> +the file =journal.org= should capture journal entries.  A possible
> +configuration would look like:
> +
> +#+begin_src emacs-lisp
> +(setq org-capture-templates
> +      '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks")
> +         "* TODO %?\n  %i\n  %a")
> +        ("j" "Journal" entry (file+datetree "~/org/journal.org")
> +         "* %?\nEntered on %U\n  %i\n  %a")))
> +#+end_src
> +
> +If you then press {{{kbd(t)}}} from the capture menu, Org will prepare
> +the template for you like this:
> +
> +#+begin_example
> +,* TODO
> +  [[file:LINK TO WHERE YOU INITIATED CAPTURE]]
> +#+end_example
> +
> +#+texinfo: @noindent
> +During expansion of the template, =%a= has been replaced by a link to
> +the location from where you called the capture command.  This can be
> +extremely useful for deriving tasks from emails, for example.  You
> +fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns
> +you to the same place where you started the capture process.
> +
> +To define special keys to capture to a particular template without
> +going through the interactive template selection, you can create your
>  key binding like this:
>  
>  #+begin_src emacs-lisp
> @@ -7437,28 +7776,30 @@ See the docstring of the variable for more information.
>  
>  ** Attachments
>  :PROPERTIES:
> -:DESCRIPTION: Add files to tasks.
> +:DESCRIPTION: Attach files to outlines.
>  :END:
>  #+cindex: attachments
> -#+vindex: org-attach-directory
>  
>  It is often useful to associate reference material with an outline
> -node/task.  Small chunks of plain text can simply be stored in the
> -subtree of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish
> -associations with files that live elsewhere on your computer or in the
> -cloud, like emails or source code files belonging to a project.
> -Another method is /attachments/, which are files located in
> -a directory belonging to an outline node.  Org uses directories named
> -by the unique ID of each entry.  These directories are located in the
> -=data/= directory which lives in the same directory where your Org
> -file lives[fn:87].  If you initialize this directory with =git init=,
> -Org automatically commits changes when it sees them.  The attachment
> -system has been contributed to Org by John Wiegley.
> -
> -In cases where it seems better to do so, you can attach a directory of
> -your choice to an entry.  You can also make children inherit the
> -attachment directory from a parent, so that an entire subtree uses the
> -same attached directory.
> +node.  Small chunks of plain text can simply be stored in the subtree
> +of a project.  Hyperlinks (see [[*Hyperlinks]]) can establish associations
> +with files that live elsewhere on your computer or in the cloud, like
> +emails or source code files belonging to a project.
> +
> +Another method is /attachments/, which are files located in a
> +directory belonging to an outline node.  Org uses directories either
> +named by a unique ID of each entry, or by a =DIR= property.
> +
> +*** Attachment defaults and dispatcher
> +By default, org-attach will use ID properties when adding attachments
> +to outline nodes.  This makes working with attachments fully
> +automated.  There is no decision needed for folder-name or location.
> +ID-based directories are by default located in the =data/= directory,
> +which lives in the same directory where your Org file lives[fn:87].
> +For more control over the setup, see [[*Attachment options]].
> +
> +When attachments are made using ~org-attach~ a default tag =ATTACH= is
> +added to the node that gets the attachments.
>  
>  The following commands deal with attachments:
>  
> @@ -7543,25 +7884,144 @@ The following commands deal with attachments:
>  
>    - {{{kbd(D)}}} (~org-attach-delete-all~) ::
>  
> -    #+kindex: C-c C-a D
> -    Delete all of a task's attachments.  A safer way is to open the
> -    directory in Dired and delete from there.
> +    #+kindex: C-c C-a D
> +    Delete all of a task's attachments.  A safer way is to open the
> +    directory in Dired and delete from there.
> +
> +  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
> +
> +    #+kindex: C-c C-a s
> +    #+cindex: @samp{DIR}, property
> +    Set a specific directory as the entry's attachment directory.
> +    This works by putting the directory path into the =DIR=
> +    property.
> +
> +  - {{{kbd(S)}}} (~org-attach-unset-directory~) ::
> +
> +    #+kindex: C-c C-a S
> +    #+cindex: @samp{DIR}, property
> +    Remove the attachment directory.  This command removes the =DIR=
> +    property and asks the user to either move content inside that
> +    folder, if an =ID= property is set, delete the content, or to
> +    leave the attachment directory as is but no longer attached to the
> +    outline node.
> +
> +*** Attachment options
> +There are a couple of options for attachments that are worth
> +mentioning.
> +
> +- ~org-attach-id-dir~ ::
> +  #+vindex: org-attach-id-dir
> +  The directory where attachments are stored when =ID= is used as
> +  method.
> +
> +- ~org-attach-dir-relative~ ::
> +  #+vindex: org-attach-dir-relative
> +  When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}}
> +  (~org-attach-set-directory~), absolute links are entered by default.
> +  This option changes that to relative links.
> +
> +- ~org-attach-use-inheritance~ ::
> +  #+vindex: org-attach-use-inheritance
> +  By default folders attached to an outline node are inherited from
> +  parents according to ~org-use-property-inheritance~.  If one instead
> +  want to set inheritance specifically for org-attach that can be done
> +  using ~org-attach-use-inheritance~.  Inheriting documents through
> +  the node hierarchy makes a lot of sense in most cases. Especially
> +  since the introduction of [[* Attachment links]].  The following example
> +  shows one use case for attachment inheritance:
> +
> +  #+begin_example
> +  ,* Chapter A ...
> +    :PROPERTIES:
> +    :DIR: Chapter A/
> +    :END:
> +  ,** Introduction
> +  Some text
> +
> +  #+NAME: Image 1
> +  [[Attachment:image 1.jpg]]
> +  #+end_example
> +
> +  Without inheritance one would not be able to resolve the link to
> +  image =1.jpg=, since the link is inside a sub-heading to =Chapter
> +  A=.
> +
> +  Inheritance works the same way for both =ID= and =DIR= property.  If
> +  both properties are defined on the same headline then =DIR= takes
> +  precedance.  This is also true if inheritance is enabled.  If =DIR=
> +  is inherited from a parent node in the outline, that property still
> +  takes precedence over an =ID= property defined on the node itself.
> +
> +- ~org-attach-method~ ::
> +  #+vindex: org-attach-method
> +  When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it
> +  defaults to copying files.  The behaviour can be changed by
> +  customizing ~org-attach-method~.  Options are Copy, Move/Rename,
> +  Hard link or Symbolic link.
> +
> +- ~org-attach-preferred-new-method~ ::
> +  #+vindex: org-attach-preferred-new-method
> +  This customization lets you choose the default way to attach to
> +  nodes without existing =ID= and =DIR= property.  It defaults to ~id~
> +  but can also be set to ~dir~, ~ask~ or ~nil~.
> +
> +- ~org-attach-archive-delete~ ::
> +  #+vindex: org-attach-archive-delete
> +  Configure this to determine if attachments should be deleted or not
> +  when a subtree that has attachments is archived.
> +
> +- ~org-attach-auto-tag~ ::
> +  #+vindex: org-attach-auto-tag
> +  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
> +  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!
> +
> +- ~org-attach-expert~ ::
> +  #+vindex: org-attach-expert
> +  Do not show the splash buffer with the attach dispatcher when
> +  ~org-attach-expert~ is set to non-~nil~.
> +
> +See customization group =Org Attach= if you want to change the
> +default settings.
> +
> +*** Attachment links
> +Attached files and folders can be referenced using attachment links.
> +This makes it easy to refer to the material added to an outline node.
> +Especially if it was attached using the unique ID of the entry!
> +
> +#+begin_example
> +,* TODO Some task
> +  :PROPERTIES:
> +  :ID:       95d50008-c12e-479f-a4f2-cc0238205319
> +  :END:
> +See attached document for more information: [[attachment:info.org]]
> +#+end_example
>  
> -  - {{{kbd(s)}}} (~org-attach-set-directory~) ::
> +See [[*External Links]] for more information about these links.
>  
> -    #+kindex: C-c C-a s
> -    #+cindex: @samp{ATTACH_DIR}, property
> -    Set a specific directory as the entry's attachment directory.
> -    This works by putting the directory path into the =ATTACH_DIR=
> -    property.
> +*** Automatic version-control with Git
> +If the directory attached to an outline node is a Git repository, Org
> +can be configured to automatically commit changes to that repository
> +when it sees them.
>  
> -  - {{{kbd(i)}}} (~org-attach-set-inherit~) ::
> +To make Org mode take care of versioning of attachments for you, add
> +the following to your Emacs config:
>  
> -    #+kindex: C-c C-a i
> -    #+cindex: @samp{ATTACH_DIR_INHERIT}, property
> -    Set the =ATTACH_DIR_INHERIT= property, so that children use the
> -    same directory for attachments as the parent does.
> +#+begin_src emacs-lisp
> +  (require 'org-attach-git)
> +#+end_src
>  
> +*** Attach from Dired
>  #+cindex: attach from Dired
>  #+findex: org-attach-dired-to-subtree
>  It is possible to attach files to a subtree from a Dired buffer.  To
> @@ -7832,249 +8292,6 @@ valid contents: ~org-protocol-create~ and
>  ~org-protocol-create-for-org~.  The latter is of use if you're editing
>  an Org file that is part of a publishing project.
>  
> -** Refile and Copy
> -:PROPERTIES:
> -:DESCRIPTION: Moving/copying a tree from one place to another.
> -:END:
> -#+cindex: refiling notes
> -#+cindex: copying notes
> -
> -When reviewing the captured data, you may want to refile or to copy
> -some of the entries into a different list, for example into a project.
> -Cutting, finding the right location, and then pasting the note is
> -cumbersome.  To simplify this process, you can use the following
> -special command:
> -
> -- {{{kbd(C-c C-w)}}} (~org-refile~) ::
> -
> -  #+kindex: C-c C-w
> -  #+findex: org-refile
> -  #+vindex: org-reverse-note-order
> -  #+vindex: org-refile-targets
> -  #+vindex: org-refile-use-outline-path
> -  #+vindex: org-outline-path-complete-in-steps
> -  #+vindex: org-refile-allow-creating-parent-nodes
> -  #+vindex: org-log-refile
> -  Refile the entry or region at point.  This command offers possible
> -  locations for refiling the entry and lets you select one with
> -  completion.  The item (or all items in the region) is filed below
> -  the target heading as a subitem.  Depending on
> -  ~org-reverse-note-order~, it is either the first or last subitem.
> -
> -  By default, all level 1 headlines in the current buffer are
> -  considered to be targets, but you can have more complex definitions
> -  across a number of files.  See the variable ~org-refile-targets~ for
> -  details.  If you would like to select a location via
> -  a file-path-like completion along the outline path, see the
> -  variables ~org-refile-use-outline-path~ and
> -  ~org-outline-path-complete-in-steps~.  If you would like to be able
> -  to create new nodes as new parents for refiling on the fly, check
> -  the variable ~org-refile-allow-creating-parent-nodes~.  When the
> -  variable ~org-log-refile~[fn:88] is set, a timestamp or a note is
> -  recorded whenever an entry is refiled.
> -
> -- {{{kbd(C-u C-c C-w)}}} ::
> -
> -  #+kindex: C-u C-c C-w
> -  Use the refile interface to jump to a heading.
> -
> -- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) ::
> -
> -  #+kindex: C-u C-u C-c C-w
> -  #+findex: org-refile-goto-last-stored
> -  Jump to the location where ~org-refile~ last moved a tree to.
> -
> -- {{{kbd(C-2 C-c C-w)}}} ::
> -
> -  #+kindex: C-2 C-c C-w
> -  Refile as the child of the item currently being clocked.
> -
> -- {{{kbd(C-3 C-c C-w)}}} ::
> -
> -  #+kindex: C-3 C-c C-w
> -  #+vindex: org-refile-keep
> -  Refile and keep the entry in place.  Also see ~org-refile-keep~ to
> -  make this the default behavior, and beware that this may result in
> -  duplicated =ID= properties.
> -
> -- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) ::
> -
> -  #+kindex: C-u C-u C-u C-c C-w
> -  #+kindex: C-0 C-c C-w
> -  #+findex: org-refile-cache-clear
> -  #+vindex: org-refile-use-cache
> -  Clear the target cache.  Caching of refile targets can be turned on
> -  by setting ~org-refile-use-cache~.  To make the command see new
> -  possible targets, you have to clear the cache with this command.
> -
> -- {{{kbd(C-c M-w)}}} (~org-copy~) ::
> -
> -  #+kindex: C-c M-w
> -  #+findex: org-copy
> -  Copying works like refiling, except that the original note is not
> -  deleted.
> -
> -** Archiving
> -:PROPERTIES:
> -:DESCRIPTION: What to do with finished products.
> -:END:
> -#+cindex: archiving
> -
> -When a project represented by a (sub)tree is finished, you may want to
> -move the tree out of the way and to stop it from contributing to the
> -agenda.  Archiving is important to keep your working files compact and
> -global searches like the construction of agenda views fast.
> -
> -- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) ::
> -
> -  #+kindex: C-c C-x C-a
> -  #+findex: org-archive-subtree-default
> -  #+vindex: org-archive-default-command
> -  Archive the current entry using the command specified in the
> -  variable ~org-archive-default-command~.
> -
> -*** Moving a tree to an archive file
> -:PROPERTIES:
> -:DESCRIPTION: Moving a tree to an archive file.
> -:ALT_TITLE: Moving subtrees
> -:END:
> -#+cindex: external archiving
> -
> -The most common archiving action is to move a project tree to another
> -file, the archive file.
> -
> -- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) ::
> -
> -  #+kindex: C-c C-x C-s
> -  #+kindex: C-c $
> -  #+findex: org-archive-subtree
> -  #+vindex: org-archive-location
> -  Archive the subtree starting at point position to the location given
> -  by ~org-archive-location~.
> -
> -- {{{kbd(C-u C-c C-x C-s)}}} ::
> -
> -  #+kindex: C-u C-c C-x C-s
> -  Check if any direct children of the current headline could be moved
> -  to the archive.  To do this, check each subtree for open TODO
> -  entries.  If none is found, the command offers to move it to the
> -  archive location.  If point is /not/ on a headline when this command
> -  is invoked, check level 1 trees.
> -
> -- {{{kbd(C-u C-u C-c C-x C-s)}}} ::
> -
> -  #+kindex: C-u C-u C-c C-x C-s
> -  As above, but check subtree for timestamps instead of TODO entries.
> -  The command offers to archive the subtree if it /does/ contain
> -  a timestamp, and that timestamp is in the past.
> -
> -#+cindex: archive locations
> -The default archive location is a file in the same directory as the
> -current file, with the name derived by appending =_archive= to the
> -current file name.  You can also choose what heading to file archived
> -items under, with the possibility to add them to a datetree in a file.
> -For information and examples on how to specify the file and the
> -heading, see the documentation string of the variable
> -~org-archive-location~.
> -
> -There is also an in-buffer option for setting this variable, for
> -example:
> -
> -#+cindex: @samp{ARCHIVE}, keyword
> -: #+ARCHIVE: %s_done::
> -
> -#+cindex: ARCHIVE, property
> -If you would like to have a special archive location for a single
> -entry or a (sub)tree, give the entry an =ARCHIVE= property with the
> -location as the value (see [[*Properties and Columns]]).
> -
> -#+vindex: org-archive-save-context-info
> -When a subtree is moved, it receives a number of special properties
> -that record context information like the file from where the entry
> -came, its outline path the archiving time etc.  Configure the variable
> -~org-archive-save-context-info~ to adjust the amount of information
> -added.
> -
> -*** Internal archiving
> -:PROPERTIES:
> -:DESCRIPTION: Switch off a tree but keep it in the file.
> -:END:
> -
> -#+cindex: @samp{ARCHIVE}, tag
> -If you want to just switch off---for agenda views---certain subtrees
> -without moving them to a different file, you can use the =ARCHIVE=
> -tag.
> -
> -A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at
> -its location in the outline tree, but behaves in the following way:
> -
> --
> -  #+vindex: org-cycle-open-archived-trees
> -  It does not open when you attempt to do so with a visibility cycling
> -  command (see [[*Visibility Cycling]]).  You can force cycling archived
> -  subtrees with {{{kbd(C-TAB)}}}, or by setting the option
> -  ~org-cycle-open-archived-trees~.  Also normal outline commands, like
> -  ~outline-show-all~, open archived subtrees.
> -
> --
> -  #+vindex: org-sparse-tree-open-archived-trees
> -  During sparse tree construction (see [[*Sparse Trees]]), matches in
> -  archived subtrees are not exposed, unless you configure the option
> -  ~org-sparse-tree-open-archived-trees~.
> -
> --
> -  #+vindex: org-agenda-skip-archived-trees
> -  During agenda view construction (see [[*Agenda Views]]), the content of
> -  archived trees is ignored unless you configure the option
> -  ~org-agenda-skip-archived-trees~, in which case these trees are
> -  always included.  In the agenda you can press {{{kbd(v a)}}} to get
> -  archives temporarily included.
> -
> --
> -  #+vindex: org-export-with-archived-trees
> -  Archived trees are not exported (see [[*Exporting]]), only the headline
> -  is.  Configure the details using the variable
> -  ~org-export-with-archived-trees~.
> -
> --
> -  #+vindex: org-columns-skip-archived-trees
> -  Archived trees are excluded from column view unless the variable
> -  ~org-columns-skip-archived-trees~ is configured to ~nil~.
> -
> -The following commands help manage the =ARCHIVE= tag:
> -
> -- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) ::
> -
> -  #+kindex: C-c C-x a
> -  #+findex: org-toggle-archive-tag
> -  Toggle the archive tag for the current headline.  When the tag is
> -  set, the headline changes to a shadowed face, and the subtree below
> -  it is hidden.
> -
> -- {{{kbd(C-u C-c C-x a)}}} ::
> -
> -  #+kindex: C-u C-c C-x a
> -  Check if any direct children of the current headline should be
> -  archived.  To do this, check each subtree for open TODO entries.  If
> -  none is found, the command offers to set the =ARCHIVE= tag for the
> -  child.  If point is /not/ on a headline when this command is
> -  invoked, check the level 1 trees.
> -
> -- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) ::
> -
> -  #+kindex: C-TAB
> -  Cycle a tree even if it is tagged with =ARCHIVE=.
> -
> -- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) ::
> -
> -  #+kindex: C-c C-x A
> -  #+findex: org-archive-to-archive-sibling
> -  Move the current entry to the /Archive Sibling/.  This is a sibling
> -  of the entry with the heading =Archive= and the archive tag.  The
> -  entry becomes a child of that sibling and in this way retains a lot
> -  of its original context, including inherited tags and approximate
> -  position in the outline.
> -
>  * Agenda Views
>  :PROPERTIES:
>  :DESCRIPTION: Collecting information into views.
> @@ -21244,7 +21461,7 @@ accessed in capture templates in a similar way.
>  ~org-link-from-user-regexp~.
>  
>  [fn:87] If you move entries or Org files from one directory to
> -another, you may want to configure ~org-attach-directory~ to contain
> +another, you may want to configure ~org-attach-id-dir~ to contain
>  an absolute path.
>  
>  [fn:88] Note the corresponding =STARTUP= options =logrefile=,
> diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
> index 4abecdfbc..bbd9dc975 100644
> --- a/etc/ORG-NEWS
> +++ b/etc/ORG-NEWS
> @@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI
>  alternative was removed and there is no more a :use-xcolor options
>  since now it's implicitly always true.
>  
> +*** Org-Attach Git commit
> +[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality.  Not
> +much, but the following changes are required if you still need to
> +auto-commit attachments to git:
> +
> +- Customization of ~org-attach-annex-auto-get~ needs to be renamed to
> +  ~org-attach-git-annex-auto-get~.
> +
> +- Customization of ~org-attach-commit~ is no longer needed.  Instead
> +  one need to require the =org-attach-git= module in the startup.
> +
>  ** New features
> +*** Org-Attach has been refactored and extended
> +Org attach has been refactored and the functionality extended.  It
> +should now be easier to understand how it works.  A few improvements
> +and extra options have been added as well.
> +
> +From the initial comment in org-attach source-code:
> +
> +- Attachments are managed either by using a custom property DIR or by
> +  using property ID from org-id.  When DIR is defined, a location in
> +  the filesystem is directly attached to the outline node.  When
> +  org-id is used, attachments are stored in a folder named after the
> +  ID, in a location defined by ~org-attach-id-dir~.  DIR has
> +  precedence over ID when both parameters are defined for the current
> +  outline node (also when inherited parameters are taken into
> +  account).
> +
> +From now on inheritance requires no extra property and will adhere to
> +~org-attach-use-inheritance~ by default.  Inheritance can be
> +customized to always be activated or never be activated in
> +~org-attach-use-inheritance~.
> +
> +The ATTACH_DIR property is deprecated in favour of the shorter
> +property DIR.  Links to folders inside the DIR property can now be
> +declared as relative links.  This is not enabled by default, but can
> +be set in ~org-attach-dir-relative~.
> +
> +When adding new attachment to the outline node the preferred way of
> +doing so can be customized.  Take a look at
> +~org-attach-preferred-new-method~.  It defaults to using ID since that
> +was the behaviour before this change.
> +
> +If both DIR and ID properties are set on the same node, DIR has
> +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.
> +
> +If you've used ATTACH_DIR properties to manage attachments, use the
> +following code to rename that property to DIR which supports the same
> +functionality.  ATTACH_DIR_INHERIT is no longer supported and is
> +removed.
> +
> +#+begin_src emacs-lisp
> +  (defun org-update-attach-properties ()
> +      "Change properties for Org-Attach."
> +      (interactive)
> +      (org-with-point-at 1
> +	(while (outline-next-heading)
> +	  (let ((DIR (org--property-local-values "ATTACH_DIR" nil)))
> +	    (when DIR
> +	      (org-set-property "DIR" (car DIR))
> +	      (org-delete-property "ATTACH_DIR"))))
> +	(org-delete-property-globally "ATTACH_DIR_INHERIT")))
> +#+end_src
> +
> +For those who hate breaking changes, even though the changes are made
> +to clean things up; fear not.  ATTACH_DIR will still continue to work.
> +It's just not documented any longer.  When you get the chance, run the
> +code above to clean things up anyways!
> +
> +**** New hooks
> +Two hooks are added to org-attach:
> +- org-attach-after-change-hook
> +- org-attach-open-hook
> +
> +They are added mostly for internal restructuring purposes, but can
> +ofc. be used for other things as well.
> +
> +*** New link-type: Attachment
> +Attachment-links are now first-class citizens.  They mimick file-links
> +in everything they do but use the existing attachment-folder as a base
> +when expanding the links. Both =DIR= and =ID= properties are used to
> +try to resolve the links, in exactly the same way as Org-Attach uses
> +those properties.
> +
>  *** Handle overlay specification for notes in Beamer export
>  
>  This aligns Beamer notes with slide overlays.
> @@ -243,6 +332,11 @@ dynamic block in ~org-dynamic-block-alist~.
>  ** Removed functions
>  *** ~org-babel-set-current-result-hash~
>  *** ~org-capture-insert-template-here~
> +*** ~org-attach-directory~
> +
> +It has been deprecated in favour of ~org-attach-id-dir~ which is less
> +ambigous given the restructured org-attach.
> +
>  ** Miscellaneous
>  *** Change signature for ~org-list-to-subtree~
>  The function now accepts the level of the subtree as an optional
> diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el
> new file mode 100644
> index 000000000..f40eb966d
> --- /dev/null
> +++ b/lisp/org-attach-git.el
> @@ -0,0 +1,117 @@
> +;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*-
> +
> +;; Copyright (C) 2019 Free Software Foundation, Inc.
> +
> +;; Original Author: John Wiegley <johnw@newartisans.com>
> +;; Restructurer: Gustav Wikstr¶m <gustav@whil.se>
> +;; Keywords: org data git
> +
> +;; This file is part of GNU Emacs.
> +;;
> +;; GNU Emacs is free software: you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GNU Emacs is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; An extention to org-attach.  If the attachment-directory to an
> +;; outline node (using either DIR or ID) is initialized as a Git
> +;; repository, then org-attach-git will automatically commit changes
> +;; when it sees them.
> +
> +;;; Code:
> +
> +(require 'org-attach)
> +(require 'vc-git)
> +
> +(defcustom org-attach-git-annex-cutoff (* 32 1024)
> +  "If non-nil, files larger than this will be annexed instead of stored."
> +  :group 'org-attach
> +  :version "24.4"
> +  :package-version '(Org . "8.0")
> +  :type '(choice
> +	  (const :tag "None" nil)
> +	  (integer :tag "Bytes")))
> +
> +(defcustom org-attach-git-annex-auto-get 'ask
> +  "Confirmation preference for automatically getting annex files.
> +If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
> +  :group 'org-attach
> +  :package-version '(Org . "9.0")
> +  :version "26.1"
> +  :type '(choice
> +	  (const :tag "confirm with `y-or-n-p'" ask)
> +	  (const :tag "always get from annex if necessary" t)
> +	  (const :tag "never get from annex" nil)))
> +
> +(defun org-attach-git-use-annex ()
> +  "Return non-nil if git annex can be used."
> +  (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir))))
> +    (and org-attach-git-annex-cutoff
> +         (or (file-exists-p (expand-file-name "annex" git-dir))
> +             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
> +
> +(defun org-attach-git-annex-get-maybe (path)
> +  "Call git annex get PATH (via shell) if using git annex.
> +Signals an error if the file content is not available and it was not retrieved."
> +  (let* ((default-directory (expand-file-name org-attach-id-dir))
> +	 (path-relative (file-relative-name path)))
> +    (when (and (org-attach-git-use-annex)
> +	       (not
> +		(string-equal
> +		 "found"
> +		 (shell-command-to-string
> +		  (format "git annex find --format=found --in=here %s"
> +			  (shell-quote-argument path-relative))))))
> +      (let ((should-get
> +	     (if (eq org-attach-git-annex-auto-get 'ask)
> +		 (y-or-n-p (format "Run git annex get %s? " path-relative))
> +	       org-attach-git-annex-auto-get)))
> +	(unless should-get
> +	  (error "File %s stored in git annex but unavailable" path))
> +	(message "Running git annex get \"%s\"." path-relative)
> +	(call-process "git" nil nil nil "annex" "get" path-relative)))))
> +
> +(defun org-attach-git-commit ()
> +  "Commit changes to git if `org-attach-id-dir' is properly initialized.
> +This checks for the existence of a \".git\" directory in that directory."
> +  (let* ((dir (expand-file-name org-attach-id-dir))
> +	 (git-dir (vc-git-root dir))
> +	 (use-annex (org-attach-git-use-annex))
> +	 (changes 0))
> +    (when (and git-dir (executable-find "git"))
> +      (with-temp-buffer
> +	(cd dir)
> +        (dolist (new-or-modified
> +                 (split-string
> +                  (shell-command-to-string
> +                   "git ls-files -zmo --exclude-standard") "\0" t))
> +          (if (and use-annex
> +                   (>= (file-attribute-size (file-attributes new-or-modified))
> +                       org-attach-git-annex-cutoff))
> +              (call-process "git" nil nil nil "annex" "add" new-or-modified)
> +            (call-process "git" nil nil nil "add" new-or-modified))
> +	    (cl-incf changes))
> +	(dolist (deleted
> +		 (split-string
> +		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
> +	  (call-process "git" nil nil nil "rm" deleted)
> +	  (cl-incf changes))
> +	(when (> changes 0)
> +	  (shell-command "git commit -m 'Synchronized attachments'"))))))
> +
> +(add-hook 'org-attach-after-change-hook 'org-attach-git-commit)
> +(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe)
> +
> +(provide 'org-attach-git)
> +
> +;;; org-attach-git.el ends here
> diff --git a/lisp/org-attach.el b/lisp/org-attach.el
> index a715c89e9..726085014 100644
> --- a/lisp/org-attach.el
> +++ b/lisp/org-attach.el
> @@ -1,9 +1,9 @@
> -;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*-
> +;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*-
>  
>  ;; Copyright (C) 2008-2019 Free Software Foundation, Inc.
>  
>  ;; Author: John Wiegley <johnw@newartisans.com>
> -;; Keywords: org data task
> +;; Keywords: org data attachment
>  
>  ;; This file is part of GNU Emacs.
>  ;;
> @@ -24,32 +24,30 @@
>  
>  ;; See the Org manual for information on how to use it.
>  ;;
> -;; Attachments are managed in a special directory called "data", which
> -;; lives in the same directory as the org file itself.  If this data
> -;; directory is initialized as a Git repository, then org-attach will
> -;; automatically commit changes when it sees them.
> -;;
> -;; Attachment directories are identified using a UUID generated for the
> -;; task which has the attachments.  These are added as property to the
> -;; task when necessary, and should not be deleted or changed by the
> -;; user, ever.  UUIDs are generated by a mechanism defined in the variable
> -;; `org-id-method'.
> +;; Attachments are managed either by using a custom property DIR or by
> +;; using property ID from org-id.  When DIR is defined, a location in
> +;; the filesystem is directly attached to the outline node.  When
> +;; org-id is used, attachments are stored in a folder named after the
> +;; ID, in a location defined by `org-attach-id-dir'.  DIR has
> +;; precedence over ID when both parameters are defined for the current
> +;; outline node (also when inherited parameters are taken into
> +;; account).
>  
>  ;;; Code:
>  
>  (require 'cl-lib)
>  (require 'org)
> +(require 'ol)
>  (require 'org-id)
> -(require 'vc-git)
>  
>  (declare-function dired-dwim-target-directory "dired-aux")
>  
>  (defgroup org-attach nil
> -  "Options concerning entry attachments in Org mode."
> +  "Options concerning attachments in Org mode."
>    :tag "Org Attach"
>    :group 'org)
>  
> -(defcustom org-attach-directory "data/"
> +(defcustom org-attach-id-dir "data/"
>    "The directory where attachments are stored.
>  If this is a relative path, it will be interpreted relative to the directory
>  where the Org file lives."
> @@ -57,22 +55,13 @@ where the Org file lives."
>    :type 'directory
>    :safe #'stringp)
>  
> -(defcustom org-attach-commit t
> -  "If non-nil commit attachments with git.
> -This is only done if the Org file is in a git repository."
> +(defcustom org-attach-dir-relative nil
> +  "Non-nil means directories in DIR property are added as relative links.
> +Defaults to absolute location."
>    :group 'org-attach
>    :type 'boolean
> -  :version "26.1"
> -  :package-version '(Org . "9.0"))
> -
> -(defcustom org-attach-git-annex-cutoff (* 32 1024)
> -  "If non-nil, files larger than this will be annexed instead of stored."
> -  :group 'org-attach
> -  :version "24.4"
> -  :package-version '(Org . "8.0")
> -  :type '(choice
> -	  (const :tag "None" nil)
> -	  (integer :tag "Bytes")))
> +  :package-version '(Org . "9.3")
> +  :safe #'booleanp)
>  
>  (defcustom org-attach-auto-tag "ATTACH"
>    "Tag that will be triggered automatically when an entry has an attachment."
> @@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository."
>  	  (const :tag "None" nil)
>  	  (string :tag "Tag")))
>  
> -(defcustom org-attach-file-list-property "Attachments"
> -  "The property used to keep a list of attachment belonging to this entry.
> -This is not really needed, so you may set this to nil if you don't want it.
> -Also, for entries where children inherit the directory, the list of
> -attachments is not kept in this property."
> +(defcustom org-attach-preferred-new-method 'id
> +  "Preferred way to attach to nodes without existing ID and DIR property.
> +This choice is used when adding attachments to nodes without ID
> +and DIR properties.
> +
> +Allowed values are:
> +
> +id         Create and use an ID parameter
> +dir        Create and use a DIR parameter
> +ask        Ask the user for input of which method to choose
> +nil        Prefer to not create a new parameter
> +
> +           nil means that ID or DIR has to be created explicitly
> +           before attaching files."
>    :group 'org-attach
> +  :package-version '(org . "9.3")
>    :type '(choice
> -	  (const :tag "None" nil)
> -	  (string :tag "Tag")))
> +	  (const :tag "ID parameter" id)
> +	  (const :tag "DIR parameter" dir)
> +	  (const :tag "Ask user" ask)
> +	  (const :tag "Don't create" nil)))
>  
>  (defcustom org-attach-method 'cp
>    "The preferred method to attach a file.
> @@ -113,14 +114,24 @@ lns   create a symbol link.  Note that this is not supported
>    :group 'org-attach
>    :type 'boolean)
>  
> -(defcustom org-attach-allow-inheritance t
> -  "Non-nil means allow attachment directories be inherited."
> +(defcustom org-attach-use-inheritance 'selective
> +  "Attachment inheritance for the outline.
> +
> +Enabling inheritance for org-attach implies two things.  First,
> +that attachment links will look through all parent headings until
> +it finds the linked attachment.  Second, that running org-attach
> +inside a node without attachments will make org-attach operate on
> +the first parent heading it finds with an attachment.
> +
> +Selective means to respect the inheritance setting in
> +`org-use-property-inheritance'."
>    :group 'org-attach
> +  :type '(choice
> +	  (const :tag "Don't use inheritance" nil)
> +	  (const :tag "Inherit parent node attachments" t)
> +	  (const :tag "Respect org-use-property-inheritance" selective))
>    :type 'boolean)
>  
> -(defvar org-attach-inherited nil
> -  "Indicates if the last access to the attachment directory was inherited.")
> -
>  (defcustom org-attach-store-link-p nil
>    "Non-nil means store a link to a file when attaching it."
>    :group 'org-attach
> @@ -141,16 +152,28 @@ When set to `query', ask the user instead."
>  	  (const :tag "Always delete attachments" t)
>  	  (const :tag "Query the user" query)))
>  
> -(defcustom org-attach-annex-auto-get 'ask
> -  "Confirmation preference for automatically getting annex files.
> -If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If nil, never get."
> +(defun org-attach-id-folder-format (id)
> +  "Translate an ID into a folder-path.
> +Default format for how Org translates ID properties to a path for
> +attachments."
> +  (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."
>    :group 'org-attach
> -  :package-version '(Org . "9.0")
> -  :version "26.1"
> -  :type '(choice
> -	  (const :tag "confirm with `y-or-n-p'" ask)
> -	  (const :tag "always get from annex if necessary" t)
> -	  (const :tag "never get from annex" nil)))
> +  :package-version '(Org . "9.3")
> +  :type 'function)
> +
> +(defvar org-attach-after-change-hook nil
> +  "Hook to be called when files have been added or removed to the attachment folder.")
> +
> +(defvar org-attach-open-hook nil
> +  "Hook that is invoked by `org-attach-open'.
> +
> +Created mostly to be compatible with org-attach-git after removing
> +git-funtionality from this file.")
>  
>  (defcustom org-attach-commands
>    '(((?a ?\C-a) org-attach-attach
> @@ -186,9 +209,9 @@ you added attachments yourself.\n")
>       "Delete all of a task's attachments.  A safer way is\n to open the \
>  directory in dired and delete from there.\n")
>      ((?s ?\C-s) org-attach-set-directory
> -     "Set a specific attachment directory for this entry or reset to default.")
> -    ((?i ?\C-i) org-attach-set-inherit
> -     "Make children of the current entry inherit its attachment directory.\n")
> +     "Set a specific attachment directory for this entry. Sets DIR property.")
> +    ((?S ?\C-S) org-attach-unset-directory
> +     "Unset the attachment directory for this entry.  Removes DIR property.")
>      ((?q) (lambda () (interactive) (message "Abort")) "Abort."))
>    "The list of commands for the attachment dispatcher.
>  Each entry in this list is a list of three elements:
> @@ -215,7 +238,7 @@ Shows a list of commands and prompts for another key to execute a command."
>        (setq marker (or (get-text-property (point) 'org-hd-marker)
>  		       (get-text-property (point) 'org-marker)))
>        (unless marker
> -	(error "No task in current line")))
> +	(error "No item in current line")))
>      (save-excursion
>        (when marker
>  	(set-buffer (marker-buffer marker))
> @@ -225,24 +248,28 @@ Shows a list of commands and prompts for another key to execute a command."
>  	(save-window-excursion
>  	  (unless org-attach-expert
>  	    (with-output-to-temp-buffer "*Org Attach*"
> -	      (princ
> -	       (format "Select an Attachment Command:\n\n%s"
> -		       (mapconcat
> -			(lambda (entry)
> -			  (pcase entry
> -			    (`((,key . ,_) ,_ ,docstring)
> -			     (format "%c       %s"
> -				     key
> -				     (replace-regexp-in-string "\n\\([\t ]*\\)"
> -							       "        "
> -							       docstring
> -							       nil nil 1)))
> -			    (_
> -			     (user-error
> -			      "Invalid `org-attach-commands' item: %S"
> -			      entry))))
> -			org-attach-commands
> -			"\n")))))
> +              (princ
> +               (concat "Attachment folder:\n"
> +		       (or (org-attach-dir)
> +			   "Can't find an existing attachment-folder")
> +		       "\n\n"
> +	               (format "Select an Attachment Command:\n\n%s"
> +		               (mapconcat
> +		                (lambda (entry)
> +		                  (pcase entry
> +		                    (`((,key . ,_) ,_ ,docstring)
> +		                     (format "%c       %s"
> +			                     key
> +			                     (replace-regexp-in-string "\n\\([\t ]*\\)"
> +							               "        "
> +							               docstring
> +							               nil nil 1)))
> +		                    (_
> +		                     (user-error
> +			              "Invalid `org-attach-commands' item: %S"
> +			              entry))))
> +		                org-attach-commands
> +		                "\n"))))))
>  	  (org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
>  	  (message "Select command: [%s]"
>  		   (concat (mapcar #'caar org-attach-commands)))
> @@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command."
>  	  (error "No such attachment command: %c" c))))))
>  
>  (defun org-attach-dir (&optional create-if-not-exists-p)
> -  "Return the directory associated with the current entry.
> -This first checks for a local property ATTACH_DIR, and then for an inherited
> -property ATTACH_DIR_INHERIT.  If neither exists, the default mechanism
> -using the entry ID will be invoked to access the unique directory for the
> -current entry.
> -If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil,
> -the directory and (if necessary) the corresponding ID will be created."
> -  (let (attach-dir uuid)
> -    (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT"))
> +  "Return the directory associated with the current outline node.
> +First check for DIR property, then ID property.
> +`org-attach-use-inheritance' determines whether inherited
> +properties also will be considered.
> +
> +If an ID property is found the default mechanism using that ID
> +will be invoked to access the directory for the current entry.
> +
> +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create'
> +is run."
> +  (let (attach-dir id)
>      (cond
> -     ((setq attach-dir (org-entry-get nil "ATTACH_DIR"))
> +     (create-if-not-exists-p
> +      (setq attach-dir (org-attach-dir-get-create)))
> +     ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance))
>        (org-attach-check-absolute-path attach-dir))
> -     ((and org-attach-allow-inheritance
> -	   (org-entry-get nil "ATTACH_DIR_INHERIT" t))
> -      (setq attach-dir
> -	    (org-with-wide-buffer
> -	     (if (marker-position org-entry-property-inherited-from)
> -		 (goto-char org-entry-property-inherited-from)
> -	       (org-back-to-heading t))
> -	     (let (org-attach-allow-inheritance)
> -	       (org-attach-dir create-if-not-exists-p))))
> -      (org-attach-check-absolute-path attach-dir)
> -      (setq org-attach-inherited t))
> -     (t					; use the ID
> +     ;; Deprecated and removed from documentation, but still
> +     ;; works. FIXME: Remove after major nr change.
> +     ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance))
> +      (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 uuid (org-id-get (point) create-if-not-exists-p))
> -      (when (or uuid create-if-not-exists-p)
> -	(unless uuid (error "ID retrieval/creation failed"))
> -	(setq attach-dir (expand-file-name
> -			  (format "%s/%s"
> -				  (substring uuid 0 2)
> -				  (substring uuid 2))
> -			  (expand-file-name org-attach-directory))))))
> -    (when attach-dir
> -      (if (and create-if-not-exists-p
> -	       (not (file-directory-p attach-dir)))
> -	  (make-directory attach-dir t))
> -      (and (file-exists-p attach-dir)
> -	   attach-dir))))
> +      (setq attach-dir (org-attach-dir-from-id id))))
> +    attach-dir))
> +
> +(defun org-attach-dir-get-create ()
> +  "Return existing or new directory associated with the current outline node.
> +
> +`org-attach-preferred-new-method' decides how to attach
> +new directory."
> +  (interactive)
> +  (let ((attach-dir (org-attach-dir)))
> +    (unless attach-dir
> +      (let (answer)
> +	(when (eq org-attach-preferred-new-method 'ask)
> +	  (message "Create new ID [1] property or DIR [2] property for attachments?")
> +	  (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))))
> +	 ((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)
> +	  (error "No existing directory. DIR or ID property has to be explicitly created")))))
> +    (unless attach-dir
> +      (error "No attachment directory is associated with the current node"))
> +    (unless (file-directory-p attach-dir)
> +      (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-check-absolute-path (dir)
>    "Check if we have enough information to root the attachment directory.
>  When DIR is given, check also if it is already absolute.  Otherwise,
> -assume that it will be relative, and check if `org-attach-directory' is
> +assume that it will be relative, and check if `org-attach-id-dir' is
>  absolute, or if at least the current buffer has a file name.
>  Throw an error if we cannot root the directory."
>    (or (and dir (file-name-absolute-p dir))
> -      (file-name-absolute-p org-attach-directory)
> +      (file-name-absolute-p org-attach-id-dir)
>        (buffer-file-name (buffer-base-buffer))
> -      (error "Need absolute `org-attach-directory' to attach in buffers without filename")))
> +      (error "Need absolute `org-attach-id-dir' to attach in buffers without filename")))
>  
> -(defun org-attach-set-directory (&optional arg)
> -  "Set the ATTACH_DIR node property and ask to move files there.
> +(defun org-attach-set-directory ()
> +  "Set the DIR node property and ask to move files there.
>  The property defines the directory that is used for attachments
> -of the entry.  When called with `\\[universal-argument]', reset \
> -the directory to
> -the default ID based one."
> -  (interactive "P")
> +of the entry.  Creates relative links if `org-attach-dir-relative'
> +is non-nil.
> +
> +Return the directory."
> +  (interactive)
>    (let ((old (org-attach-dir))
> -        (new
> -         (progn
> -           (if arg (org-entry-delete nil "ATTACH_DIR")
> -             (let ((dir (read-directory-name
> -                         "Attachment directory: "
> -                         (org-entry-get nil
> -                                        "ATTACH_DIR"
> -                                        (and org-attach-allow-inheritance t)))))
> -               (org-entry-put nil "ATTACH_DIR" dir)))
> -           (org-attach-dir t))))
> +	(new
> +	 (let* ((attach-dir (read-directory-name
> +			     "Attachment directory: "
> +			     (org-entry-get nil "DIR")))
> +		(current-dir (file-name-directory (or default-directory
> +						      buffer-file-name)))
> +		(attach-dir-relative (file-relative-name attach-dir current-dir)))
> +	   (org-entry-put nil "DIR" (if org-attach-dir-relative
> +					attach-dir-relative
> +				      attach-dir))
> +           attach-dir)))
>      (unless (or (string= old new)
>                  (not old))
>        (when (yes-or-no-p "Copy over attachments from old directory? ")
> +        (copy-directory old new t t t))
> +      (when (yes-or-no-p (concat "Delete " old))
> +        (delete-directory old t)))
> +    new))
> +
> +(defun org-attach-unset-directory ()
> +  "Removes DIR node property.
> +If attachment folder is changed due to removal of DIR-property
> +ask to move attachments to new location and ask to delete old
> +attachment-folder.
> +
> +Change of attachment-folder due to unset might be if an ID
> +property is set on the node, or if a separate inherited
> +DIR-property exists (that is different than the unset one)."
> +  (interactive)
> +  (let ((old (org-attach-dir))
> +	(new
> +         (progn
> +	   (org-entry-delete nil "DIR")
> +	   ;; ATTACH-DIR is deprecated and removed from documentation,
> +	   ;; but still works. Remove code for it after major nr change.
> +	   (org-entry-delete nil "ATTACH_DIR")
> +	   (org-attach-dir))))
> +    (unless (or (string= old new)
> +                (not old))
> +      (when (and new (yes-or-no-p "Copy over attachments from old directory? "))
>          (copy-directory old new t nil t))
>        (when (yes-or-no-p (concat "Delete " old))
>          (delete-directory old t)))))
>  
> -(defun org-attach-set-inherit ()
> -  "Set the ATTACH_DIR_INHERIT property of the current entry.
> -The property defines the directory that is used for attachments
> -of the entry and any children that do not explicitly define (by setting
> -the ATTACH_DIR property) their own attachment directory."
> -  (interactive)
> -  (org-entry-put nil "ATTACH_DIR_INHERIT" "t")
> -  (message "Children will inherit attachment directory"))
> -
> -(defun org-attach-use-annex ()
> -  "Return non-nil if git annex can be used."
> -  (let ((git-dir (vc-git-root (expand-file-name org-attach-directory))))
> -    (and org-attach-git-annex-cutoff
> -         (or (file-exists-p (expand-file-name "annex" git-dir))
> -             (file-exists-p (expand-file-name ".git/annex" git-dir))))))
> -
> -(defun org-attach-annex-get-maybe (path)
> -  "Call git annex get PATH (via shell) if using git annex.
> -Signals an error if the file content is not available and it was not retrieved."
> -  (let* ((default-directory (expand-file-name org-attach-directory))
> -	 (path-relative (file-relative-name path)))
> -    (when (and (org-attach-use-annex)
> -	       (not
> -		(string-equal
> -		 "found"
> -		 (shell-command-to-string
> -		  (format "git annex find --format=found --in=here %s"
> -			  (shell-quote-argument path-relative))))))
> -      (let ((should-get
> -	     (if (eq org-attach-annex-auto-get 'ask)
> -		 (y-or-n-p (format "Run git annex get %s? " path-relative))
> -	       org-attach-annex-auto-get)))
> -	(if should-get
> -	    (progn (message "Running git annex get \"%s\"." path-relative)
> -		   (call-process "git" nil nil nil "annex" "get" path-relative))
> -	  (error "File %s stored in git annex but it is not available, and was not retrieved"
> -		 path))))))
> -
> -(defun org-attach-commit ()
> -  "Commit changes to git if `org-attach-directory' is properly initialized.
> -This checks for the existence of a \".git\" directory in that directory."
> -  (let* ((dir (expand-file-name org-attach-directory))
> -	 (git-dir (vc-git-root dir))
> -	 (use-annex (org-attach-use-annex))
> -	 (changes 0))
> -    (when (and git-dir (executable-find "git"))
> -      (with-temp-buffer
> -	(cd dir)
> -        (dolist (new-or-modified
> -                 (split-string
> -                  (shell-command-to-string
> -                   "git ls-files -zmo --exclude-standard") "\0" t))
> -          (if (and use-annex
> -                   (>= (file-attribute-size (file-attributes new-or-modified))
> -                       org-attach-git-annex-cutoff))
> -              (call-process "git" nil nil nil "annex" "add" new-or-modified)
> -            (call-process "git" nil nil nil "add" new-or-modified))
> -	    (cl-incf changes))
> -	(dolist (deleted
> -		 (split-string
> -		  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
> -	  (call-process "git" nil nil nil "rm" deleted)
> -	  (cl-incf changes))
> -	(when (> changes 0)
> -	  (shell-command "git commit -m 'Synchronized attachments'"))))))
> -
>  (defun org-attach-tag (&optional off)
>    "Turn the autotag on or (if OFF is set) off."
>    (when org-attach-auto-tag
> @@ -423,22 +428,21 @@ Only do this when `org-attach-store-link-p' is non-nil."
>      (org-attach-attach url)))
>  
>  (defun org-attach-buffer (buffer-name)
> -  "Attach BUFFER-NAME's contents to current task.
> +  "Attach BUFFER-NAME's contents to current outline node.
>  BUFFER-NAME is a string.  Signals a `file-already-exists' error
>  if it would overwrite an existing filename."
>    (interactive "bBuffer whose contents should be attached: ")
> -  (let ((output (expand-file-name buffer-name (org-attach-dir t))))
> +  (let* ((attach-dir (org-attach-dir 'get-create))
> +	 (output (expand-file-name buffer-name attach-dir)))
>      (when (file-exists-p output)
>        (signal 'file-already-exists (list "File exists" output)))
> -    (when (and org-attach-file-list-property (not org-attach-inherited))
> -      (org-entry-add-to-multivalued-property
> -       (point) org-attach-file-list-property buffer-name))
> +    (run-hook-with-args 'org-attach-after-change-hook attach-dir)
>      (org-attach-tag)
>      (with-temp-file output
>        (insert-buffer-substring buffer-name))))
>  
>  (defun org-attach-attach (file &optional visit-dir method)
> -  "Move/copy/link FILE into the attachment directory of the current task.
> +  "Move/copy/link FILE into the attachment directory of the current outline node.
>  If VISIT-DIR is non-nil, visit the directory with dired.
>  METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
>  `org-attach-method'."
> @@ -453,10 +457,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
>      nil))
>    (setq method (or method org-attach-method))
>    (let ((basename (file-name-nondirectory file)))
> -    (when (and org-attach-file-list-property (not org-attach-inherited))
> -      (org-entry-add-to-multivalued-property
> -       (point) org-attach-file-list-property basename))
> -    (let* ((attach-dir (org-attach-dir t))
> +    (let* ((attach-dir (org-attach-dir 'get-create))
>             (fname (expand-file-name basename attach-dir)))
>        (cond
>         ((eq method 'mv) (rename-file file fname))
> @@ -464,8 +465,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
>         ((eq method 'ln) (add-name-to-file file fname))
>         ((eq method 'lns) (make-symbolic-link file fname))
>         ((eq method 'url) (url-copy-file file fname)))
> -      (when org-attach-commit
> -        (org-attach-commit))
> +      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
>        (org-attach-tag)
>        (cond ((eq org-attach-store-link-p 'attached)
>               (org-attach-store-link fname))
> @@ -473,7 +473,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
>               (org-attach-store-link file)))
>        (if visit-dir
>            (dired attach-dir)
> -        (message "File %S is now a task attachment." basename)))))
> +        (message "File %S is now an attachment." basename)))))
>  
>  (defun org-attach-attach-cp ()
>    "Attach a file by copying it."
> @@ -498,13 +498,10 @@ On some systems, this apparently does copy the file instead."
>    (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach)))
>  
>  (defun org-attach-new (file)
> -  "Create a new attachment FILE for the current task.
> +  "Create a new attachment FILE for the current outline node.
>  The attachment is created as an Emacs buffer."
>    (interactive "sCreate attachment named: ")
> -  (when (and org-attach-file-list-property (not org-attach-inherited))
> -    (org-entry-add-to-multivalued-property
> -     (point) org-attach-file-list-property file))
> -  (let ((attach-dir (org-attach-dir t)))
> +  (let ((attach-dir (org-attach-dir 'get-create)))
>      (org-attach-tag)
>      (find-file (expand-file-name file attach-dir))
>      (message "New attachment %s" file)))
> @@ -512,7 +509,7 @@ The attachment is created as an Emacs buffer."
>  (defun org-attach-delete-one (&optional file)
>    "Delete a single attachment."
>    (interactive)
> -  (let* ((attach-dir (org-attach-dir t))
> +  (let* ((attach-dir (org-attach-dir))
>  	 (files (org-attach-file-list attach-dir))
>  	 (file (or file
>  		   (completing-read
> @@ -524,44 +521,32 @@ The attachment is created as an Emacs buffer."
>      (unless (file-exists-p file)
>        (error "No such attachment: %s" file))
>      (delete-file file)
> -    (when org-attach-commit
> -      (org-attach-commit))))
> +    (run-hook-with-args 'org-attach-after-change-hook attach-dir)))
>  
>  (defun org-attach-delete-all (&optional force)
> -  "Delete all attachments from the current task.
> +  "Delete all attachments from the current outline node.
>  This actually deletes the entire attachment directory.
>  A safer way is to open the directory in dired and delete from there."
>    (interactive "P")
> -  (when (and org-attach-file-list-property (not org-attach-inherited))
> -    (org-entry-delete (point) org-attach-file-list-property))
>    (let ((attach-dir (org-attach-dir)))
> -    (when
> -	(and attach-dir
> -	     (or force
> -		 (y-or-n-p "Are you sure you want to remove all attachments of this entry? ")))
> -      (shell-command (format "rm -fr %s" attach-dir))
> +    (when (and attach-dir
> +	       (or force
> +		   (yes-or-no-p "Really remove all attachments of this entry? ")))
> +      (delete-directory attach-dir (yes-or-no-p "Recursive?") t)
>        (message "Attachment directory removed")
> -      (when org-attach-commit
> -        (org-attach-commit))
> +      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
>        (org-attach-untag))))
>  
>  (defun org-attach-sync ()
> -  "Synchronize the current tasks with its attachments.
> +  "Synchronize the current outline node with its attachments.
>  This can be used after files have been added externally."
>    (interactive)
> -  (when org-attach-commit
> -    (org-attach-commit))
> -  (when (and org-attach-file-list-property (not org-attach-inherited))
> -    (org-entry-delete (point) org-attach-file-list-property))
>    (let ((attach-dir (org-attach-dir)))
>      (when attach-dir
> +      (run-hook-with-args 'org-attach-after-change-hook attach-dir)
>        (let ((files (org-attach-file-list attach-dir)))
> -	(org-attach-tag (not files))
> -	(when org-attach-file-list-property
> -	  (dolist (file files)
> -	    (unless (string-match "^\\.\\.?\\'" file)
> -	      (org-entry-add-to-multivalued-property
> -	       (point) org-attach-file-list-property file))))))))
> +	(org-attach-tag (not files))))
> +    (unless attach-dir (org-attach-tag t))))
>  
>  (defun org-attach-file-list (dir)
>    "Return a list of files in the attachment directory.
> @@ -570,35 +555,40 @@ This ignores files ending in \"~\"."
>  	(mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x))
>  		(directory-files dir nil "[^~]\\'"))))
>  
> -(defun org-attach-reveal (&optional if-exists)
> -  "Show the attachment directory of the current task.
> +(defun org-attach-reveal ()
> +  "Show the attachment directory of the current outline node.
>  This will attempt to use an external program to show the directory."
> -  (interactive "P")
> -  (let ((attach-dir (org-attach-dir (not if-exists))))
> -    (and attach-dir (org-open-file attach-dir))))
> +  (interactive)
> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(org-open-file attach-dir)
> +      (error "No attachment directory exist"))))
>  
>  (defun org-attach-reveal-in-emacs ()
> -  "Show the attachment directory of the current task in dired."
> +  "Show the attachment directory of the current outline node in dired."
>    (interactive)
> -  (let ((attach-dir (org-attach-dir t)))
> -    (dired attach-dir)))
> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(dired attach-dir)
> +      (error "No attachment directory exist"))))
>  
>  (defun org-attach-open (&optional in-emacs)
> -  "Open an attachment of the current task.
> +  "Open an attachment of the current outline node.
>  If there are more than one attachment, you will be prompted for the file name.
>  This command will open the file using the settings in `org-file-apps'
>  and in the system-specific variants of this variable.
>  If IN-EMACS is non-nil, force opening in Emacs."
>    (interactive "P")
> -  (let* ((attach-dir (org-attach-dir t))
> -	 (files (org-attach-file-list attach-dir))
> -	 (file (if (= (length files) 1)
> -		   (car files)
> -		 (completing-read "Open attachment: "
> -				  (mapcar #'list files) nil t)))
> -         (path (expand-file-name file attach-dir)))
> -    (org-attach-annex-get-maybe path)
> -    (org-open-file path in-emacs)))
> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(let* ((file (pcase (org-attach-file-list attach-dir)
> +		       (`(,file) file)
> +		       (files (completing-read "Open attachment: "
> +					       (mapcar #'list files) nil t))))
> +	       (path (expand-file-name file attach-dir)))
> +	  (run-hook-with-args 'org-attach-open-hook path)
> +	  (org-open-file path in-emacs))
> +      (error "No attachment directory exist"))))
>  
>  (defun org-attach-open-in-emacs ()
>    "Open attachment, force opening in Emacs.
> @@ -617,6 +607,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\"
>  prefix."
>    (concat "file:" (org-attach-expand file)))
>  
> +(org-link-set-parameters "attachment"
> +                         :follow #'org-attach-open-link
> +                         :export #'org-attach-export-link
> +                         :complete #'org-attach-complete-link)
> +
> +(defun org-attach-open-link (link &optional in-emacs)
> +  "Attachment link type LINK is expanded with the attached directory and opened.
> +
> +With optional prefix argument IN-EMACS, Emacs will visit the file.
> +With a double \\[universal-argument] \\[universal-argument] \
> +prefix arg, Org tries to avoid opening in Emacs
> +and to use an external application to visit the file."
> +  (interactive "P")
> +  (let (line search)
> +    (cond
> +     ((string-match "::\\([0-9]+\\)\\'" link)
> +      (setq line (string-to-number (match-string 1 link))
> +	    link (substring link 0 (match-beginning 0))))
> +     ((string-match "::\\(.+\\)\\'" link)
> +      (setq search (match-string 1 link)
> +            link (substring link 0 (match-beginning 0)))))
> +    (if (string-match "[*?{]" (file-name-nondirectory link))
> +        (dired (org-attach-expand link))
> +      (org-open-file (org-attach-expand link) in-emacs line search))))
> +
> +(defun org-attach-complete-link ()
> +  "Advise the user with the available files in the attachment directory."
> +  (let ((attach-dir (org-attach-dir)))
> +    (if attach-dir
> +	(let* ((attached-dir (expand-file-name attach-dir))
> +	       (file (read-file-name "File: " attached-dir))
> +	       (pwd (file-name-as-directory attached-dir))
> +               (pwd-relative (file-name-as-directory
> +			      (abbreviate-file-name attached-dir))))
> +	  (cond
> +	   ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file)
> +	    (concat "attachment:" (match-string 1 file)))
> +	   ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
> +			  (expand-file-name file))
> +	    (concat "attachment:" (match-string 1 (expand-file-name file))))
> +	   (t (concat "attachment:" file))))
> +      (error "No attachment directory exist"))))
> +
> +(defun org-attach-export-link (link description format)
> +  "Translate attachment LINK from Org mode format to exported FORMAT.
> +Also includes the DESCRIPTION of the link in the export."
> +  (save-excursion
> +    (let (path desc)
> +      (cond
> +       ((string-match "::\\([0-9]+\\)\\'" link)
> +        (setq link (substring link 0 (match-beginning 0))))
> +       ((string-match "::\\(.+\\)\\'" link)
> +        (setq link (substring link 0 (match-beginning 0)))))
> +      (setq path (file-relative-name (org-attach-expand link))
> +            desc (or description link))
> +      (pcase format
> +        (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
> +        (`latex (format "\\href{%s}{%s}" path desc))
> +        (`texinfo (format "@uref{%s,%s}" path desc))
> +        (`ascii (format "%s (%s)" desc path))
> +        (`md (format "[%s](%s)" desc path))
> +        (_ path)))))
> +
>  (defun org-attach-archive-delete-maybe ()
>    "Maybe delete subtree attachments when archiving.
>  This function is called by `org-archive-hook'.  The option
> @@ -644,7 +697,7 @@ Idea taken from `gnus-dired-attach'."
>    (interactive
>     (list (dired-get-marked-files)))
>    (unless (eq major-mode 'dired-mode)
> -    (user-error "This command must be triggered in a dired buffer."))
> +    (user-error "This command must be triggered in a dired buffer"))
>    (let ((start-win (selected-window))
>          (other-win
>           (get-window-with-predicate
> diff --git a/lisp/org-compat.el b/lisp/org-compat.el
> index 9cb396fe9..42fe64379 100644
> --- a/lisp/org-compat.el
> +++ b/lisp/org-compat.el
> @@ -263,6 +263,9 @@ Counting starts at 1."
>  (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays
>    'org-clear-latex-preview "Org 9.3")
>  
> +(define-obsolete-variable-alias 'org-attach-directory
> +  'org-attach-id-dir "Org 9.3")
> +
>  (defun org-in-fixed-width-region-p ()
>    "Non-nil if point in a fixed-width region."
>    (save-match-data
> diff --git a/lisp/org.el b/lisp/org.el
> index 9601ecf2e..5d6cc757d 100644
> --- a/lisp/org.el
> +++ b/lisp/org.el
> @@ -3847,7 +3847,9 @@ This is needed for font-lock setup.")
>  		  (beg end))
>  (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type))
>  (declare-function org-agenda-skip "org-agenda" ())
> -(declare-function org-attach-reveal "org-attach" (&optional if-exists))
> +(declare-function org-attach-expand "org-attach" (file))
> +(declare-function org-attach-reveal "org-attach" ())
> +(declare-function org-attach-reveal-in-emacs "org-attach" ())
>  (declare-function org-gnus-follow-link "org-gnus" (&optional group article))
>  (declare-function org-indent-mode "org-indent" (&optional arg))
>  (declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
> @@ -8645,12 +8647,15 @@ a link."
>  	  (pcase (org-offer-links-in-entry (current-buffer) (point) arg)
>  	    (`(nil . ,_)
>  	     (require 'org-attach)
> -	     (org-attach-reveal 'if-exists))
> +	     (message "Opening attachment-dir")
> +	     (if (equal arg '(4))
> +		 (org-attach-reveal-in-emacs)
> +	       (org-attach-reveal)))
>  	    (`(,links . ,links-end)
>  	     (dolist (link (if (stringp links) (list links) links))
>  	       (search-forward link nil links-end)
>  	       (goto-char (match-beginning 0))
> -	       (org-open-at-point))))))
> +	       (org-open-at-point arg))))))
>         ;; On a footnote reference or at definition's label.
>         ((or (eq type 'footnote-reference)
>  	    (and (eq type 'footnote-definition)
> @@ -16630,13 +16635,14 @@ boundaries."
>  	     ;; "file:" links.  Also check link abbreviations since
>  	     ;; some might expand to "file" links.
>  	     (file-types-re
> -	      (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
> +	      (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
>  		      (if (not link-abbrevs) ""
>  			(concat "\\|" (regexp-opt link-abbrevs))))))
>  	(while (re-search-forward file-types-re end t)
>  	  (let* ((link (org-element-lineage
>  			(save-match-data (org-element-context))
>  			'(link) t))
> +                 (linktype (org-element-property :type link))
>  		 (inner-start (match-beginning 1))
>  		 (path
>  		  (cond
> @@ -16650,7 +16656,8 @@ boundaries."
>  		   ;; INCLUDE-LINKED is non-nil.
>  		   ((or (not (org-element-property :contents-begin link))
>  			include-linked)
> -		    (and (equal "file" (org-element-property :type link))
> +		    (and (or (equal "file" linktype)
> +                             (equal "attachment" linktype))
>  			 (org-element-property :path link)))
>  		   ;; Link with a description.  Check if description
>  		   ;; is a filename.  Even if Org doesn't have syntax
> @@ -16669,7 +16676,11 @@ boundaries."
>  			      (match-end 0))
>  			   (match-string 2)))))))
>  	    (when (and path (string-match-p file-extension-re path))
> -	      (let ((file (expand-file-name path)))
> +	      (let ((file (if (equal "attachment" linktype)
> +                              (progn
> +                                (require 'org-attach)
> +                                (org-attach-expand path))
> +                            (expand-file-name path))))
>  		(when (file-exists-p file)
>  		  (let ((width
>  			 ;; Apply `org-image-actual-width' specifications.
> diff --git a/lisp/ox-html.el b/lisp/ox-html.el
> index f1c06e069..757006321 100644
> --- a/lisp/ox-html.el
> +++ b/lisp/ox-html.el
> @@ -884,6 +884,7 @@ link to the image."
>  
>  (defcustom org-html-inline-image-rules
>    '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
> +    ("attachment" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
>      ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
>      ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'"))
>    "Rules characterizing image files that can be inlined into HTML.
> diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA
> new file mode 100644
> index 000000000..9a0406c0d
> --- /dev/null
> +++ b/testing/examples/att1/fileA
> @@ -0,0 +1 @@
> +Text in fileA
> diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB
> new file mode 100644
> index 000000000..dd2331824
> --- /dev/null
> +++ b/testing/examples/att1/fileB
> @@ -0,0 +1 @@
> +Text in fileB
> diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC
> new file mode 100644
> index 000000000..2c9a92bfe
> --- /dev/null
> +++ b/testing/examples/att2/fileC
> @@ -0,0 +1 @@
> +Text in fileC
> \ No newline at end of file
> diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD
> new file mode 100644
> index 000000000..c706556c5
> --- /dev/null
> +++ b/testing/examples/att2/fileD
> @@ -0,0 +1 @@
> +text in fileD
> diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org
> new file mode 100644
> index 000000000..ab4a4e548
> --- /dev/null
> +++ b/testing/examples/attachments.org
> @@ -0,0 +1,32 @@
> +#+TITLE: Org attach testfile
> +Used to test and verify the functionality of org-attach.
> +
> +* H1
> + :PROPERTIES:
> + :DIR:      att1
> + :END:
> +A link to one attachment: [[attachment:fileA]]
> +
> +** H1.1
> +A link to another attachment: [[attachment:fileB]]
> +
> +** H1.2
> +  :PROPERTIES:
> +  :DIR:      att2
> +  :END:
> +
> +* H2
> + :PROPERTIES:
> + :ID:       abcd123
> + :END:
> +
> +* H3
> + :PROPERTIES:
> + :DIR:      att1
> + :ID:       abcd1234
> + :END:
> +
> +** H3.1
> +  :PROPERTIES:
> +  :ID:       abcd12345
> +  :END:
> diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE
> new file mode 100644
> index 000000000..80d337772
> --- /dev/null
> +++ b/testing/examples/data/ab/cd123/fileE
> @@ -0,0 +1 @@
> +peek-a-boo
> diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el
> similarity index 93%
> rename from testing/lisp/test-org-attach-annex.el
> rename to testing/lisp/test-org-attach-git.el
> index 7f2792696..8b826b72f 100644
> --- a/testing/lisp/test-org-attach-annex.el
> +++ b/testing/lisp/test-org-attach-git.el
> @@ -20,19 +20,19 @@
>  
>  ;;; Code:
>  (org-test-for-executable "git-annex")
> -(require 'org-attach)
> +(require 'org-attach-git)
>  (require 'cl-lib)
>  
> -(defmacro test-org-attach-annex/with-annex (&rest body)
> +(defmacro test-org-attach-git/with-annex (&rest body)
>    `(let ((tmpdir (make-temp-file "org-annex-test" t "/")))
>       (unwind-protect
>  	 (let ((default-directory tmpdir)
> -	       (org-attach-directory tmpdir))
> +	       (org-attach-id-dir tmpdir))
>  	   (shell-command "git init")
>  	   (shell-command "git annex init")
>  	   ,@body))))
>  
> -(ert-deftest test-org-attach/use-annex ()
> +(ert-deftest test-org-attach-git/use-annex ()
>    (test-org-attach-annex/with-annex
>     (let ((org-attach-git-annex-cutoff 1))
>       (should (org-attach-use-annex)))
> @@ -44,12 +44,12 @@
>    (let ((tmpdir (make-temp-file "org-annex-test" t "/")))
>       (unwind-protect
>  	 (let ((default-directory tmpdir)
> -	       (org-attach-directory tmpdir))
> +	       (org-attach-id-dir tmpdir))
>  	   (shell-command "git init")
>  	   (should-not (org-attach-use-annex)))
>         (delete-directory tmpdir 'recursive))))
>  
> -(ert-deftest test-org-attach/get-maybe ()
> +(ert-deftest test-org-attach-git/get-maybe ()
>    (test-org-attach-annex/with-annex
>     (let ((path (expand-file-name "test-file"))
>  	 (annex-dup (make-temp-file "org-annex-test" t "/")))
> diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el
> index c2f2be356..5bcfe86fd 100644
> --- a/testing/lisp/test-org-attach.el
> +++ b/testing/lisp/test-org-attach.el
> @@ -28,6 +28,75 @@
>  (require 'org-attach)
>  (eval-and-compile (require 'cl-lib))
>  
> +(ert-deftest test-org-attach/dir ()
> +  "Test `org-attach-get' specifications."
> +  (should (equal "Text in fileA\n"
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 157) ;; First attachment link
> +		   (org-open-at-point)
> +		   (buffer-string))))
> +  (should-not (equal "Text in fileB\n"
> +		     (org-test-in-example-file org-test-attachments-file
> +		       (goto-char 219) ;; Second attachment link
> +		       (let ((org-attach-use-inheritance nil))
> +			 (org-open-at-point)
> +			 (buffer-string)))))
> +  (should (equal "Text in fileB\n"
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 219) ;; Second attachment link
> +		   (let ((org-attach-use-inheritance t))
> +		     (org-open-at-point)
> +		     (buffer-string)))))
> +  (should-not (equal "att1"
> +		     (org-test-in-example-file org-test-attachments-file
> +		       (goto-char 179) ;; H1.1
> +		       (let ((org-attach-use-inheritance nil))
> +			 (org-attach-dir)))))
> +  (should (equal "att1"
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 179) ;; H1.1
> +		   (let ((org-attach-use-inheritance t))
> +		     (org-attach-dir)))))
> +  (should (equal '("fileC" "fileD")
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 239) ;; H1.2
> +		   (org-attach-file-list (org-attach-dir)))))
> +  (should (equal '("fileC" "fileD")
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 239) ;; H1.2
> +		   (org-attach-file-list (org-attach-dir)))))
> +  (should (equal '("fileE")
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 289) ;; H2
> +		   (let ((org-attach-id-dir "data/"))
> +		     (org-attach-file-list (org-attach-dir))))))
> +  (should (equal "peek-a-boo\n"
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 289) ;; H2
> +		   (let ((org-attach-id-dir "data/"))
> +		     (org-attach-open-in-emacs)
> +		     (buffer-string)))))
> +  (should (equal  '("fileA" "fileB")
> +		  (org-test-in-example-file org-test-attachments-file
> +		    (goto-char 336) ;; H3
> +		    (org-attach-file-list (org-attach-dir)))))
> +  (should (equal "data/ab/cd12345"
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 401) ;; H3.1
> +		   (let ((org-attach-use-inheritance nil)
> +			 (org-attach-id-dir "data/"))
> +		     (file-relative-name (org-attach-dir))))))
> +  (should (equal '("fileA" "fileB")
> +		 (org-test-in-example-file org-test-attachments-file
> +		   (goto-char 401) ;; H3.1
> +		   (let ((org-attach-use-inheritance t))
> +		     ;; This is where it get's a bit sketchy...! DIR always has
> +		     ;; priority over ID, even if ID is declared "higher up" in the
> +		     ;; tree.  This can potentially be revised.  But it is also
> +		     ;; pretty clean.  DIR is always higher in priority than ID right
> +		     ;; now, no matter the depth in the tree.
> +		     (org-attach-file-list (org-attach-dir)))))))
> +
>  (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 ()
>    "Attach file at point in dired to subtree."
>    (should
> diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
> index d671b5c78..a618da479 100644
> --- a/testing/lisp/test-org.el
> +++ b/testing/lisp/test-org.el
> @@ -2514,7 +2514,11 @@ Foo Bar
>       (catch :result
>         (cl-letf (((symbol-function 'org-tags-view)
>  		  (lambda (&rest args) (throw :result t))))
> -	 (org-open-at-point)
> +	 ;; When point isn't on a tag it's going to try other things,
> +	 ;; possibly trying to open attachments which will return an
> +	 ;; error if there isn't an attachment. Supress that error.
> +	 (ignore-errors
> +	     (org-open-at-point))
>  	 nil)))))
>  
>  \f
> diff --git a/testing/org-test.el b/testing/org-test.el
> index 295df1919..c3e21eb30 100644
> --- a/testing/org-test.el
> +++ b/testing/org-test.el
> @@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.")
>  (defconst org-test-no-heading-file
>    (expand-file-name "no-heading.org" org-test-example-dir))
>  
> +(defconst org-test-attachments-file
> +  (expand-file-name "attachments.org" org-test-example-dir))
> +
>  (defconst org-test-link-in-heading-file
>    (expand-file-name "link-in-heading.org" org-test-dir))
>  
> -- 
> 2.17.1
>

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-27 14:56                       ` Ihor Radchenko
@ 2019-07-28 20:39                         ` Gustav Wikström
  2019-07-28 23:20                           ` Ihor Radchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-07-28 20:39 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode, Nicolas Goaziou

Hi Ihor,

> -----Original Message-----
> From: Ihor Radchenko <yantar92@gmail.com>
> Sent: den 27 juli 2019 16:56
> To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: [O] [RFC] Link-type for attachments, more attach options

> I just found that removing ATTACH_DIR_INHERIT broke my current
> configuration. I do not use ATTACH_DIR property - all the attachment
> folders are created using ID. Also, I use ID property to store links to
> entries. Therefore, inheriting ATTACH_DIR does nothing for me and
> inheriting ID always gives the current entry's id value. At the end, I
> cannot make a common attachment directory for the whole subtree, like I
> was able to do with ATTACH_DIR_INHERIT.

Ah, yes. That is an unfortunate side effect of ID properties having
other use-cases outside of attachments. I thought about that for some
time during the development but didn't get to implement any solution
for it. The way I thought to do it was to create an algorithm that
looks through the outline hierarchy at successively lower hierarchy
for an ID property that has a corresponding attachment folder. If no
folder exist for the ID attribute at the given level, the inherit
functionality would continue to look at a lower level until a folder
was found. I imagined the algorithm to look for both ID and DIR
properties at each level and stop at the first property that had an
existing attachment folder, with DIR taking precedence at each level
if for some reason both ID and DIR based folders existed.

Adding such functionality means going outside the scope of current
property inheritance in Org mode. It adds some complexity but maybe
it's warranted to do so here? But, as mentioned, I only got to the
point of thinking about it, I didn't implement it.

If someone wants to take up the challenge of implementing it then the
starting point should be to modify org-attach-dir, replacing
org-entry-get with something similar to the algorithm mentioned above.

I might get to it at some point as well, but my motivation lies
elsewhere right now (document-level stuff... see other threads by
me).

Kind regards
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [RFC] Link-type for attachments, more attach options
  2019-07-28 20:39                         ` Gustav Wikström
@ 2019-07-28 23:20                           ` Ihor Radchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Ihor Radchenko @ 2019-07-28 23:20 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode, Nicolas Goaziou

Dear Gustav,

Thanks for the update. For now, I fixed the problem for me with the
following advice:

#+begin_src emacs-lisp
  (define-advice org-attach-dir (:filter-return (dir) yant/org-attach-use-attach-dir-inheritance -100)
    "Use :ATTACH_DIR_INHERIT: property."
    (let ((attach-dir-inherited (and (org-entry-get-with-inheritance "ATTACH_DIR_INHERIT")
  				     (not (org-entry-get (point) "ATTACH_DIR_INHERIT" nil))
				     (org-with-point-at org-entry-property-inherited-from (org-attach-dir)))))
      (or attach-dir-inherited
  	  dir)))
#+end_src

Regards,
Ihor



Gustav Wikström <gustav@whil.se> writes:

> Hi Ihor,
>
>> -----Original Message-----
>> From: Ihor Radchenko <yantar92@gmail.com>
>> Sent: den 27 juli 2019 16:56
>> To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou <mail@nicolasgoaziou.fr>
>> Cc: emacs-orgmode@gnu.org
>> Subject: Re: [O] [RFC] Link-type for attachments, more attach options
>
>> I just found that removing ATTACH_DIR_INHERIT broke my current
>> configuration. I do not use ATTACH_DIR property - all the attachment
>> folders are created using ID. Also, I use ID property to store links to
>> entries. Therefore, inheriting ATTACH_DIR does nothing for me and
>> inheriting ID always gives the current entry's id value. At the end, I
>> cannot make a common attachment directory for the whole subtree, like I
>> was able to do with ATTACH_DIR_INHERIT.
>
> Ah, yes. That is an unfortunate side effect of ID properties having
> other use-cases outside of attachments. I thought about that for some
> time during the development but didn't get to implement any solution
> for it. The way I thought to do it was to create an algorithm that
> looks through the outline hierarchy at successively lower hierarchy
> for an ID property that has a corresponding attachment folder. If no
> folder exist for the ID attribute at the given level, the inherit
> functionality would continue to look at a lower level until a folder
> was found. I imagined the algorithm to look for both ID and DIR
> properties at each level and stop at the first property that had an
> existing attachment folder, with DIR taking precedence at each level
> if for some reason both ID and DIR based folders existed.
>
> Adding such functionality means going outside the scope of current
> property inheritance in Org mode. It adds some complexity but maybe
> it's warranted to do so here? But, as mentioned, I only got to the
> point of thinking about it, I didn't implement it.
>
> If someone wants to take up the challenge of implementing it then the
> starting point should be to modify org-attach-dir, replacing
> org-entry-get with something similar to the algorithm mentioned above.
>
> I might get to it at some point as well, but my motivation lies
> elsewhere right now (document-level stuff... see other threads by
> me).
>
> Kind regards
> Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (3 preceding siblings ...)
  2019-01-04 12:21 ` FW: " Feng Shu
@ 2019-12-12  5:21 ` stardiviner
  2019-12-12  6:12   ` Gustav Wikström
  2019-12-16 11:21 ` stardiviner
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-12  5:21 UTC (permalink / raw)
  To: emacs-orgmode


Hi Gustav,

I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will
auto in completion list. It will be convenient for user.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-12  5:21 ` stardiviner
@ 2019-12-12  6:12   ` Gustav Wikström
  2019-12-12  9:52     ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-12-12  6:12 UTC (permalink / raw)
  To: numbchild, emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 998 bytes --]

Hi stardiviner,

It is my belief that =[Ctrl-C Ctrl-l]= already is supported. You will only get suggestions for attachments if there are any attachments on the outline node you're in. Or in any of its parents if inheritance is configured.

Regards Gustav
________________________________
From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com>
Sent: Thursday, December 12, 2019 6:21:30 AM
To: emacs-orgmode@gnu.org <emacs-orgmode@gnu.org>
Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options


Hi Gustav,

I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will
auto in completion list. It will be convenient for user.

--
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3



[-- Attachment #2: Type: text/html, Size: 2135 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-12  6:12   ` Gustav Wikström
@ 2019-12-12  9:52     ` stardiviner
  2019-12-12 19:42       ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-12  9:52 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi stardiviner,
>
> It is my belief that =[Ctrl-C Ctrl-l]= already is supported. You will only get suggestions for attachments if there are any attachments on the outline node you're in. Or in any of its parents if inheritance is configured.
>

For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c
Ctrl-l]= (~org-insert-link~) to insert link which will show a list of completions
which are all link types prefix like ~attachment:~, and
=file:data/a2/..../attachFile.png=. I mean the second link. it is already in
completion list, but ~attchment:~ does not have this support.

> Regards Gustav
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com>
> Sent: Thursday, December 12, 2019 6:21:30 AM
> To: emacs-orgmode@gnu.org <emacs-orgmode@gnu.org>
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options 
>  
>
> Hi Gustav,
>
> I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will
> auto in completion list. It will be convenient for user.


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2019-12-12  9:52     ` stardiviner
@ 2019-12-12 19:42       ` Gustav Wikström
  2019-12-13 13:38         ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-12-12 19:42 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 12 december 2019 10:53
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> ...
> 
> For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c
> Ctrl-l]= (~org-insert-link~) to insert link which will show a list of
> completions
> which are all link types prefix like ~attachment:~, and
> =file:data/a2/..../attachFile.png=. I mean the second link. it is already in
> completion list, but ~attchment:~ does not have this support.

Hmm, I'm not sure I follow. Is it in the same suggestion list for link type prefixes 
that you also get the file-link to the newly attached file? I tried to reproduce that 
using emacs -q just now but couldn't... Is there a customization that you've enabled?

Regards
Gustav 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-12 19:42       ` Gustav Wikström
@ 2019-12-13 13:38         ` stardiviner
  2019-12-13 21:37           ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-13 13:38 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: stardiviner <numbchild@gmail.com>
>> Sent: den 12 december 2019 10:53
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> ...
>> 
>> For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c
>> Ctrl-l]= (~org-insert-link~) to insert link which will show a list of
>> completions
>> which are all link types prefix like ~attachment:~, and
>> =file:data/a2/..../attachFile.png=. I mean the second link. it is already in
>> completion list, but ~attchment:~ does not have this support.
>
> Hmm, I'm not sure I follow. Is it in the same suggestion list for link type prefixes 
> that you also get the file-link to the newly attached file?

Yes.

> I tried to reproduce that using emacs -q just now but couldn't... Is there a
> customization that you've enabled?

Aha, seems yes. I checked my config. I have option enabled:

#+begin_src emacs-lisp
(setq org-attach-store-link-p 'attached)
#+end_src

About this feature, WDYT?

>
> Regards
> Gustav 


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2019-12-13 13:38         ` stardiviner
@ 2019-12-13 21:37           ` Gustav Wikström
  2019-12-13 22:15             ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-12-13 21:37 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 13 december 2019 14:39
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> ...
> > I tried to reproduce that using emacs -q just now but couldn't... Is there a
> > customization that you've enabled?
> 
> Aha, seems yes. I checked my config. I have option enabled:
> 
> #+begin_src emacs-lisp
> (setq org-attach-store-link-p 'attached)
> #+end_src
> 
> About this feature, WDYT?
 
Ah, yes of course. What you propose make sense. More sense than the current functionality!

If no one objects I'll change the link that is stored for the 'attached option to be an
attachment link instead of a file link.

Regards
Gustav 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2019-12-13 21:37           ` Gustav Wikström
@ 2019-12-13 22:15             ` Gustav Wikström
  2019-12-15  4:14               ` stardiviner
  2019-12-15  9:29               ` stardiviner
  0 siblings, 2 replies; 113+ messages in thread
From: Gustav Wikström @ 2019-12-13 22:15 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

FYI, pushed to master. Commit 26ace9004

/Gustav

> -----Original Message-----
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On Behalf
> Of Gustav Wikström
> Sent: den 13 december 2019 22:37
> To: numbchild@gmail.com
> Cc: emacs-orgmode@gnu.org
> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> Hi,
> 
> > -----Original Message-----
> > From: stardiviner <numbchild@gmail.com>
> > Sent: den 13 december 2019 14:39
> > To: Gustav Wikström <gustav@whil.se>
> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> >
> > ...
> > > I tried to reproduce that using emacs -q just now but couldn't... Is there
> a
> > > customization that you've enabled?
> >
> > Aha, seems yes. I checked my config. I have option enabled:
> >
> > #+begin_src emacs-lisp
> > (setq org-attach-store-link-p 'attached)
> > #+end_src
> >
> > About this feature, WDYT?
> 
> Ah, yes of course. What you propose make sense. More sense than the current
> functionality!
> 
> If no one objects I'll change the link that is stored for the 'attached option
> to be an
> attachment link instead of a file link.
> 
> Regards
> Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-13 22:15             ` Gustav Wikström
@ 2019-12-15  4:14               ` stardiviner
  2019-12-15  9:29               ` stardiviner
  1 sibling, 0 replies; 113+ messages in thread
From: stardiviner @ 2019-12-15  4:14 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> FYI, pushed to master. Commit 26ace9004

Thanks

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-13 22:15             ` Gustav Wikström
  2019-12-15  4:14               ` stardiviner
@ 2019-12-15  9:29               ` stardiviner
  2019-12-15 10:06                 ` Gustav Wikström
  1 sibling, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-15  9:29 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> FYI, pushed to master. Commit 26ace9004
>

After update, I found the new attachment link type can't display inline image
now. Maybe should keep *both* original ~file:~ link type and new ~attachment:~ link
type in stored link? WDYT, Gustav?

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2019-12-15  9:29               ` stardiviner
@ 2019-12-15 10:06                 ` Gustav Wikström
  2019-12-15 14:26                   ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-12-15 10:06 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hmm, inline images work for attachment links on my side on Org mode master.

I considered keeping the file link option but ruled against it in the end. I could remove some complexity from the code in the end due to it.

Don't know why attachments aren’t expanded as images for you...

/G 

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 15 december 2019 10:29
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > FYI, pushed to master. Commit 26ace9004
> >
> 
> After update, I found the new attachment link type can't display inline
> image now. Maybe should keep *both* original ~file:~ link type and new
> ~attachment:~ link type in stored link? WDYT, Gustav?
> 
> --
> [ stardiviner ]
>        I try to make every word tell the meaning what I want to express.
> 
>        Blog: https://stardiviner.github.io/
>        IRC(freenode): stardiviner, Matrix: stardiviner
>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
> 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-15 10:06                 ` Gustav Wikström
@ 2019-12-15 14:26                   ` stardiviner
  2019-12-15 20:41                     ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-15 14:26 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hmm, inline images work for attachment links on my side on Org mode master.
>
> I considered keeping the file link option but ruled against it in the end. I could remove some complexity from the code in the end due to it.
>
> Don't know why attachments aren’t expanded as images for you...
>

I figured out why on my side inline image does not work.

When have link with description, the inline image does not work. When has no
link description, inline image works.

Here is an example:

#+begin_src org
# link work for inline image
[[attachment:screenshot.png]]

# inline image does not work
[[attachment:screenshot.png][description]]
#+end_src

I tested by EMC, found this is caused by some option. I will figure it out. Thanks!

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2019-12-15 14:26                   ` stardiviner
@ 2019-12-15 20:41                     ` Gustav Wikström
  2019-12-16  3:38                       ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2019-12-15 20:41 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

> -----Original Message-----
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
> Behalf Of stardiviner
> Sent: den 15 december 2019 15:26
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> ...
> 
> I figured out why on my side inline image does not work.
> 
> When have link with description, the inline image does not work. When has
> no link description, inline image works.
> 
> Here is an example:
> 
> #+begin_src org
> # link work for inline image
> [[attachment:screenshot.png]]
> 
> # inline image does not work
> [[attachment:screenshot.png][description]]
> #+end_src
> 
> I tested by EMC, found this is caused by some option. I will figure it
> out. Thanks!

FWIW, I see the same behavior as you do when I add descriptions. The same seems to 
apply for file-links. I haven't looked it up to see if that's intended though. Just 
wanted to share how it works for me, if you're scratching you're head over this!

Actually... Not wanting to push the "Send" button without looking into the manual, I 
found the following in the "Images" section:

	"An image is a link to an image file(1) that does not have a description part"

See [[info:org#Images]]

Regards
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-15 20:41                     ` Gustav Wikström
@ 2019-12-16  3:38                       ` stardiviner
  0 siblings, 0 replies; 113+ messages in thread
From: stardiviner @ 2019-12-16  3:38 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

>> -----Original Message-----
>> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
>> Behalf Of stardiviner
>> Sent: den 15 december 2019 15:26
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: emacs-orgmode@gnu.org
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> ...
>> 
>> I figured out why on my side inline image does not work.
>> 
>> When have link with description, the inline image does not work. When has
>> no link description, inline image works.
>> 
>> Here is an example:
>> 
>> #+begin_src org
>> # link work for inline image
>> [[attachment:screenshot.png]]
>> 
>> # inline image does not work
>> [[attachment:screenshot.png][description]]
>> #+end_src
>> 
>> I tested by EMC, found this is caused by some option. I will figure it
>> out. Thanks!
>
> FWIW, I see the same behavior as you do when I add descriptions. The same seems to 
> apply for file-links. I haven't looked it up to see if that's intended though. Just 
> wanted to share how it works for me, if you're scratching you're head over this!
>
> Actually... Not wanting to push the "Send" button without looking into the manual, I 
> found the following in the "Images" section:
>
> 	"An image is a link to an image file(1) that does not have a description part"
>
> See [[info:org#Images]]
>
> Regards
> Gustav

I read Org Info manual before, forgot most things, just put memory into
usual behavior now..... I will read Org Info manual again. :) glade you figure
out my wrong point, thanks.


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (4 preceding siblings ...)
  2019-12-12  5:21 ` stardiviner
@ 2019-12-16 11:21 ` stardiviner
  2019-12-17  4:27   ` stardiviner
  2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2019-12-16 11:21 UTC (permalink / raw)
  To: emacs-orgmode


I found another problem, =[C-c C-a d]= does not give out delete available
attachment files. Maybe other places is affected, suggest you check out other
places.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2019-12-16 11:21 ` stardiviner
@ 2019-12-17  4:27   ` stardiviner
  0 siblings, 0 replies; 113+ messages in thread
From: stardiviner @ 2019-12-17  4:27 UTC (permalink / raw)
  To: emacs-orgmode


stardiviner <numbchild@gmail.com> writes:

> I found another problem, =[C-c C-a d]= does not give out delete available
> attachment files. Maybe other places is affected, suggest you check out other
> places.

Ehh, sorry, today I found I can use this again. Weird that yesterday I got
nothing.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (5 preceding siblings ...)
  2019-12-16 11:21 ` stardiviner
@ 2020-01-13 12:24 ` stardiviner
  2020-01-14  3:27   ` Gustav Wikström
  2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner
  2020-01-17  7:39 ` Missing `org-attach-set-inherit' function stardiviner
  8 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-13 12:24 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]


When I export with =[C-c C-e h o]=, I found attached inline image links are not
displayed in HTML page.

Here is Org content:

#+begin_src org
,****** Strings are not Lists, but Anyway…
       :PROPERTIES:
       :ID:       2fd354f3-ac7a-499d-9fe4-a76626bbdb38
       :END:

In Calva Paredit, strings are treated in much the same way as lists are. Here’s
an example showing Slurp and Barf, Forward/Backward List, and Grow Selection.

[[attachment:string-as-list.gif]]

#+end_src

The email attachment contains the screenshot of HTML page.

I used Edebug on functions, track down to the error function ~(org-attach-dir)~,
it returns ~nil~ when in exporting to HTML, but when I evaluate ~(org-attach-dir)~
interactively under the headline, it works correctly.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

[-- Attachment #2: screenshot --]
[-- Type: image/png, Size: 96983 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (6 preceding siblings ...)
  2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner
@ 2020-01-13 13:41 ` stardiviner
  2020-01-14 21:17   ` Gustav Wikström
  2020-01-17  7:39 ` Missing `org-attach-set-inherit' function stardiviner
  8 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-13 13:41 UTC (permalink / raw)
  To: emacs-orgmode


I found when I set option ~(setq org-attach-store-link-p t)~. Then attach a file,
store file link with =[C-c C-l]=. The stored link. I open this link got error "No
such file: ....". I tested this with minimal Emacs config. confirmed this
problem.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner
@ 2020-01-14  3:27   ` Gustav Wikström
  2020-01-14  5:04     ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-14  3:27 UTC (permalink / raw)
  To: emacs-orgmode, numbchild

Hi!

Thanks for reporting this!

The code is updated on the master branch to make the exporters aware of how to deal with attachment links. Commit d70db54db for the curious. Basically, attachment links are expanded into file-links by the exporters now, before further processing into links in the respective markup language.

Regards
Gustav

________________________________________
From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com>
Sent: Monday, January 13, 2020 13:24
To: emacs-orgmode@gnu.org
Subject: Re: attachment: link type export to HTML invalid attach dir


When I export with =[C-c C-e h o]=, I found attached inline image links are not
displayed in HTML page.

Here is Org content:

#+begin_src org
,****** Strings are not Lists, but Anyway…
       :PROPERTIES:
       :ID:       2fd354f3-ac7a-499d-9fe4-a76626bbdb38
       :END:

In Calva Paredit, strings are treated in much the same way as lists are. Here’s
an example showing Slurp and Barf, Forward/Backward List, and Grow Selection.

[[attachment:string-as-list.gif]]

#+end_src

The email attachment contains the screenshot of HTML page.

I used Edebug on functions, track down to the error function ~(org-attach-dir)~,
it returns ~nil~ when in exporting to HTML, but when I evaluate ~(org-attach-dir)~
interactively under the headline, it works correctly.

--
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-14  3:27   ` Gustav Wikström
@ 2020-01-14  5:04     ` stardiviner
  2020-01-14 20:58       ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-14  5:04 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi!
>
> Thanks for reporting this!
>
> The code is updated on the master branch to make the exporters aware of how to deal with attachment links. Commit d70db54db for the curious. Basically, attachment links are expanded into file-links by the exporters now, before further processing into links in the respective markup language.
>
> Regards
> Gustav

Many thanks for really quick patching.

I tested out the new patch, still does not work.

#+begin_src org
,****** Strings are not Lists, but Anyway…
       :PROPERTIES:
       :ID:       2fd354f3-ac7a-499d-9fe4-a76626bbdb38
       :END:

In Calva Paredit, strings are treated in much the same way as lists are. Here’s
an example showing Slurp and Barf, Forward/Backward List, and Grow Selection.

[[attachment:string-as-list.gif]]

#+end_src

The upper org content is exported as this (HTML page):

#+begin_example
Strings are not Lists, but Anyway…

In Calva Paredit, strings are treated in much the same way as lists are. Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow Selection.

file:///home/stardiviner/Org/Wiki/Computer Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif
#+end_example

You can see:

1. the link still does not contains the attach directory from ~(org-attach-dir)~.
2. image links are not exported as inline image displayed with ~<img src="...">~.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-14  5:04     ` stardiviner
@ 2020-01-14 20:58       ` Gustav Wikström
  2020-01-15  5:53         ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-14 20:58 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi again,

> -----Original Message-----
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
> Behalf Of stardiviner
> Sent: den 14 januari 2020 06:04
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> [...]
>
> Many thanks for really quick patching.
> 
> I tested out the new patch, still does not work.
> 
> #+begin_src org
> ,****** Strings are not Lists, but Anyway…
>        :PROPERTIES:
>        :ID:       2fd354f3-ac7a-499d-9fe4-a76626bbdb38
>        :END:
> 
> In Calva Paredit, strings are treated in much the same way as lists are.
> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow
> Selection.
> 
> [[attachment:string-as-list.gif]]
> 
> #+end_src
> 
> The upper org content is exported as this (HTML page):
> 
> #+begin_example
> Strings are not Lists, but Anyway…
> 
> In Calva Paredit, strings are treated in much the same way as lists are.
> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow
> Selection.
> 
> file:///home/stardiviner/Org/Wiki/Computer
> Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif
> #+end_example
> 
> You can see:
> 
> 1. the link still does not contains the attach directory from ~(org-
> attach-dir)~.
> 2. image links are not exported as inline image displayed with ~<img
> src="...">~.

Ah, you're right. I missed a few things. Should be fixed now in master. Care to verify from your end again?

Thanks
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner
@ 2020-01-14 21:17   ` Gustav Wikström
  2020-01-15  6:20     ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-14 21:17 UTC (permalink / raw)
  To: numbchild, emacs-orgmode

Hi,

> -----Original Message-----
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
> Behalf Of stardiviner
> Sent: den 13 januari 2020 14:42
> To: emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> 
> I found when I set option ~(setq org-attach-store-link-p t)~. Then attach
> a file, store file link with =[C-c C-l]=. The stored link. I open this
> link got error "No such file: ....". I tested this with minimal Emacs
> config. confirmed this problem.
> 

I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and with only that single customization it works for me. I'm testing it in linux. A wild guess.. Could it be that you used the move operation instead of the copy operation when attaching the file?

Regards
Gustav


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-14 20:58       ` Gustav Wikström
@ 2020-01-15  5:53         ` stardiviner
  2020-01-15 19:48           ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-15  5:53 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi again,
>
>> -----Original Message-----
>> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
>> Behalf Of stardiviner
>> Sent: den 14 januari 2020 06:04
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: emacs-orgmode@gnu.org
>> Subject: Re: attachment: link type export to HTML invalid attach dir
>> 
>> [...]
>>
>> Many thanks for really quick patching.
>> 
>> I tested out the new patch, still does not work.
>> 
>> #+begin_src org
>> ,****** Strings are not Lists, but Anyway…
>>        :PROPERTIES:
>>        :ID:       2fd354f3-ac7a-499d-9fe4-a76626bbdb38
>>        :END:
>> 
>> In Calva Paredit, strings are treated in much the same way as lists are.
>> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow
>> Selection.
>> 
>> [[attachment:string-as-list.gif]]
>> 
>> #+end_src
>> 
>> The upper org content is exported as this (HTML page):
>> 
>> #+begin_example
>> Strings are not Lists, but Anyway…
>> 
>> In Calva Paredit, strings are treated in much the same way as lists are.
>> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow
>> Selection.
>> 
>> file:///home/stardiviner/Org/Wiki/Computer
>> Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif
>> #+end_example
>> 
>> You can see:
>> 
>> 1. the link still does not contains the attach directory from ~(org-
>> attach-dir)~.
>> 2. image links are not exported as inline image displayed with ~<img
>> src="...">~.
>
> Ah, you're right. I missed a few things. Should be fixed now in master. Care to verify from your end again?
>
> Thanks
> Gustav

I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved. But the
~(org-attach-dir)~ still not work. The exported ~<img src="">~ inline image still
does not contains the attach directory.

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2020-01-14 21:17   ` Gustav Wikström
@ 2020-01-15  6:20     ` stardiviner
  2020-01-15 22:42       ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-15  6:20 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
>> Behalf Of stardiviner
>> Sent: den 13 januari 2020 14:42
>> To: emacs-orgmode@gnu.org
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> 
>> I found when I set option ~(setq org-attach-store-link-p t)~. Then attach
>> a file, store file link with =[C-c C-l]=. The stored link. I open this
>> link got error "No such file: ....". I tested this with minimal Emacs
>> config. confirmed this problem.
>> 
>
> I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and with only that single customization it works for me. I'm testing it in linux. A wild guess.. Could it be that you used the move operation instead of the copy operation when attaching the file?
>
> Regards
> Gustav

Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode version
which does not contains the latest version =org-attach.el=.

Here is my minimal Emacs config:

#+begin_src emacs-lisp :tangle "~/.config/emacs/minimal-init.el"
(package-initialize)

;;; add my init files directory

(add-to-list 'load-path "/usr/share/emacs/site-lisp/")

(add-to-list 'load-path (expand-file-name "init" user-emacs-directory))

;; recursively load init files.
(let ((default-directory (expand-file-name "init" user-emacs-directory)))
  (setq load-path
        (append
         (let ((load-path (copy-sequence load-path))) ; shadow
           (append
            (copy-sequence (normal-top-level-add-to-load-path '(".")))
            (normal-top-level-add-subdirs-to-load-path)))
         load-path)))

(setq load-prefer-newer t)

;;; [ package.el ] -- Emacs Lisp Package Archive (ELPA)

(require 'package)

(setq package-enable-at-startup nil)

(setq package-menu-async t)

(setq package-user-dir (expand-file-name "elpa" user-emacs-directory))

;;; ELPA Mirrors
;; (setq-default package-archives
;; 	      '(("gnu" . "https://elpa.gnu.org/packages/")
;; 		("melpa" . "http://melpa.org/packages/")
;; 		("melpa-stable" . "http://stable.melpa.org/packages/")
;; 		("marmalade" . "http://marmalade-repo.org/packages/")
;; 		("org"   . "http://orgmode.org/elpa/")))

(setq-default package-archives
              '(("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")
                ("org"   . "http://mirrors.tuna.tsinghua.edu.cn/elpa/org/")
                ("gnu"   . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")))

(let* ((elpa-archives-dir (expand-file-name "elpa/archives/" user-emacs-directory))
       (elpa-gnu-archives-dir (concat elpa-archives-dir "gnu"))
       (elpa-melpa-archives-dir (concat elpa-archives-dir "melpa"))
       (elpa-org-archives-dir (concat elpa-archives-dir "org")))
  (unless (and (file-exists-p elpa-gnu-archives-dir)
               (file-exists-p elpa-melpa-archives-dir)
               (file-exists-p elpa-org-archives-dir))
    (package-refresh-contents)))

(package-initialize)

(add-to-list 'display-buffer-alist
             '("^\\*package-build-result\\*"
               (display-buffer-reuse-window display-buffer-below-selected)))


;;; Load `use-package' ahead before `package-initialize' for (use-package org :pin manual ...).
;;; [ use-package ]

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-when-compile
  (require 'use-package))
(require 'bind-key)                     ; if you use any `:bind' variant
(use-package delight                    ; if you use `:delight'
  :ensure t)
;; (use-package deminish                   ; if you use `:diminish'
;;   :ensure t)

(setq use-package-verbose t ; 'debug: any evaluation errors report to `*use-package*` buffer.
      use-package-always-ensure nil)

;;; use latest source code version Org Mode.
(if (not (file-exists-p "~/Code/Emacs/org-mode/lisp/"))
    (progn
      (use-package org
        :pin org
        :ensure t
        :preface (setq org-modules nil)
        :mode (("\\.org\\'" . org-mode)))
      (use-package org-plus-contrib
        :pin org
        :ensure t))

  ;; disable Emacs built-in Org Mode
  (delete (format "/usr/local/share/emacs/%s/lisp/org" emacs-version) load-path)
  (delete "/usr/share/emacs/site-lisp/org/" load-path)
  
  (use-package org
    :pin manual
    :load-path "~/Code/Emacs/org-mode/lisp/"
    :defer t
    :preface
    ;; Org Mode modules -- modules that should always be loaded together with org.el.
    ;; t: greedy load all modules.
    ;; nil: disable all extra org-mode modules to speed-up Org-mode file opening.
    (setq org-modules nil)
    :mode (("\\.org\\'" . org-mode))
    :init
    ;; add source code version Org-mode Info into Emacs.
    (with-eval-after-load 'info
      (add-to-list 'Info-directory-list "~/Code/Emacs/org-mode/doc/")
      (info-initialize))
    ;; load org before using some Org settings.
    (require 'org)
    (use-package org-plus-contrib
      :pin manual
      :load-path "~/Code/Emacs/org-mode/contrib/lisp/"
      :defer t
      :no-require t)))

;;==============================================================================
;;; Here is org-attach.el customization

(require 'org-attach)

;; store link auto with `org-store-link' using `file:' link type or `attachment:' link type.
(setq org-attach-store-link-p 'attached)
(setq org-attach-dir-relative t)
(setq org-attach-preferred-new-method 'ask)
#+end_src

#+begin_src sh :eval no
emacs -q -l '~/.config/emacs/minimal-init.el'
#+end_src

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-15  5:53         ` stardiviner
@ 2020-01-15 19:48           ` Gustav Wikström
  2020-01-16 11:06             ` stardiviner
  2020-01-16 13:18             ` Nicolas Goaziou
  0 siblings, 2 replies; 113+ messages in thread
From: Gustav Wikström @ 2020-01-15 19:48 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 15 januari 2020 06:53
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
>
> [...]
>
> I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved.
> But the ~(org-attach-dir)~ still not work. The exported ~<img src="">~
> inline image still does not contains the attach directory.

Ah yes. Found the culprit for this issue. Hopefully the last one. The exporter doesn't actually move the point in the buffer during the export. So org-attach-expand tried to expand from the first character in the buffer. This should be fixed from a few minutes ago.

Crossing fingers for this to work properly now!

Regards
Gustav
 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2020-01-15  6:20     ` stardiviner
@ 2020-01-15 22:42       ` Gustav Wikström
  2020-01-16 11:15         ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-15 22:42 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 15 januari 2020 07:21
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> [...]
> 
> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then
> >> attach a file, store file link with =[C-c C-l]=. The stored link. I
> >> open this link got error "No such file: ....". I tested this with
> >> minimal Emacs config. confirmed this problem.
> >>
> >
> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and
> with only that single customization it works for me. I'm testing it in
> linux. A wild guess.. Could it be that you used the move operation instead
> of the copy operation when attaching the file?
> >
> > Regards
> > Gustav
> 
> Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode
> version which does not contains the latest version =org-attach.el=.
> 
> Here is my minimal Emacs config:
>
> [...]
>
> ;;========================================================================
> ======
> ;;; Here is org-attach.el customization
> 
> (require 'org-attach)
> 
> ;; store link auto with `org-store-link' using `file:' link type or
> `attachment:' link type.
> (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t)
> (setq org-attach-preferred-new-method 'ask) #+end_src
> 
> #+begin_src sh :eval no
> emacs -q -l '~/.config/emacs/minimal-init.el'
> #+end_src

Hmm, in the first mail you said that you set org-attach-store-link-p to t, but in your config it says 'attached. I've tried with a minimal config as well (using emacs -q because I build the newest org mode version into the emacs folder) and can only reproduce your issue when using the attached option for org-attach-store-link-p and then inserting that link with C-c C-l /in another heading/. Pasting the link in another heading is expected to break since the attachment link is context dependent (i.e. requires an attachment folder). Makes sense? If I'm still misunderstanding your use-case, would you care to describe the steps to reproduce it more in detail?

Regards	
Gustav
 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-15 19:48           ` Gustav Wikström
@ 2020-01-16 11:06             ` stardiviner
  2020-01-16 13:18             ` Nicolas Goaziou
  1 sibling, 0 replies; 113+ messages in thread
From: stardiviner @ 2020-01-16 11:06 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: stardiviner <numbchild@gmail.com>
>> Sent: den 15 januari 2020 06:53
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>> Subject: Re: attachment: link type export to HTML invalid attach dir
>>
>> [...]
>>
>> I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved.
>> But the ~(org-attach-dir)~ still not work. The exported ~<img src="">~
>> inline image still does not contains the attach directory.
>

> Ah yes. Found the culprit for this issue. Hopefully the last one. The exporter
doesn't actually move the point in the buffer during the export. So
org-attach-expand tried to expand from the first character in the buffer. This
should be fixed from a few minutes ago.

Aha, wow!!! thanks for great patch. It worked now. Thanks really. :)

>
> Crossing fingers for this to work properly now!
>
> Regards
> Gustav
>  

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2020-01-15 22:42       ` Gustav Wikström
@ 2020-01-16 11:15         ` stardiviner
  2020-01-18 14:56           ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-16 11:15 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: stardiviner <numbchild@gmail.com>
>> Sent: den 15 januari 2020 07:21
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> [...]
>> 
>> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then
>> >> attach a file, store file link with =[C-c C-l]=. The stored link. I
>> >> open this link got error "No such file: ....". I tested this with
>> >> minimal Emacs config. confirmed this problem.
>> >>
>> >
>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and
>> with only that single customization it works for me. I'm testing it in
>> linux. A wild guess.. Could it be that you used the move operation instead
>> of the copy operation when attaching the file?
>> >
>> > Regards
>> > Gustav
>> 
>> Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode
>> version which does not contains the latest version =org-attach.el=.
>> 
>> Here is my minimal Emacs config:
>>
>> [...]
>>
>> ;;========================================================================
>> ======
>> ;;; Here is org-attach.el customization
>> 
>> (require 'org-attach)
>> 
>> ;; store link auto with `org-store-link' using `file:' link type or
>> `attachment:' link type.
>> (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t)
>> (setq org-attach-preferred-new-method 'ask) #+end_src
>> 
>> #+begin_src sh :eval no
>> emacs -q -l '~/.config/emacs/minimal-init.el'
>> #+end_src
>

> Hmm, in the first mail you said that you set org-attach-store-link-p to t, but
> in your config it says 'attached.

Sorry about this.

> I've tried with a minimal config as well
> (using emacs -q because I build the newest org mode version into the emacs
> folder) and can only reproduce your issue when using the attached option for
> org-attach-store-link-p and then inserting that link with C-c C-l /in another
> heading/. Pasting the link in another heading is expected to break since the
> attachment link is context dependent (i.e. requires an attachment folder).
> Makes sense? If I'm still misunderstanding your use-case, would you care to
> describe the steps to reproduce it more in detail?

After updated commit, don't know why, but all links worked again. I'm not good
at expressing thanks, but you got all my thanks on this. :)

> Regards	
> Gustav
>  


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-15 19:48           ` Gustav Wikström
  2020-01-16 11:06             ` stardiviner
@ 2020-01-16 13:18             ` Nicolas Goaziou
  2020-01-16 21:42               ` Gustav Wikström
  1 sibling, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2020-01-16 13:18 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Ah yes. Found the culprit for this issue. Hopefully the last one. The
> exporter doesn't actually move the point in the buffer during the
> export. So org-attach-expand tried to expand from the first character
> in the buffer. This should be fixed from a few minutes ago.

I'm not sure hard-coding attachment links in exporters in the best way
forward. For example, exporters in the wild may not cope with them
before a long time, if ever. There is some code duplication, too.

If attachments links are similar to file links from an export point of
view, then I suggest to add a phase in ox.el to expand the former into
the latter, before even using export back-ends. This way, there is no
change required in the exporters, shipped in or not.

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-16 13:18             ` Nicolas Goaziou
@ 2020-01-16 21:42               ` Gustav Wikström
  2020-01-16 23:07                 ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-16 21:42 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi Nicolas,

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 16 januari 2020 14:18
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> Hello,
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Ah yes. Found the culprit for this issue. Hopefully the last one. The
> > exporter doesn't actually move the point in the buffer during the
> > export. So org-attach-expand tried to expand from the first character
> > in the buffer. This should be fixed from a few minutes ago.
> 
> I'm not sure hard-coding attachment links in exporters in the best way
> forward. For example, exporters in the wild may not cope with them before
> a long time, if ever. There is some code duplication, too.

Yes indeed, duplicated functionality for all export backends as it stands.

> 
> If attachments links are similar to file links from an export point of
> view, then I suggest to add a phase in ox.el to expand the former into the
> latter, before even using export back-ends. This way, there is no change
> required in the exporters, shipped in or not.

Yeah, I do think attachment links should be treated as file links when exported. And I like this suggestion, although that means I probably have to dig into the ox.el code. Not an easy task. I suspect you'd guide me to adding logic inside org-export-as for this. I'll have a look starting from there. But wouldn't mind some further insights here!

Regards
Gustav

> 
> Regards,
> 
> --
> Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-16 21:42               ` Gustav Wikström
@ 2020-01-16 23:07                 ` Gustav Wikström
  2020-01-17  0:39                   ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-16 23:07 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi again,

> -----Original Message-----
> From: Gustav Wikström
> Sent: den 16 januari 2020 22:42
> To: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: RE: attachment: link type export to HTML invalid attach dir
> 
> Hi Nicolas,
> 
> > -----Original Message-----
> > From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> > Sent: den 16 januari 2020 14:18
> > To: Gustav Wikström <gustav@whil.se>
> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> > Subject: Re: attachment: link type export to HTML invalid attach dir
> >
> > Hello,
> >
> > Gustav Wikström <gustav@whil.se> writes:
> >
> > > Ah yes. Found the culprit for this issue. Hopefully the last one.
> > > The exporter doesn't actually move the point in the buffer during
> > > the export. So org-attach-expand tried to expand from the first
> > > character in the buffer. This should be fixed from a few minutes ago.
> >
> > I'm not sure hard-coding attachment links in exporters in the best way
> > forward. For example, exporters in the wild may not cope with them
> > before a long time, if ever. There is some code duplication, too.
> 
> Yes indeed, duplicated functionality for all export backends as it stands.
> 
> >
> > If attachments links are similar to file links from an export point of
> > view, then I suggest to add a phase in ox.el to expand the former into
> > the latter, before even using export back-ends. This way, there is no
> > change required in the exporters, shipped in or not.
> 
> Yeah, I do think attachment links should be treated as file links when
> exported. And I like this suggestion, although that means I probably have
> to dig into the ox.el code. Not an easy task. I suspect you'd guide me to
> adding logic inside org-export-as for this. I'll have a look starting from
> there. But wouldn't mind some further insights here!

After thinking a while I'm leaning towards thinking this should be handled already in the element link parser and interpreter. Need a bit more metadata for that though, to be able to deconstruct and reconstruct the link properly while still providing the correct paths.

Hardcoding the translation of attachment-links into file-links in an in-between layer (ox.el - that is somewhat complicated as well) is not transparent and I think best to avoid. Even if an attachment link is /very/ similar to a file link it may be best still to treat them for what they are. If some export back-ends out in the wild don't work with attachment-links today then so be it. But let's at least make it easy to fix! So I'll try to remove the hard coding of org-attach invocation and instead make the attachment-path when parsed by org-element return a path that is an actual file-system path out of the box. I'll see what I figure out in terms of code I suppose...! 

What do you say? 

> 
> Regards
> Gustav
> 
> >
> > Regards,
> >
> > --
> > Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-16 23:07                 ` Gustav Wikström
@ 2020-01-17  0:39                   ` Nicolas Goaziou
  2020-01-17 14:29                     ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2020-01-17  0:39 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Gustav Wikström <gustav@whil.se> writes:

> Hardcoding the translation of attachment-links into file-links in an
> in-between layer (ox.el - that is somewhat complicated as well) is not
> transparent and I think best to avoid. Even if an attachment link is
> /very/ similar to a file link it may be best still to treat them for
> what they are. If some export back-ends out in the wild don't work
> with attachment-links today then so be it. But let's at least make it
> easy to fix! So I'll try to remove the hard coding of org-attach
> invocation and instead make the attachment-path when parsed by
> org-element return a path that is an actual file-system path out of
> the box. I'll see what I figure out in terms of code I suppose...!
>
> What do you say?

It is true that Element library expands link abbreviations right before
parsing a link, and an attachment is similar to a local link
abbreviation. This is not great because some information is lost in the
process: interpreting the parse tree will not bring the abbreviation
back, only its expanded form. Actually, `org-link-expand-abbrev' is
called so that the parser knows what is the true type of the link, since
abbreviations could expand to anything. OTOH, attachments can only
expand to a "file" link, so the motivation for expansion doesn't hold.

Besides, there's no good reason to store redundant, or even remote,
information in the parse tree. The parser needs to be as low level as
possible.

Moreover, the issue encountered here is specific to export, so it makes
sense to solve at the export level, i.e., in "ox.el". This is not
trivial though, as it needs to be done very early, much link footnotes.
Indeed, since the meaning of the link is position dependent, including
parts of a document, or executing arbitrary code can mess it up. IOW
expansion should happen in `org-export--prepare-file-contents', i.e.,
within every included piece of text, and in `org-export-as', somewhere
after `org-export-expand-include-keyword' call, but before Babel code
execution.

HTH,

Regards,

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Missing `org-attach-set-inherit' function
  2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
                   ` (7 preceding siblings ...)
  2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner
@ 2020-01-17  7:39 ` stardiviner
  2020-01-17 16:31   ` Gustav Wikström
  8 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-17  7:39 UTC (permalink / raw)
  To: emacs-orgmode


I found the function ~org-attach-set-inherit~ is missing. I noticed it in the Info
document.

#+begin_quote
     ‘i’ (‘org-attach-set-inherit’)
          Set the ‘ATTACH_DIR_INHERIT’ property, so that children use
          the same directory for attachments as the parent does.
#+end_quote

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-17  0:39                   ` Nicolas Goaziou
@ 2020-01-17 14:29                     ` Gustav Wikström
  2020-01-17 18:36                       ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-17 14:29 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 17 januari 2020 01:40
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Hardcoding the translation of attachment-links into file-links in an
> > in-between layer (ox.el - that is somewhat complicated as well) is not
> > transparent and I think best to avoid. Even if an attachment link is
> > /very/ similar to a file link it may be best still to treat them for
> > what they are. If some export back-ends out in the wild don't work
> > with attachment-links today then so be it. But let's at least make it
> > easy to fix! So I'll try to remove the hard coding of org-attach
> > invocation and instead make the attachment-path when parsed by
> > org-element return a path that is an actual file-system path out of
> > the box. I'll see what I figure out in terms of code I suppose...!
> >
> > What do you say?
> 
> It is true that Element library expands link abbreviations right before
> parsing a link, and an attachment is similar to a local link abbreviation.
> This is not great because some information is lost in the
> process: interpreting the parse tree will not bring the abbreviation back,
> only its expanded form. Actually, `org-link-expand-abbrev' is called so
> that the parser knows what is the true type of the link, since
> abbreviations could expand to anything. OTOH, attachments can only expand
> to a "file" link, so the motivation for expansion doesn't hold.

Hmm, interesting... And are we sure the destructive behavior is something we want to maintain? I for one would vote for the parsers ability to provide information that can reconstruct the source... Is it really worth the space saving in the parse tree to do that destruction? I feel inclined here to add a :link and :raw-path property to the output from the link parser for example. That would allow those links that expand to be stored in the parse tree in both expanded and non-expanded form. 

Reasons against?  

> Besides, there's no good reason to store redundant, or even remote,
> information in the parse tree. The parser needs to be as low level as
> possible.

Yes, this is a reason against... But big enough? I humbly question that a bit. Also, would it be feasible to store the original "raw" form only if it differs from the expanded form? It may complicate the interpreters work though... They would have to have a bit more insight into when the original form will be needed. Not sure of the better design decision here. 

> Moreover, the issue encountered here is specific to export, so it makes
> sense to solve at the export level, i.e., in "ox.el". This is not trivial
> though, as it needs to be done very early, much link footnotes.
> Indeed, since the meaning of the link is position dependent, including
> parts of a document, or executing arbitrary code can mess it up. IOW
> expansion should happen in `org-export--prepare-file-contents', i.e.,
> within every included piece of text, and in `org-export-as', somewhere
> after `org-export-expand-include-keyword' call, but before Babel code
> execution.

It's actually not only specific to exporting. Opening attachment links show a similar issue (org-link-open). Because the current way to open files and attachments differ. And it shouldn't have to! That as well would be solved if the link parser would take care of the path expansion. One example of the difference today is that attachment links cannot abide to any prefix argument. As a user I would expect the prefix arguments that work for files to also work for attachments. Something I think we can fix here, by making the parser do a little bit more work. I'd be happy to apply a patch. 

Kind regards
Gustav


^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: Missing `org-attach-set-inherit' function
  2020-01-17  7:39 ` Missing `org-attach-set-inherit' function stardiviner
@ 2020-01-17 16:31   ` Gustav Wikström
  2020-01-18 14:54     ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-17 16:31 UTC (permalink / raw)
  To: numbchild, emacs-orgmode

Hi,

> -----Original Message-----
> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
> Behalf Of stardiviner
> Sent: den 17 januari 2020 08:39
> To: emacs-orgmode@gnu.org
> Subject: Missing `org-attach-set-inherit' function
> 
> 
> I found the function ~org-attach-set-inherit~ is missing. I noticed it in
> the Info document.
> 
> #+begin_quote
>      ‘i’ (‘org-attach-set-inherit’)
>           Set the ‘ATTACH_DIR_INHERIT’ property, so that children use
>           the same directory for attachments as the parent does.
> #+end_quote

I can't find that reference in the newest version of the documentation. Should be removed since commit ae9cd437.

Are you sure the documentation and your Org mode version is the same?

> 
> --
> [ stardiviner ]
>        I try to make every word tell the meaning what I want to express.
> 
>        Blog: https://stardiviner.github.io/
>        IRC(freenode): stardiviner, Matrix: stardiviner
>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-17 14:29                     ` Gustav Wikström
@ 2020-01-17 18:36                       ` Gustav Wikström
  2020-01-18  1:13                         ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-17 18:36 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi again,

> -----Original Message-----
> From: Gustav Wikström
> Sent: den 17 januari 2020 15:30
> To: 'Nicolas Goaziou' <mail@nicolasgoaziou.fr>
> Cc: emacs-orgmode@gnu.org
> Subject: RE: attachment: link type export to HTML invalid attach dir
> 
> Hi,
> 
> [...]
>
> >
> > It is true that Element library expands link abbreviations right
> > before parsing a link, and an attachment is similar to a local link
> abbreviation.
> > This is not great because some information is lost in the
> > process: interpreting the parse tree will not bring the abbreviation
> > back, only its expanded form. Actually, `org-link-expand-abbrev' is
> > called so that the parser knows what is the true type of the link,
> > since abbreviations could expand to anything. OTOH, attachments can
> > only expand to a "file" link, so the motivation for expansion doesn't
> hold.
> 
> Hmm, interesting... And are we sure the destructive behavior is something
> we want to maintain? I for one would vote for the parsers ability to
> provide information that can reconstruct the source... Is it really worth
> the space saving in the parse tree to do that destruction? I feel inclined
> here to add a :link and :raw-path property to the output from the link
> parser for example. That would allow those links that expand to be stored
> in the parse tree in both expanded and non-expanded form.
> 
> Reasons against?

Hmm, I'm actually kind of going full circle here, back to think that the logic currently implemented is in its right place... Either that, or to just decorate the link in the parse-tree with some auxiliary information that can be specific for the type of link. For attachment links that auxiliary information would be attachment-path-prefix (or something shorter but possibly less clear). For abbreviated links possibly the auxiliary information would be it's unexpanded form. But I'm not sure of the necessity or need for that, except from allowing interpreters to reconstruct the original link.

> 
> [...]
> 

Regards
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-17 18:36                       ` Gustav Wikström
@ 2020-01-18  1:13                         ` Gustav Wikström
  2020-01-18 11:34                           ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-18  1:13 UTC (permalink / raw)
  To: Nicolas Goaziou, emacs-orgmode

Ok, so change pushed...

Where org-element-link-parser now sets one extra property only for attachment links. The exporters and org-link-open use this additional information when exporting and opening attachment links. Feature parity with file links should now be complete. Note that exporters outside of the Org mode repo need to be aware of the attachment link type if the path expansion is to be correct. They aren't translated in between into file-links. Not doing that translation is the proper think in my opinion. No magic hiding of the attachment link type. Who knows - maybe some exporters in the future need the link as is, without expansion!?. Making an exporter in the wild aware of attachment links can be done using org-element-property and the new property :attachment-path created by the parser only for attachment links.

Regards
Gustav

> -----Original Message-----
> From: Gustav Wikström
> Sent: den 17 januari 2020 19:36
> To: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Cc: emacs-orgmode@gnu.org
> Subject: RE: attachment: link type export to HTML invalid attach dir
> 
> Hi again,
> 
> > -----Original Message-----
> > From: Gustav Wikström
> > Sent: den 17 januari 2020 15:30
> > To: 'Nicolas Goaziou' <mail@nicolasgoaziou.fr>
> > Cc: emacs-orgmode@gnu.org
> > Subject: RE: attachment: link type export to HTML invalid attach dir
> >
> > Hi,
> >
> > [...]
> >
> > >
> > > It is true that Element library expands link abbreviations right
> > > before parsing a link, and an attachment is similar to a local link
> > abbreviation.
> > > This is not great because some information is lost in the
> > > process: interpreting the parse tree will not bring the abbreviation
> > > back, only its expanded form. Actually, `org-link-expand-abbrev' is
> > > called so that the parser knows what is the true type of the link,
> > > since abbreviations could expand to anything. OTOH, attachments can
> > > only expand to a "file" link, so the motivation for expansion
> > > doesn't
> > hold.
> >
> > Hmm, interesting... And are we sure the destructive behavior is
> > something we want to maintain? I for one would vote for the parsers
> > ability to provide information that can reconstruct the source... Is
> > it really worth the space saving in the parse tree to do that
> > destruction? I feel inclined here to add a :link and :raw-path
> > property to the output from the link parser for example. That would
> > allow those links that expand to be stored in the parse tree in both
> expanded and non-expanded form.
> >
> > Reasons against?
> 
> Hmm, I'm actually kind of going full circle here, back to think that the
> logic currently implemented is in its right place... Either that, or to
> just decorate the link in the parse-tree with some auxiliary information
> that can be specific for the type of link. For attachment links that
> auxiliary information would be attachment-path-prefix (or something
> shorter but possibly less clear). For abbreviated links possibly the
> auxiliary information would be it's unexpanded form. But I'm not sure of
> the necessity or need for that, except from allowing interpreters to
> reconstruct the original link.
> 
> >
> > [...]
> >
> 
> Regards
> Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-18  1:13                         ` Gustav Wikström
@ 2020-01-18 11:34                           ` Nicolas Goaziou
  2020-01-18 15:14                             ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2020-01-18 11:34 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Ok, so change pushed...

I'm sorry, but this is going too fast. We're discussing core design here
(the parser), and I couldn't even answer your proposal. Let's at least
reach an agreement on the change to make.

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: Missing `org-attach-set-inherit' function
  2020-01-17 16:31   ` Gustav Wikström
@ 2020-01-18 14:54     ` stardiviner
  0 siblings, 0 replies; 113+ messages in thread
From: stardiviner @ 2020-01-18 14:54 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi,
>
>> -----Original Message-----
>> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On
>> Behalf Of stardiviner
>> Sent: den 17 januari 2020 08:39
>> To: emacs-orgmode@gnu.org
>> Subject: Missing `org-attach-set-inherit' function
>> 
>> 
>> I found the function ~org-attach-set-inherit~ is missing. I noticed it in
>> the Info document.
>> 
>> #+begin_quote
>>      ‘i’ (‘org-attach-set-inherit’)
>>           Set the ‘ATTACH_DIR_INHERIT’ property, so that children use
>>           the same directory for attachments as the parent does.
>> #+end_quote
>
> I can't find that reference in the newest version of the documentation. Should be removed since commit ae9cd437.
>
> Are you sure the documentation and your Org mode version is the same?

You're right, seems my org.info file is old. I recompiled it with command =make
info=, That "i" is gone now. Thanks for hint. :)

>
>> 
>> --
>> [ stardiviner ]
>>        I try to make every word tell the meaning what I want to express.
>> 
>>        Blog: https://stardiviner.github.io/
>>        IRC(freenode): stardiviner, Matrix: stardiviner
>>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
>> 


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2020-01-16 11:15         ` stardiviner
@ 2020-01-18 14:56           ` stardiviner
  2020-01-18 15:30             ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-18 14:56 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 3089 bytes --]


stardiviner <numbchild@gmail.com> writes:

I finally figured out why the link always failed. Because it use wrong variable
which is old filename path. I attached a patch.

> Gustav Wikström <gustav@whil.se> writes:
>
>> Hi,
>>
>>> -----Original Message-----
>>> From: stardiviner <numbchild@gmail.com>
>>> Sent: den 15 januari 2020 07:21
>>> To: Gustav Wikström <gustav@whil.se>
>>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>>> 
>>> [...]
>>> 
>>> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then
>>> >> attach a file, store file link with =[C-c C-l]=. The stored link. I
>>> >> open this link got error "No such file: ....". I tested this with
>>> >> minimal Emacs config. confirmed this problem.
>>> >>
>>> >
>>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and
>>> with only that single customization it works for me. I'm testing it in
>>> linux. A wild guess.. Could it be that you used the move operation instead
>>> of the copy operation when attaching the file?
>>> >
>>> > Regards
>>> > Gustav
>>> 
>>> Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode
>>> version which does not contains the latest version =org-attach.el=.
>>> 
>>> Here is my minimal Emacs config:
>>>
>>> [...]
>>>
>>> ;;========================================================================
>>> ======
>>> ;;; Here is org-attach.el customization
>>> 
>>> (require 'org-attach)
>>> 
>>> ;; store link auto with `org-store-link' using `file:' link type or
>>> `attachment:' link type.
>>> (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t)
>>> (setq org-attach-preferred-new-method 'ask) #+end_src
>>> 
>>> #+begin_src sh :eval no
>>> emacs -q -l '~/.config/emacs/minimal-init.el'
>>> #+end_src
>>
>
>> Hmm, in the first mail you said that you set org-attach-store-link-p to t, but
>> in your config it says 'attached.
>
> Sorry about this.
>
>> I've tried with a minimal config as well
>> (using emacs -q because I build the newest org mode version into the emacs
>> folder) and can only reproduce your issue when using the attached option for
>> org-attach-store-link-p and then inserting that link with C-c C-l /in another
>> heading/. Pasting the link in another heading is expected to break since the
>> attachment link is context dependent (i.e. requires an attachment folder).
>> Makes sense? If I'm still misunderstanding your use-case, would you care to
>> describe the steps to reproduce it more in detail?
>
> After updated commit, don't know why, but all links worked again. I'm not good
> at expressing thanks, but you got all my thanks on this. :)
>
>> Regards	
>> Gustav
>>  

-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-org-attach-store-link-use-old-filename.patch --]
[-- Type: text/x-patch, Size: 882 bytes --]

From 006583a83bc3b05b28ed1ad3610081066c0b1f95 Mon Sep 17 00:00:00 2001
From: stardiviner <numbchild@gmail.com>
Date: Sat, 18 Jan 2020 22:51:53 +0800
Subject: [PATCH] Fix org-attach store link use old filename

---
 lisp/org-attach.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 6bb438c72..c3d3ecda9 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -504,8 +504,8 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
 			 (file-name-nondirectory fname))
 		   org-stored-links))
             ((eq org-attach-store-link-p t)
-             (push (list (concat "file:" file)
-			 (file-name-nondirectory file))
+             (push (list (concat "file:" fname)
+			 (file-name-nondirectory fname))
 		   org-stored-links)))
       (if visit-dir
           (dired attach-dir)
-- 
2.25.0


^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-18 11:34                           ` Nicolas Goaziou
@ 2020-01-18 15:14                             ` Gustav Wikström
  2020-01-19 21:12                               ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-18 15:14 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 18 januari 2020 12:34
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> Hello,
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Ok, so change pushed...
> 
> I'm sorry, but this is going too fast. We're discussing core design here
> (the parser), and I couldn't even answer your proposal. Let's at least
> reach an agreement on the change to make.

Yes, agreed, it was a bit fast. The final changes was done to not stop "in the middle" so to say, with something both you and me think is suboptimal. Functionally it's in a good (and maintainable) state right now, in my opinion. But I do understand that the contextual attribute added to the parser may require some discussion. If the decision is to not allow contextual attributes in the parser I'm prepared to revert and change again. No stress though.

Just to add a note about the trail of my thoughts regarding this... And why I thought the contextual attribute was a good option here:

I argue that the attachment folder is a part of the attachment link, even though the information is found at a different location in the document (i.e. as a property to nodes in the document hierarchy). Parsing an attachment link would then be incomplete if that information is discarded. One option to adding an attribute could be to modify existing properties by adding the attachment folder to, for example, the path property. But that means to remove information about what was written as path in the original link. So I argue to keep path as the original path. But that means extra information is needed to also make it work in the filesystem. If we would translate an attachment link to a file link in ox.el that means we remove the option for exporters to decide for themselves what to do with the link. And I think the exporter should have that option. :) Right now the ASCII exporter for example outputs attachment links as attachment:expanded_path instead of file:expanded_path. Since the link type actually is attachment. And for a solemnly textual export the exported information should be kept as close to source as possible. So either we explicitly and always say attachment-links *are* file-links in disguise (i.e. even change type in the parser), or we don't say that, and then don't say that all the way to the edge of the system. And let the uses of the link type decide themselves what to do. Which is what I propose. But with the addition of a bit of extra information contextual for the attachment links. 
 
Whoops long paragraph, sorry... I'm just trying to explain my current way of looking at this.

Regards
Gustav


^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2020-01-18 14:56           ` stardiviner
@ 2020-01-18 15:30             ` Gustav Wikström
  2020-01-19  4:28               ` stardiviner
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-18 15:30 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi!

org-attach-store-link-p with option t is supposed to store a link to the original location (i.e. the location the file was/is in before it was attached to the node. That was the default before I started working with attachments I believe. Haven't ever used that feature myself but the patch you provide would change the functionality which I don't think is correct. It would also not match the documentation any longer.

See the documentation for the customization parameter:

#+begin_src emacs-lisp
  (defcustom org-attach-store-link-p nil
    "Non-nil means store a link to a file when attaching it."
    :group 'org-attach
    :version "24.1"
    :type '(choice
            (const :tag "Don't store link" nil)
            (const :tag "Link to origin location" t)
            (const :tag "Link to the attach-dir location" attached)))
#+end_src

Regards
Gustav

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 18 januari 2020 15:56
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> 
> stardiviner <numbchild@gmail.com> writes:
> 
> I finally figured out why the link always failed. Because it use wrong
> variable which is old filename path. I attached a patch.
> 
> > Gustav Wikström <gustav@whil.se> writes:
> >
> >> Hi,
> >>
> >>> -----Original Message-----
> >>> From: stardiviner <numbchild@gmail.com>
> >>> Sent: den 15 januari 2020 07:21
> >>> To: Gustav Wikström <gustav@whil.se>
> >>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> >>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach
> >>> options
> >>>
> >>> [...]
> >>>
> >>> >> I found when I set option ~(setq org-attach-store-link-p t)~.
> >>> >> Then attach a file, store file link with =[C-c C-l]=. The stored
> >>> >> link. I open this link got error "No such file: ....". I tested
> >>> >> this with minimal Emacs config. confirmed this problem.
> >>> >>
> >>> >
> >>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q)
> >>> > and
> >>> with only that single customization it works for me. I'm testing it
> >>> in linux. A wild guess.. Could it be that you used the move
> >>> operation instead of the copy operation when attaching the file?
> >>> >
> >>> > Regards
> >>> > Gustav
> >>>
> >>> Did you reproduce this issue with =emacs -q= ? That is a built-in
> >>> Org Mode version which does not contains the latest version =org-
> attach.el=.
> >>>
> >>> Here is my minimal Emacs config:
> >>>
> >>> [...]
> >>>
> >>> ;;==================================================================
> >>> ======
> >>> ======
> >>> ;;; Here is org-attach.el customization
> >>>
> >>> (require 'org-attach)
> >>>
> >>> ;; store link auto with `org-store-link' using `file:' link type or
> >>> `attachment:' link type.
> >>> (setq org-attach-store-link-p 'attached) (setq
> >>> org-attach-dir-relative t) (setq org-attach-preferred-new-method
> >>> 'ask) #+end_src
> >>>
> >>> #+begin_src sh :eval no
> >>> emacs -q -l '~/.config/emacs/minimal-init.el'
> >>> #+end_src
> >>
> >
> >> Hmm, in the first mail you said that you set org-attach-store-link-p
> >> to t, but in your config it says 'attached.
> >
> > Sorry about this.
> >
> >> I've tried with a minimal config as well (using emacs -q because I
> >> build the newest org mode version into the emacs
> >> folder) and can only reproduce your issue when using the attached
> >> option for org-attach-store-link-p and then inserting that link with
> >> C-c C-l /in another heading/. Pasting the link in another heading is
> >> expected to break since the attachment link is context dependent (i.e.
> requires an attachment folder).
> >> Makes sense? If I'm still misunderstanding your use-case, would you
> >> care to describe the steps to reproduce it more in detail?
> >
> > After updated commit, don't know why, but all links worked again. I'm
> > not good at expressing thanks, but you got all my thanks on this. :)
> >
> >> Regards
> >> Gustav
> >>
> 
> --
> [ stardiviner ]
>        I try to make every word tell the meaning what I want to express.
> 
>        Blog: https://stardiviner.github.io/
>        IRC(freenode): stardiviner, Matrix: stardiviner
>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
> 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: FW: [RFC] Link-type for attachments, more attach options
  2020-01-18 15:30             ` Gustav Wikström
@ 2020-01-19  4:28               ` stardiviner
  2020-01-19  9:53                 ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: stardiviner @ 2020-01-19  4:28 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode


Gustav Wikström <gustav@whil.se> writes:

> Hi!
>
> org-attach-store-link-p with option t is supposed to store a link to the original location (i.e. the location the file was/is in before it was attached to the node. That was the default before I started working with attachments I believe. Haven't ever used that feature myself but the patch you provide would change the functionality which I don't think is correct. It would also not match the documentation any longer.
>
> See the documentation for the customization parameter:
>
> #+begin_src emacs-lisp
>   (defcustom org-attach-store-link-p nil
>     "Non-nil means store a link to a file when attaching it."
>     :group 'org-attach
>     :version "24.1"
>     :type '(choice
>             (const :tag "Don't store link" nil)
>             (const :tag "Link to origin location" t)
>             (const :tag "Link to the attach-dir location" attached)))
> #+end_src
>
> Regards
> Gustav

I've been used this functionality for a long time, I always store the link after
attached file. Because the old path is gone.

For example, I have a file in =~/Downloads/kk.png=, then I attached it under a
node, then the file moved to =data/images/kk.png=. The original file
=~/Downloads/kk.png= is gone, does not exist, because I use =mv= method. If still
link to original location, so the link file does not exist. That's why I found
it inconsistent.

Here is the commit which might affected this behavior if I guess right.

#+begin_src diff
26ace9004 origin/master Make org-attach store links using attachment-links
modified   lisp/org-attach.el
@@ -487,33 +479,37 @@
 (defun org-attach-attach (file &optional visit-dir method)
   "Move/copy/link FILE into the attachment directory of the current outline node.
 If VISIT-DIR is non-nil, visit the directory with dired.
 METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
 `org-attach-method'."
   (interactive
    (list
     (read-file-name "File to keep as an attachment:"
                     (or (progn
                           (require 'dired-aux)
                           (dired-dwim-target-directory))
                         default-directory))
     current-prefix-arg
     nil))
   (setq method (or method org-attach-method))
   (let ((basename (file-name-nondirectory file)))
     (let* ((attach-dir (org-attach-dir 'get-create))
            (fname (expand-file-name basename attach-dir)))
       (cond
        ((eq method 'mv) (rename-file file fname))
        ((eq method 'cp) (copy-file file fname))
        ((eq method 'ln) (add-name-to-file file fname))
        ((eq method 'lns) (make-symbolic-link file fname))
        ((eq method 'url) (url-copy-file file fname)))
       (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-tag)
       (cond ((eq org-attach-store-link-p 'attached)
-             (org-attach-store-link fname))
+	     (push (list (concat "attachment:" (file-name-nondirectory fname))
+			 (file-name-nondirectory fname))
+		   org-stored-links))
             ((eq org-attach-store-link-p t)
-             (org-attach-store-link file)))
+             (push (list (concat "file:" file)
+			 (file-name-nondirectory file))
+		   org-stored-links)))
       (if visit-dir
           (dired attach-dir)
         (message "File %S is now an attachment." basename)))))
#+end_src

And in the commit "26ace9004260a056acef58a7c1c80222bc9587c9":

#+begin_src diff
modified   lisp/org-attach.el
@@ -457,14 +457,6 @@ DIR-property exists (that is different than the unset one)."
   "Turn the autotag off."
   (org-attach-tag 'off))
 
-(defun org-attach-store-link (file)
-  "Add a link to `org-stored-link' when attaching a file.
-Only do this when `org-attach-store-link-p' is non-nil."
-  (setq org-stored-links
-	(cons (list (org-attach-expand-link file)
-		    (file-name-nondirectory file))
-	      org-stored-links)))
-
 (defun org-attach-url (url)
   (interactive "MURL of the file to attach: \n")
   (let ((org-attach-method 'url))
@@ -511,9 +503,13 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
       (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (org-attach-tag)
       (cond ((eq org-attach-store-link-p 'attached)
-             (org-attach-store-link fname))
+	     (push (list (concat "attachment:" (file-name-nondirectory fname))
+			 (file-name-nondirectory fname))
+		   org-stored-links))
             ((eq org-attach-store-link-p t)
-             (org-attach-store-link file)))
+             (push (list (concat "file:" file)
+			 (file-name-nondirectory file))
+		   org-stored-links)))
       (if visit-dir
           (dired attach-dir)
         (message "File %S is now an attachment." basename)))))
@@ -642,12 +638,6 @@ See `org-attach-open'."
 Basically, this adds the path to the attachment directory."
   (expand-file-name file (org-attach-dir)))
 
-(defun org-attach-expand-link (file)
-  "Return a file link pointing to the current entry's attachment file FILE.
-Basically, this adds the path to the attachment directory, and a \"file:\"
-prefix."
-  (concat "file:" (org-attach-expand file)))
-
 (org-link-set-parameters "attachment"
                          :follow #'org-attach-open-link
                          :export #'org-attach-export-link
#+end_src

From the source code, it seems indeed still original code logic.

Then I checked out my Emacs init git log, confirmed it is ~'attached~ option value
at first time. So this is my mistake.

Because this new ~attachment:~ link type has potential issues like on exporting.
So I decided to still use old ~file:~ link type. So I thought should set
~org-attach-store-link-p~ to ~t~. It indeed use ~file:~ link type instead of
~attachment:~ now. But the store link behavior affected. 

So the problem is how can I use both ~file:~ link type for attachments and use
this new attached store link?

>
>> -----Original Message-----
>> From: stardiviner <numbchild@gmail.com>
>> Sent: den 18 januari 2020 15:56
>> To: Gustav Wikström <gustav@whil.se>
>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
>> 
>> 
>> stardiviner <numbchild@gmail.com> writes:
>> 
>> I finally figured out why the link always failed. Because it use wrong
>> variable which is old filename path. I attached a patch.
>> 
>> > Gustav Wikström <gustav@whil.se> writes:
>> >
>> >> Hi,
>> >>
>> >>> -----Original Message-----
>> >>> From: stardiviner <numbchild@gmail.com>
>> >>> Sent: den 15 januari 2020 07:21
>> >>> To: Gustav Wikström <gustav@whil.se>
>> >>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
>> >>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach
>> >>> options
>> >>>
>> >>> [...]
>> >>>
>> >>> >> I found when I set option ~(setq org-attach-store-link-p t)~.
>> >>> >> Then attach a file, store file link with =[C-c C-l]=. The stored
>> >>> >> link. I open this link got error "No such file: ....". I tested
>> >>> >> this with minimal Emacs config. confirmed this problem.
>> >>> >>
>> >>> >
>> >>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q)
>> >>> > and
>> >>> with only that single customization it works for me. I'm testing it
>> >>> in linux. A wild guess.. Could it be that you used the move
>> >>> operation instead of the copy operation when attaching the file?
>> >>> >
>> >>> > Regards
>> >>> > Gustav
>> >>>
>> >>> Did you reproduce this issue with =emacs -q= ? That is a built-in
>> >>> Org Mode version which does not contains the latest version =org-
>> attach.el=.
>> >>>
>> >>> Here is my minimal Emacs config:
>> >>>
>> >>> [...]
>> >>>
>> >>> ;;==================================================================
>> >>> ======
>> >>> ======
>> >>> ;;; Here is org-attach.el customization
>> >>>
>> >>> (require 'org-attach)
>> >>>
>> >>> ;; store link auto with `org-store-link' using `file:' link type or
>> >>> `attachment:' link type.
>> >>> (setq org-attach-store-link-p 'attached) (setq
>> >>> org-attach-dir-relative t) (setq org-attach-preferred-new-method
>> >>> 'ask) #+end_src
>> >>>
>> >>> #+begin_src sh :eval no
>> >>> emacs -q -l '~/.config/emacs/minimal-init.el'
>> >>> #+end_src
>> >>
>> >
>> >> Hmm, in the first mail you said that you set org-attach-store-link-p
>> >> to t, but in your config it says 'attached.
>> >
>> > Sorry about this.
>> >
>> >> I've tried with a minimal config as well (using emacs -q because I
>> >> build the newest org mode version into the emacs
>> >> folder) and can only reproduce your issue when using the attached
>> >> option for org-attach-store-link-p and then inserting that link with
>> >> C-c C-l /in another heading/. Pasting the link in another heading is
>> >> expected to break since the attachment link is context dependent (i.e.
>> requires an attachment folder).
>> >> Makes sense? If I'm still misunderstanding your use-case, would you
>> >> care to describe the steps to reproduce it more in detail?
>> >
>> > After updated commit, don't know why, but all links worked again. I'm
>> > not good at expressing thanks, but you got all my thanks on this. :)
>> >
>> >> Regards
>> >> Gustav
>> >>
>> 
>> --
>> [ stardiviner ]
>>        I try to make every word tell the meaning what I want to express.
>> 
>>        Blog: https://stardiviner.github.io/
>>        IRC(freenode): stardiviner, Matrix: stardiviner
>>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
>> 


-- 
[ stardiviner ]
       I try to make every word tell the meaning what I want to express.

       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner, Matrix: stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: FW: [RFC] Link-type for attachments, more attach options
  2020-01-19  4:28               ` stardiviner
@ 2020-01-19  9:53                 ` Gustav Wikström
  0 siblings, 0 replies; 113+ messages in thread
From: Gustav Wikström @ 2020-01-19  9:53 UTC (permalink / raw)
  To: numbchild; +Cc: emacs-orgmode

Hi,

> -----Original Message-----
> From: stardiviner <numbchild@gmail.com>
> Sent: den 19 januari 2020 05:28
> To: Gustav Wikström <gustav@whil.se>
> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org
> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options
> 
> [...]
> 
> From the source code, it seems indeed still original code logic.
> 
> Then I checked out my Emacs init git log, confirmed it is ~'attached~
> option value at first time. So this is my mistake.
> 
> Because this new ~attachment:~ link type has potential issues like on
> exporting.

The issue with attachment links in the exporters should be fixed since the report of the export issues you sent a short while back. Any external exporter you use may ofc still need to be updated for attachment links.

> So I decided to still use old ~file:~ link type. So I thought should set
> ~org-attach-store-link-p~ to ~t~. It indeed use ~file:~ link type instead
> of ~attachment:~ now. But the store link behavior affected.
> 
> So the problem is how can I use both ~file:~ link type for attachments and
> use this new attached store link?

Understood, and I see no issue with complementing org-attach-store-link-p with another option. One that stores a file link to the attached files location. Pushed a change for that just now. 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-18 15:14                             ` Gustav Wikström
@ 2020-01-19 21:12                               ` Nicolas Goaziou
  2020-01-19 23:29                                 ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2020-01-19 21:12 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Hello,

Gustav Wikström <gustav@whil.se> writes:

> Functionally it's in a good (and maintainable) state right now, in my
> opinion. But I do understand that the contextual attribute added to
> the parser may require some discussion.

This is not my main gripe here, although I'm not convinced that extra
attribute is warranted. My concern is that you hard-code "attachment"
type in the parser. I don't think this is the correct way to handle the
situation.

Some link types specifically handle files, e.g., "docview", yet do not
need a special treatment in the parser. Note that "file" links have
a good reason to be treated specially there, besides their obvious
importance, as their type can be omitted. E.g., [[~/file.org]]. OTOH,
I see no strong reason to handle "attachments" in here, since they
behave like any other link type.

Worse, the parser is more or less the definition of the Org syntax.
Therefore, including "attachment" in the parser is a signal meaning that
in order to fully implement Org syntax, e.g., in another language, one
need to support attachment links. Attachment links are undoubtedly
useful, but they are not core, at all. So, I feel uneasy about leaking
that type of link in the Element library.

Also, you sometimes seem to blur, on purpose, the difference between
"attachment" and "file" links. If there should be no difference of
treatment between them, as I already suggested, you may want to consider
"attachment" as some functional link abbreviation. Then the "attachment"
type doesn't really exist, much like the "bugzilla" link type from the
manual.

In any case, we need a proper definition, a proper category too, for
"attachment" links. Meanwhile, modifying the parser is just grasping at
straws.

> I argue that the attachment folder is a part of the attachment link,
> even though the information is found at a different location in the
> document (i.e. as a property to nodes in the document hierarchy).
> Parsing an attachment link would then be incomplete if that
> information is discarded.

I argue that the buffer position of the attachment link and the path as
written in the link are enough to fully expand the attachment file name.

If I'm wrong, which could be, I probably didn't invest enough time in
the Attach changes, then having the expanded form in :path and the
initial form in :raw-path is enough.

> One option to adding an attribute could be to modify existing
> properties by adding the attachment folder to, for example, the path
> property. But that means to remove information about what was written
> as path in the original link.

There is :raw-path for that purpose.

> So I argue to keep path as the original path. But that means extra
> information is needed to also make it work in the filesystem. If we
> would translate an attachment link to a file link in ox.el that means
> we remove the option for exporters to decide for themselves what to do
> with the link. And I think the exporter should have that option. :)

Let's first think about what category of object an attachment link
belongs to. Then we can discuss about how to export it. 

Again, if "attachment" == "file", the exporters shouldn't treat them
differently. If "attachment" is a new link type, it should define its
own rules in its own library, namely "org-attach.el".

> Right now the ASCII exporter for example outputs attachment links as
> attachment:expanded_path instead of file:expanded_path. Since the link
> type actually is attachment. And for a solemnly textual export the
> exported information should be kept as close to source as possible. So
> either we explicitly and always say attachment-links *are* file-links
> in disguise (i.e. even change type in the parser), or we don't say
> that, and then don't say that all the way to the edge of the system.
> And let the uses of the link type decide themselves what to do. Which
> is what I propose.

As I explained above, your proposal is not crystal clear.

My gut feeling is that "attachment" links are just a regular link type,
that can be opened, and exported, like "file" links. They should live in
"org-attach.el", using the provided tools to define new link types, like
almost every other link types do. If those tools are not enough to
express all the subtleties of "attachment" links, then let's spot the
needs and improve those tools. That will benefit to every developer that
wants to implement a new link type, what creating another corner case in
the parser cannot do.


Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-19 21:12                               ` Nicolas Goaziou
@ 2020-01-19 23:29                                 ` Gustav Wikström
  2020-01-20  1:25                                   ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-19 23:29 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi Nicolas,

Thanks for your comments!

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 19 januari 2020 22:12
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> Hello,
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Functionally it's in a good (and maintainable) state right now, in my
> > opinion. But I do understand that the contextual attribute added to
> > the parser may require some discussion.
> 
> This is not my main gripe here, although I'm not convinced that extra
> attribute is warranted. My concern is that you hard-code "attachment"
> type in the parser. I don't think this is the correct way to handle the
> situation.

Ok, noted. To my defense I was thinking more in the terms of subtyping then hardcoding. Because we have multiple link types which try to share an interface. But the interface isn't perfect for all different kinds of links. So it doesn't seem too farfetched that some of those link types would benefit from additional custom properties, specific for those types. =application= and =search-option= for example isn't universally applicable to all link types. And link abbreviations are completely hidden from the parser output, since even the raw-link is expanded. So maybe, in the quest for completion, link abbreviations should have custom properties as well? And allowing some kind of sub-typing might make the parsed output more easy to use, because the interpreter can infer based on type (which already exist as a link property) what extra properties to use.

What I'm trying to argue for here is: Maybe it's not that crazy after all to allow links to have additional properties in the parser based on its type? (While certainly still trying to avoid it if possible!)

> Some link types specifically handle files, e.g., "docview", yet do not
> need a special treatment in the parser. Note that "file" links have a good
> reason to be treated specially there, besides their obvious importance, as
> their type can be omitted. E.g., [[~/file.org]]. OTOH, I see no strong
> reason to handle "attachments" in here, since they behave like any other
> link type.
> 
> Worse, the parser is more or less the definition of the Org syntax.
> Therefore, including "attachment" in the parser is a signal meaning that
> in order to fully implement Org syntax, e.g., in another language, one
> need to support attachment links. Attachment links are undoubtedly useful,
> but they are not core, at all. So, I feel uneasy about leaking that type
> of link in the Element library.
> 
> Also, you sometimes seem to blur, on purpose, the difference between
> "attachment" and "file" links. If there should be no difference of
> treatment between them, as I already suggested, you may want to consider
> "attachment" as some functional link abbreviation. Then the "attachment"
> type doesn't really exist, much like the "bugzilla" link type from the
> manual.

(Off topic) I'm sorry to hear that you think I'm intentionally making things fuzzy. If it seems so, then please take it as a lack of clarity of thought or communication rather than intentional bad will. (/Off topic)

> In any case, we need a proper definition, a proper category too, for
> "attachment" links. Meanwhile, modifying the parser is just grasping at
> straws.
> 
> > I argue that the attachment folder is a part of the attachment link,
> > even though the information is found at a different location in the
> > document (i.e. as a property to nodes in the document hierarchy).
> > Parsing an attachment link would then be incomplete if that
> > information is discarded.
> 
> I argue that the buffer position of the attachment link and the path as
> written in the link are enough to fully expand the attachment file name.

One can indeed use the buffer position to derive the part of the path that comes from the subtree. But leaving it at that puts more requirements on the user of the parsed link in order to use it. Which takes us back to my first implementation of how the exporters would deal with the parsed link information (d70db54dbc).

> If I'm wrong, which could be, I probably didn't invest enough time in the
> Attach changes, then having the expanded form in :path and the initial
> form in :raw-path is enough.
> 
> > One option to adding an attribute could be to modify existing
> > properties by adding the attachment folder to, for example, the path
> > property. But that means to remove information about what was written
> > as path in the original link.
> 
> There is :raw-path for that purpose.

There is no :raw-path available in the properties for a parsed link. If there were we surely wouldn't have this conversation and I'd be using that already! :) I.e. I like this suggestion. I considered using the :raw-link property, but the way it's currently used by the parser (i.e. expanding abbreviations) stopped me. It felt rather like no matter how I tried to utilize the existing parameters I were making an overload with a slightly different meaning. Might have been a lack on my part. In that case, please someone enlighten me! 

> > So I argue to keep path as the original path. But that means extra
> > information is needed to also make it work in the filesystem. If we
> > would translate an attachment link to a file link in ox.el that means
> > we remove the option for exporters to decide for themselves what to do
> > with the link. And I think the exporter should have that option. :)
> 
> Let's first think about what category of object an attachment link belongs
> to. Then we can discuss about how to export it.

So, we're discussing regarding attachment as either: an abbreviation or a proper separate link type? I'm not sure what other options we have? I personally can't categorize it as an abbreviation since that is handled by a separate piece of code with other specifications. I.e. attachment wouldn't fit well inside org-link-abbrev-alist. Attachments should function in the same way as file links, with search options and all. But be limited to the current set of attached files. Which it has completion functionality for when inserting links using C-c C-l. 

> Again, if "attachment" == "file", the exporters shouldn't treat them
> differently. If "attachment" is a new link type, it should define its own
> rules in its own library, namely "org-attach.el".
> 
> > Right now the ASCII exporter for example outputs attachment links as
> > attachment:expanded_path instead of file:expanded_path. Since the link
> > type actually is attachment. And for a solemnly textual export the
> > exported information should be kept as close to source as possible. So
> > either we explicitly and always say attachment-links *are* file-links
> > in disguise (i.e. even change type in the parser), or we don't say
> > that, and then don't say that all the way to the edge of the system.
> > And let the uses of the link type decide themselves what to do. Which
> > is what I propose.
> 
> As I explained above, your proposal is not crystal clear.

Sorry for that...

> My gut feeling is that "attachment" links are just a regular link type,
> that can be opened, and exported, like "file" links. They should live in
> "org-attach.el", using the provided tools to define new link types, like
> almost every other link types do. If those tools are not enough to express
> all the subtleties of "attachment" links, then let's spot the needs and
> improve those tools. That will benefit to every developer that wants to
> implement a new link type, what creating another corner case in the parser
> cannot do.

That's basically the way it was before the patches to fix stardiviners issues. Except not functioning well enough. It would require quite some code in org-attach to replicate existing file links functionality. Mostly code duplication I presume. 

The raw-path option sounds better to my ears. Sub-typing links by saying there are link types which have additional properties feels like a sound option too. I wouldn't regard that as hardcoding.

One improvement I can think of (outside of the discussion above) is to make it possible to pass the argument to org-link-open along to each separate 
link type specialization. That one has bugged me for some time now, when I've wanted to force opening attachment links in emacs but couldn't. Not an issue for attachments any longer (for now I suppose), but all other link types still have that limitation.

Respectfully,
Gustav

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: attachment: link type export to HTML invalid attach dir
  2020-01-19 23:29                                 ` Gustav Wikström
@ 2020-01-20  1:25                                   ` Nicolas Goaziou
  2020-01-25 11:34                                     ` Gustav Wikström
  0 siblings, 1 reply; 113+ messages in thread
From: Nicolas Goaziou @ 2020-01-20  1:25 UTC (permalink / raw)
  To: Gustav Wikström; +Cc: emacs-orgmode

Gustav Wikström <gustav@whil.se> writes:

> Ok, noted. To my defense I was thinking more in the terms of subtyping
> then hardcoding. Because we have multiple link types which try to
> share an interface. But the interface isn't perfect for all different
> kinds of links.

Then, I suggest to improve the interface.

> So it doesn't seem too farfetched that some of those link types would
> benefit from additional custom properties, specific for those types.
> =application= and =search-option= for example isn't universally
> applicable to all link types.

As a side note, :application is on its way out, i.e., "file+emacs" stuff
is in "org-compat.el".

Also, IIRC, "docview" links have "go to page" option, and they don't
touch the parser.

> What I'm trying to argue for here is: Maybe it's not that crazy after
> all to allow links to have additional properties in the parser based
> on its type? (While certainly still trying to avoid it if possible!)

If new link types may not function correctly without touching the
parser, how do you create new link types out of Org's core? This is not
modular at all.

> (Off topic) I'm sorry to hear that you think I'm intentionally making
> things fuzzy.

Not at all! My wording is terrible. When I wrote

    Also, you sometimes seem to blur, on purpose, the difference between
    "attachment" and "file" links.

I meant something like:

   It seems to me that your intent is to have "attachment" links
   transparently become "file" links to the user.

Hence my suggestion to use link abbreviations. There's nothing negative
in it.

> One can indeed use the buffer position to derive the part of the path
> that comes from the subtree. But leaving it at that puts more
> requirements on the user of the parsed link in order to use it.

And higher order functions in "org-attach" could take care of it. Note
that expanding a link in the parser means all attachment links are
always expanded, even if they are not used. There's a cost to consider.

Besides, parser focus on the contents of the buffer. I think it is out
of its scope to infer file names for abbreviation links. It's more the
job of the parts consuming the parsed data.

> There is no :raw-path available in the properties for a parsed link.
> If there were we surely wouldn't have this conversation and I'd be
> using that already! :) 

I meant :raw-link, sorry.

> I.e. I like this suggestion. I considered using the :raw-link
> property, but the way it's currently used by the parser (i.e.
> expanding abbreviations) stopped me.

Please take how link abbreviations are handled in the parser out of the
equation. I already stated this is not a good way to handle them. We
should probably expand them in a "temp-link" variable, and parse it,
while keeping original link in :raw-link (barring white spaces fixes).
That would not be perfect either, because we would still be inferring
stuff.

That's another topic, really. Let's just ignore it for now.

> So, we're discussing regarding attachment as either: an abbreviation
> or a proper separate link type? I'm not sure what other options we
> have? I personally can't categorize it as an abbreviation since that
> is handled by a separate piece of code with other specifications. I.e.
> attachment wouldn't fit well inside org-link-abbrev-alist. 

What makes you think it wouldn't fit well?

> Attachments should function in the same way as file links, with search
> options and all. But be limited to the current set of attached files.

This isn't incompatible with the above, AFAICT.

> That's basically the way it was before the patches to fix stardiviners
> issues. Except not functioning well enough. It would require quite
> some code in org-attach to replicate existing file links
> functionality. Mostly code duplication I presume.

I didn't read stardiviner issues. Would you mind summarizing them? Or,
at least could you explain what is not functioning well enough?

Anyhow, you may have missed the "let's spot the needs and improve these
tools" part. If current tools lead to code duplication, we can fix that.

> The raw-path option sounds better to my ears.

Except I was meaning :raw-link :)

> One improvement I can think of (outside of the discussion above) is to
> make it possible to pass the argument to org-link-open along to each
> separate link type specialization.

Isn't that the job of :follow when defining a new link type?

> That one has bugged me for some time now, when I've wanted to force
> opening attachment links in emacs but couldn't.

IMO, forcing users to open stuff in a specific, non-configurable, way is
a bad idea. Why would we know better than them?

^ permalink raw reply	[flat|nested] 113+ messages in thread

* RE: attachment: link type export to HTML invalid attach dir
  2020-01-20  1:25                                   ` Nicolas Goaziou
@ 2020-01-25 11:34                                     ` Gustav Wikström
  2020-02-05 16:54                                       ` Nicolas Goaziou
  0 siblings, 1 reply; 113+ messages in thread
From: Gustav Wikström @ 2020-01-25 11:34 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 10666 bytes --]

Hi again,

> -----Original Message-----
> From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
> Sent: den 20 januari 2020 02:25
> To: Gustav Wikström <gustav@whil.se>
> Cc: emacs-orgmode@gnu.org
> Subject: Re: attachment: link type export to HTML invalid attach dir
> 
> Gustav Wikström <gustav@whil.se> writes:
> 
> > Ok, noted. To my defense I was thinking more in the terms of subtyping
> > then hardcoding. Because we have multiple link types which try to
> > share an interface. But the interface isn't perfect for all different
> > kinds of links.
> 
> Then, I suggest to improve the interface.

That was kind of what I was trying to do, by allowing subtyping, so that the parser would be more knowledgeable about particular types of links, by allowing extended attributes. Maybe not implemented in the most extensible way though I'll admit.

My suggestion to the link parser would be to have the following properties as the catch-all properties for links:
- type :: Which type of link protocol applies. E.g. file, http, ftp, attachment, duckduckgo (ex. for a custom link abbreviation to search ddg)
- raw-path :: The path to use for the particular protocol. Would contain everything in the link following "protocol:"
- format :: Which format the link has. Plain, bracket or angular bracket
- description :: The description part of the link ([[protocol:path][description]])
- begin, end, post-blank :: The default properties used for all elements. Not sure if contents-begin and contents-end are a part here as well.

In addition to that each protocol would be able to declare their own properties using a :parse function. All would probably implement a path property. Some would implement an options property, and some maybe would maybe declare their own properties.

As you've stated previously, from a performance perspective maybe it will be best to not expand the specific properties and instead let the expansion of those be handled in code by the link type owner (e.g. org-attach.el for attachment links). But not letting specific protocol parsers expand their own properties into a link makes it more difficult to implement support outside of emacs for the org specification, which in my opinion includes also a certain set of link protocols which do have their own specifications.

> > So it doesn't seem too farfetched that some of those link types would
> > benefit from additional custom properties, specific for those types.
> > =application= and =search-option= for example isn't universally
> > applicable to all link types.
> 
> As a side note, :application is on its way out, i.e., "file+emacs" stuff
> is in "org-compat.el".
> 
> Also, IIRC, "docview" links have "go to page" option, and they don't
> touch the parser.

Ah yes. Just briefly looking at the docview code. Docview doesn't seem to use the parser when extracting information about that "go to page" information from the link. Which means docview links doesn't really care how the link information is encoded in the parser anyways. Maybe if docview were allowed to encode custom docview information into the parsed link in the parser it and others could reused that encoded information later? Docview would be able to add a ":go-to-page" option, for example. Just a thought.

> > What I'm trying to argue for here is: Maybe it's not that crazy after
> > all to allow links to have additional properties in the parser based
> > on its type? (While certainly still trying to avoid it if possible!)
> 
> If new link types may not function correctly without touching the
> parser, how do you create new link types out of Org's core? This is not
> modular at all.

Most link types probably won't need custom link properties anyways. But could maybe let the parser know stuff by use of higher order functions? Or push for being important enough to be included into Org and allowed to be known by the parser.

> > (Off topic) I'm sorry to hear that you think I'm intentionally making
> > things fuzzy.
> 
> Not at all! My wording is terrible. When I wrote
> 
>     Also, you sometimes seem to blur, on purpose, the difference between
>     "attachment" and "file" links.
> 
> I meant something like:
> 
>    It seems to me that your intent is to have "attachment" links
>    transparently become "file" links to the user.
> 
> Hence my suggestion to use link abbreviations. There's nothing negative
> in it.

Ok, got it. Thanks for explaining. I'll admit it hasn't been totally clear to me what the best way forward is. After refreshing my understanding on links the conclusion I came to was that link abbreviations in its current form was not a fitting concept for attachment links. Attachments are pretty much similar to file links though, so even if my intention isn't to blur the meaning they will and should be treated very similar, since functionality is so similar.

> > One can indeed use the buffer position to derive the part of the path
> > that comes from the subtree. But leaving it at that puts more
> > requirements on the user of the parsed link in order to use it.
> 
> And higher order functions in "org-attach" could take care of it. Note
> that expanding a link in the parser means all attachment links are
> always expanded, even if they are not used. There's a cost to consider.

Higher order functions were used for exporting attachments previously. But the intention to keep functionality as close to file links as possible made me move the code from there into the separate exporters, to let all functionality be inherited by the way file exports were done, with the minor tweak needed to make it work for attachment links as well.

I've attached a patch that lets org-attach take care of expanding the link element into a path, instead of sub-typing inside org-element. While I'm still pro sub-typing links according to their type, this patch removes that. I.e. the performance cost of parsing is moved to the points where the information actually is used, with a sort of "informational cost" of not letting the org parser know about the peculiarities of certain link types.
 
> Besides, parser focus on the contents of the buffer. I think it is out
> of its scope to infer file names for abbreviation links. It's more the
> job of the parts consuming the parsed data.
> 
> > There is no :raw-path available in the properties for a parsed link.
> > If there were we surely wouldn't have this conversation and I'd be
> > using that already! :)
> 
> I meant :raw-link, sorry.
> 
> > I.e. I like this suggestion. I considered using the :raw-link
> > property, but the way it's currently used by the parser (i.e.
> > expanding abbreviations) stopped me.
> 
> Please take how link abbreviations are handled in the parser out of the
> equation. I already stated this is not a good way to handle them. We
> should probably expand them in a "temp-link" variable, and parse it,
> while keeping original link in :raw-link (barring white spaces fixes).
> That would not be perfect either, because we would still be inferring
> stuff.
> 
> That's another topic, really. Let's just ignore it for now.
> 
> > So, we're discussing regarding attachment as either: an abbreviation
> > or a proper separate link type? I'm not sure what other options we
> > have? I personally can't categorize it as an abbreviation since that
> > is handled by a separate piece of code with other specifications. I.e.
> > attachment wouldn't fit well inside org-link-abbrev-alist.
> 
> What makes you think it wouldn't fit well?

That list seems more like a feature to let end users expand links using find-replace with a tag in an existing path. Actually looking more into it now I see that it can also use expansion with functions. So maybe that could be used as a way of implementation. I'm not sure if there are other side effects of that though so it's nothing I'm pursuing now.

> > Attachments should function in the same way as file links, with search
> > options and all. But be limited to the current set of attached files.
> 
> This isn't incompatible with the above, AFAICT.

The path for attachment links needs to be complemented with the part from the attachment directory to make it work in the file system. That is the difference between the link types. 

> > That's basically the way it was before the patches to fix stardiviners
> > issues. Except not functioning well enough. It would require quite
> > some code in org-attach to replicate existing file links
> > functionality. Mostly code duplication I presume.
> 
> I didn't read stardiviner issues. Would you mind summarizing them? Or,
> at least could you explain what is not functioning well enough?

The expansions of image links didn't work correctly for attachment links. Simply because org-attach-export-link didn't support that.

> Anyhow, you may have missed the "let's spot the needs and improve these
> tools" part. If current tools lead to code duplication, we can fix that.

Speaking from the perspective of attachment links, if there were a file link type exporter function available that could be used by attachment links without code duplication. Another thing might be to make the higher order functions in the interface for adding new link types be able to use the parsed link instead of just certain properties of the link. Not sure if performance would be an issue then though.

> > The raw-path option sounds better to my ears.
> 
> Except I was meaning :raw-link :)
> 
> > One improvement I can think of (outside of the discussion above) is to
> > make it possible to pass the argument to org-link-open along to each
> > separate link type specialization.
> 
> Isn't that the job of :follow when defining a new link type?

Yes, and the function that implements that would also need the user argument as input. In addition to the link path.

> > That one has bugged me for some time now, when I've wanted to force
> > opening attachment links in emacs but couldn't.
> 
> IMO, forcing users to open stuff in a specific, non-configurable, way is
> a bad idea. Why would we know better than them?

I was not clear enough with what I meant. I meant not to force the user in the code to a specific choice, but to let the user force emacs to open the link. By use of arg as is specified in org-link-open.

Anyways, patch attached that makes org-element not know about attachments any longer, and moves most of the responsibility to org-attach.el. The exporters still needs to know to use the new function inside org-attach.el though.

Regards
Gustav

[-- Attachment #2: attachment-links.patch --]
[-- Type: application/octet-stream, Size: 10107 bytes --]

diff --git a/lisp/ol.el b/lisp/ol.el
index 31c34ec7b..10ce83f50 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -75,6 +75,7 @@
 (declare-function org-src-source-type "org-src" ())
 (declare-function org-time-stamp-format "org" (&optional long inactive))
 (declare-function outline-next-heading "outline" ())
+(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name))
 
 \f
 ;;; Customization
@@ -934,7 +935,7 @@ a \"file\" link."
     (cond
      ((member type '("file" "attachment"))
       (when (string= type "attachment")
-	(setq path (org-element-property :attachment-path link)))
+	(setq path (org-attach-link-expand link)))
       (if (string-match "[*?{]" (file-name-nondirectory path))
 	  (dired path)
 	;; Look into `org-link-parameters' in order to find
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index f5c81e01f..8709c8b88 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -41,6 +41,7 @@
 (require 'org-id)
 
 (declare-function dired-dwim-target-directory "dired-aux")
+(declare-function org-element-property "org-element" (property element))
 
 (defgroup org-attach nil
   "Options concerning attachments in Org mode."
@@ -640,6 +641,21 @@ See `org-attach-open'."
 Basically, this adds the path to the attachment directory."
   (expand-file-name file (org-attach-dir)))
 
+(defun org-attach-link-expand (link &optional buffer-or-name)
+  "Return the full path to the attachment in the LINK element.
+Takes LINK which is a link element, as defined by
+`org-element-link-parser'.  If LINK `:type' is attachment the
+full path to the attachment is expanded and returned.  Otherwise,
+return nil.  If BUFFER-OR-NAME is specified, LINK is expanded in
+that buffer, otherwise current buffer is assumed."
+  (let ((type (org-element-property :type link))
+	(file (org-element-property :path link))
+	(pos (org-element-property :begin link)))
+    (when (string= type "attachment")
+      (with-current-buffer (or buffer-or-name (current-buffer))
+	(goto-char pos)
+	(org-attach-expand file)))))
+
 (org-link-set-parameters "attachment"
                          :complete #'org-attach-compl