emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@gmail.com>
To: "Gustav Wikström" <gustav@whil.se>,
	"Nicolas Goaziou" <mail@nicolasgoaziou.fr>
Cc: "emacs-orgmode@gnu.org" <emacs-orgmode@gnu.org>
Subject: Re: [RFC] Link-type for attachments, more attach options
Date: Sat, 27 Jul 2019 22:56:17 +0800	[thread overview]
Message-ID: <87y30j34ry.fsf@yantar92-laptop.i-did-not-set--mail-host-address--so-tickle-me> (raw)
In-Reply-To: <HE1PR02MB3033AFD29F6692A154E5B1EADAF70@HE1PR02MB3033.eurprd02.prod.outlook.com>

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
>

  parent reply	other threads:[~2019-07-27 14:57 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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
2018-11-02 23:07   ` Gustav Wikström
2018-11-03  3:37     ` Ihor Radchenko
2018-11-17 12:13       ` Gustav Wikström
2018-11-18  0:42         ` Ihor Radchenko
2018-11-18  8:57           ` Gustav Wikström
2018-11-20 14:00             ` Ihor Radchenko
2018-11-24 13:56               ` Gustav Wikström
2018-12-14  2:16                 ` Ihor Radchenko
2019-05-26 22:24                   ` Gustav Wikström
2018-11-04 22:37 ` Nicolas Goaziou
2018-11-17 11:58   ` Gustav Wikström
     [not found]     ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com>
2018-11-19 23:52       ` Nicolas Goaziou
2018-11-25 21:13         ` Gustav Wikström
2018-11-27  9:39           ` Nicolas Goaziou
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
2019-07-06 21:46                   ` Nicolas Goaziou
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 [this message]
2019-07-28 20:39                         ` Gustav Wikström
2019-07-28 23:20                           ` Ihor Radchenko
2019-01-04 12:21 ` FW: " Feng Shu
2019-05-26 23:15   ` Gustav Wikström
2019-12-12  5:21 ` stardiviner
2019-12-12  6:12   ` Gustav Wikström
2019-12-12  9:52     ` stardiviner
2019-12-12 19:42       ` Gustav Wikström
2019-12-13 13:38         ` stardiviner
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
2019-12-15 10:06                 ` Gustav Wikström
2019-12-15 14:26                   ` stardiviner
2019-12-15 20:41                     ` Gustav Wikström
2019-12-16  3:38                       ` 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
2020-01-14  3:27   ` Gustav Wikström
2020-01-14  5:04     ` stardiviner
2020-01-14 20:58       ` Gustav Wikström
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
2020-01-16 21:42               ` Gustav Wikström
2020-01-16 23:07                 ` Gustav Wikström
2020-01-17  0:39                   ` Nicolas Goaziou
2020-01-17 14:29                     ` Gustav Wikström
2020-01-17 18:36                       ` Gustav Wikström
2020-01-18  1:13                         ` Gustav Wikström
2020-01-18 11:34                           ` Nicolas Goaziou
2020-01-18 15:14                             ` Gustav Wikström
2020-01-19 21:12                               ` Nicolas Goaziou
2020-01-19 23:29                                 ` Gustav Wikström
2020-01-20  1:25                                   ` Nicolas Goaziou
2020-01-25 11:34                                     ` Gustav Wikström
2020-02-05 16:54                                       ` Nicolas Goaziou
2020-02-06 20:55                                         ` Gustav Wikström
2020-02-07 14:28                                           ` Nicolas Goaziou
2020-02-08 15:39                                             ` Gustav Wikström
2020-02-13 20:41                                               ` Nicolas Goaziou
2020-02-13 21:11                                                 ` Gustav Wikström
2020-02-13 21:37                                                   ` Nicolas Goaziou
2020-02-13 22:07                                                     ` Gustav Wikström
2020-02-14  0:16                                                       ` Nicolas Goaziou
2020-02-14  7:23                                                         ` Gustav Wikström
2020-02-14  2:42                                                       ` Kyle Meyer
2020-02-14  7:35                                                         ` Gustav Wikström
2020-02-14  7:41                                                         ` Gustav Wikström
2020-02-14 11:06                                                       ` Bastien
2020-02-14 17:12                                                         ` Nicolas Goaziou
2020-02-14 20:33                                                           ` Bastien
2020-02-15 18:08                                                             ` Nicolas Goaziou
2020-02-15 23:04                                                               ` Kyle Meyer
2020-02-16  8:51                                                                 ` Nicolas Goaziou
2020-02-16 23:59                                                                   ` Bastien
2020-02-17  9:37                                                                     ` Nicolas Goaziou
2020-02-17 10:25                                                                       ` Bastien
2020-02-16 23:58                                                               ` Bastien
2020-02-17 10:32                                                                 ` Nicolas Goaziou
2020-02-17 10:53                                                                   ` Bastien
2020-02-20  9:20                                                               ` Nicolas Goaziou
2020-02-20 10:20                                                                 ` Bastien
2020-02-22 12:58                                                                   ` Nicolas Goaziou
2020-02-22 13:32                                                                     ` Bastien
2020-02-25 23:36                                                                       ` Gustav Wikström
2020-02-26 15:22                                                                         ` Nicolas Goaziou
2020-02-27 19:02                                                                           ` Gustav Wikström
2020-02-28  0:37                                                                             ` Nicolas Goaziou
2020-02-13 21:57                                                 ` Gustav Wikström
2020-02-14 10:02                                                 ` Bastien
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
2020-01-15 22:42       ` Gustav Wikström
2020-01-16 11:15         ` stardiviner
2020-01-18 14:56           ` stardiviner
2020-01-18 15:30             ` Gustav Wikström
2020-01-19  4:28               ` stardiviner
2020-01-19  9:53                 ` Gustav Wikström
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y30j34ry.fsf@yantar92-laptop.i-did-not-set--mail-host-address--so-tickle-me \
    --to=yantar92@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=gustav@whil.se \
    --cc=mail@nicolasgoaziou.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).