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
>
next prev 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).