* FW: [RFC] Link-type for attachments, more attach options @ 2018-10-21 7:53 Gustav Wikström 2018-11-01 1:45 ` tumashu ` (8 more replies) 0 siblings, 9 replies; 113+ messages in thread From: Gustav Wikström @ 2018-10-21 7:53 UTC (permalink / raw) To: emacs-orgmode@gnu.org [-- Attachment #1.1: Type: text/plain, Size: 1056 bytes --] Hi, I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review. Kind regards Gustav ___ Patch comments: * Add new linktype "attached" for attachments A new linktype "attached" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. Inline images will trigger also for attachments, as well as search-decorations in the links. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a couple of new options available: - org-attach-dir-inherit-by-default - org-attach-dir-create-if-not-exist - org-attach-dir-relative Descriptions of them can be found in the commit for each new customization. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. [-- Attachment #1.2: Type: text/html, Size: 5038 bytes --] [-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-more-attach-.patch --] [-- Type: application/octet-stream, Size: 21974 bytes --] From fe676033f871466493a9584972c3b110f4c55363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com> Date: Sun, 23 Sep 2018 02:43:16 +0200 Subject: [PATCH] org-attach, org-manual, org: New link-type, more attach options * Add new linktype "attached" for attachments A new linktype "attached" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. Inline images will trigger also for attachments, as well as search-decorations in the links. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a couple of new options available: - org-attach-dir-inherit-by-default - org-attach-dir-create-if-not-exist - org-attach-dir-relative Descriptions of them can be found in the commit for each new customization. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. --- doc/org-manual.org | 144 +++++++++++++++++++++++++++------------------ lisp/org-attach.el | 138 +++++++++++++++++++++++++++++++++++-------- lisp/org.el | 17 ++++-- 3 files changed, 212 insertions(+), 87 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 7945b7333..144f5993e 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3137,6 +3137,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: attached links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3148,38 +3149,63 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. - -| =http://www.astro.uva.nl/=dominik= | on the web | -| =doi:10.1000/182= | DOI for an electronic resource | -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | -| =/home/dominik/images/jupiter.jpg= | same as above | -| =file:papers/last.pdf= | file, relative path | -| =./papers/last.pdf= | same as above | -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | -| =/ssh:me@some.where:papers/last.pdf= | same as above | -| =file:sometextfile::NNN= | file, jump to line number | -| =file:projects.org= | another Org file | -| =file:projects.org::some words= | text search in Org file[fn:28] | -| =file:projects.org::*task title= | heading search in Org file | -| =file+sys:/path/to/file= | open via OS, like double-click | -| =file+emacs:/path/to/file= | force opening by Emacs | -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | -| =news:comp.emacs= | Usenet link | -| =mailto:adent@galaxy.net= | mail link | -| =mhe:folder= | MH-E folder link | -| =mhe:folder#id= | MH-E message link | -| =rmail:folder= | Rmail folder link | -| =rmail:folder#id= | Rmail message link | -| =gnus:group= | Gnus group link | -| =gnus:group#id= | Gnus article link | -| =bbdb:R.*Stallman= | BBDB link (with regexp) | -| =irc:/irc.com/#emacs/bob= | IRC link | -| =info:org#External links= | Info node link | -| =shell:ls *.org= | shell command | -| =elisp:org-agenda= | interactive Elisp command | -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | +the colon. + +This list shows the full set of built-in external link types: +| http | web | +| https | secure web | +| doi | DOI for electronic resources | +| file | file-links | +| file+sys | file-links forced to open via OS | +| file+emacs | file-links forced to open via emacs | +| attached | links to attachments for nodes | +| docview | doc-view mode | +| id | Link to heading by id | +| news | Usenet link | +| mailto | mail link | +| mhe | MH-E folder link | +| rmail | Rmail link | +| gnus | Gnus link | +| bbdb | BBDB link | +| irc | IRC link | +| info | Info link | +| shell | shell command | +| elisp | interactive elisp command link | + +The following list shows examples for each link type. + +| =http://www.astro.uva.nl/=dominik= | on the web | +| =doi:10.1000/182= | DOI for an electronic resource | +| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | +| =/home/dominik/images/jupiter.jpg= | same as above | +| =file:papers/last.pdf= | file, relative path | +| =./papers/last.pdf= | same as above | +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | +| =/ssh:me@some.where:papers/last.pdf= | same as above | +| =file:sometextfile::NNN= | file, jump to line number | +| =file:projects.org= | another Org file | +| =file:projects.org::some words= | text search in Org file[fn:28] | +| =file:projects.org::*task title= | heading search in Org file | +| =file+sys:/path/to/file= | open via OS, like double-click | +| =file+emacs:/path/to/file= | force opening by Emacs | +| =attached:projects.org= | file in folder attached to headline | +| =attached:projects.org::some words= | text search in attached file | +| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | +| =news:comp.emacs= | Usenet link | +| =mailto:adent@galaxy.net= | mail link | +| =mhe:folder= | MH-E folder link | +| =mhe:folder#id= | MH-E message link | +| =rmail:folder= | Rmail folder link | +| =rmail:folder#id= | Rmail message link | +| =gnus:group= | Gnus group link | +| =gnus:group#id= | Gnus article link | +| =bbdb:R.*Stallman= | BBDB link (with regexp) | +| =irc:/irc.com/#emacs/bob= | IRC link | +| =info:org#External links= | Info node link | +| =shell:ls *.org= | shell command | +| =elisp:org-agenda= | interactive Elisp command | +| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | #+cindex: VM links #+cindex: Wanderlust links @@ -3532,24 +3558,26 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: attached links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:35]. For -example, when the command ~org-store-link~ creates a link (see -[[*Handling Links]]) to a file, it encodes the words in the current line -as a search string that can be used to find this line back later when -following the link with {{{kbd(C-c C-o)}}}. +File links and attached file links can contain additional information +to make Emacs jump to a particular location in the file when following +a link. This can be a line number or a search option after a double +colon[fn:35]. For example, when the command ~org-store-link~ creates +a link (see [[*Handling Links]]) to a file, it encodes the words in the +current line as a search string that can be used to find this line +back later when following the link with {{{kbd(C-c C-o)}}}. Here is the syntax of the different ways to attach a search to a file link, together with explanations for each: #+begin_example -[[file:~/code/main.c::255]] -[[file:~/xx.org::My Target]] -[[file:~/xx.org::*My Target]] -[[file:~/xx.org::#my-custom-id]] -[[file:~/xx.org::/regexp/]] + [[file:~/code/main.c::255]] + [[file:~/xx.org::My Target]] + [[file:~/xx.org::*My Target]] + [[file:~/xx.org::#my-custom-id]] + [[file:~/xx.org::/regexp/]] + [[attached:~/code/main.c::255]] #+end_example - =255= :: @@ -7527,18 +7555,22 @@ node/task. Small chunks of plain text can simply be stored in the subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations with files that live elsewhere on your computer or in the cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -~data~ directory which lives in the same directory where your Org file -lives[fn:86]. If you initialize this directory with =git init=, Org -automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by the unique ID of each entry, or by the =ATTACH_DIR= property. +ID-based directories are by default located in the ~data~ directory +which lives in the same directory where your Org file lives[fn:86]. +If you initialize this directory with =git init=, Org automatically +commits changes when it sees them. The attachment system has been +contributed to Org by John Wiegley. + +In cases where =ATTACH_DIR= property is used to declare attachments, +you can choose to either use absolute (default) or relative links. +You can also make children inherit the attachment directory from a +parent, so that an entire subtree uses the same attached directory. + +See customization group =Org Attach= if you want to change the default +settings for attachments to fit your preferred style. The following commands deal with attachments: diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 53389f782..daf8cf2dd 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -57,6 +57,25 @@ where the Org file lives." :type 'directory :safe #'stringp) +(defcustom org-attach-dir-inherit-by-default nil + "Defines whether ATTACH_DIR-directories should be inherited by + subheadings by default when created. Defaults to not being + inherited." + :group 'org-attach + :type 'boolean) + +(defcustom org-attach-dir-create-if-not-exists t + "Choose whether ATTACH_DIR-directories should be created if +they do not exist since before. Default is to create them." + :group 'org-attach + :type 'boolean) + +(defcustom org-attach-dir-relative nil + "Choose whether ATTACH_DIR-directories should be added as +relative links or not. Defaults to not relative." + :group 'org-attach + :type 'boolean) + (defcustom org-attach-commit t "If non-nil commit attachments with git. This is only done if the Org file is in a git repository." @@ -280,20 +299,26 @@ Throw an error if we cannot root the directory." "Set the ATTACH_DIR node property and ask to move files there. The property defines the directory that is used for attachments of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." +the directory to the default ID based one. Creates relative links +if ORG-ATTACH-DIR-RELATIVE is t, and sets inheritance based on +ORG-ATTACH-DIR-INHERIT-BY-DEFAULT" (interactive "P") - (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (let ((old (org-attach-dir nil)) + (new + (progn + (if arg (org-entry-delete nil "ATTACH_DIR") + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil + "ATTACH_DIR"))) + (current-dir (file-name-directory (or load-file-name + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (if org-attach-dir-relative + (org-entry-put nil "ATTACH_DIR" attach-dir-relative) + (org-entry-put nil "ATTACH_DIR" attach-dir)))) + (org-attach-dir t)))) + (when org-attach-dir-inherit-by-default (org-attach-set-inherit)) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") @@ -527,14 +552,15 @@ This ignores files ending in \"~\"." "Show the attachment directory of the current task. This will attempt to use an external program to show the directory." (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) - (and attach-dir (org-open-file attach-dir)))) + (let* ((create-if-not-exist (if if-exists nil org-attach-dir-create-if-not-exists)) + (attach-dir (org-attach-dir create-if-not-exist))) + (when attach-dir (org-open-file attach-dir)))) (defun org-attach-reveal-in-emacs () "Show the attachment directory of the current task in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists))) + (when attach-dir (dired attach-dir)))) (defun org-attach-open (&optional in-emacs) "Open an attachment of the current task. @@ -543,15 +569,17 @@ This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists))) + (if attach-dir + (let* ((files (org-attach-file-list attach-dir)) + (file (if (= (length files) 1) + (car files) + (completing-read "Open attachment: " + (mapcar #'list files) nil t))) + (path (expand-file-name file attach-dir))) + (org-attach-annex-get-maybe path) + (org-open-file path in-emacs)) + (message "No attachment exists!")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -570,6 +598,64 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(defun org-attach-open-link (link &optional in-emacs) + "LINK is expanded with the attached directory and opened the same +way as file-links are." + (interactive "P") + (let (line search) + (if (string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0))) + (if (string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment +directory." + (let (file link attached-dir) + (setq attached-dir (expand-file-name (org-attach-dir))) + (setq file (read-file-name "File: " attached-dir)) + (let ((pwd (file-name-as-directory attached-dir)) + (pwd1 (file-name-as-directory (abbreviate-file-name + attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file) + (setq link (concat "attached:" (match-string 1 file)))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (setq link (concat + "attached:" (match-string 1 (expand-file-name file))))) + (t (setq link (concat "attached:" file))))) + link)) + +(defun org-attach-export-link (link description format) + "Export an \"attached\" link from Org files." + (save-excursion + (let (path desc) + (if (string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))) + (if (string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (search-forward (concat "attached:" (org-link-escape link))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + +(org-link-set-parameters "attached" + :follow 'org-attach-open-link + :export 'org-attach-export-link + :complete 'org-attach-complete-link) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option diff --git a/lisp/org.el b/lisp/org.el index c0eaecdab..1eac53e0a 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -4427,6 +4427,7 @@ This is needed for font-lock setup.") (beg end)) (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) (declare-function org-agenda-skip "org-agenda" ()) +(declare-function org-attach-expand "org-attach" (&optional if-exists)) (declare-function org-attach-reveal "org-attach" (&optional if-exists)) (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) (declare-function org-indent-mode "org-indent" (&optional arg)) @@ -18759,7 +18760,7 @@ boundaries." ;; Check absolute, relative file names and explicit ;; "file:" links. Also check link abbreviations since ;; some might expand to "file" links. - (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)" + (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)" (if (not link-abbrevs) "" (format "\\|\\(?:%s:\\)" (regexp-opt link-abbrevs)))))) @@ -18768,14 +18769,20 @@ boundaries." ;; Check if we're at an inline image, i.e., an image file ;; link without a description (unless INCLUDE-LINKED is ;; non-nil). - (when (and (equal "file" (org-element-property :type link)) + (when (and (or (equal "file" (org-element-property :type link)) + (equal "attached" (org-element-property :type link))) (or include-linked (null (org-element-contents link))) (string-match-p file-extension-re (org-element-property :path link))) - (let ((file (expand-file-name - (org-link-unescape - (org-element-property :path link))))) + (let ((file (if (equal "attached" (org-element-property :type link)) + (require 'org-attach) + (org-attach-expand + (org-link-unescape + (org-element-property :path link))) + (expand-file-name + (org-link-unescape + (org-element-property :path link)))))) (when (file-exists-p file) (let ((width ;; Apply `org-image-actual-width' specifications. -- 2.19.1.windows.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström @ 2018-11-01 1:45 ` tumashu 2018-11-02 22:40 ` Gustav Wikström 2018-11-01 16:00 ` Marco Wahl ` (7 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: tumashu @ 2018-11-01 1:45 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 1210 bytes --] Hello, this feature seem to be very useful, what is this patch status? At 2018-10-21 15:53:38, "Gustav Wikström" <gustav@whil.se> wrote: Hi, I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review. Kind regards Gustav ___ Patch comments: * Add new linktype "attached" for attachments A new linktype "attached" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. Inline images will trigger also for attachments, as well as search-decorations in the links. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a couple of new options available: - org-attach-dir-inherit-by-default - org-attach-dir-create-if-not-exist - org-attach-dir-relative Descriptions of them can be found in the commit for each new customization. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. [-- Attachment #2: Type: text/html, Size: 4683 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-01 1:45 ` tumashu @ 2018-11-02 22:40 ` Gustav Wikström 0 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2018-11-02 22:40 UTC (permalink / raw) To: tumashu; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 2043 bytes --] Hi, nice to hear that you find it useful! I don’t have access to apply the patch myself. So I’d be happy if one of the frequent maintainers could help out with that, and at the same time look a bit at the quality of it. I’ve used most of the functionality personally for well over a year in my local setup and just now took the time to repackage it into something reusable. Hopefully it’s seen as “good enough” to warrant a merge into one of the org-mode branches! From my perspective the patch adds a lot of utility to the attachment-functionality. Regards Gustav From: tumashu <tumashu@163.com> Sent: den 1 november 2018 02:46 To: Gustav Wikström <gustav@whil.se> Cc: emacs-orgmode <emacs-orgmode@gnu.org> Subject: Re:[O] FW: [RFC] Link-type for attachments, more attach options Hello, this feature seem to be very useful, what is this patch status? At 2018-10-21 15:53:38, "Gustav Wikström" <gustav@whil.se<mailto:gustav@whil.se>> wrote: Hi, I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review. Kind regards Gustav ___ Patch comments: * Add new linktype "attached" for attachments A new linktype "attached" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. Inline images will trigger also for attachments, as well as search-decorations in the links. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a couple of new options available: - org-attach-dir-inherit-by-default - org-attach-dir-create-if-not-exist - org-attach-dir-relative Descriptions of them can be found in the commit for each new customization. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. [-- Attachment #2: Type: text/html, Size: 9329 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström 2018-11-01 1:45 ` tumashu @ 2018-11-01 16:00 ` Marco Wahl 2018-11-02 23:07 ` Gustav Wikström 2018-11-04 22:37 ` Nicolas Goaziou ` (6 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: Marco Wahl @ 2018-11-01 16:00 UTC (permalink / raw) To: emacs-orgmode Hi Gustav, I played a bit with your proposition. I like it; in particular the completion function to insert links from the attachment directory with C-c C-l attached RET It seems natural to me to have a more specific link type for attached files. In my opinion your patch should be applied to the 'next' branch. My 2ct, Marco ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-01 16:00 ` Marco Wahl @ 2018-11-02 23:07 ` Gustav Wikström 2018-11-03 3:37 ` Ihor Radchenko 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-02 23:07 UTC (permalink / raw) To: Marco Wahl; +Cc: emacs-orgmode Hi Marco, Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it all the time to quickly add links to attached files. One use case I have for this (as an example) is for projects and tasks. I have a 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the task is about some digital work, there are files involved with it. So I have a convention to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', and attach the folder to each task/project node. C-c C-l attached RET then makes it super-easy to refer to particular files within that folder, from within the node in the 'tasks.org' file! Another use case is for my 'digital brain', where it's also fairly common for me to have attachment folders where I want to refer to files within them. Images for example, that then will be displayed in the org-mode file. Haven't settled on whether I should use auto-managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit of both... I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. But if 'master' is to offensive to merge into straight away, 'next' sounds like a good option! Kind regards Gustav -----Original Message----- From: Marco Wahl <marcowahlsoft@gmail.com> Sent: den 1 november 2018 17:01 To: Gustav Wikström <gustav@whil.se> Subject: Re: FW: [RFC] Link-type for attachments, more attach options The following message is a courtesy copy of an article that has been posted to gmane.emacs.orgmode as well. Hi Gustav, I played a bit with your proposition. I like it; in particular the completion function to insert links from the attachment directory with C-c C-l attached RET It seems natural to me to have a more specific link type for attached files. In my opinion your patch should be applied to the 'next' branch. My 2ct, Marco ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-02 23:07 ` Gustav Wikström @ 2018-11-03 3:37 ` Ihor Radchenko 2018-11-17 12:13 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Ihor Radchenko @ 2018-11-03 3:37 UTC (permalink / raw) To: Gustav Wikström, Marco Wahl; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 3393 bytes --] Hi Gustav, Thanks for the patch! I am a heavy user of org attachments, so it is pleasant that someone spent a time to implement this useful feature into org. A comment regarding the code. Your new link types appears to reimplement some of the code for the "file:" links. Would it make more sense to implement the "attachment:" link type as abbreviation? I mean something like the code below: ```` (defun yant/process-att-abbrev (arg) "Return `org-attach-dir' for the current entry." (s-concat (org-attach-dir 'CREATE) arg)) (add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)")) (defun org-att-link-complete (&optional arg) "Completion function for att: link." (let* ((ref-dir (org-attach-dir 'CREATE)) (filelink (let ((default-directory ref-dir)) (org-file-complete-link))) (filepath (apply #'s-concat (cdr (s-split ":" filelink))))) (format "att:%s" filepath))) (org-link-set-parameters "att" :complete #'org-att-link-complete) ```` Also, is anyone interested in automatic placing of org attachments into a folder structure, which mirrors the org path? Something like in the following Stack Exchange question: https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org-attach Best, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi Marco, > > Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it all the time to quickly add links to attached files. > > One use case I have for this (as an example) is for projects and tasks. I have a 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the task is about some digital work, there are files involved with it. So I have a convention to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', and attach the folder to each task/project node. C-c C-l attached RET then makes it super-easy to refer to particular files within that folder, from within the node in the 'tasks.org' file! > > Another use case is for my 'digital brain', where it's also fairly common for me to have attachment folders where I want to refer to files within them. Images for example, that then will be displayed in the org-mode file. Haven't settled on whether I should use auto-managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit of both... > > I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. But if 'master' is to offensive to merge into straight away, 'next' sounds like a good option! > > Kind regards > Gustav > > -----Original Message----- > From: Marco Wahl <marcowahlsoft@gmail.com> > Sent: den 1 november 2018 17:01 > To: Gustav Wikström <gustav@whil.se> > Subject: Re: FW: [RFC] Link-type for attachments, more attach options > > The following message is a courtesy copy of an article that has been posted to gmane.emacs.orgmode as well. > > Hi Gustav, > > I played a bit with your proposition. I like it; in particular the completion function to insert links from the attachment directory with > > C-c C-l attached RET > > It seems natural to me to have a more specific link type for attached files. > > In my opinion your patch should be applied to the 'next' branch. > > > My 2ct, > Marco > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 487 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-03 3:37 ` Ihor Radchenko @ 2018-11-17 12:13 ` Gustav Wikström 2018-11-18 0:42 ` Ihor Radchenko 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-17 12:13 UTC (permalink / raw) To: Ihor Radchenko, Marco Wahl; +Cc: emacs-orgmode Hi Ihor, I'm not sure I follow your suggestion regarding changing the implementation. But anyhow I don't think the implementation is heavy and at risk of cumbersome code duplication. My opinion ofc 😊 I like the idea of a function that would symbolically links folders from "ID"-folder structure to a hierarchy-folder structure, based on the name and path of the org-file and its headings containing the links. I probably wouldn't use it much myself though. Not until org-mode starts working better with multiple files, allowing us to more easily define "org-mode libraries". /G > -----Original Message----- > From: Ihor Radchenko <yantar92@gmail.com> > Sent: den 3 november 2018 04:38 > To: Gustav Wikström <gustav@whil.se>; Marco Wahl <marcowahlsoft@gmail.com> > Cc: emacs-orgmode <emacs-orgmode@gnu.org> > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > Hi Gustav, > > Thanks for the patch! > I am a heavy user of org attachments, so it is pleasant that someone > spent a time to implement this useful feature into org. > > A comment regarding the code. > Your new link types appears to reimplement some of the code for the > "file:" links. > Would it make more sense to implement the "attachment:" link type as > abbreviation? > I mean something like the code below: > > ```` > (defun yant/process-att-abbrev (arg) > "Return `org-attach-dir' for the current entry." > (s-concat (org-attach-dir 'CREATE) arg)) > > (add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)")) > > (defun org-att-link-complete (&optional arg) > "Completion function for att: link." > (let* ((ref-dir (org-attach-dir 'CREATE)) > (filelink (let ((default-directory ref-dir)) > (org-file-complete-link))) > (filepath (apply #'s-concat (cdr (s-split ":" filelink))))) > (format "att:%s" filepath))) > > (org-link-set-parameters "att" > :complete #'org-att-link-complete) > ```` > > Also, is anyone interested in automatic placing of org attachments into > a folder structure, which mirrors the org path? > Something like in the following Stack Exchange question: > https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org- > attach > > Best, > Ihor > > Gustav Wikström <gustav@whil.se> writes: > > > Hi Marco, > > > > Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it > all the time to quickly add links to attached files. > > > > One use case I have for this (as an example) is for projects and tasks. I have a > 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the > task is about some digital work, there are files involved with it. So I have a convention > to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', > and attach the folder to each task/project node. C-c C-l attached RET then makes it super- > easy to refer to particular files within that folder, from within the node in the > 'tasks.org' file! > > > > Another use case is for my 'digital brain', where it's also fairly common for me to have > attachment folders where I want to refer to files within them. Images for example, that > then will be displayed in the org-mode file. Haven't settled on whether I should use auto- > managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit > of both... > > > > I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. > But if 'master' is to offensive to merge into straight away, 'next' sounds like a good > option! > > > > Kind regards > > Gustav > > > > -----Original Message----- > > From: Marco Wahl <marcowahlsoft@gmail.com> > > Sent: den 1 november 2018 17:01 > > To: Gustav Wikström <gustav@whil.se> > > Subject: Re: FW: [RFC] Link-type for attachments, more attach options > > > > The following message is a courtesy copy of an article that has been posted to > gmane.emacs.orgmode as well. > > > > Hi Gustav, > > > > I played a bit with your proposition. I like it; in particular the completion function > to insert links from the attachment directory with > > > > C-c C-l attached RET > > > > It seems natural to me to have a more specific link type for attached files. > > > > In my opinion your patch should be applied to the 'next' branch. > > > > > > My 2ct, > > Marco > > ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-17 12:13 ` Gustav Wikström @ 2018-11-18 0:42 ` Ihor Radchenko 2018-11-18 8:57 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Ihor Radchenko @ 2018-11-18 0:42 UTC (permalink / raw) To: Gustav Wikström, Marco Wahl; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 5690 bytes --] Hi Gustav, > I'm not sure I follow your suggestion regarding changing the > implementation. But anyhow I don't think the implementation is heavy > and at risk of cumbersome code duplication. My opinion ofc 😊 Sure. The code is not that complicated. > I like the idea of a function that would symbolically links folders > from "ID"-folder structure to a hierarchy-folder structure, based on > the name and path of the org-file and its headings containing the > links. I probably wouldn't use it much myself though. Not until > org-mode starts working better with multiple files, allowing us to > more easily define "org-mode libraries". I am wondering what you mean by "org-mode libraries". Can you explain further? Also, another thought about the attachment: links. It would be useful to implement links to attachments, which are not in the current org entry. For example, something like "attachment:ORG-ID:file-name", where ORG-ID refers to ID of an arbitrary org entry. Best, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi Ihor, > > I'm not sure I follow your suggestion regarding changing the implementation. But anyhow I don't think the implementation is heavy and at risk of cumbersome code duplication. My opinion ofc 😊 > > I like the idea of a function that would symbolically links folders from "ID"-folder structure to a hierarchy-folder structure, based on the name and path of the org-file and its headings containing the links. I probably wouldn't use it much myself though. Not until org-mode starts working better with multiple files, allowing us to more easily define "org-mode libraries". > > /G > >> -----Original Message----- >> From: Ihor Radchenko <yantar92@gmail.com> >> Sent: den 3 november 2018 04:38 >> To: Gustav Wikström <gustav@whil.se>; Marco Wahl <marcowahlsoft@gmail.com> >> Cc: emacs-orgmode <emacs-orgmode@gnu.org> >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> Hi Gustav, >> >> Thanks for the patch! >> I am a heavy user of org attachments, so it is pleasant that someone >> spent a time to implement this useful feature into org. >> >> A comment regarding the code. >> Your new link types appears to reimplement some of the code for the >> "file:" links. >> Would it make more sense to implement the "attachment:" link type as >> abbreviation? >> I mean something like the code below: >> >> ```` >> (defun yant/process-att-abbrev (arg) >> "Return `org-attach-dir' for the current entry." >> (s-concat (org-attach-dir 'CREATE) arg)) >> >> (add-to-list 'org-link-abbrev-alist (cons "att" "file:%(yant/process-att-abbrev)")) >> >> (defun org-att-link-complete (&optional arg) >> "Completion function for att: link." >> (let* ((ref-dir (org-attach-dir 'CREATE)) >> (filelink (let ((default-directory ref-dir)) >> (org-file-complete-link))) >> (filepath (apply #'s-concat (cdr (s-split ":" filelink))))) >> (format "att:%s" filepath))) >> >> (org-link-set-parameters "att" >> :complete #'org-att-link-complete) >> ```` >> >> Also, is anyone interested in automatic placing of org attachments into >> a folder structure, which mirrors the org path? >> Something like in the following Stack Exchange question: >> https://emacs.stackexchange.com/questions/26412/human-readable-directory-tree-with-org- >> attach >> >> Best, >> Ihor >> >> Gustav Wikström <gustav@whil.se> writes: >> >> > Hi Marco, >> > >> > Nice to hear you like it! Yeah, I'm pretty happy with that functionality as well. Use it >> all the time to quickly add links to attached files. >> > >> > One use case I have for this (as an example) is for projects and tasks. I have a >> 'tasks.org' file with nodes for each of my tasks and each of my projects. Usually, if the >> task is about some digital work, there are files involved with it. So I have a convention >> to add folders next to the 'tasks.org' file with names like 'YYMM [task/project title]', >> and attach the folder to each task/project node. C-c C-l attached RET then makes it super- >> easy to refer to particular files within that folder, from within the node in the >> 'tasks.org' file! >> > >> > Another use case is for my 'digital brain', where it's also fairly common for me to have >> attachment folders where I want to refer to files within them. Images for example, that >> then will be displayed in the org-mode file. Haven't settled on whether I should use auto- >> managed ID's for these folders, or :ATTACH_DIR: properties though. Currently using a bit >> of both... >> > >> > I'm not familiar with the 'next' branch and the plans for integrating it into 'master'. >> But if 'master' is to offensive to merge into straight away, 'next' sounds like a good >> option! >> > >> > Kind regards >> > Gustav >> > >> > -----Original Message----- >> > From: Marco Wahl <marcowahlsoft@gmail.com> >> > Sent: den 1 november 2018 17:01 >> > To: Gustav Wikström <gustav@whil.se> >> > Subject: Re: FW: [RFC] Link-type for attachments, more attach options >> > >> > The following message is a courtesy copy of an article that has been posted to >> gmane.emacs.orgmode as well. >> > >> > Hi Gustav, >> > >> > I played a bit with your proposition. I like it; in particular the completion function >> to insert links from the attachment directory with >> > >> > C-c C-l attached RET >> > >> > It seems natural to me to have a more specific link type for attached files. >> > >> > In my opinion your patch should be applied to the 'next' branch. >> > >> > >> > My 2ct, >> > Marco >> > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 487 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-18 0:42 ` Ihor Radchenko @ 2018-11-18 8:57 ` Gustav Wikström 2018-11-20 14:00 ` Ihor Radchenko 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-18 8:57 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode Hi, > -----Original Message----- > From: Ihor Radchenko <yantar92@gmail.com> > Sent: den 18 november 2018 01:42 > To: Gustav Wikström <gustav@whil.se>; Marco Wahl > <marcowahlsoft@gmail.com> > Cc: emacs-orgmode <emacs-orgmode@gnu.org> > Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options > > Hi Gustav, > > > I like the idea of a function that would symbolically links folders > > from "ID"-folder structure to a hierarchy-folder structure, based on > > the name and path of the org-file and its headings containing the > > links. I probably wouldn't use it much myself though. Not until > > org-mode starts working better with multiple files, allowing us to > > more easily define "org-mode libraries". > > I am wondering what you mean by "org-mode libraries". Can you explain > further? This goes a bit off topic; But what I mean is mainly two things: 1) Generalize the org-agenda so that we can have multiple ones Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas. 2) Make files function as virtual "level-0 headings" If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well. > > Also, another thought about the attachment: links. > It would be useful to implement links to attachments, which are not in the > current org entry. > For example, something like "attachment:ORG-ID:file-name", where ORG-ID > refers to ID of an arbitrary org entry. I wouldn't call that attachment-links, but rather ID-based links (since attachments are local based on either headline ID or attach-dir of the current headline). ID links exist already but link to headlines. If you rather see ID-based attachments as some kind of global attachments for all your org-mode files, I'd think the link-type should reflect that and be called something like "ID-attachment:file-name", "ID-@:file-name", "@ID:file-name" and be a separate link-type. > > Best, > Ihor > > Kind regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-18 8:57 ` Gustav Wikström @ 2018-11-20 14:00 ` Ihor Radchenko 2018-11-24 13:56 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Ihor Radchenko @ 2018-11-20 14:00 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 4798 bytes --] Hi, > Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas. Isn't this already in org? You can use custom agendas with multiple "agendas" (custom commands) and set the files they operate on with org-agenda-files within custom commands. > If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well. You can do something like below. It is pretty much what you want, except I am not sure how to update the headings from local org files. Current org version does not allow `:results replace` on raw org output. * Main heading #+name: org-files-here #+begin_src bash ls *.org #+end_src #+begin_src emacs-lisp :var files=org-files-here() :var stars=(make-string (car (org-heading-components)) ?*) :results raw replace drawer (let ((files (mapcar #'car files))) (cl-loop for file in files concat (with-current-buffer (find-file-noselect file) (concat (format "* %s\n" (buffer-file-name)) (replace-regexp-in-string "^\\*" (concat "*" stars) (buffer-string)))))) #+end_src Best, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: Ihor Radchenko <yantar92@gmail.com> >> Sent: den 18 november 2018 01:42 >> To: Gustav Wikström <gustav@whil.se>; Marco Wahl >> <marcowahlsoft@gmail.com> >> Cc: emacs-orgmode <emacs-orgmode@gnu.org> >> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options >> >> Hi Gustav, >> >> > I like the idea of a function that would symbolically links folders >> > from "ID"-folder structure to a hierarchy-folder structure, based on >> > the name and path of the org-file and its headings containing the >> > links. I probably wouldn't use it much myself though. Not until >> > org-mode starts working better with multiple files, allowing us to >> > more easily define "org-mode libraries". >> >> I am wondering what you mean by "org-mode libraries". Can you explain >> further? > > This goes a bit off topic; But what I mean is mainly two things: > 1) Generalize the org-agenda so that we can have multiple ones > > Generalize org-agenda by allowing us to have multiple ones, and make them more general by thinking of them as a set of views that works on sets of files. Maybe this is not for all, but I would appreciate to create multiple "agendas" (even though I'd call them "libraries" in instead), and possibly also an aggregate agenda consisting of other agendas. > > 2) Make files function as virtual "level-0 headings" > > If two org-mode files exist in the same folder with different names, it would be awesome to think of (and work with) them as two top-level headings inside one org-mode buffer. Similar to two level-1 headings inside an org-mode file. For this to work all properties we can define for regular headings should be possible to define for these "level-0 headings". For example an attachment-folder or ID, a deadline, scheduled date, or TODO-keyword should in that case be configurable on the whole file. I guess some new conventions regarding syntax and existing properties would have to be created as well. > >> >> Also, another thought about the attachment: links. >> It would be useful to implement links to attachments, which are not in the >> current org entry. >> For example, something like "attachment:ORG-ID:file-name", where ORG-ID >> refers to ID of an arbitrary org entry. > > I wouldn't call that attachment-links, but rather ID-based links (since attachments are local based on either headline ID or attach-dir of the current headline). ID links exist already but link to headlines. > > If you rather see ID-based attachments as some kind of global attachments for all your org-mode files, I'd think the link-type should reflect that and be called something like "ID-attachment:file-name", "ID-@:file-name", "@ID:file-name" and be a separate link-type. > >> >> Best, >> Ihor >> >> > > Kind regards > Gustav [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 487 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-20 14:00 ` Ihor Radchenko @ 2018-11-24 13:56 ` Gustav Wikström 2018-12-14 2:16 ` Ihor Radchenko 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-24 13:56 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode Hi, > -----Original Message----- > From: Ihor Radchenko <yantar92@gmail.com> > Sent: den 20 november 2018 15:01 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode <emacs-orgmode@gnu.org> > Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options > > Hi, > > > Generalize org-agenda by allowing us to have multiple ones, and make > them more general by thinking of them as a set of views that works on sets > of files. Maybe this is not for all, but I would appreciate to create > multiple "agendas" (even though I'd call them "libraries" in instead), and > possibly also an aggregate agenda consisting of other agendas. > > Isn't this already in org? You can use custom agendas with multiple > "agendas" (custom commands) and set the files they operate on with org- > agenda-files within custom commands. No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. > > > If two org-mode files exist in the same folder with different names, it > would be awesome to think of (and work with) them as two top-level headings > inside one org-mode buffer. Similar to two level-1 headings inside an org- > mode file. For this to work all properties we can define for regular > headings should be possible to define for these "level-0 headings". For > example an attachment-folder or ID, a deadline, scheduled date, or TODO- > keyword should in that case be configurable on the whole file. I guess some > new conventions regarding syntax and existing properties would have to be > created as well. > > You can do something like below. It is pretty much what you want, except I > am not sure how to update the headings from local org files. Current org > version does not allow `:results replace` on raw org output. > > * Main heading > > #+name: org-files-here > #+begin_src bash > ls *.org > #+end_src > > #+begin_src emacs-lisp :var files=org-files-here() :var stars=(make-string > (car (org-heading-components)) ?*) :results raw replace drawer (let ((files > (mapcar #'car files))) > (cl-loop for file in files > concat (with-current-buffer (find-file-noselect file) > (concat (format "* %s\n" (buffer-file-name)) > (replace-regexp-in-string "^\\*" (concat "*" stars) > (buffer-string)))))) #+end_src No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept. Thanks for your idea and suggestion though! > > Best, > Ihor Kind Regards, Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-24 13:56 ` Gustav Wikström @ 2018-12-14 2:16 ` Ihor Radchenko 2019-05-26 22:24 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Ihor Radchenko @ 2018-12-14 2:16 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 4549 bytes --] > No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. I just tried: #+begin_src emacs-lisp (setq org-agenda-custom-commands (quote (("v" "Test" tags-todo nil ((org-agenda-files '("~/Org/inbox.org")))) ("w" "Test 2" tags-todo nil ((org-agenda-files '("~/Knowledge_base/2016/Private/Get_started_with_org_mode/get_started_org_mode.org"))))))) #+end_src It works fine for me. > No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept. Yeah. But someone needs to volunteer with the patch. It would be even better if these 0-level headings can be edited from the referencing file. Regards, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: Ihor Radchenko <yantar92@gmail.com> >> Sent: den 20 november 2018 15:01 >> To: Gustav Wikström <gustav@whil.se> >> Cc: emacs-orgmode <emacs-orgmode@gnu.org> >> Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options >> >> Hi, >> >> > Generalize org-agenda by allowing us to have multiple ones, and make >> them more general by thinking of them as a set of views that works on sets >> of files. Maybe this is not for all, but I would appreciate to create >> multiple "agendas" (even though I'd call them "libraries" in instead), and >> possibly also an aggregate agenda consisting of other agendas. >> >> Isn't this already in org? You can use custom agendas with multiple >> "agendas" (custom commands) and set the files they operate on with org- >> agenda-files within custom commands. > > No, it's not there. I know of the custom agendas and use it currently. But I cannot anywhere specify more than one org-agenda-files parameter, for example. > >> >> > If two org-mode files exist in the same folder with different names, it >> would be awesome to think of (and work with) them as two top-level headings >> inside one org-mode buffer. Similar to two level-1 headings inside an org- >> mode file. For this to work all properties we can define for regular >> headings should be possible to define for these "level-0 headings". For >> example an attachment-folder or ID, a deadline, scheduled date, or TODO- >> keyword should in that case be configurable on the whole file. I guess some >> new conventions regarding syntax and existing properties would have to be >> created as well. >> >> You can do something like below. It is pretty much what you want, except I >> am not sure how to update the headings from local org files. Current org >> version does not allow `:results replace` on raw org output. >> >> * Main heading >> >> #+name: org-files-here >> #+begin_src bash >> ls *.org >> #+end_src >> >> #+begin_src emacs-lisp :var files=org-files-here() :var stars=(make-string >> (car (org-heading-components)) ?*) :results raw replace drawer (let ((files >> (mapcar #'car files))) >> (cl-loop for file in files >> concat (with-current-buffer (find-file-noselect file) >> (concat (format "* %s\n" (buffer-file-name)) >> (replace-regexp-in-string "^\\*" (concat "*" stars) >> (buffer-string)))))) #+end_src > > No, that's not what I want. What I'm talking about is extending org-mode conceptually with the concept of 0-level headlines, where the body of that "headline" would be everything before the first headline in a file, and where I could specify (for example) an attachment-directory and be able to use it with this new syntax to link to attached files. I guess I took it a bit far with the example of visualizing multiple files from a folder as separate headlines inside a single emacs-buffer though. It would be cool to be able to do that but my intention was more about introducing the 0-level headline concept. > > Thanks for your idea and suggestion though! > >> >> Best, >> Ihor > > Kind Regards, > Gustav > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 487 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-12-14 2:16 ` Ihor Radchenko @ 2019-05-26 22:24 ` Gustav Wikström 0 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2019-05-26 22:24 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode Hi again! > -----Original Message----- > From: Ihor Radchenko <yantar92@gmail.com> > Sent: den 14 december 2018 03:16 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode <emacs-orgmode@gnu.org> > Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options > > > No, that's not what I want. What I'm talking about is extending org-mode conceptually > > with the concept of 0-level headlines, where the body of that "headline" would be > > everything before the first headline in a file, and where I could specify (for example) an > > attachment-directory and be able to use it with this new syntax to link to attached files. > > I guess I took it a bit far with the example of visualizing multiple files from a folder > > as separate headlines inside a single emacs-buffer though. It would be cool to be able to > > do that but my intention was more about introducing the 0-level headline concept. > > Yeah. But someone needs to volunteer with the patch. I just wanted to say I'm working on this. More info will come in a separate thread soon! Kind regards, Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström 2018-11-01 1:45 ` tumashu 2018-11-01 16:00 ` Marco Wahl @ 2018-11-04 22:37 ` Nicolas Goaziou 2018-11-17 11:58 ` Gustav Wikström 2019-01-04 12:21 ` FW: " Feng Shu ` (5 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2018-11-04 22:37 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > I’ve attached a patch with some suggested additions to org-attach. > Patch comments below. Please review. Thank you. Some comments follow. > * Add new linktype "attached" for attachments This seem a bit long. Why not "att" links? > * Add further options for ATTACH_DIR > > When working with ATTACH_DIR there are now a couple of new options available: > - org-attach-dir-inherit-by-default What is the difference between this and `org-attach-allow-inheritance'? > - org-attach-dir-create-if-not-exist What is the use-case for this one? It doesn't seem terribly useful at first glance. > - org-attach-dir-relative I'm not sure to understand this one. > > +This list shows the full set of built-in external link types: > +| http | web | > +| https | secure web | > +| doi | DOI for electronic resources | > +| file | file-links | > +| file+sys | file-links forced to open via OS | > +| file+emacs | file-links forced to open via emacs | > +| attached | links to attachments for nodes | > +| docview | doc-view mode | > +| id | Link to heading by id | > +| news | Usenet link | > +| mailto | mail link | > +| mhe | MH-E folder link | > +| rmail | Rmail link | > +| gnus | Gnus link | > +| bbdb | BBDB link | > +| irc | IRC link | > +| info | Info link | > +| shell | shell command | > +| elisp | interactive elisp command link | > + > +The following list shows examples for each link type. > + > +| =http://www.astro.uva.nl/=dominik= | on the web | > +| =doi:10.1000/182= | DOI for an electronic resource | > +| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | > +| =/home/dominik/images/jupiter.jpg= | same as above | > +| =file:papers/last.pdf= | file, relative path | > +| =./papers/last.pdf= | same as above | > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | > +| =/ssh:me@some.where:papers/last.pdf= | same as above | > +| =file:sometextfile::NNN= | file, jump to line number | > +| =file:projects.org= | another Org file | > +| =file:projects.org::some words= | text search in Org file[fn:28] | > +| =file:projects.org::*task title= | heading search in Org file | > +| =file+sys:/path/to/file= | open via OS, like double-click | > +| =file+emacs:/path/to/file= | force opening by Emacs | > +| =attached:projects.org= | file in folder attached to headline | > +| =attached:projects.org::some words= | text search in attached file | > +| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | > +| =news:comp.emacs= | Usenet link | > +| =mailto:adent@galaxy.net= | mail link | > +| =mhe:folder= | MH-E folder link | > +| =mhe:folder#id= | MH-E message link | > +| =rmail:folder= | Rmail folder link | > +| =rmail:folder#id= | Rmail message link | > +| =gnus:group= | Gnus group link | > +| =gnus:group#id= | Gnus article link | > +| =bbdb:R.*Stallman= | BBDB link (with regexp) | > +| =irc:/irc.com/#emacs/bob= | IRC link | > +| =info:org#External links= | Info node link | > +| =shell:ls *.org= | shell command | > +| =elisp:org-agenda= | interactive Elisp command | > +| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | I'm not sure to like the change above. It introduces a lot of redundancy. > Here is the syntax of the different ways to attach a search to a file > link, together with explanations for each: > > #+begin_example > -[[file:~/code/main.c::255]] > -[[file:~/xx.org::My Target]] > -[[file:~/xx.org::*My Target]] > -[[file:~/xx.org::#my-custom-id]] > -[[file:~/xx.org::/regexp/]] > + [[file:~/code/main.c::255]] > + [[file:~/xx.org::My Target]] > + [[file:~/xx.org::*My Target]] > + [[file:~/xx.org::#my-custom-id]] > + [[file:~/xx.org::/regexp/]] > + [[attached:~/code/main.c::255]] > #+end_example Please discard this change. > +Another method is /attachments/, which are files located in a > +directory belonging to an outline node. Org uses directories either > +named by the unique ID of each entry, or by the =ATTACH_DIR= property. > +ID-based directories are by default located in the ~data~ directory ... =data/= directory, which ... > +(defcustom org-attach-dir-inherit-by-default nil > + "Defines whether ATTACH_DIR-directories should be inherited by > + subheadings by default when created. Defaults to not being > + inherited." > + :group 'org-attach > + :type 'boolean) First line in a docstring must be a full sentence. Indentation is wrong in the subsequent lines. Also, the `defcustom' is missing keywords, e.g., :package-version and :safe. > +(defcustom org-attach-dir-create-if-not-exists t > + "Choose whether ATTACH_DIR-directories should be created if > +they do not exist since before. Default is to create them." > + :group 'org-attach > + :type 'boolean) > + > +(defcustom org-attach-dir-relative nil > + "Choose whether ATTACH_DIR-directories should be added as > +relative links or not. Defaults to not relative." > + :group 'org-attach > + :type 'boolean) Ditto. > (defcustom org-attach-commit t > "If non-nil commit attachments with git. > This is only done if the Org file is in a git repository." > @@ -280,20 +299,26 @@ Throw an error if we cannot root the directory." > "Set the ATTACH_DIR node property and ask to move files there. > The property defines the directory that is used for attachments > of the entry. When called with `\\[universal-argument]', reset \ > -the directory to > -the default ID based one." > +the directory to the default ID based one. Creates relative links You need to use two spaces to separate sentences. > + (let ((old (org-attach-dir nil)) > + (new > + (progn > + (if arg (org-entry-delete nil "ATTACH_DIR") > + (let* ((attach-dir (read-directory-name > + "Attachment directory: " > + (org-entry-get nil > + "ATTACH_DIR"))) > + (current-dir (file-name-directory (or load-file-name > + buffer-file-name))) Why `load-file-name'? Why not using `default-directory'? > +(defun org-attach-open-link (link &optional in-emacs) > + "LINK is expanded with the attached directory and opened the same > +way as file-links are." You need to expound the arguments in the docstring. > + (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)" > (if (not link-abbrevs) "" > (format "\\|\\(?:%s:\\)" > (regexp-opt link-abbrevs)))))) Why is it needed? "attached" link type is already registered, so you don't need to also hard-code it here. > + (when (and (or (equal "file" (org-element-property :type link)) > + (equal "attached" (org-element-property :type link))) Ditto. > + (let ((file (if (equal "attached" (org-element-property :type link)) > + (require 'org-attach) > + (org-attach-expand > + (org-link-unescape > + (org-element-property :path link))) > + (expand-file-name > + (org-link-unescape > + (org-element-property :path link)))))) Ditto. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-11-04 22:37 ` Nicolas Goaziou @ 2018-11-17 11:58 ` Gustav Wikström [not found] ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com> 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-17 11:58 UTC (permalink / raw) To: mail@nicolasgoaziou.fr; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 11534 bytes --] Hi Nicolas, Thanks for your detailed comments. Much appreciated. > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 4 november 2018 23:37 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: FW: [RFC] Link-type for attachments, more attach options > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > I’ve attached a patch with some suggested additions to org-attach. > > Patch comments below. Please review. > > Thank you. Some comments follow. > > > * Add new linktype "attached" for attachments > > This seem a bit long. Why not "att" links? Yeah - I liked "attached" because I prefer clear keywords. But sure, we can keep it shorter. I'd suggest "@" instead in that case. Patch updated with that. > > > * Add further options for ATTACH_DIR > > > > When working with ATTACH_DIR there are now a couple of new options available: > > - org-attach-dir-inherit-by-default > > What is the difference between this and `org-attach-allow-inheritance'? > > > - org-attach-dir-create-if-not-exist > > What is the use-case for this one? It doesn't seem terribly useful at > first glance. If you try to open attachments on a node where there is no ID or ATTACH_DIR, the default behavior is to add an ID and create a folder based on that ID. I would like Org-mode to not do that. This customization give the user the option to change that. Instead of providing this customization one could just change the default behavior of org-attach, since it's a bit offensive to create folders when I didn't ask for it. But instead of changing the default, I thought this way was more graceful. I wouldn't mind skipping this customization though, if the behavior was changed to what I implemented with org-attach-dir-create-if-not-exist set to nil. > > > - org-attach-dir-relative > > I'm not sure to understand this one. When adding folders to nodes using option "s" in org-attach, the path is absolute. This makes attachment-directory paths relative to location of the file instead. > > > > +This list shows the full set of built-in external link types: > > +| http | web | > > +| https | secure web | > > +| doi | DOI for electronic resources | > > +| file | file-links | > > +| file+sys | file-links forced to open via OS | > > +| file+emacs | file-links forced to open via emacs | > > +| attached | links to attachments for nodes | > > +| docview | doc-view mode | > > +| id | Link to heading by id | > > +| news | Usenet link | > > +| mailto | mail link | > > +| mhe | MH-E folder link | > > +| rmail | Rmail link | > > +| gnus | Gnus link | > > +| bbdb | BBDB link | > > +| irc | IRC link | > > +| info | Info link | > > +| shell | shell command | > > +| elisp | interactive elisp command link | > > + > > +The following list shows examples for each link type. > > + > > +| =http://www.astro.uva.nl/=dominik= | on the web | > > +| =doi:10.1000/182= | DOI for an electronic resource | > > +| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | > > +| =/home/dominik/images/jupiter.jpg= | same as above | > > +| =file:papers/last.pdf= | file, relative path | > > +| =./papers/last.pdf= | same as above | > > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | > > +| =/ssh:me@some.where:papers/last.pdf= | same as above | > > +| =file:sometextfile::NNN= | file, jump to line number | > > +| =file:projects.org= | another Org file | > > +| =file:projects.org::some words= | text search in Org file[fn:28] | > > +| =file:projects.org::*task title= | heading search in Org file | > > +| =file+sys:/path/to/file= | open via OS, like double-click | > > +| =file+emacs:/path/to/file= | force opening by Emacs | > > +| =attached:projects.org= | file in folder attached to headline | > > +| =attached:projects.org::some words= | text search in attached file | > > +| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | > > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | > > +| =news:comp.emacs= | Usenet link | > > +| =mailto:adent@galaxy.net= | mail link | > > +| =mhe:folder= | MH-E folder link | > > +| =mhe:folder#id= | MH-E message link | > > +| =rmail:folder= | Rmail folder link | > > +| =rmail:folder#id= | Rmail message link | > > +| =gnus:group= | Gnus group link | > > +| =gnus:group#id= | Gnus article link | > > +| =bbdb:R.*Stallman= | BBDB link (with regexp) | > > +| =irc:/irc.com/#emacs/bob= | IRC link | > > +| =info:org#External links= | Info node link | > > +| =shell:ls *.org= | shell command | > > +| =elisp:org-agenda= | interactive Elisp command | > > +| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | > > I'm not sure to like the change above. It introduces a lot of > redundancy. > Currently the list in the documentation is just a bunch of examples. I've looked at it a couple of times asking myself "What is the complete list of built in link types?". This commit "fixes" that. I wouldn't say its redundant since all the rows in the second list are just examples. > > Here is the syntax of the different ways to attach a search to a file > > link, together with explanations for each: > > > > #+begin_example > > -[[file:~/code/main.c::255]] > > -[[file:~/xx.org::My Target]] > > -[[file:~/xx.org::*My Target]] > > -[[file:~/xx.org::#my-custom-id]] > > -[[file:~/xx.org::/regexp/]] > > + [[file:~/code/main.c::255]] > > + [[file:~/xx.org::My Target]] > > + [[file:~/xx.org::*My Target]] > > + [[file:~/xx.org::#my-custom-id]] > > + [[file:~/xx.org::/regexp/]] > > + [[attached:~/code/main.c::255]] > > #+end_example > > Please discard this change. Ofc, sorry for that. > > > +Another method is /attachments/, which are files located in a > > +directory belonging to an outline node. Org uses directories either > > +named by the unique ID of each entry, or by the =ATTACH_DIR= property. > > +ID-based directories are by default located in the ~data~ directory > > ... =data/= directory, which ... Done. > > > +(defcustom org-attach-dir-inherit-by-default nil > > + "Defines whether ATTACH_DIR-directories should be inherited by > > + subheadings by default when created. Defaults to not being > > + inherited." > > + :group 'org-attach > > + :type 'boolean) > > First line in a docstring must be a full sentence. Indentation is wrong > in the subsequent lines. Also, the `defcustom' is missing keywords, > e.g., :package-version and :safe. I can't say I understand the use of :safe here. But added it anyways. If you care, please explain why it's needed. Package-version is added. I set it to 9.2. Correct? > > > +(defcustom org-attach-dir-create-if-not-exists t > > + "Choose whether ATTACH_DIR-directories should be created if > > +they do not exist since before. Default is to create them." > > + :group 'org-attach > > + :type 'boolean) > > + > > +(defcustom org-attach-dir-relative nil > > + "Choose whether ATTACH_DIR-directories should be added as > > +relative links or not. Defaults to not relative." > > + :group 'org-attach > > + :type 'boolean) > > Ditto. Ok > > > (defcustom org-attach-commit t > > "If non-nil commit attachments with git. > > This is only done if the Org file is in a git repository." > > @@ -280,20 +299,26 @@ Throw an error if we cannot root the directory." > > "Set the ATTACH_DIR node property and ask to move files there. > > The property defines the directory that is used for attachments > > of the entry. When called with `\\[universal-argument]', reset \ > > -the directory to > > -the default ID based one." > > +the directory to the default ID based one. Creates relative links > > You need to use two spaces to separate sentences. Ah, yes ofc. Fixed. > > > + (let ((old (org-attach-dir nil)) > > + (new > > + (progn > > + (if arg (org-entry-delete nil "ATTACH_DIR") > > + (let* ((attach-dir (read-directory-name > > + "Attachment directory: " > > + (org-entry-get nil > > + "ATTACH_DIR"))) > > + (current-dir (file-name-directory (or load-file-name > > + buffer-file-name))) > > Why `load-file-name'? Why not using `default-directory'? Good question. I don't remember having any particular arguments for it. I'll change to your suggestion. > > > +(defun org-attach-open-link (link &optional in-emacs) > > + "LINK is expanded with the attached directory and opened the same > > +way as file-links are." > > You need to expound the arguments in the docstring. Sorry, I don't understand what I'm supposed to do here... I changed the comment to (maybe?) make it read better. Other than that, I'm at a loss. > > > + (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)" > > (if (not link-abbrevs) "" > > (format "\\|\\(?:%s:\\)" > > (regexp-opt link-abbrevs)))))) > > Why is it needed? "attached" link type is already registered, so you > don't need to also hard-code it here. This is when parsing the buffer for images. I couldn't get org-mode to display images without this. > > > + (when (and (or (equal "file" (org-element-property :type link)) > > + (equal "attached" (org-element-property :type link))) > > Ditto. Same comment as above. > > > + (let ((file (if (equal "attached" (org-element-property :type link)) > > + (require 'org-attach) > > + (org-attach-expand > > + (org-link-unescape > > + (org-element-property :path link))) > > + (expand-file-name > > + (org-link-unescape > > + (org-element-property :path link)))))) > > Ditto. Same comment as above. > > Regards, > > -- > Nicolas Goaziou Thanks again for your comments. Updated patch is attached/att/@! Kind regards, Gustav [-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-more-attach-.patch --] [-- Type: application/octet-stream, Size: 17679 bytes --] From f556e3e1dcfff6103e54aee244bbeacf13aeeb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com> Date: Sun, 23 Sep 2018 02:43:16 +0200 Subject: [PATCH] org-attach, org-manual, org: New link-type, more attach options * Add new linktype "attached" for attachments A new linktype "attached" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. Inline images will trigger also for attachments, as well as search-decorations in the links. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a couple of new options available: - org-attach-dir-inherit-by-default - org-attach-dir-create-if-not-exist - org-attach-dir-relative Descriptions of them can be found in the commit for each new customization. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. --- doc/org-manual.org | 72 ++++++++++++++++------- lisp/org-attach.el | 143 ++++++++++++++++++++++++++++++++++++--------- lisp/org.el | 17 ++++-- 3 files changed, 181 insertions(+), 51 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 5e4effb6f..960292ab2 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3141,6 +3141,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: @ links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3152,7 +3153,30 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. +the colon. + +This list shows the full set of built-in external link types: +| http | web | +| https | secure web | +| doi | DOI for electronic resources | +| file | file-links | +| file+sys | file-links forced to open via OS | +| file+emacs | file-links forced to open via emacs | +| @ | links to attachments for nodes | +| docview | doc-view mode | +| id | Link to heading by id | +| news | Usenet link | +| mailto | mail link | +| mhe | MH-E folder link | +| rmail | Rmail link | +| gnus | Gnus link | +| bbdb | BBDB link | +| irc | IRC link | +| info | Info link | +| shell | shell command | +| elisp | interactive elisp command link | + +The following list shows examples for each link type. | =http://www.astro.uva.nl/=dominik= | on the web | | =doi:10.1000/182= | DOI for an electronic resource | @@ -3168,6 +3192,8 @@ the colon. The following list shows examples for each link type. | =file:projects.org::*task title= | heading search in Org file | | =file+sys:/path/to/file= | open via OS, like double-click | | =file+emacs:/path/to/file= | force opening by Emacs | +| =@:projects.org= | file attached to headline | +| =@:projects.org::some words= | text search in attached file | | =docview:papers/last.pdf::NNN= | open in doc-view mode at page | | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | | =news:comp.emacs= | Usenet link | @@ -3538,14 +3564,15 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: @ links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:35]. For -example, when the command ~org-store-link~ creates a link (see -[[*Handling Links]]) to a file, it encodes the words in the current line -as a search string that can be used to find this line back later when -following the link with {{{kbd(C-c C-o)}}}. +File links and attached (@) links can contain additional information +to make Emacs jump to a particular location in the file when following +a link. This can be a line number or a search option after a double +colon[fn:35]. For example, when the command ~org-store-link~ creates +a link (see [[*Handling Links]]) to a file, it encodes the words in the +current line as a search string that can be used to find this line +back later when following the link with {{{kbd(C-c C-o)}}}. Here is the syntax of the different ways to attach a search to a file link, together with explanations for each: @@ -3556,6 +3583,7 @@ link, together with explanations for each: [[file:~/xx.org::*My Target]] [[file:~/xx.org::#my-custom-id]] [[file:~/xx.org::/regexp/]] +[[@:~/code/main.c::255]] #+end_example - =255= :: @@ -7533,18 +7561,22 @@ node/task. Small chunks of plain text can simply be stored in the subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations with files that live elsewhere on your computer or in the cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -~data~ directory which lives in the same directory where your Org file -lives[fn:86]. If you initialize this directory with =git init=, Org -automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by the unique ID of each entry, or by the =ATTACH_DIR= property. +ID-based directories are by default located in the =data/= directory, +which lives in the same directory where your Org file lives[fn:86]. +If you initialize this directory with =git init=, Org automatically +commits changes when it sees them. The attachment system has been +contributed to Org by John Wiegley. + +In cases where =ATTACH_DIR= property is used to declare attachments, +you can choose to either use absolute (default) or relative links. +You can also make children inherit the attachment directory from a +parent, so that an entire subtree uses the same attached directory. + +See customization group =Org Attach= if you want to change the default +settings for attachments. The following commands deal with attachments: diff --git a/lisp/org-attach.el b/lisp/org-attach.el index e827d3721..bc7f02669 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -57,6 +57,30 @@ where the Org file lives." :type 'directory :safe #'stringp) +(defcustom org-attach-dir-inherit-by-default nil + "Defines whether ATTACH_DIR-directories should be inherited by subheadings by default when created. +Defaults to not being inherited." + :group 'org-attach + :type 'boolean + :package-version '(Org . "9.2") + :safe #'booleanp) + +(defcustom org-attach-dir-create-if-not-exists t + "Choose whether ATTACH_DIR-directories should be created if they do not exist since before. +Default is to create them." + :group 'org-attach + :type 'boolean + :package-version '(Org . "9.2") + :safe #'booleanp) + +(defcustom org-attach-dir-relative nil + "Choose whether ATTACH_DIR-directories should be added as relative links or not. +Defaults to not relative." + :group 'org-attach + :type 'boolean + :package-version '(Org . "9.2") + :safe #'booleanp) + (defcustom org-attach-commit t "If non-nil commit attachments with git. This is only done if the Org file is in a git repository." @@ -280,20 +304,26 @@ Throw an error if we cannot root the directory." "Set the ATTACH_DIR node property and ask to move files there. The property defines the directory that is used for attachments of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." +the directory to the default ID based one. Creates relative +links if ORG-ATTACH-DIR-RELATIVE is t, and sets inheritance based +on ORG-ATTACH-DIR-INHERIT-BY-DEFAULT." (interactive "P") - (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (let ((old (org-attach-dir nil)) + (new + (progn + (if arg (org-entry-delete nil "ATTACH_DIR") + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil + "ATTACH_DIR"))) + (current-dir (file-name-directory (or default-directory + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (if org-attach-dir-relative + (org-entry-put nil "ATTACH_DIR" attach-dir-relative) + (org-entry-put nil "ATTACH_DIR" attach-dir)))) + (org-attach-dir t)))) + (when org-attach-dir-inherit-by-default (org-attach-set-inherit)) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") @@ -527,14 +557,15 @@ This ignores files ending in \"~\"." "Show the attachment directory of the current task. This will attempt to use an external program to show the directory." (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) - (and attach-dir (org-open-file attach-dir)))) + (let* ((create-if-not-exist (if if-exists nil org-attach-dir-create-if-not-exists)) + (attach-dir (org-attach-dir create-if-not-exist))) + (when attach-dir (org-open-file attach-dir)))) (defun org-attach-reveal-in-emacs () "Show the attachment directory of the current task in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists))) + (when attach-dir (dired attach-dir)))) (defun org-attach-open (&optional in-emacs) "Open an attachment of the current task. @@ -543,15 +574,17 @@ This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir org-attach-dir-create-if-not-exists))) + (if attach-dir + (let* ((files (org-attach-file-list attach-dir)) + (file (if (= (length files) 1) + (car files) + (completing-read "Open attachment: " + (mapcar #'list files) nil t))) + (path (expand-file-name file attach-dir))) + (org-attach-annex-get-maybe path) + (org-open-file path in-emacs)) + (message "No attachment exists!")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -570,6 +603,64 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(defun org-attach-open-link (link &optional in-emacs) + "Attach link type LINK is expanded with the attached directory and opened. +This is done in the same way as file-links are opened." + (interactive "P") + (let (line search) + (if (string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0))) + (if (string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment directory." + (let (file link attached-dir) + (setq attached-dir (expand-file-name (org-attach-dir))) + (setq file (read-file-name "File: " attached-dir)) + (let ((pwd (file-name-as-directory attached-dir)) + (pwd1 (file-name-as-directory (abbreviate-file-name + attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file) + (setq link (concat "@:" (match-string 1 file)))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (setq link (concat + "@:" (match-string 1 (expand-file-name file))))) + (t (setq link (concat "@:" file))))) + link)) + +(defun org-attach-export-link (link description format) + "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT. +Also includes the DESCRIPTION of the link in the export." + (save-excursion + (let (path desc) + (if (string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))) + (if (string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (search-forward (concat "@:" (org-link-escape link))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + +(org-link-set-parameters "@" + :follow 'org-attach-open-link + :export 'org-attach-export-link + :complete 'org-attach-complete-link) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option diff --git a/lisp/org.el b/lisp/org.el index eb1affbc7..9ed663bb9 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -4428,6 +4428,7 @@ This is needed for font-lock setup.") (beg end)) (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) (declare-function org-agenda-skip "org-agenda" ()) +(declare-function org-attach-expand "org-attach" (&optional if-exists)) (declare-function org-attach-reveal "org-attach" (&optional if-exists)) (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) (declare-function org-indent-mode "org-indent" (&optional arg)) @@ -18721,7 +18722,7 @@ boundaries." ;; Check absolute, relative file names and explicit ;; "file:" links. Also check link abbreviations since ;; some might expand to "file" links. - (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)" + (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)" (if (not link-abbrevs) "" (format "\\|\\(?:%s:\\)" (regexp-opt link-abbrevs)))))) @@ -18730,14 +18731,20 @@ boundaries." ;; Check if we're at an inline image, i.e., an image file ;; link without a description (unless INCLUDE-LINKED is ;; non-nil). - (when (and (equal "file" (org-element-property :type link)) + (when (and (or (equal "file" (org-element-property :type link)) + (equal "@" (org-element-property :type link))) (or include-linked (null (org-element-contents link))) (string-match-p file-extension-re (org-element-property :path link))) - (let ((file (expand-file-name - (org-link-unescape - (org-element-property :path link))))) + (let ((file (if (equal "@" (org-element-property :type link)) + (require 'org-attach) + (org-attach-expand + (org-link-unescape + (org-element-property :path link))) + (expand-file-name + (org-link-unescape + (org-element-property :path link)))))) (when (file-exists-p file) (let ((width ;; Apply `org-image-actual-width' specifications. -- 2.19.1.windows.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
[parent not found: <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com>]
* Re: [RFC] Link-type for attachments, more attach options [not found] ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com> @ 2018-11-19 23:52 ` Nicolas Goaziou 2018-11-25 21:13 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2018-11-19 23:52 UTC (permalink / raw) To: Gustav Wikström; +Cc: Org Mode List Hello, Gustav Wikström <gustav@whil.se> writes: > Yeah - I liked "attached" because I prefer clear keywords. But sure, > we can keep it shorter. I'd suggest "@" instead in that case. Patch > updated with that. "@" syntax is a reserved syntax for citations in the "wip-cite" branch. I'd rather not use it here. Also, years ago, "att" link type was used to link to attachments, hence my proposal. >> > When working with ATTACH_DIR there are now a couple of new options available: >> > - org-attach-dir-inherit-by-default >> >> What is the difference between this and >> `org-attach-allow-inheritance'? You didn't answer this question, did you? Something is fishy here anyways. Why is "ATTACH_DIR_INHERIT" needed at all? If `org-attach-allow-inheritance', "ATTACH_DIR" should be inherited. Why depend on another property? I'd rather not make these things more complex. >> > - org-attach-dir-create-if-not-exist >> >> What is the use-case for this one? It doesn't seem terribly useful at >> first glance. > > If you try to open attachments on a node where there is no ID or >> ATTACH_DIR, the default behavior is to add an ID and create a folder >> based on that ID. I would like Org-mode to not do that. This >> customization give the user the option to change that. Instead of >> providing this customization one could just change the default >> behavior of org-attach, since it's a bit offensive to create folders >> when I didn't ask for it. But instead of changing the default, >> I thought this way was more graceful. I wouldn't mind skipping this >> customization though, if the behavior was changed to what >> I implemented with org-attach-dir-create-if-not-exist set to nil. Considering attaching is about moving, or copying files somewhere, creating a folder doesn't sound terribly offensive. You don't even have to know the name of the folder. Do you suggest to raise an error if there is no folder available for the attached documents? If so, wouldn't it be better to ask the user first? >> > - org-attach-dir-relative >> >> I'm not sure to understand this one. > > When adding folders to nodes using option "s" in org-attach, the path > is absolute. This makes attachment-directory paths relative to > location of the file instead. OK. >> > +This list shows the full set of built-in external link types: >> > +| http | web | >> > +| https | secure web | >> > +| doi | DOI for electronic resources | >> > +| file | file-links | >> > +| file+sys | file-links forced to open via OS | >> > +| file+emacs | file-links forced to open via emacs | >> > +| attached | links to attachments for nodes | >> > +| docview | doc-view mode | >> > +| id | Link to heading by id | >> > +| news | Usenet link | >> > +| mailto | mail link | >> > +| mhe | MH-E folder link | >> > +| rmail | Rmail link | >> > +| gnus | Gnus link | >> > +| bbdb | BBDB link | >> > +| irc | IRC link | >> > +| info | Info link | >> > +| shell | shell command | >> > +| elisp | interactive elisp command link | >> > + >> > +The following list shows examples for each link type. >> > + >> > +| =http://www.astro.uva.nl/=dominik= | on the web | >> > +| =doi:10.1000/182= | DOI for an electronic resource | >> > +| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | >> > +| =/home/dominik/images/jupiter.jpg= | same as above | >> > +| =file:papers/last.pdf= | file, relative path | >> > +| =./papers/last.pdf= | same as above | >> > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | >> > +| =/ssh:me@some.where:papers/last.pdf= | same as above | >> > +| =file:sometextfile::NNN= | file, jump to line number | >> > +| =file:projects.org= | another Org file | >> > +| =file:projects.org::some words= | text search in Org file[fn:28] | >> > +| =file:projects.org::*task title= | heading search in Org file | >> > +| =file+sys:/path/to/file= | open via OS, like double-click | >> > +| =file+emacs:/path/to/file= | force opening by Emacs | >> > +| =attached:projects.org= | file in folder attached to headline | >> > +| =attached:projects.org::some words= | text search in attached file | >> > +| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | >> > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | >> > +| =news:comp.emacs= | Usenet link | >> > +| =mailto:adent@galaxy.net= | mail link | >> > +| =mhe:folder= | MH-E folder link | >> > +| =mhe:folder#id= | MH-E message link | >> > +| =rmail:folder= | Rmail folder link | >> > +| =rmail:folder#id= | Rmail message link | >> > +| =gnus:group= | Gnus group link | >> > +| =gnus:group#id= | Gnus article link | >> > +| =bbdb:R.*Stallman= | BBDB link (with regexp) | >> > +| =irc:/irc.com/#emacs/bob= | IRC link | >> > +| =info:org#External links= | Info node link | >> > +| =shell:ls *.org= | shell command | >> > +| =elisp:org-agenda= | interactive Elisp command | >> > +| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | >> >> I'm not sure to like the change above. It introduces a lot of >> redundancy. >> > > Currently the list in the documentation is just a bunch of examples. >> I've looked at it a couple of times asking myself "What is the >> complete list of built in link types?". This commit "fixes" that. >> I wouldn't say its redundant since all the rows in the second list >> are just examples. It is still redundant. For example, the first table has | info | Info link | whereas the second one tells us | info:org#External links | Info node link | In this case, | Info link | info:org#External links | would be sufficient enough. I have the feeling documentation can be improved here. Also, file+sys and file+emacs are deprecated. They can be removed. > I can't say I understand the use of :safe here. But added it anyways. > If you care, please explain why it's needed. Package-version is added. > I set it to 9.2. Correct? If :safe is not set, Emacs will warn every time the variable is set as a local file variable. It should be 9.3, not 9.2. >> > +(defun org-attach-open-link (link &optional in-emacs) >> > + "LINK is expanded with the attached directory and opened the same >> > +way as file-links are." >> >> You need to expound the arguments in the docstring. > > Sorry, I don't understand what I'm supposed to do here... I changed > the comment to (maybe?) make it read better. Other than that, I'm at > a loss. Every argument needs to be documented in the docstring. What is LINK type? What is IN-EMACS? >> > + (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)" >> > (if (not link-abbrevs) "" >> > (format "\\|\\(?:%s:\\)" >> > (regexp-opt link-abbrevs)))))) >> >> Why is it needed? "attached" link type is already registered, so you >> don't need to also hard-code it here. > > This is when parsing the buffer for images. I couldn't get org-mode to > display images without this. This is still a hack, and clearly not the way to go, IMO. If not already possible, we could add a new parameter in `org-link-parameters' or some such. This is another issue, tho. > +(defcustom org-attach-dir-create-if-not-exists t > + "Choose whether ATTACH_DIR-directories should be created if they do > not exist since before. Too long. Maybe: When non-nil, ATTACH_DIR is created automatically if it doesn't exist. Otherwise, ... > +Default is to create them." > + :group 'org-attach > + :type 'boolean > + :package-version '(Org . "9.2") > + :safe #'booleanp) > + > +(defcustom org-attach-dir-relative nil > + "Choose whether ATTACH_DIR-directories should be added as relative links or not. Too long. Maybe something like: Non-nil means ATTACH_DIR is relative to the attachment node directory. > +Defaults to not relative." Defaults to absolute location. > + (let ((old (org-attach-dir nil)) > + (new > + (progn > + (if arg (org-entry-delete nil "ATTACH_DIR") > + (let* ((attach-dir (read-directory-name > + "Attachment directory: " > + (org-entry-get nil > + "ATTACH_DIR"))) > + (current-dir (file-name-directory (or default-directory > + buffer-file-name))) > + (attach-dir-relative (file-relative-name attach-dir current-dir))) > + (if org-attach-dir-relative > + (org-entry-put nil "ATTACH_DIR" attach-dir-relative) > + (org-entry-put nil "ATTACH_DIR" attach-dir)))) (org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative attach-dir-relative attach-dir)) > +(defun org-attach-open-link (link &optional in-emacs) > + "Attach link type LINK is expanded with the attached directory and opened. > +This is done in the same way as file-links are opened." > + (interactive "P") > + (let (line search) > + (if (string-match "::\\([0-9]+\\)\\'" link) > + (setq line (string-to-number (match-string 1 link)) > + link (substring link 0 (match-beginning 0))) > + (if (string-match "::\\(.+\\)\\'" link) > + (setq search (match-string 1 link) > + link (substring link 0 (match-beginning 0))))) Use `cond' instead. > + (if (string-match "[*?{]" (file-name-nondirectory link)) > + (dired (org-attach-expand link)) > + (org-open-file (org-attach-expand link) in-emacs line search)))) > + > +(defun org-attach-complete-link () > + "Advise the user with the available files in the attachment directory." > + (let (file link attached-dir) > + (setq attached-dir (expand-file-name (org-attach-dir))) > + (setq file (read-file-name "File: " attached-dir)) > + (let ((pwd (file-name-as-directory attached-dir)) > + (pwd1 (file-name-as-directory (abbreviate-file-name > + attached-dir)))) > + (cond > + ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file) > + (setq link (concat "@:" (match-string 1 file)))) > + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") > + (expand-file-name file)) > + (setq link (concat > + "@:" (match-string 1 (expand-file-name file))))) > + (t (setq link (concat "@:" file))))) > + link)) I suggest: (let* ((attached-dir (expand-file-name (org-attach-dir))) (file (read-file-name "File: " attached-dir)) (pwd (file-name-as-directory attached-dir)) (pwd-relative (file-name-as-directory (abbreviate-file-name attached-dir)))) (cond ((string-match ...) (concat ...)) ... (t (concat ...)))) > +(defun org-attach-export-link (link description format) > + "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT. > +Also includes the DESCRIPTION of the link in the export." > + (save-excursion > + (let (path desc) > + (if (string-match "::\\([0-9]+\\)\\'" link) > + (setq link (substring link 0 (match-beginning 0))) > + (if (string-match "::\\(.+\\)\\'" link) > + (setq link (substring link 0 (match-beginning 0))))) Use `cond' instead. > + (search-forward (concat "@:" (org-link-escape link))) What is the use for the line above? > diff --git a/lisp/org.el b/lisp/org.el > index eb1affbc7..9ed663bb9 100644 > --- a/lisp/org.el > +++ b/lisp/org.el > @@ -4428,6 +4428,7 @@ This is needed for font-lock setup.") > (beg end)) > (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) > (declare-function org-agenda-skip "org-agenda" ()) > +(declare-function org-attach-expand "org-attach" (&optional if-exists)) > (declare-function org-attach-reveal "org-attach" (&optional if-exists)) > (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) > (declare-function org-indent-mode "org-indent" (&optional arg)) > @@ -18721,7 +18722,7 @@ boundaries." > ;; Check absolute, relative file names and explicit > ;; "file:" links. Also check link abbreviations since > ;; some might expand to "file" links. > - (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)" > + (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)" > (if (not link-abbrevs) "" > (format "\\|\\(?:%s:\\)" > (regexp-opt link-abbrevs)))))) > @@ -18730,14 +18731,20 @@ boundaries." > ;; Check if we're at an inline image, i.e., an image file > ;; link without a description (unless INCLUDE-LINKED is > ;; non-nil). > - (when (and (equal "file" (org-element-property :type link)) > + (when (and (or (equal "file" (org-element-property :type link)) > + (equal "@" (org-element-property :type link))) > (or include-linked > (null (org-element-contents link))) > (string-match-p file-extension-re > (org-element-property :path link))) > - (let ((file (expand-file-name > - (org-link-unescape > - (org-element-property :path link))))) > + (let ((file (if (equal "@" (org-element-property :type link)) > + (require 'org-attach) > + (org-attach-expand > + (org-link-unescape > + (org-element-property :path link))) > + (expand-file-name > + (org-link-unescape > + (org-element-property :path link)))))) > (when (file-exists-p file) > (let ((width > ;; Apply `org-image-actual-width' specifications. This part can be omitted for now. Something better has to be found. Thank you. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2018-11-19 23:52 ` Nicolas Goaziou @ 2018-11-25 21:13 ` Gustav Wikström 2018-11-27 9:39 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2018-11-25 21:13 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 18838 bytes --] Hi again, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 20 november 2018 00:52 > To: Gustav Wikström <gustav@whil.se> > Cc: Org Mode List <emacs-orgmode@gnu.org> > Subject: Re: [RFC] Link-type for attachments, more attach options > > > Yeah - I liked "attached" because I prefer clear keywords. But sure, > > we can keep it shorter. I'd suggest "@" instead in that case. Patch > > updated with that. > > "@" syntax is a reserved syntax for citations in the "wip-cite" branch. > I'd rather not use it here. Also, years ago, "att" link type was used to > link to attachments, hence my proposal. Too bad, "@" was growing on me. @ is currently automatically set as a tag when attaching files to nodes. So it was fitting to use it also in links in my opinion. Is the cite-syntax the same as the regular link-pattern? [[@: ...]] ? Otherwise I'd suggest them to coexist. Or to change the cite-symbol to ... "c" maybe? @ is a pretty standard symbol for attachments. Just have a look at Gmail, Outlook etc. I didn't change this in the attached patch. I'm hoping for second thoughts! :) The future ease of use (i.e. clarity and standardization of symbols in this case) should have precedence over current work in progress... > >> > When working with ATTACH_DIR there are now a couple of new options available: > >> > - org-attach-dir-inherit-by-default > >> > >> What is the difference between this and > >> `org-attach-allow-inheritance'? > > You didn't answer this question, did you? No, seems I missed it. > Something is fishy here anyways. Why is "ATTACH_DIR_INHERIT" needed at > all? If `org-attach-allow-inheritance', "ATTACH_DIR" should be > inherited. Why depend on another property? Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not sure of what way to go forward though. I can see at least two paths: 1) Rename `org-attach-allow-inheritance' to `org-attach-enable-inheritance' and always make attachments inherited when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd also change the precedence-logic between ATTACH_DIR & ID properties and make ID-based attachment inherit as well. The properties ATTACH_DIR and ID should be inherited from the closest node when resolving attachments, with ATTACH_DIR having precedence over ID if both exist for the same node. 2) remove `org-attach-allow-inheritance' and only rely on the "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if the "ATTACH_DIR" property should be inherited. This would be a smaller change from the user's perspective, where we're basically saying you cannot disable inheritance, but it's only active when a node has the ATTACH_DIR_INHERIT-property. I prefer path (1). That would be a great default. But that change is bigger and should be separated from this patch anyways. To not increase the complexity I've removed the `org-attach-dir-inherit-by-default' customization. > >> > - org-attach-dir-create-if-not-exist > >> > >> What is the use-case for this one? It doesn't seem terribly useful at > >> first glance. > > > > If you try to open attachments on a node where there is no ID or > >> ATTACH_DIR, the default behavior is to add an ID and create a folder > >> based on that ID. I would like Org-mode to not do that. This > >> customization give the user the option to change that. Instead of > >> providing this customization one could just change the default > >> behavior of org-attach, since it's a bit offensive to create folders > >> when I didn't ask for it. But instead of changing the default, > >> I thought this way was more graceful. I wouldn't mind skipping this > >> customization though, if the behavior was changed to what > >> I implemented with org-attach-dir-create-if-not-exist set to nil. > > Considering attaching is about moving, or copying files somewhere, > creating a folder doesn't sound terribly offensive. You don't even have > to know the name of the folder. > > Do you suggest to raise an error if there is no folder available for the > attached documents? If so, wouldn't it be better to ask the user first? Agreed, the parameter can be removed and a "do you want to create a folder?" question could be raised instead, when it's not intuitive for the program to create the folder by itself. > >> > +This list shows the full set of built-in external link types: > >> > +| http | web | > >> > +| https | secure web | > >> > +| doi | DOI for electronic resources | > >> > +| file | file-links | > >> > +| file+sys | file-links forced to open via OS | > >> > +| file+emacs | file-links forced to open via emacs | > >> > +| attached | links to attachments for nodes | > >> > +| docview | doc-view mode | > >> > +| id | Link to heading by id | > >> > +| news | Usenet link | > >> > +| mailto | mail link | > >> > +| mhe | MH-E folder link | > >> > +| rmail | Rmail link | > >> > +| gnus | Gnus link | > >> > +| bbdb | BBDB link | > >> > +| irc | IRC link | > >> > +| info | Info link | > >> > +| shell | shell command | > >> > +| elisp | interactive elisp command link | > >> > + > >> > +The following list shows examples for each link type. > >> > + > >> > +| =http://www.astro.uva.nl/=dominik= | on the web | > >> > +| =doi:10.1000/182= | DOI for an electronic resource | > >> > +| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | > >> > +| =/home/dominik/images/jupiter.jpg= | same as above | > >> > +| =file:papers/last.pdf= | file, relative path | > >> > +| =./papers/last.pdf= | same as above | > >> > +| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | > >> > +| =/ssh:me@some.where:papers/last.pdf= | same as above | > >> > +| =file:sometextfile::NNN= | file, jump to line number | > >> > +| =file:projects.org= | another Org file | > >> > +| =file:projects.org::some words= | text search in Org file[fn:28] | > >> > +| =file:projects.org::*task title= | heading search in Org file | > >> > +| =file+sys:/path/to/file= | open via OS, like double-click | > >> > +| =file+emacs:/path/to/file= | force opening by Emacs | > >> > +| =attached:projects.org= | file in folder attached to headline | > >> > +| =attached:projects.org::some words= | text search in attached file | > >> > +| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | > >> > +| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | > >> > +| =news:comp.emacs= | Usenet link | > >> > +| =mailto:adent@galaxy.net= | mail link | > >> > +| =mhe:folder= | MH-E folder link | > >> > +| =mhe:folder#id= | MH-E message link | > >> > +| =rmail:folder= | Rmail folder link | > >> > +| =rmail:folder#id= | Rmail message link | > >> > +| =gnus:group= | Gnus group link | > >> > +| =gnus:group#id= | Gnus article link | > >> > +| =bbdb:R.*Stallman= | BBDB link (with regexp) | > >> > +| =irc:/irc.com/#emacs/bob= | IRC link | > >> > +| =info:org#External links= | Info node link | > >> > +| =shell:ls *.org= | shell command | > >> > +| =elisp:org-agenda= | interactive Elisp command | > >> > +| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | > >> > >> I'm not sure to like the change above. It introduces a lot of > >> redundancy. > >> > > > > Currently the list in the documentation is just a bunch of examples. > >> I've looked at it a couple of times asking myself "What is the > >> complete list of built in link types?". This commit "fixes" that. > >> I wouldn't say its redundant since all the rows in the second list > >> are just examples. > > It is still redundant. For example, the first table has > > | info | Info link | > > whereas the second one tells us > > | info:org#External links | Info node link | > > In this case, > > | Info link | info:org#External links | > > would be sufficient enough. I have the feeling documentation can be > improved here. The problem I had with the second list is that it's just a list of examples. Nowhere does it say it's the complete list of commands. Anyways, I've tried to merge the two lists. Hope you'll find it more to your liking. > > Also, file+sys and file+emacs are deprecated. They can be removed. Ok, removed. > > > I can't say I understand the use of :safe here. But added it anyways. > > If you care, please explain why it's needed. Package-version is added. > > I set it to 9.2. Correct? > > If :safe is not set, Emacs will warn every time the variable is set as > a local file variable. Ok > > It should be 9.3, not 9.2. Ok, fixed > > >> > +(defun org-attach-open-link (link &optional in-emacs) > >> > + "LINK is expanded with the attached directory and opened the same > >> > +way as file-links are." > >> > >> You need to expound the arguments in the docstring. > > > > Sorry, I don't understand what I'm supposed to do here... I changed > > the comment to (maybe?) make it read better. Other than that, I'm at > > a loss. > > Every argument needs to be documented in the docstring. What is LINK > type? What is IN-EMACS? Ok, got it. > > >> > + (file-types-re (format "[][]\\[\\(?:file\\|attached\\|[./~]%s\\)" > >> > (if (not link-abbrevs) "" > >> > (format "\\|\\(?:%s:\\)" > >> > (regexp-opt link-abbrevs)))))) > >> > >> Why is it needed? "attached" link type is already registered, so you > >> don't need to also hard-code it here. > > > > This is when parsing the buffer for images. I couldn't get org-mode to > > display images without this. > > This is still a hack, and clearly not the way to go, IMO. If not already > possible, we could add a new parameter in `org-link-parameters' or some > such. This is another issue, tho. Ok, sure. Although to be fair it's an existing hack, which was expanded just a tiny bit. Removed anyways. > > > +(defcustom org-attach-dir-create-if-not-exists t > > + "Choose whether ATTACH_DIR-directories should be created if they do > > not exist since before. > > Too long. Maybe: > > When non-nil, ATTACH_DIR is created automatically if it doesn't exist. > Otherwise, ... > > > +Default is to create them." > > + :group 'org-attach > > + :type 'boolean > > + :package-version '(Org . "9.2") > > + :safe #'booleanp) > > + > > +(defcustom org-attach-dir-relative nil > > + "Choose whether ATTACH_DIR-directories should be added as relative links or not. > > Too long. Maybe something like: > > Non-nil means ATTACH_DIR is relative to the attachment node directory. > > > +Defaults to not relative." > > Defaults to absolute location. Yeah, that's better. Fixed. > > > + (let ((old (org-attach-dir nil)) > > + (new > > + (progn > > + (if arg (org-entry-delete nil "ATTACH_DIR") > > + (let* ((attach-dir (read-directory-name > > + "Attachment directory: " > > + (org-entry-get nil > > + "ATTACH_DIR"))) > > + (current-dir (file-name-directory (or default-directory > > + buffer-file-name))) > > + (attach-dir-relative (file-relative-name attach-dir current-dir))) > > + (if org-attach-dir-relative > > + (org-entry-put nil "ATTACH_DIR" attach-dir-relative) > > + (org-entry-put nil "ATTACH_DIR" attach-dir)))) > > (org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative > attach-dir-relative > attach-dir)) Yeah, that's nicer. Changed. > > > +(defun org-attach-open-link (link &optional in-emacs) > > + "Attach link type LINK is expanded with the attached directory and opened. > > +This is done in the same way as file-links are opened." > > + (interactive "P") > > + (let (line search) > > + (if (string-match "::\\([0-9]+\\)\\'" link) > > + (setq line (string-to-number (match-string 1 link)) > > + link (substring link 0 (match-beginning 0))) > > + (if (string-match "::\\(.+\\)\\'" link) > > + (setq search (match-string 1 link) > > + link (substring link 0 (match-beginning 0))))) > > Use `cond' instead. Ok. > > > + (if (string-match "[*?{]" (file-name-nondirectory link)) > > + (dired (org-attach-expand link)) > > + (org-open-file (org-attach-expand link) in-emacs line search)))) > > + > > +(defun org-attach-complete-link () > > + "Advise the user with the available files in the attachment directory." > > + (let (file link attached-dir) > > + (setq attached-dir (expand-file-name (org-attach-dir))) > > + (setq file (read-file-name "File: " attached-dir)) > > + (let ((pwd (file-name-as-directory attached-dir)) > > + (pwd1 (file-name-as-directory (abbreviate-file-name > > + attached-dir)))) > > + (cond > > + ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file) > > + (setq link (concat "@:" (match-string 1 file)))) > > + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") > > + (expand-file-name file)) > > + (setq link (concat > > + "@:" (match-string 1 (expand-file-name file))))) > > + (t (setq link (concat "@:" file))))) > > + link)) > > I suggest: > > (let* ((attached-dir (expand-file-name (org-attach-dir))) > (file (read-file-name "File: " attached-dir)) > (pwd (file-name-as-directory attached-dir)) > (pwd-relative (file-name-as-directory > (abbreviate-file-name attached-dir)))) > (cond > ((string-match ...) > (concat ...)) > ... > (t (concat ...)))) Yeah, clearly an improvement. > > > +(defun org-attach-export-link (link description format) > > + "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT. > > +Also includes the DESCRIPTION of the link in the export." > > + (save-excursion > > + (let (path desc) > > + (if (string-match "::\\([0-9]+\\)\\'" link) > > + (setq link (substring link 0 (match-beginning 0))) > > + (if (string-match "::\\(.+\\)\\'" link) > > + (setq link (substring link 0 (match-beginning 0))))) > > Use `cond' instead. Ok. > > > + (search-forward (concat "@:" (org-link-escape link))) > > What is the use for the line above? Hmm, good question. Looking through my commit history I find no reason to justify it... I wonder how that got there. Effectively, I guess that row does nothing except stealing a few CPU-cycles... Removed. > > diff --git a/lisp/org.el b/lisp/org.el > > index eb1affbc7..9ed663bb9 100644 > > --- a/lisp/org.el > > +++ b/lisp/org.el > > @@ -4428,6 +4428,7 @@ This is needed for font-lock setup.") > > (beg end)) > > (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) > > (declare-function org-agenda-skip "org-agenda" ()) > > +(declare-function org-attach-expand "org-attach" (&optional if-exists)) > > (declare-function org-attach-reveal "org-attach" (&optional if-exists)) > > (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) > > (declare-function org-indent-mode "org-indent" (&optional arg)) > > @@ -18721,7 +18722,7 @@ boundaries." > > ;; Check absolute, relative file names and explicit > > ;; "file:" links. Also check link abbreviations since > > ;; some might expand to "file" links. > > - (file-types-re (format "[][]\\[\\(?:file\\|[./~]%s\\)" > > + (file-types-re (format "[][]\\[\\(?:file\\|@\\|[./~]%s\\)" > > (if (not link-abbrevs) "" > > (format "\\|\\(?:%s:\\)" > > (regexp-opt link-abbrevs)))))) > > @@ -18730,14 +18731,20 @@ boundaries." > > ;; Check if we're at an inline image, i.e., an image file > > ;; link without a description (unless INCLUDE-LINKED is > > ;; non-nil). > > - (when (and (equal "file" (org-element-property :type link)) > > + (when (and (or (equal "file" (org-element-property :type link)) > > + (equal "@" (org-element-property :type link))) > > (or include-linked > > (null (org-element-contents link))) > > (string-match-p file-extension-re > > (org-element-property :path link))) > > - (let ((file (expand-file-name > > - (org-link-unescape > > - (org-element-property :path link))))) > > + (let ((file (if (equal "@" (org-element-property :type link)) > > + (require 'org-attach) > > + (org-attach-expand > > + (org-link-unescape > > + (org-element-property :path link))) > > + (expand-file-name > > + (org-link-unescape > > + (org-element-property :path link)))))) > > (when (file-exists-p file) > > (let ((width > > ;; Apply `org-image-actual-width' specifications. > > This part can be omitted for now. Something better has to be found. Ok, sure. I'll keep it on my local branch but it's omitted from the patch. > > Thank you. > > Regards, > > -- > Nicolas Goaziou New patch attached updated according to the comments. Regards, Gustav [-- Attachment #2: 0001-org-attach-org-manual-org-New-link-type-new-option.patch --] [-- Type: application/octet-stream, Size: 20080 bytes --] From 88e23fd0d7bf8321dc5ea8e396a97500b1035b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav.erik@gmail.com> Date: Sun, 25 Nov 2018 21:38:44 +0100 Subject: [PATCH] org-attach, org-manual, org: New link-type, new option * Add new linktype "@" for attachments A new linktype "@" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID-based attachments and ATTACH_DIR. The goal is to make the functionality for attached-links mirror file-links. * Add further options for ATTACH_DIR When working with ATTACH_DIR there are now a new option available: - org-attach-dir-relative With that option set to t ATTACH_DIR is stored as relative to the file-location. * Documentation in org-manual Org-manual is updated with the new link-type as well as some minor cleanup in the documentation related to external links and attachments. --- doc/org-manual.org | 114 ++++++++++++++++++++----------------- lisp/org-attach.el | 137 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 172 insertions(+), 79 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 5e4effb6f..0b626a1a8 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3141,6 +3141,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: @ links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3152,38 +3153,43 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. - -| =http://www.astro.uva.nl/=dominik= | on the web | -| =doi:10.1000/182= | DOI for an electronic resource | -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | -| =/home/dominik/images/jupiter.jpg= | same as above | -| =file:papers/last.pdf= | file, relative path | -| =./papers/last.pdf= | same as above | -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | -| =/ssh:me@some.where:papers/last.pdf= | same as above | -| =file:sometextfile::NNN= | file, jump to line number | -| =file:projects.org= | another Org file | -| =file:projects.org::some words= | text search in Org file[fn:28] | -| =file:projects.org::*task title= | heading search in Org file | -| =file+sys:/path/to/file= | open via OS, like double-click | -| =file+emacs:/path/to/file= | force opening by Emacs | -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | -| =news:comp.emacs= | Usenet link | -| =mailto:adent@galaxy.net= | mail link | -| =mhe:folder= | MH-E folder link | -| =mhe:folder#id= | MH-E message link | -| =rmail:folder= | Rmail folder link | -| =rmail:folder#id= | Rmail message link | -| =gnus:group= | Gnus group link | -| =gnus:group#id= | Gnus article link | -| =bbdb:R.*Stallman= | BBDB link (with regexp) | -| =irc:/irc.com/#emacs/bob= | IRC link | -| =info:org#External links= | Info node link | -| =shell:ls *.org= | shell command | -| =elisp:org-agenda= | interactive Elisp command | -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | +the colon. + +This list shows the full set of built-in external link types, +including examples for each: + +| Link Type | Description | Example | +|-----------+------------------------------+-------------------------------------------------------| +| http | web | =http://www.astro.uva.nl/=dominik= | +| https | secure web | =https://orgmode.org/= | +| doi | DOI for electronic resources | =doi:10.1000/182= | +| file | file-links | =file:/home/dominik/images/jupiter.jpg= | +| | | =/home/dominik/images/jupiter.jpg= (same as above) | +| | | =file:papers/last.pdf= | +| | | =./papers/last.pdf= (same as above) | +| | | =file:/ssh:me@some.where:papers/last.pdf= (remote) | +| | | =/ssh:me@some.where:papers/last.pdf= (same as above) | +| | | =file:sometextfile::NNN= (jump to line number) | +| | | =file:projects.org= | +| | | =file:projects.org::some words= (text search) [fn:28] | +| | | =file:projects.org::*task title= (headline search) | +| @ | links to attachments | =@:projects.org= | +| | | =@:projects.org::some words= (text search) | +| docview | doc-view mode | =docview:papers/last.pdf::NNN= | +| id | Link to heading by id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | +| news | Usenet link | =news:comp.emacs= | +| mailto | mail link | =mailto:adent@galaxy.net= | +| mhe | MH-E folder link | =mhe:folder= (folder link) | +| | | =mhe:folder#id= (message link) | +| rmail | Rmail link | =rmail:folder= (folder link) | +| | | =rmail:folder#id= (message link) | +| gnus | Gnus link | =gnus:group= (group link) | +| | | =gnus:group#id= (article link) | +| bbdb | BBDB link | =bbdb:R.*Stallman= (link with regexp) | +| irc | IRC link | =irc:/irc.com/#emacs/bob= | +| info | Info link | =info:org#External links= | +| shell | shell command | =shell:ls *.org= | +| elisp | interactive elisp command | =elisp:(find-file "Elisp.org")= | #+cindex: VM links #+cindex: Wanderlust links @@ -3538,14 +3544,15 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: @ links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:35]. For -example, when the command ~org-store-link~ creates a link (see -[[*Handling Links]]) to a file, it encodes the words in the current line -as a search string that can be used to find this line back later when -following the link with {{{kbd(C-c C-o)}}}. +File links and attached (@) links can contain additional information +to make Emacs jump to a particular location in the file when following +a link. This can be a line number or a search option after a double +colon[fn:35]. For example, when the command ~org-store-link~ creates +a link (see [[*Handling Links]]) to a file, it encodes the words in the +current line as a search string that can be used to find this line +back later when following the link with {{{kbd(C-c C-o)}}}. Here is the syntax of the different ways to attach a search to a file link, together with explanations for each: @@ -3556,6 +3563,7 @@ link, together with explanations for each: [[file:~/xx.org::*My Target]] [[file:~/xx.org::#my-custom-id]] [[file:~/xx.org::/regexp/]] +[[@:~/code/main.c::255]] #+end_example - =255= :: @@ -7533,18 +7541,22 @@ node/task. Small chunks of plain text can simply be stored in the subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations with files that live elsewhere on your computer or in the cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -~data~ directory which lives in the same directory where your Org file -lives[fn:86]. If you initialize this directory with =git init=, Org -automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by the unique ID of each entry, or by the =ATTACH_DIR= property. +ID-based directories are by default located in the =data/= directory, +which lives in the same directory where your Org file lives[fn:86]. +If you initialize this directory with =git init=, Org automatically +commits changes when it sees them. The attachment system has been +contributed to Org by John Wiegley. + +In cases where =ATTACH_DIR= property is used to declare attachments, +you can choose to either use absolute (default) or relative links. +You can also make children inherit the attachment directory from a +parent, so that an entire subtree uses the same attached directory. + +See customization group =Org Attach= if you want to change the default +settings for attachments. The following commands deal with attachments: diff --git a/lisp/org-attach.el b/lisp/org-attach.el index e827d3721..4054a8044 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -57,6 +57,14 @@ where the Org file lives." :type 'directory :safe #'stringp) +(defcustom org-attach-dir-relative nil + "Choose whether ATTACH_DIR-directories should be added as relative links or not. +Defaults to absolute location." + :group 'org-attach + :type 'boolean + :package-version '(Org . "9.3") + :safe #'booleanp) + (defcustom org-attach-commit t "If non-nil commit attachments with git. This is only done if the Org file is in a git repository." @@ -224,14 +232,18 @@ i Make children of the current entry inherit its attachment directory."))) 'org-attach-set-inherit)) (t (error "No such attachment command %c" c)))))) -(defun org-attach-dir (&optional create-if-not-exists-p) +(defun org-attach-dir (&optional create-if-not-exists-p verify-create-p) "Return the directory associated with the current entry. This first checks for a local property ATTACH_DIR, and then for an inherited property ATTACH_DIR_INHERIT. If neither exists, the default mechanism using the entry ID will be invoked to access the unique directory for the current entry. + If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, -the directory and (if necessary) the corresponding ID will be created." +the directory and (if necessary) the corresponding ID will be created. + +If VERIFY-CREATE is non-nil, ask for verification from the user +before directory is created." (let (attach-dir uuid) (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) (cond @@ -245,7 +257,7 @@ the directory and (if necessary) the corresponding ID will be created." (goto-char org-entry-property-inherited-from) (org-back-to-heading t)) (let (org-attach-allow-inheritance) - (org-attach-dir create-if-not-exists-p)))) + (org-attach-dir create-if-not-exists-p verify-create-p)))) (org-attach-check-absolute-path attach-dir) (setq org-attach-inherited t)) (t ; use the ID @@ -260,7 +272,10 @@ the directory and (if necessary) the corresponding ID will be created." (expand-file-name org-attach-directory)))))) (when attach-dir (if (and create-if-not-exists-p - (not (file-directory-p attach-dir))) + (not (file-directory-p attach-dir)) + (if verify-create-p + (yes-or-no-p "Create attachment directory?") + t)) (make-directory attach-dir t)) (and (file-exists-p attach-dir) attach-dir)))) @@ -280,20 +295,24 @@ Throw an error if we cannot root the directory." "Set the ATTACH_DIR node property and ask to move files there. The property defines the directory that is used for attachments of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." +the directory to the default ID based one. Creates relative +links if ORG-ATTACH-DIR-RELATIVE is t." (interactive "P") (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (new + (progn + (if arg (org-entry-delete nil "ATTACH_DIR") + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil + "ATTACH_DIR"))) + (current-dir (file-name-directory (or default-directory + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (org-entry-put nil "ATTACH_DIR" (if org-attach-dir-relative + attach-dir-relative + attach-dir)))) + (org-attach-dir t)))) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") @@ -527,14 +546,14 @@ This ignores files ending in \"~\"." "Show the attachment directory of the current task. This will attempt to use an external program to show the directory." (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) + (let ((attach-dir (org-attach-dir (not if-exists) t))) (and attach-dir (org-open-file attach-dir)))) (defun org-attach-reveal-in-emacs () "Show the attachment directory of the current task in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir t t))) + (when attach-dir (dired attach-dir)))) (defun org-attach-open (&optional in-emacs) "Open an attachment of the current task. @@ -543,15 +562,17 @@ This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir t t))) + (if attach-dir + (let* ((files (org-attach-file-list attach-dir)) + (file (if (= (length files) 1) + (car files) + (completing-read "Open attachment: " + (mapcar #'list files) nil t))) + (path (expand-file-name file attach-dir))) + (org-attach-annex-get-maybe path) + (org-open-file path in-emacs)) + (message "No attachment exist!")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -570,6 +591,66 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(defun org-attach-open-link (link &optional in-emacs) + "Attach link type LINK is expanded with the attached directory and opened. + +With optional prefix argument IN-EMACS, Emacs will visit the file. +With a double \\[universal-argument] \\[universal-argument] \ +prefix arg, Org tries to avoid opening in Emacs +and to use an external application to visit the file." + (interactive "P") + (let (line search) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment directory." + (let* ((attached-dir (expand-file-name (org-attach-dir))) + (file (read-file-name "File: " attached-dir)) + (pwd (file-name-as-directory attached-dir)) + (pwd-relative (file-name-as-directory + (abbreviate-file-name attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file) + (concat "@:" (match-string 1 file))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (concat "@:" (match-string 1 (expand-file-name file)))) + (t (concat "@:" file))))) + +(defun org-attach-export-link (link description format) + "Translate \"attached\" (@) LINK from Org mode format to exported FORMAT. +Also includes the DESCRIPTION of the link in the export." + (save-excursion + (let (path desc) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + +(org-link-set-parameters "@" + :follow 'org-attach-open-link + :export 'org-attach-export-link + :complete 'org-attach-complete-link) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option -- 2.19.1.windows.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2018-11-25 21:13 ` Gustav Wikström @ 2018-11-27 9:39 ` Nicolas Goaziou 2019-05-26 23:05 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2018-11-27 9:39 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode Hello, Gustav Wikström <gustav@whil.se> writes: > Too bad, "@" was growing on me. @ is currently automatically set as > a tag when attaching files to nodes. You probably customized `org-attach-auto-tag' because this is not the default behaviour. It adds "ATTACH" tag automatically. > So it was fitting to use it also > in links in my opinion. Is the cite-syntax the same as the regular > link-pattern? [[@: ...]] ? It could be [@...], which is close enough to be confusing. Moreover, all default link types currently use alphabetic characters. Using a symbol here would be weird. > Otherwise I'd suggest them to coexist. Or > to change the cite-symbol to ... "c" maybe? "@" is used for the citation key. Using a letter could interfere with the key itself: @key vs. ckey. > @ is a pretty standard symbol for attachments. Just have a look at > Gmail, Outlook etc. I prefer not to consider Gmail and Outlook as references, or even standards. As another data point, Gnus uses "Attachment: " to list attachments. > I didn't change this in the attached patch. I'm hoping for second > thoughts! :) The future ease of use (i.e. clarity and standardization > of symbols in this case) should have precedence over current work in > progress... The citation syntax was discussed, and implemented, years ago. Also, some external libraries apparently rely on it. I still vote for "att", or "attachment". > Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not sure of what way to go forward though. I can see at least two paths: > > 1) Rename `org-attach-allow-inheritance' to > `org-attach-enable-inheritance' and always make attachments inherited > when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd > also change the precedence-logic between ATTACH_DIR & ID properties > and make ID-based attachment inherit as well. The properties > ATTACH_DIR and ID should be inherited from the closest node when > resolving attachments, with ATTACH_DIR having precedence over ID if > both exist for the same node. Why defining `org-attach-enable-inheritance' at all? There is already `org-use-property-inheritance' for this. We do not need another conflicting variable. I don't think we should inherit ID properties either. ID is defined outside "org-attach.el", so this library shouldn't mess with its meaning. Does inheriting ID properties give anything valuable? > 2) remove `org-attach-allow-inheritance' and only rely on the > "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if > the "ATTACH_DIR" property should be inherited. This would be a smaller > change from the user's perspective, where we're basically saying you > cannot disable inheritance, but it's only active when a node has the > ATTACH_DIR_INHERIT-property. > > I prefer path (1). So do I, with the remarks above. > +This list shows the full set of built-in external link types, > +including examples for each: > + > +| Link Type | Description | Example | > +|-----------+------------------------------+-------------------------------------------------------| > +| http | web | =http://www.astro.uva.nl/=dominik= | > +| https | secure web | =https://orgmode.org/= | > +| doi | DOI for electronic resources | =doi:10.1000/182= | > +| file | file-links | =file:/home/dominik/images/jupiter.jpg= | > +| | | =/home/dominik/images/jupiter.jpg= (same as above) | > +| | | =file:papers/last.pdf= | > +| | | =./papers/last.pdf= (same as above) | > +| | | =file:/ssh:me@some.where:papers/last.pdf= (remote) | > +| | | =/ssh:me@some.where:papers/last.pdf= (same as above) | > +| | | =file:sometextfile::NNN= (jump to line number) | > +| | | =file:projects.org= | > +| | | =file:projects.org::some words= (text search) [fn:28] | > +| | | =file:projects.org::*task title= (headline search) | > +| @ | links to attachments | =@:projects.org= | > +| | | =@:projects.org::some words= (text search) | > +| docview | doc-view mode | =docview:papers/last.pdf::NNN= | > +| id | Link to heading by id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | > +| news | Usenet link | =news:comp.emacs= | > +| mailto | mail link | =mailto:adent@galaxy.net= | > +| mhe | MH-E folder link | =mhe:folder= (folder link) | > +| | | =mhe:folder#id= (message link) | > +| rmail | Rmail link | =rmail:folder= (folder link) | > +| | | =rmail:folder#id= (message link) | > +| gnus | Gnus link | =gnus:group= (group link) | > +| | | =gnus:group#id= (article link) | > +| bbdb | BBDB link | =bbdb:R.*Stallman= (link with regexp) | > +| irc | IRC link | =irc:/irc.com/#emacs/bob= | > +| info | Info link | =info:org#External links= | > +| shell | shell command | =shell:ls *.org= | > +| elisp | interactive elisp command | =elisp:(find-file "Elisp.org")= | The second column still doesn't bring much information compared to the first one. Getting back to your first idea, we may try to do something like the following: --8<---------------cut here---------------start------------->8--- Here is the full set of built-in link types. - =file= :: File links. File name may be remote, absolute, or relative. Additionally, you can specify a line number, or a text search. In Org files, you may link to a headline name, a custom ID, or a code reference instead. As a special case, "file" prefix may be omitted if the file name is complete, e.g., it starts with =./=, or =/=. - =att= :: Same as file links, but for attached documents to the current node (see [[*Attachments]]). - =bbdb= :: Link to a BBDB record, with possible regexp completion. - =docview= :: Link to a document opened with DocView mode. You may specify a page number. - =doi= :: Link to an electronic ressource, through its handle. - =elisp= :: Execute an Elisp command upon activation. - =gnus=, =rmail=, =mhe= :: Links to messages or folders from a given Emacs' MUA. - =http=, =https= :: Web links. - =id= :: Link to a specific headline by its ID property, in an Org file. - =info= :: Link to an Info manual, or to a specific node. - =irc= :: Link to an IRC channel. - =mailto= :: Link to message composition. - =news= :: Usenet links. - =shell= :: Execute a shell command upon activation. The following table illustrates the link types above, along with their options: | Link Type | Example | |-----------+-------------------------------------------------------| | http | =http://www.astro.uva.nl/=dominik= | | https | =https://orgmode.org/= | | doi | =doi:10.1000/182= | | file | =file:/home/dominik/images/jupiter.jpg= | | | =/home/dominik/images/jupiter.jpg= (same as above) | | | =file:papers/last.pdf= | | | =./papers/last.pdf= (same as above) | | | =file:/ssh:me@some.where:papers/last.pdf= (remote) | | | =/ssh:me@some.where:papers/last.pdf= (same as above) | | | =file:sometextfile::NNN= (jump to line number) | | | =file:projects.org= | | | =file:projects.org::some words= (text search) [fn:28] | | | =file:projects.org::*task title= (headline search) | | | =file:projects.org::#custom-id= (headline search) | | att | =att:projects.org= | | | =att:projects.org::some words= (text search) | | docview | =docview:papers/last.pdf::NNN= | | id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | | news | =news:comp.emacs= | | mailto | =mailto:adent@galaxy.net= | | mhe | =mhe:folder= (folder link) | | | =mhe:folder#id= (message link) | | rmail | =rmail:folder= (folder link) | | | =rmail:folder#id= (message link) | | gnus | =gnus:group= (group link) | | | =gnus:group#id= (article link) | | bbdb | =bbdb:R.*Stallman= (record with regexp) | | irc | =irc:/irc.com/#emacs/bob= | | info | =info:org::External links= | | shell | =shell:ls *.org= | | elisp | =elisp:(find-file "Elisp.org")= | --8<---------------cut here---------------end--------------->8--- WDYT? Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2018-11-27 9:39 ` Nicolas Goaziou @ 2019-05-26 23:05 ` Gustav Wikström 2019-06-15 13:29 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-05-26 23:05 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 10736 bytes --] Hi again, Some updates, and a fresh patch...! I won't say that much here since the patch speaks for itself (It contains a chapter to be added to ORG-NEWS). It's patch 0002 that is the important one. See sidenote below for a comment about patch 0001. I have to mention that the patch has grown quite a lot. With the Additional changes, I've taken the liberty to promote attachments to a level-1 headline within the documentation! Please review the new and improved" patch. > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 27 november 2018 10:40 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode <emacs-orgmode@gnu.org> > Subject: Re: [RFC] Link-type for attachments, more attach options > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > Too bad, "@" was growing on me. @ is currently automatically set as > > a tag when attaching files to nodes. > > You probably customized `org-attach-auto-tag' because this is not the > default behaviour. It adds "ATTACH" tag automatically. Yeah, you're right. My bad! > I prefer not to consider Gmail and Outlook as references, or even > standards. As another data point, Gnus uses "Attachment: " to list > attachments. I won't argue any longer. And I'll do as you say. Attachment: it is! > > Yeah, I don't know why it's configured like that from the start. A bit convoluted. Not > > sure of what way to go forward though. I can see at least two paths: > > > > 1) Rename `org-attach-allow-inheritance' to > > `org-attach-enable-inheritance' and always make attachments inherited > > when that is set to "t". Deprecate "ATTACH_DIR_INHERIT". With this I'd > > also change the precedence-logic between ATTACH_DIR & ID properties > > and make ID-based attachment inherit as well. The properties > > ATTACH_DIR and ID should be inherited from the closest node when > > resolving attachments, with ATTACH_DIR having precedence over ID if > > both exist for the same node. > > Why defining `org-attach-enable-inheritance' at all? There is already > `org-use-property-inheritance' for this. We do not need another > conflicting variable. > > I don't think we should inherit ID properties either. ID is defined > outside "org-attach.el", so this library shouldn't mess with its > meaning. Does inheriting ID properties give anything valuable? Inheriting ID's for attachments is actually valuable. It makes it possible, for example, to add attachment-links in subheadings to the node the attachment is defined on. After having used this for quite some time now it feels quite natural to have inheritance switched on for attachments. No negative side-effects at all. > > 2) remove `org-attach-allow-inheritance' and only rely on the > > "ATTACH_DIR_INHERIT" property of any of the parent nodes to decide if > > the "ATTACH_DIR" property should be inherited. This would be a smaller > > change from the user's perspective, where we're basically saying you > > cannot disable inheritance, but it's only active when a node has the > > ATTACH_DIR_INHERIT-property. > > > > I prefer path (1). > > So do I, with the remarks above. I went with path (1) and tried to fit it into the already existing property inheritance framework. > > +This list shows the full set of built-in external link types, > > +including examples for each: > > + > > +| Link Type | Description | Example| > > +|-----------+------------------------------+-------------------------------------------------------| > > +| http | web | =http://www.astro.uva.nl/=dominik= | > > +| https | secure web | =https://orgmode.org/= | > > +| doi | DOI for electronic resources | =doi:10.1000/182= | > > +| file | file-links | =file:/home/dominik/images/jupiter.jpg= | > > +| | | =/home/dominik/images/jupiter.jpg= (same as above) | > > +| | | =file:papers/last.pdf= | > > +| | | =./papers/last.pdf= (same as above) | > > +| | | =file:/ssh:me@some.where:papers/last.pdf= (remote) | > > +| | | =/ssh:me@some.where:papers/last.pdf= (same as above) | > > +| | | =file:sometextfile::NNN= (jump to line number) | > > +| | | =file:projects.org= | > > +| | | =file:projects.org::some words= (text search) [fn:28] | > > +| | | =file:projects.org::*task title= (headline search) | > > +| @ | links to attachments | =@:projects.org= | > > +| | | =@:projects.org::some words= (text search) | > > +| docview | doc-view mode | =docview:papers/last.pdf::NNN= | > > +| id | Link to heading by id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | > > +| news | Usenet link | =news:comp.emacs= | > > +| mailto | mail link | =mailto:adent@galaxy.net= | > > +| mhe | MH-E folder link | =mhe:folder= (folder link) | > > +| | | =mhe:folder#id= (message link) | > > +| rmail | Rmail link | =rmail:folder= (folder link) | > > +| | | =rmail:folder#id= (message link) | > > +| gnus | Gnus link | =gnus:group= (group link) | > > +| | | =gnus:group#id= (article link) | > > +| bbdb | BBDB link | =bbdb:R.*Stallman= (link with regexp) | > > +| irc | IRC link | =irc:/irc.com/#emacs/bob= | > > +| info | Info link | =info:org#External links=| > > +| shell | shell command | =shell:ls *.org= | > > +| elisp | interactive elisp command | =elisp:(find-file "Elisp.org")= | > > The second column still doesn't bring much information compared to the > first one. Getting back to your first idea, we may try to do something > like the following: > > --8<---------------cut here---------------start------------->8--- > Here is the full set of built-in link types. > > - =file= :: File links. File name may be remote, absolute, or relative. > > Additionally, you can specify a line number, or a text search. In Org > files, you may link to a headline name, a custom ID, or a code > reference instead. > > As a special case, "file" prefix may be omitted if the file name is > complete, e.g., it starts with =./=, or =/=. > > - =att= :: Same as file links, but for attached documents to the current > node (see [[*Attachments]]). > > - =bbdb= :: Link to a BBDB record, with possible regexp completion. > > - =docview= :: Link to a document opened with DocView mode. You may > specify a page number. > > - =doi= :: Link to an electronic ressource, through its handle. > > - =elisp= :: Execute an Elisp command upon activation. > > - =gnus=, =rmail=, =mhe= :: Links to messages or folders from a given > Emacs' MUA. > > - =http=, =https= :: Web links. > > - =id= :: Link to a specific headline by its ID property, in an Org > file. > > - =info= :: Link to an Info manual, or to a specific node. > > - =irc= :: Link to an IRC channel. > > - =mailto= :: Link to message composition. > > - =news= :: Usenet links. > > - =shell= :: Execute a shell command upon activation. > > The following table illustrates the link types above, along with their > options: > > | Link Type | Example | > |-----------+-------------------------------------------------------| > | http | =http://www.astro.uva.nl/=dominik= | > | https | =https://orgmode.org/= | > | doi | =doi:10.1000/182= | > | file | =file:/home/dominik/images/jupiter.jpg= | > | | =/home/dominik/images/jupiter.jpg= (same as above) | > | | =file:papers/last.pdf= | > | | =./papers/last.pdf= (same as above) | > | | =file:/ssh:me@some.where:papers/last.pdf= (remote) | > | | =/ssh:me@some.where:papers/last.pdf= (same as above) | > | | =file:sometextfile::NNN= (jump to line number) | > | | =file:projects.org= | > | | =file:projects.org::some words= (text search) [fn:28] | > | | =file:projects.org::*task title= (headline search) | > | | =file:projects.org::#custom-id= (headline search) | > | att | =att:projects.org= | > | | =att:projects.org::some words= (text search) | > | docview | =docview:papers/last.pdf::NNN= | > | id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | > | news | =news:comp.emacs= | > | mailto | =mailto:adent@galaxy.net= | > | mhe | =mhe:folder= (folder link) | > | | =mhe:folder#id= (message link) | > | rmail | =rmail:folder= (folder link) | > | | =rmail:folder#id= (message link) | > | gnus | =gnus:group= (group link) | > | | =gnus:group#id= (article link) | > | bbdb | =bbdb:R.*Stallman= (record with regexp) | > | irc | =irc:/irc.com/#emacs/bob= | > | info | =info:org::External links= | > | shell | =shell:ls *.org= | > | elisp | =elisp:(find-file "Elisp.org")= | > --8<---------------cut here---------------end--------------->8--- > > WDYT? Thumbs up! (Sidenote 1; what do I need to do to gain access to the official git-repository? Would be nice to be able to provide pull requests there!) (Sidenote 2; The first patch is some minor unrelated fixups - it breaks test-org-export/expand-include as a side-effect. But that's probably because the test doesn't do what it should! 😲 ) Kind regards Gustav [-- Attachment #2: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --] [-- Type: application/octet-stream, Size: 6293 bytes --] From 91c01d90b1143cc4559cc886bcd176f1cd82576d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 26 May 2019 03:34:34 +0200 Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox, test-property-inheritance * org-test.el: Fix org-test-with-temp-text, make it work with <point>, as some tests already expect it to do! * testing/lisp/test-org-element.el Fix a temp-text strings so that it doesn't have an initial newline. * testing/lisp/test-org.el Minor cleanup to align code-structure with other tests. Nothing changes in the test execpt style. * testing/lisp/test-ox.el Fix a couple of temp-text strings so that they don't have initial newlines. * testing/lisp/test-property-inheritance.el Fix wrong file-header and file-ending. --- testing/lisp/test-org-element.el | 4 ++-- testing/lisp/test-org.el | 12 +++++----- testing/lisp/test-ox.el | 28 +++++++++++------------ testing/lisp/test-property-inheritance.el | 4 ++-- testing/org-test.el | 7 +++++- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 8b4081ee2..4c1e4d181 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -3250,8 +3250,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu (ert-deftest test-org-element/granularity () "Test granularity impact on buffer parsing." - (org-test-with-temp-text " -* Head 1 + (org-test-with-temp-text + "* Head 1 ** Head 2 #+BEGIN_CENTER Centered paragraph. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index abc004689..d671b5c78 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -5060,18 +5060,18 @@ Paragraph<point>" (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" - (org-entry-get (point) "A" t)))) + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" + (org-entry-get (point-max) "A" t)))) (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance t)) - (org-entry-get (point) "A" 'selective))))) + (org-entry-get (point-max) "A" 'selective))))) (should-not - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance nil)) - (org-entry-get (point) "A" 'selective)))) + (org-entry-get (point-max) "A" 'selective)))) (should (equal "1 2" diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 43637b926..e5b4d3c92 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after comments removal." (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment # Comment @@ -2012,15 +2012,15 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2029,8 +2029,8 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2040,24 +2040,24 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "- item 1\n\n- item 2\n" - (org-test-with-temp-text " -- item 1 + (org-test-with-temp-text + "- item 1 # Comment diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el index 0f803e5f7..1d0dcfbe1 100644 --- a/testing/lisp/test-property-inheritance.el +++ b/testing/lisp/test-property-inheritance.el @@ -1,4 +1,4 @@ -;;; test-ob-R.el --- tests for ob-R.el +;;; test-property-inheritance.el --- tests for property-inheritance.el ;; Copyright (c) 2011-2014, 2019 Eric Schulte ;; Authors: Eric Schulte @@ -47,4 +47,4 @@ (provide 'test-ob-R) -;;; test-ob-R.el ends here +;;; test-property-inheritance.el ends here diff --git a/testing/org-test.el b/testing/org-test.el index 39c346410..6b218fc00 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -198,7 +198,10 @@ otherwise place the point at the beginning of the inserted text." (def-edebug-spec org-test-with-temp-text (form body)) (defmacro org-test-with-temp-text-in-file (text &rest body) - "Run body in a temporary file buffer with Org mode as the active mode." + "Run body in a temporary file buffer with Org mode as the active mode. +If the string \"<point>\" appears in TEXT then remove it and +place the point there before running BODY, otherwise place the +point at the beginning of the buffer." (declare (indent 1)) (let ((results (cl-gensym))) `(let ((file (make-temp-file "org-test")) @@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text." ,results) (with-temp-file file (insert inside-text)) (find-file file) + (when (re-search-forward "<point>" nil t) + (replace-match "")) (org-mode) (setq ,results (progn ,@body)) (save-buffer) (kill-buffer (current-buffer)) -- 2.17.1 [-- Attachment #3: 0002-org-attach-org-org-manual-org-news-testing-test-org-.patch --] [-- Type: application/octet-stream, Size: 83011 bytes --] From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 25 Nov 2018 21:38:44 +0100 Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, testing/**/test-org-attach* * org-attach.el Changed the way attachments deal with property-inheritance. It now adheres to the =org-use-property-inheritance= setting by default but it can be customized if needed (I recommend to enable it!). The property ATTACH_DIR is depricated in favour of the shorter and simpler property DIR. Added an explicit option to =org-attach= for unsetting attachment-directories (i.e. remove DIR property and deal with the attachments by interaction). Added attachment link type with the prefix "attachment:". Added customizations: - org-attach-dir-relative - org-attach-preferred-new-method - org-attach-use-inheritance - org-attach-id-to-path-function Hooks added: - org-attach-after-change-hook - org-attach-open-hook * Add new linktype "attachment" for attachments A new linktype "attachment" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID and DIR properties. The goal is to make the functionality for attached-links mirror file-links. * org-attach-git.el New file, existing functionality. Code here has been factored out from org-attach.el and if GIT-functionality is to be used this module needs to be required sepatately. It extends org-attach by use of its hooks. Activating git functionality in org-attach is done by loading org-attach-git from now on, instead of customizing a variable. Naming of both functions and tests has been modified to match the move of functionality into its own module. * org.el Inline images are shown also using attachment-links, exactly the same as it works for file-links today. Make org-open-at-point respect ARG when opening attachment-dir * org-compat.el org-attach-directory has been deprecated in favour for org-attach-id-dir. The new name matches its purpose better. * org-manual.org Attachments have been promoted into its own top-level node! There are a lot of goodies to mention here that didn't fit naturally with "capture" and "archive" before. Nothing from the old documentation is deleted. It's just been restructured and complemented with further information. The manual is updated to include information about org-attach options. The new attachment link type is mentioned both inside the attachments-chapter and in the chapter dealing with links. Documentation related to external links has been improved. * testing/lisp/test-org-attach-annex.el Require org-attach-git instead of org-attach, since this file tests the GIT-functionality. * testing/org-test.el Define a symbol for a file to test attachments with. * testing/examples/* A bunch of new example files and folders are created and are used in testing of org-attach to verify its functionality. --- doc/org-manual.org | 614 ++++++++++++------ etc/ORG-NEWS | 82 +++ lisp/org-attach-git.el | 118 ++++ lisp/org-attach.el | 564 ++++++++-------- lisp/org-compat.el | 3 + lisp/org.el | 23 +- testing/examples/att1/fileA | 1 + testing/examples/att1/fileB | 1 + testing/examples/att2/fileC | 1 + testing/examples/att2/fileD | 1 + testing/examples/attachments.org | 32 + testing/examples/data/ab/cd123/fileE | 1 + ...attach-annex.el => test-org-attach-git.el} | 12 +- testing/lisp/test-org-attach.el | 50 ++ testing/lisp/test-org.el | 6 +- testing/org-test.el | 3 + 16 files changed, 1034 insertions(+), 478 deletions(-) create mode 100644 lisp/org-attach-git.el create mode 100644 testing/examples/att1/fileA create mode 100644 testing/examples/att1/fileB create mode 100644 testing/examples/att2/fileC create mode 100644 testing/examples/att2/fileD create mode 100644 testing/examples/attachments.org create mode 100644 testing/examples/data/ab/cd123/fileE rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%) diff --git a/doc/org-manual.org b/doc/org-manual.org index c519d310b..8f86c5228 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3068,6 +3068,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: attachment links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3079,38 +3080,112 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. - -| =http://www.astro.uva.nl/=dominik= | on the web | -| =doi:10.1000/182= | DOI for an electronic resource | -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | -| =/home/dominik/images/jupiter.jpg= | same as above | -| =file:papers/last.pdf= | file, relative path | -| =./papers/last.pdf= | same as above | -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | -| =/ssh:me@some.where:papers/last.pdf= | same as above | -| =file:sometextfile::NNN= | file, jump to line number | -| =file:projects.org= | another Org file | -| =file:projects.org::some words= | text search in Org file[fn:27] | -| =file:projects.org::*task title= | heading search in Org file | -| =file+sys:/path/to/file= | open via OS, like double-click | -| =file+emacs:/path/to/file= | force opening by Emacs | -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | -| =news:comp.emacs= | Usenet link | -| =mailto:adent@galaxy.net= | mail link | -| =mhe:folder= | MH-E folder link | -| =mhe:folder#id= | MH-E message link | -| =rmail:folder= | Rmail folder link | -| =rmail:folder#id= | Rmail message link | -| =gnus:group= | Gnus group link | -| =gnus:group#id= | Gnus article link | -| =bbdb:R.*Stallman= | BBDB link (with regexp) | -| =irc:/irc.com/#emacs/bob= | IRC link | -| =info:org#External links= | Info node link | -| =shell:ls *.org= | shell command | -| =elisp:org-agenda= | interactive Elisp command | -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | +the colon. + +Here is the full set of built-in link types: + +- =file= :: + + File links. File name may be remote, absolute, or relative. + + Additionally, you can specify a line number, or a text search. + In Org files, you may link to a headline name, a custom ID, or a + code reference instead. + + As a special case, "file" prefix may be omitted if the file name + is complete, e.g., it starts with =./=, or =/=. + +- =attachment= :: + + Same as file links, but for attached documents to the current + node (see [[*Attachments]]). + +- =bbdb= :: + + Link to a BBDB record, with possible regexp completion. + +- =docview= :: + + Link to a document opened with DocView mode. You may specify a + page number. + +- =doi= :: + + Link to an electronic ressource, through its handle. + +- =elisp= :: + + Execute an Elisp command upon activation. + +- =gnus=, =rmail=, =mhe= :: + + Links to messages or folders from a given Emacs' MUA. + +- =http=, =https= :: + + Web links. + +- =id= :: + + Link to a specific headline by its ID property, in an Org file. + +- =info= :: + + Link to an Info manual, or to a specific node. + +- =irc= :: + + Link to an IRC channel. + +- =mailto= :: + + Link to message composition. + +- =news= :: + + Usenet links. + +- =shell= :: + + Execute a shell command upon activation. + +The following table illustrates the link types above, along with their +options: + +| Link Type | Example | +|------------+----------------------------------------------------------| +| http | =http://www.astro.uva.nl/=dominik= | +| https | =https://orgmode.org/= | +| doi | =doi:10.1000/182= | +| file | =file:/home/dominik/images/jupiter.jpg= | +| | =/home/dominik/images/jupiter.jpg= (same as above) | +| | =file:papers/last.pdf= | +| | =./papers/last.pdf= (same as above) | +| | =file:/ssh:me@some.where:papers/last.pdf= (remote) | +| | =/ssh:me@some.where:papers/last.pdf= (same as above) | +| | =file:sometextfile::NNN= (jump to line number) | +| | =file:projects.org= | +| | =file:projects.org::some words= (text search) [fn:28] | +| | =file:projects.org::*task title= (headline search) | +| | =file:projects.org::#custom-id= (headline search) | +| attachment | =attachment:projects.org= | +| | =attachment:projects.org::some words= (text search) | +| docview | =docview:papers/last.pdf::NNN= | +| id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | +| news | =news:comp.emacs= | +| mailto | =mailto:adent@galaxy.net= | +| mhe | =mhe:folder= (folder link) | +| | =mhe:folder#id= (message link) | +| rmail | =rmail:folder= (folder link) | +| | =rmail:folder#id= (message link) | +| gnus | =gnus:group= (group link) | +| | =gnus:group#id= (article link) | +| bbdb | =bbdb:R.*Stallman= (record with regexp) | +| irc | =irc:/irc.com/#emacs/bob= | +| info | =info:org#External links= | +| shell | =shell:ls *.org= | +| elisp | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) | +| | =elisp:org-agenda= (interactive Elisp command) | #+cindex: VM links #+cindex: Wanderlust links @@ -3462,20 +3537,22 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: attachment links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:34]. For -example, when the command ~org-store-link~ creates a link (see -[[*Handling Links]]) to a file, it encodes the words in the current line -as a search string that can be used to find this line back later when -following the link with {{{kbd(C-c C-o)}}}. +File links and attachment links can contain additional information to +make Emacs jump to a particular location in the file when following a +link. This can be a line number or a search option after a double +colon[fn:34]. For example, when the command ~org-store-link~ creates +a link (see [[*Handling Links]]) to a file, it encodes the words in the +current line as a search string that can be used to find this line +back later when following the link with {{{kbd(C-c C-o)}}}. Here is the syntax of the different ways to attach a search to a file -link, together with explanations for each: +link or attachment link, together with explanations for each: #+begin_example [[file:~/code/main.c::255]] +[[attachment:main.c::255]] [[file:~/xx.org::My Target]] [[file:~/xx.org::*My Target]] [[file:~/xx.org::#my-custom-id]] @@ -6901,11 +6978,9 @@ same commands. An important part of any organization system is the ability to quickly capture new ideas and tasks, and to associate reference material with -them. Org does this using a process called /capture/. It also can -store files related to a task (/attachments/) in a special directory. -Once in the system, tasks and projects need to be moved around. -Moving completed project trees to an archive file keeps the system -compact and fast. +them. Org does this using a process called /capture/. Once in the +system, tasks and projects need to be moved around. Moving completed +project trees to an archive file keeps the system compact and fast. ** Capture :PROPERTIES: @@ -7432,168 +7507,6 @@ another template. In that case, add this command key like this: See the docstring of the variable for more information. -** Attachments -:PROPERTIES: -:DESCRIPTION: Add files to tasks. -:END: -#+cindex: attachments -#+vindex: org-attach-directory - -It is often useful to associate reference material with an outline -node/task. Small chunks of plain text can simply be stored in the -subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish -associations with files that live elsewhere on your computer or in the -cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -=data/= directory which lives in the same directory where your Org -file lives[fn:87]. If you initialize this directory with =git init=, -Org automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. - -The following commands deal with attachments: - -- {{{kbd(C-c C-a)}}} (~org-attach~) :: - - #+kindex: C-c C-a - #+findex: org-attach - The dispatcher for commands related to the attachment system. After - these keys, a list of commands is displayed and you must press an - additional key to select a command: - - - {{{kbd(a)}}} (~org-attach-attach~) :: - - #+kindex: C-c C-a a - #+findex: org-attach-attach - #+vindex: org-attach-method - Select a file and move it into the task's attachment directory. - The file is copied, moved, or linked, depending on - ~org-attach-method~. Note that hard links are not supported on - all systems. - - - {{{kbd(c)}}}/{{{kbd(m)}}}/{{{kbd(l)}}} :: - - #+kindex: C-c C-a c - #+kindex: C-c C-a m - #+kindex: C-c C-a l - Attach a file using the copy/move/link method. Note that hard - links are not supported on all systems. - - - {{{kbd(b)}}} (~org-attach-buffer~) :: - - #+kindex: C-c C-a b - #+findex: org-attach-buffer - Select a buffer and save it as a file in the task's attachment - directory. - - - {{{kbd(n)}}} (~org-attach-new~) :: - - #+kindex: C-c C-a n - #+findex: org-attach-new - Create a new attachment as an Emacs buffer. - - - {{{kbd(z)}}} (~org-attach-sync~) :: - - #+kindex: C-c C-a z - #+findex: org-attach-sync - Synchronize the current task with its attachment directory, in - case you added attachments yourself. - - - {{{kbd(o)}}} (~org-attach-open~) :: - - #+kindex: C-c C-a o - #+findex: org-attach-open - #+vindex: org-file-apps - Open current task's attachment. If there is more than one, prompt - for a file name first. Opening follows the rules set by - ~org-file-apps~. For more details, see the information on - following hyperlinks (see [[*Handling Links]]). - - - {{{kbd(O)}}} (~org-attach-open-in-emacs~) :: - - #+kindex: C-c C-a O - #+findex: org-attach-open-in-emacs - Also open the attachment, but force opening the file in Emacs. - - - {{{kbd(f)}}} (~org-attach-reveal~) :: - - #+kindex: C-c C-a f - #+findex: org-attach-reveal - Open the current task's attachment directory. - - - {{{kbd(F)}}} (~org-attach-reveal-in-emacs~) :: - - #+kindex: C-c C-a F - #+findex: org-attach-reveal-in-emacs - Also open the directory, but force using Dired in Emacs. - - - {{{kbd(d)}}} (~org-attach-delete-one~) :: - - #+kindex: C-c C-a d - Select and delete a single attachment. - - - {{{kbd(D)}}} (~org-attach-delete-all~) :: - - #+kindex: C-c C-a D - Delete all of a task's attachments. A safer way is to open the - directory in Dired and delete from there. - - - {{{kbd(s)}}} (~org-attach-set-directory~) :: - - #+kindex: C-c C-a s - #+cindex: @samp{ATTACH_DIR}, property - Set a specific directory as the entry's attachment directory. - This works by putting the directory path into the =ATTACH_DIR= - property. - - - {{{kbd(i)}}} (~org-attach-set-inherit~) :: - - #+kindex: C-c C-a i - #+cindex: @samp{ATTACH_DIR_INHERIT}, property - Set the =ATTACH_DIR_INHERIT= property, so that children use the - same directory for attachments as the parent does. - -#+cindex: attach from Dired -#+findex: org-attach-dired-to-subtree -It is possible to attach files to a subtree from a Dired buffer. To -use this feature, have one window in Dired mode containing the file(s) -to be attached and another window with point in the subtree that shall -get the attachments. In the Dired window, with point on a file, -{{{kbd(M-x org-attach-dired-to-subtree)}}} attaches the file to the -subtree using the attachment method set by variable -~org-attach-method~. When files are marked in the Dired window then -all marked files get attached. - -Add the following lines to the Emacs init file to have {{{kbd(C-c C-x -a)}}} attach files in Dired buffers. - -#+begin_src emacs-lisp -(add-hook 'dired-mode-hook - (lambda () - (define-key dired-mode-map - (kbd "C-c C-x a") - #'org-attach-dired-to-subtree))) -#+end_src - -The following code shows how to bind the previous command with -a specific attachment method. - -#+begin_src emacs-lisp -(add-hook 'dired-mode-hook - (lambda () - (define-key dired-mode-map (kbd "C-c C-x c") - (lambda () - (interactive) - (let ((org-attach-method 'cp)) - (call-interactively #'org-attach-dired-to-subtree)))))) -#+end_src - ** RSS Feeds :PROPERTIES: :DESCRIPTION: Getting input from RSS feeds. @@ -8072,6 +7985,291 @@ The following commands help manage the =ARCHIVE= tag: of its original context, including inherited tags and approximate position in the outline. +* Attachments +:PROPERTIES: +:DESCRIPTION: Attach files to outlines. +:END: +#+cindex: attachments +#+vindex: org-attach-id-dir + +It is often useful to associate reference material with an outline +node/task. Small chunks of plain text can simply be stored in the +subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish +associations with files that live elsewhere on your computer or in the +cloud, like emails or source code files belonging to a project. + +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by a unique ID of each entry, or by a =DIR= property. + +The attachment system has been contributed to Org by John Wiegley. + +** Attachment defaults and dispatcher +By default, org-attach will use ID properties when adding attachments +to outline nodes. This makes working with attachments fully +automated. There is no decision needed for folder-name or location. +ID-based directories are by default located in the =data/= directory, +which lives in the same directory where your Org file lives[fn:87]. +For more control over the setup, see [[*Attachment options]]. + +When attachments are made using ~org-attach~ a default tag =ATTACH= is +added to the node that gets the attachments. + +The following commands deal with attachments: + +- {{{kbd(C-c C-a)}}} (~org-attach~) :: + + #+kindex: C-c C-a + #+findex: org-attach + The dispatcher for commands related to the attachment system. After + these keys, a list of commands is displayed and you must press an + additional key to select a command: + + - {{{kbd(a)}}} (~org-attach-attach~) :: + + #+kindex: C-c C-a a + #+findex: org-attach-attach + #+vindex: org-attach-method + Select a file and move it into the task's attachment directory. + The file is copied, moved, or linked, depending on + ~org-attach-method~. Note that hard links are not supported on + all systems. + + - {{{kbd(c)}}}/{{{kbd(m)}}}/{{{kbd(l)}}} :: + + #+kindex: C-c C-a c + #+kindex: C-c C-a m + #+kindex: C-c C-a l + Attach a file using the copy/move/link method. Note that hard + links are not supported on all systems. + + - {{{kbd(b)}}} (~org-attach-buffer~) :: + + #+kindex: C-c C-a b + #+findex: org-attach-buffer + Select a buffer and save it as a file in the task's attachment + directory. + + - {{{kbd(n)}}} (~org-attach-new~) :: + + #+kindex: C-c C-a n + #+findex: org-attach-new + Create a new attachment as an Emacs buffer. + + - {{{kbd(z)}}} (~org-attach-sync~) :: + + #+kindex: C-c C-a z + #+findex: org-attach-sync + Synchronize the current task with its attachment directory, in + case you added attachments yourself. + + - {{{kbd(o)}}} (~org-attach-open~) :: + + #+kindex: C-c C-a o + #+findex: org-attach-open + #+vindex: org-file-apps + Open current task's attachment. If there is more than one, prompt + for a file name first. Opening follows the rules set by + ~org-file-apps~. For more details, see the information on + following hyperlinks (see [[*Handling Links]]). + + - {{{kbd(O)}}} (~org-attach-open-in-emacs~) :: + + #+kindex: C-c C-a O + #+findex: org-attach-open-in-emacs + Also open the attachment, but force opening the file in Emacs. + + - {{{kbd(f)}}} (~org-attach-reveal~) :: + + #+kindex: C-c C-a f + #+findex: org-attach-reveal + Open the current task's attachment directory. + + - {{{kbd(F)}}} (~org-attach-reveal-in-emacs~) :: + + #+kindex: C-c C-a F + #+findex: org-attach-reveal-in-emacs + Also open the directory, but force using Dired in Emacs. + + - {{{kbd(d)}}} (~org-attach-delete-one~) :: + + #+kindex: C-c C-a d + Select and delete a single attachment. + + - {{{kbd(D)}}} (~org-attach-delete-all~) :: + + #+kindex: C-c C-a D + Delete all of a task's attachments. A safer way is to open the + directory in Dired and delete from there. + + - {{{kbd(s)}}} (~org-attach-set-directory~) :: + + #+kindex: C-c C-a s + #+cindex: @samp{DIR}, property + Set a specific directory as the entry's attachment directory. + This works by putting the directory path into the =DIR= + property. + + - {{{kbd(S)}}} (~org-attach-unset-directory~) :: + + #+kindex: C-c C-a S + #+cindex: @samp{DIR}, property + Remove the attachment-directory. This command removes the =DIR= + property and asks the user to either move content inside that + folder, if an =ID= property is set, delete the content, or to + leave the attachment-directory as is but no longer attached to the + outline node. + +** Attachment options +There are a couple of options for attachments that are worth +mentioning. + +- ~org-attach-id-dir~ :: + #+vindex: org-attach-id-dir + The directory where attachments are stored when =ID= is used as + method. + +- ~org-attach-dir-relative~ :: + #+vindex: org-attach-dir-relative + When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}} + (~org-attach-set-directory~), absolute links are entered by default. + This option changes that to relative links. + +- ~org-attach-use-inheritance~ :: + #+vindex: org-attach-use-inheritance + By default folders attached to an outline node are inherited from + parents according to ~org-use-property-inheritance~. If one instead + want to set inheritance specifically for org-attach that can be done + using ~org-attach-use-inheritance~. Inheriting documents through + the node hierarchy makes a lot of sense in most cases. Especially + since the introduction of [[* Attachment links]]. The following example + shows one use case for attachment inheritance: + + #+begin_example + ,* Chapter A ... + :PROPERTIES: + :DIR: Chapter A/ + :END: + ,** Introduction + Some text + + #+NAME: Image 1 + [[Attachment:image 1.jpg]] + #+end_example + + Without inheritance one would not be able to resolve the link to image + 1.jpg, since the link is inside a sub-heading to Chapter A. + + Inheritance works the same way for both =ID= and =DIR= property. If + both properties are defined on the same headline then =DIR= takes + precedance. This is also true if inheritance is enabled. If =DIR= is + inherited from a parent node in the outline, that property still takes + precedence over an =ID= property defined on the node itself. + +- ~org-attach-method~ :: + #+vindex: org-attach-method + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it + defaults to copying files. The behaviour can be changed by + customizing ~org-attach-method~. Options are =Copy=, =Move/Rename=, + =Hard link= or =Symbolic link=. + +- ~org-attach-preferred-new-method~ :: + #+vindex: org-attach-preferred-new-method + This customization lets you choose the default way to attach to + nodes without existing ID and DIR property. It defaults to =id= but + can also be set to =dir=, =ask= or =nil=. + +- ~org-attach-archive-delete~ :: + #+vindex: org-attach-archive-delete + Configure this to determine if attachments should be deleted or not + when a subtree that has attachments is archived. + +- ~org-attach-auto-tag~ :: + #+vindex: org-attach-auto-tag + When attaching files to a heading it will be assigned a tag + according to what is set here. + +- ~org-attach-id-to-path-function~ :: + #+vindex: org-attach-id-to-path-function + When =ID= is used for attachments, the ID is parsed into a part of a + directory-path. See ~org-attach-id-folder-format~ for the default + function. Define a new one and add it to + ~org-attach-id-to-path-function~ if you want the folder structure + any other way. Note that modifying this makes org-attach dependent + on your function also for opening attachments, not only setting + them! + +- ~org-attach-expert~ :: + #+vindex: org-attach-expert + Do not show the splash buffer with the attach dispatcher when + ~org-attach-expert~ is set to Non-nil. + +See customization group =Org Attach= if you want to change the +default settings. + +** Attachment links +Attached files and folders can be referenced using attachment-links. +This makes it easy to refer to the material added to an outline node. +Especially if it was attached using the unique ID of the entry! + +#+begin_example +,* TODO Some task + :PROPERTIES: + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 + :END: +See attached document for more information: [[attachment:info.org]] +#+end_example + +See [[* External Links]] for more information about these links. + +** Automatic version-control with git +If the directory attached to an outline node is a git repository, Org +can be configured to automatically commit changes to that repository +when it sees them. + +To make org-mode take care of versioning of attachments for you, add +the following to your Emacs config: + +#+begin_src emacs-lisp + (require 'org-attach-git) +#+end_src + +** Attach from Dired +#+cindex: attach from Dired +#+findex: org-attach-dired-to-subtree +It is possible to attach files to a subtree from a Dired buffer. To +use this feature, have one window in Dired mode containing the file(s) +to be attached and another window with point in the subtree that shall +get the attachments. In the Dired window, with point on a file, +{{{kbd(M-x org-attach-dired-to-subtree)}}} attaches the file to the +subtree using the attachment method set by variable +~org-attach-method~. When files are marked in the Dired window then +all marked files get attached. + +Add the following lines to the Emacs init file to have {{{kbd(C-c C-x +a)}}} attach files in Dired buffers. + +#+begin_src emacs-lisp +(add-hook 'dired-mode-hook + (lambda () + (define-key dired-mode-map + (kbd "C-c C-x a") + #'org-attach-dired-to-subtree))) +#+end_src + +The following code shows how to bind the previous command with +a specific attachment method. + +#+begin_src emacs-lisp +(add-hook 'dired-mode-hook + (lambda () + (define-key dired-mode-map (kbd "C-c C-x c") + (lambda () + (interactive) + (let ((org-attach-method 'cp)) + (call-interactively #'org-attach-dired-to-subtree)))))) +#+end_src + * Agenda Views :PROPERTIES: :DESCRIPTION: Collecting information into views. @@ -21225,7 +21423,7 @@ accessed in capture templates in a similar way. ~org-link-from-user-regexp~. [fn:87] If you move entries or Org files from one directory to -another, you may want to configure ~org-attach-directory~ to contain +another, you may want to configure ~org-attach-id-dir~ to contain an absolute path. [fn:88] Note the corresponding =STARTUP= options =logrefile=, diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 541559e64..5a868ca99 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -112,6 +112,84 @@ alternative was removed and there is no more a :use-xcolor options since now it's implicitly always true. ** New features +*** Org-Attach has been refactored and extended +Org attach has been refactored and the functionality extended. It +should now be easier to understand how it works. A few improvements +and extra options have been added as well. + +From the initial comment in org-attach source-code: + +- Attachments are managed either by using a custom property DIR or by + using property ID from org-id. When DIR is defined, a location in + the filesystem is directly attached to the outline node. When + org-id is used, attachments are stored in a folder named after the + ID, in a location defined by ~org-attach-id-dir~. DIR has + precedence over ID when both parameters are defined for the current + outline node (also when inherited parameters are taken into + account). + +From now on inheritance requires no extra property and will adhere to +~org-attach-use-inheritance~ by default. Inheritance can be +customized to always be activated or never be activated in +~org-attach-use-inheritance~. + +The ATTACH_DIR property is depricated in favour of the shorter +property DIR. Links to folders inside the DIR property can now be +declared as relative links. This is not enabled by default, but can +be set in ~org-attach-dir-relative~. + +When adding new attachment to the outline node the preferred way of +doing so can be customized. Take a look at +~org-attach-preferred-new-method~. It defaults to using ID since that +was the behaviour before this change. + +If both DIR and ID properties are set on the same node, DIR has +precedence and will be used. + +One can now also choose to build attachment-directory-paths in a +customized way. This is an advanced topic, but in some case it makes +sense to parse an ID in a different way than the default one. Create +your own function and use it is ~org-attach-id-to-path-function~ if +you want to customize the ID-based folder structure. + +If you've used ATTACH_DIR properties to manage attachments, use the +following code to rename that property to DIR which supports the same +functionality. ATTACH_DIR_INHERIT is no longer supported and is +removed. + +#+begin_src emacs-lisp + (defun org-update-attach-properties () + "Change properties for Org-Attach." + (interactive "P") + (org-with-point-at 1 + (while (outline-next-heading) + (let ((DIR (org--property-local-values "ATTACH_DIR" nil))) + (when DIR + (org-set-property "DIR" (car DIR)) + (org-delete-property "ATTACH_DIR")))) + (org-delete-property-globally "ATTACH_DIR_INHERIT"))) +#+end_src + +For those who hate breaking changes, even though the changes are made +to clean things up; fear not. ATTACH_DIR will still continue to work. +It's just not documented any longer. When you get the chance, run the +code above to clean things up anyways! + +**** New hooks +Two hooks are added to org-attach: +- org-attach-after-change-hook +- org-attach-open-hook + +They are added mostly for internal restructuring purposes, but can +ofc. be used for other things as well. + +*** New link-type: Attachment +Attachment-links are now first-class citizens. They mimick file-links +in everything they do but use the existing attachment-folder as a base +when expanding the links. Both =DIR= and =ID= properties are used to +try to resolve the links, in exactly the same way as Org-Attach uses +those properties. + *** Handle overlay specification for notes in Beamer export This aligns Beamer notes with slide overlays. @@ -228,6 +306,10 @@ dynamic block in ~org-dynamic-block-alist~. *** ~org-babel-set-current-result-hash~ It was unused throughout the code base. +*** ~org-attach-directory~ + +It has been deprecated in favour of ~org-attach-id-dir~ which is less +ambigous given the restructured org-attach. ** Miscellaneous *** LaTeX preview is simplified diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el new file mode 100644 index 000000000..924d04157 --- /dev/null +++ b/lisp/org-attach-git.el @@ -0,0 +1,118 @@ +;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Free Software Foundation, Inc. + +;; Original Author: John Wiegley <johnw@newartisans.com> +;; Restructurer: Gustav Wikström <gustav@whil.se> +;; Keywords: org data git + +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; An extention to org-attach. If the attachment-directory to an +;; outline node (using either DIR or ID) is initialized as a Git +;; repository, then org-attach-git will automatically commit changes +;; when it sees them. + +;;; Code: + +(require 'org-attach) +(require 'vc-git) + +(defcustom org-attach-git-annex-cutoff (* 32 1024) + "If non-nil, files larger than this will be annexed instead of stored." + :group 'org-attach + :version "24.4" + :package-version '(Org . "8.0") + :type '(choice + (const :tag "None" nil) + (integer :tag "Bytes"))) + +(defcustom org-attach-git-annex-auto-get 'ask + "Confirmation preference for automatically getting annex files. +If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." + :group 'org-attach + :package-version '(Org . "9.0") + :version "26.1" + :type '(choice + (const :tag "confirm with `y-or-n-p'" ask) + (const :tag "always get from annex if necessary" t) + (const :tag "never get from annex" nil))) + +(defun org-attach-git-use-annex () + "Return non-nil if git annex can be used." + (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir)))) + (and org-attach-git-annex-cutoff + (or (file-exists-p (expand-file-name "annex" git-dir)) + (file-exists-p (expand-file-name ".git/annex" git-dir)))))) + +(defun org-attach-git-annex-get-maybe (path) + "Call git annex get PATH (via shell) if using git annex. +Signals an error if the file content is not available and it was not retrieved." + (let* ((default-directory (expand-file-name org-attach-id-dir)) + (path-relative (file-relative-name path))) + (when (and (org-attach-git-use-annex) + (not + (string-equal + "found" + (shell-command-to-string + (format "git annex find --format=found --in=here %s" + (shell-quote-argument path-relative)))))) + (let ((should-get + (if (eq org-attach-git-annex-auto-get 'ask) + (y-or-n-p (format "Run git annex get %s? " path-relative)) + org-attach-git-annex-auto-get))) + (if should-get + (progn (message "Running git annex get \"%s\"." path-relative) + (call-process "git" nil nil nil "annex" "get" path-relative)) + (error "File %s stored in git annex but it is not available, and was not retrieved" + path)))))) + +(defun org-attach-git-commit () + "Commit changes to git if `org-attach-id-dir' is properly initialized. +This checks for the existence of a \".git\" directory in that directory." + (let* ((dir (expand-file-name org-attach-id-dir)) + (git-dir (vc-git-root dir)) + (use-annex (org-attach-git-use-annex)) + (changes 0)) + (when (and git-dir (executable-find "git")) + (with-temp-buffer + (cd dir) + (dolist (new-or-modified + (split-string + (shell-command-to-string + "git ls-files -zmo --exclude-standard") "\0" t)) + (if (and use-annex + (>= (file-attribute-size (file-attributes new-or-modified)) + org-attach-git-annex-cutoff)) + (call-process "git" nil nil nil "annex" "add" new-or-modified) + (call-process "git" nil nil nil "add" new-or-modified)) + (cl-incf changes)) + (dolist (deleted + (split-string + (shell-command-to-string "git ls-files -z --deleted") "\0" t)) + (call-process "git" nil nil nil "rm" deleted) + (cl-incf changes)) + (when (> changes 0) + (shell-command "git commit -m 'Synchronized attachments'")))))) + +(add-hook 'org-attach-after-change-hook 'org-attach-git-commit) +(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe) + +(provide 'org-attach-git) + +;;; org-attach-git.el ends here diff --git a/lisp/org-attach.el b/lisp/org-attach.el index de8b2fc96..d863aa38b 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -1,9 +1,9 @@ -;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*- +;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*- ;; Copyright (C) 2008-2019 Free Software Foundation, Inc. ;; Author: John Wiegley <johnw@newartisans.com> -;; Keywords: org data task +;; Keywords: org data attachment ;; This file is part of GNU Emacs. ;; @@ -24,32 +24,30 @@ ;; See the Org manual for information on how to use it. ;; -;; Attachments are managed in a special directory called "data", which -;; lives in the same directory as the org file itself. If this data -;; directory is initialized as a Git repository, then org-attach will -;; automatically commit changes when it sees them. -;; -;; Attachment directories are identified using a UUID generated for the -;; task which has the attachments. These are added as property to the -;; task when necessary, and should not be deleted or changed by the -;; user, ever. UUIDs are generated by a mechanism defined in the variable -;; `org-id-method'. +;; Attachments are managed either by using a custom property DIR or by +;; using property ID from org-id. When DIR is defined, a location in +;; the filesystem is directly attached to the outline node. When +;; org-id is used, attachments are stored in a folder named after the +;; ID, in a location defined by `org-attach-id-dir'. DIR has +;; precedence over ID when both parameters are defined for the current +;; outline node (also when inherited parameters are taken into +;; account). ;;; Code: (require 'cl-lib) (require 'org) +(require 'ol) (require 'org-id) -(require 'vc-git) (declare-function dired-dwim-target-directory "dired-aux") (defgroup org-attach nil - "Options concerning entry attachments in Org mode." + "Options concerning attachments in Org mode." :tag "Org Attach" :group 'org) -(defcustom org-attach-directory "data/" +(defcustom org-attach-id-dir "data/" "The directory where attachments are stored. If this is a relative path, it will be interpreted relative to the directory where the Org file lives." @@ -57,22 +55,13 @@ where the Org file lives." :type 'directory :safe #'stringp) -(defcustom org-attach-commit t - "If non-nil commit attachments with git. -This is only done if the Org file is in a git repository." +(defcustom org-attach-dir-relative nil + "Choose whether directories in DIR property should be added as relative links or not. +Defaults to absolute location." :group 'org-attach :type 'boolean - :version "26.1" - :package-version '(Org . "9.0")) - -(defcustom org-attach-git-annex-cutoff (* 32 1024) - "If non-nil, files larger than this will be annexed instead of stored." - :group 'org-attach - :version "24.4" - :package-version '(Org . "8.0") - :type '(choice - (const :tag "None" nil) - (integer :tag "Bytes"))) + :package-version '(Org . "9.3") + :safe #'booleanp) (defcustom org-attach-auto-tag "ATTACH" "Tag that will be triggered automatically when an entry has an attachment." @@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository." (const :tag "None" nil) (string :tag "Tag"))) -(defcustom org-attach-file-list-property "Attachments" - "The property used to keep a list of attachment belonging to this entry. -This is not really needed, so you may set this to nil if you don't want it. -Also, for entries where children inherit the directory, the list of -attachments is not kept in this property." +(defcustom org-attach-preferred-new-method 'id + "Preferred way to attach to nodes without existing ID and DIR property. +This choice is used when adding attachments to nodes without ID +and DIR properties. + +Allowed values are: + +id Create and use an ID parameter +dir Create and use a DIR parameter +ask Ask the user for input of which method to choose +nil Prefer to not create a new parameter + + nil means that ID or DIR has to be created explicitly + before attaching files." :group 'org-attach + :package-version '(org . "9.3") :type '(choice - (const :tag "None" nil) - (string :tag "Tag"))) + (const :tag "ID parameter" id) + (const :tag "DIR parameter" dir) + (const :tag "Ask user" ask) + (const :tag "Don't create" nil))) (defcustom org-attach-method 'cp "The preferred method to attach a file. @@ -113,14 +114,22 @@ lns create a symbol link. Note that this is not supported :group 'org-attach :type 'boolean) -(defcustom org-attach-allow-inheritance t - "Non-nil means allow attachment directories be inherited." +(defcustom org-attach-use-inheritance 'selective + "Non-nil means allow attachments to be inherited from parent outline nodes. + +The implication of this is that (1) attachment links will look +through all parent headings until it finds the linked attachment +and (2) that running org-attach inside a node without attachments +will make org-attach operate on the first parent heading it finds +with attachments." :group 'org-attach + :type '(choice + (const :tag "Don't use inheritance" nil) + (const :tag "Inherit parent node attachments" t) + (const :tag "Respect org-use-property-inheritance" selective) + ) :type 'boolean) -(defvar org-attach-inherited nil - "Indicates if the last access to the attachment directory was inherited.") - (defcustom org-attach-store-link-p nil "Non-nil means store a link to a file when attaching it." :group 'org-attach @@ -141,16 +150,27 @@ When set to `query', ask the user instead." (const :tag "Always delete attachments" t) (const :tag "Query the user" query))) -(defcustom org-attach-annex-auto-get 'ask - "Confirmation preference for automatically getting annex files. -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." +(defun org-attach-id-folder-format (id) + (format "%s/%s" + (substring id 0 2) + (substring id 2)) + ) + +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format + "The function parsing the ID parameter into a folder-path" :group 'org-attach - :package-version '(Org . "9.0") - :version "26.1" - :type '(choice - (const :tag "confirm with `y-or-n-p'" ask) - (const :tag "always get from annex if necessary" t) - (const :tag "never get from annex" nil))) + :package-version '(Org . "9.3") + :type 'function + ) + +(defvar org-attach-after-change-hook nil + "Hook to be called when files have been added or removed to the attachment folder.") + +(defvar org-attach-open-hook nil + "Hook that is invoked by `org-attach-open'. + +Created mostly to be compatible with org-attach-git after removing +git-funtionality from this file.") (defcustom org-attach-commands '(((?a ?\C-a) org-attach-attach @@ -186,9 +206,9 @@ you added attachments yourself.\n") "Delete all of a task's attachments. A safer way is\n to open the \ directory in dired and delete from there.\n") ((?s ?\C-s) org-attach-set-directory - "Set a specific attachment directory for this entry or reset to default.") - ((?i ?\C-i) org-attach-set-inherit - "Make children of the current entry inherit its attachment directory.\n") + "Set a specific attachment directory for this entry. Sets DIR property.") + ((?S ?\C-S) org-attach-unset-directory + "Unset the attachment directory for this entry. Removes DIR property.") ((?q) (lambda () (interactive) (message "Abort")) "Abort.")) "The list of commands for the attachment dispatcher. Each entry in this list is a list of three elements: @@ -210,12 +230,14 @@ Each entry in this list is a list of three elements: "The dispatcher for attachment commands. Shows a list of commands and prompts for another key to execute a command." (interactive) - (let (c marker) + (let (c marker attachment) (when (eq major-mode 'org-agenda-mode) (setq marker (or (get-text-property (point) 'org-hd-marker) (get-text-property (point) 'org-marker))) (unless marker - (error "No task in current line"))) + (error "No item in current line"))) + (setq attachment (or (org-attach-dir) + (quote "No existing attachment-folder"))) (save-excursion (when marker (set-buffer (marker-buffer marker)) @@ -225,24 +247,25 @@ Shows a list of commands and prompts for another key to execute a command." (save-window-excursion (unless org-attach-expert (with-output-to-temp-buffer "*Org Attach*" - (princ - (format "Select an Attachment Command:\n\n%s" - (mapconcat - (lambda (entry) - (pcase entry - (`((,key . ,_) ,_ ,docstring) - (format "%c %s" - key - (replace-regexp-in-string "\n\\([\t ]*\\)" - " " - docstring - nil nil 1))) - (_ - (user-error - "Invalid `org-attach-commands' item: %S" - entry)))) - org-attach-commands - "\n"))))) + (princ + (concat "Attachment folder:\n" attachment "\n\n" + (format "Select an Attachment Command:\n\n%s" + (mapconcat + (lambda (entry) + (pcase entry + (`((,key . ,_) ,_ ,docstring) + (format "%c %s" + key + (replace-regexp-in-string "\n\\([\t ]*\\)" + " " + docstring + nil nil 1))) + (_ + (user-error + "Invalid `org-attach-commands' item: %S" + entry)))) + org-attach-commands + "\n")))))) (org-fit-window-to-buffer (get-buffer-window "*Org Attach*")) (message "Select command: [%s]" (concat (mapcar #'caar org-attach-commands))) @@ -256,148 +279,128 @@ Shows a list of commands and prompts for another key to execute a command." (error "No such attachment command: %c" c)))))) (defun org-attach-dir (&optional create-if-not-exists-p) - "Return the directory associated with the current entry. -This first checks for a local property ATTACH_DIR, and then for an inherited -property ATTACH_DIR_INHERIT. If neither exists, the default mechanism -using the entry ID will be invoked to access the unique directory for the -current entry. -If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, -the directory and (if necessary) the corresponding ID will be created." - (let (attach-dir uuid) - (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) - (cond - ((setq attach-dir (org-entry-get nil "ATTACH_DIR")) - (org-attach-check-absolute-path attach-dir)) - ((and org-attach-allow-inheritance - (org-entry-get nil "ATTACH_DIR_INHERIT" t)) - (setq attach-dir - (org-with-wide-buffer - (if (marker-position org-entry-property-inherited-from) - (goto-char org-entry-property-inherited-from) - (org-back-to-heading t)) - (let (org-attach-allow-inheritance) - (org-attach-dir create-if-not-exists-p)))) - (org-attach-check-absolute-path attach-dir) - (setq org-attach-inherited t)) - (t ; use the ID - (org-attach-check-absolute-path nil) - (setq uuid (org-id-get (point) create-if-not-exists-p)) - (when (or uuid create-if-not-exists-p) - (unless uuid (error "ID retrieval/creation failed")) - (setq attach-dir (expand-file-name - (format "%s/%s" - (substring uuid 0 2) - (substring uuid 2)) - (expand-file-name org-attach-directory)))))) - (when attach-dir - (if (and create-if-not-exists-p - (not (file-directory-p attach-dir))) - (make-directory attach-dir t)) - (and (file-exists-p attach-dir) - attach-dir)))) + "Return the directory associated with the current outline node. +First check for DIR property, then ID property. +`org-attach-use-inheritance' determines whether inherited +properties also will be considered. + +If an ID property is found the default mechanism using that ID +will be invoked to access the directory for the current entry. + +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' +is run." + (if create-if-not-exists-p + (org-attach-dir-get-create) + (let (attach-dir id) + (cond + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) + (org-attach-check-absolute-path attach-dir)) + ;; Depricated and removed from documentation, but still + ;; works. Remove after major nr change... + ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance)) + (org-attach-check-absolute-path attach-dir)) + ((setq id (org-entry-get nil "ID" org-attach-use-inheritance)) + (org-attach-check-absolute-path nil) + (setq attach-dir (org-attach-dir-from-id id)))) + attach-dir))) + +(defun org-attach-dir-get-create () + "Return existing or new directory associated with the current outline node. + +`org-attach-preferred-new-method' decides how to attach +new directory." + (interactive) + (let ((attach-dir (org-attach-dir))) + (unless attach-dir + (let (answer) + (when (eq org-attach-preferred-new-method 'ask) + (message "Create new ID [1] property or DIR [2] property for attachments?") + (setq answer (read-char-exclusive))) + (cond + ((or (eq org-attach-preferred-new-method 'id) (eq answer ?1)) + (setq attach-dir (org-attach-dir-from-id (org-id-get nil t)))) + ((or (eq org-attach-preferred-new-method 'dir) (eq answer ?2)) + (setq attach-dir (org-attach-set-directory))) + ((eq org-attach-preferred-new-method 'nil) + (error "No existing directory. DIR or ID property has to be explicitly created."))))) + (if attach-dir + (progn (if (not (file-directory-p attach-dir)) + (make-directory attach-dir t)) + (if (file-exists-p attach-dir) + attach-dir + (error "Path does not exist: %s." attach-dir))) + (error "No attachment directory is associated with the current node.")))) + +(defun org-attach-dir-from-id (id) + "Creates a path based on `org-attach-id-dir' and ID." + (expand-file-name + (funcall org-attach-id-to-path-function id) + (expand-file-name org-attach-id-dir))) (defun org-attach-check-absolute-path (dir) "Check if we have enough information to root the attachment directory. When DIR is given, check also if it is already absolute. Otherwise, -assume that it will be relative, and check if `org-attach-directory' is +assume that it will be relative, and check if `org-attach-id-dir' is absolute, or if at least the current buffer has a file name. Throw an error if we cannot root the directory." (or (and dir (file-name-absolute-p dir)) - (file-name-absolute-p org-attach-directory) + (file-name-absolute-p org-attach-id-dir) (buffer-file-name (buffer-base-buffer)) - (error "Need absolute `org-attach-directory' to attach in buffers without filename"))) + (error "Need absolute `org-attach-id-dir' to attach in buffers without filename"))) -(defun org-attach-set-directory (&optional arg) - "Set the ATTACH_DIR node property and ask to move files there. +(defun org-attach-set-directory () + "Set the DIR node property and ask to move files there. The property defines the directory that is used for attachments -of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." - (interactive "P") +of the entry. Creates relative links if `org-attach-dir-relative' +is t. + +Return the directory." + (interactive) (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (new + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil "DIR"))) + (current-dir (file-name-directory (or default-directory + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (org-entry-put nil "DIR" (if org-attach-dir-relative + attach-dir-relative + attach-dir)) + attach-dir))) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") + (copy-directory old new t t t)) + (when (yes-or-no-p (concat "Delete " old)) + (delete-directory old t))) + new)) + +(defun org-attach-unset-directory () + "Removes DIR node property. +If attachment folder is changed due to removal of DIR-property +ask to move attachments to new location and ask to delete old +attachment-folder. + +Change of attachment-folder due to unset might be if an ID +property is set on the node, or if a separate inherited +DIR-property exists (that is different than the unset one)." + (interactive) + (let ((old (org-attach-dir)) + (new + (progn + (org-entry-delete nil "DIR") + ;; ATTACH-DIR is depricated and removed from documentation, + ;; but still works. Remove code for it after major nr change. + (org-entry-delete nil "ATTACH_DIR") + (org-attach-dir)))) + (unless (or (string= old new) + (not old)) + (when (and new (yes-or-no-p "Copy over attachments from old directory? ")) (copy-directory old new t nil t)) (when (yes-or-no-p (concat "Delete " old)) (delete-directory old t))))) -(defun org-attach-set-inherit () - "Set the ATTACH_DIR_INHERIT property of the current entry. -The property defines the directory that is used for attachments -of the entry and any children that do not explicitly define (by setting -the ATTACH_DIR property) their own attachment directory." - (interactive) - (org-entry-put nil "ATTACH_DIR_INHERIT" "t") - (message "Children will inherit attachment directory")) - -(defun org-attach-use-annex () - "Return non-nil if git annex can be used." - (let ((git-dir (vc-git-root (expand-file-name org-attach-directory)))) - (and org-attach-git-annex-cutoff - (or (file-exists-p (expand-file-name "annex" git-dir)) - (file-exists-p (expand-file-name ".git/annex" git-dir)))))) - -(defun org-attach-annex-get-maybe (path) - "Call git annex get PATH (via shell) if using git annex. -Signals an error if the file content is not available and it was not retrieved." - (let* ((default-directory (expand-file-name org-attach-directory)) - (path-relative (file-relative-name path))) - (when (and (org-attach-use-annex) - (not - (string-equal - "found" - (shell-command-to-string - (format "git annex find --format=found --in=here %s" - (shell-quote-argument path-relative)))))) - (let ((should-get - (if (eq org-attach-annex-auto-get 'ask) - (y-or-n-p (format "Run git annex get %s? " path-relative)) - org-attach-annex-auto-get))) - (if should-get - (progn (message "Running git annex get \"%s\"." path-relative) - (call-process "git" nil nil nil "annex" "get" path-relative)) - (error "File %s stored in git annex but it is not available, and was not retrieved" - path)))))) - -(defun org-attach-commit () - "Commit changes to git if `org-attach-directory' is properly initialized. -This checks for the existence of a \".git\" directory in that directory." - (let* ((dir (expand-file-name org-attach-directory)) - (git-dir (vc-git-root dir)) - (use-annex (org-attach-use-annex)) - (changes 0)) - (when (and git-dir (executable-find "git")) - (with-temp-buffer - (cd dir) - (dolist (new-or-modified - (split-string - (shell-command-to-string - "git ls-files -zmo --exclude-standard") "\0" t)) - (if (and use-annex - (>= (file-attribute-size (file-attributes new-or-modified)) - org-attach-git-annex-cutoff)) - (call-process "git" nil nil nil "annex" "add" new-or-modified) - (call-process "git" nil nil nil "add" new-or-modified)) - (cl-incf changes)) - (dolist (deleted - (split-string - (shell-command-to-string "git ls-files -z --deleted") "\0" t)) - (call-process "git" nil nil nil "rm" deleted) - (cl-incf changes)) - (when (> changes 0) - (shell-command "git commit -m 'Synchronized attachments'")))))) - (defun org-attach-tag (&optional off) "Turn the autotag on or (if OFF is set) off." (when org-attach-auto-tag @@ -422,22 +425,21 @@ Only do this when `org-attach-store-link-p' is non-nil." (org-attach-attach url)) (defun org-attach-buffer (buffer-name) - "Attach BUFFER-NAME's contents to current task. + "Attach BUFFER-NAME's contents to current outline node. BUFFER-NAME is a string. Signals a `file-already-exists' error if it would overwrite an existing filename." (interactive "bBuffer whose contents should be attached: ") - (let ((output (expand-file-name buffer-name (org-attach-dir t)))) + (let* ((attach-dir (org-attach-dir 'get-create)) + (output (expand-file-name buffer-name attach-dir))) (when (file-exists-p output) (signal 'file-already-exists (list "File exists" output))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property buffer-name)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (with-temp-file output (insert-buffer-substring buffer-name)))) (defun org-attach-attach (file &optional visit-dir method) - "Move/copy/link FILE into the attachment directory of the current task. + "Move/copy/link FILE into the attachment directory of the current outline node. If VISIT-DIR is non-nil, visit the directory with dired. METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from `org-attach-method'." @@ -452,10 +454,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from nil)) (setq method (or method org-attach-method)) (let ((basename (file-name-nondirectory file))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property basename)) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir 'get-create)) (fname (expand-file-name basename attach-dir))) (cond ((eq method 'mv) (rename-file file fname)) @@ -463,8 +462,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from ((eq method 'ln) (add-name-to-file file fname)) ((eq method 'lns) (make-symbolic-link file fname)) ((eq method 'url) (url-copy-file file fname))) - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (cond ((eq org-attach-store-link-p 'attached) (org-attach-store-link fname)) @@ -472,7 +470,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from (org-attach-store-link file))) (if visit-dir (dired attach-dir) - (message "File %S is now a task attachment." basename))))) + (message "File %S is now an attachment." basename))))) (defun org-attach-attach-cp () "Attach a file by copying it." @@ -497,13 +495,10 @@ On some systems, this apparently does copy the file instead." (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) (defun org-attach-new (file) - "Create a new attachment FILE for the current task. + "Create a new attachment FILE for the current outline node. The attachment is created as an Emacs buffer." (interactive "sCreate attachment named: ") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)) - (let ((attach-dir (org-attach-dir t))) + (let ((attach-dir (org-attach-dir 'get-create))) (org-attach-tag) (find-file (expand-file-name file attach-dir)) (message "New attachment %s" file))) @@ -511,7 +506,7 @@ The attachment is created as an Emacs buffer." (defun org-attach-delete-one (&optional file) "Delete a single attachment." (interactive) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir)) (files (org-attach-file-list attach-dir)) (file (or file (completing-read @@ -523,44 +518,33 @@ The attachment is created as an Emacs buffer." (unless (file-exists-p file) (error "No such attachment: %s" file)) (delete-file file) - (when org-attach-commit - (org-attach-commit)))) + (run-hook-with-args 'org-attach-after-change-hook attach-dir))) (defun org-attach-delete-all (&optional force) - "Delete all attachments from the current task. + "Delete all attachments from the current outline node. This actually deletes the entire attachment directory. A safer way is to open the directory in dired and delete from there." (interactive "P") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) - (when - (and attach-dir - (or force - (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) - (shell-command (format "rm -fr %s" attach-dir)) + (when (and attach-dir + (or force + (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) + (delete-directory attach-dir (yes-or-no-p "Recursive?") t) (message "Attachment directory removed") - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-untag)))) (defun org-attach-sync () - "Synchronize the current tasks with its attachments. + "Synchronize the current outline node with its attachments. This can be used after files have been added externally." (interactive) - (when org-attach-commit - (org-attach-commit)) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) (when attach-dir + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (let ((files (org-attach-file-list attach-dir))) - (org-attach-tag (not files)) - (when org-attach-file-list-property - (dolist (file files) - (unless (string-match "^\\.\\.?\\'" file) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)))))))) + (org-attach-tag (not files)))) + (when (not attach-dir) + (org-attach-tag t)))) (defun org-attach-file-list (dir) "Return a list of files in the attachment directory. @@ -569,35 +553,41 @@ This ignores files ending in \"~\"." (mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x)) (directory-files dir nil "[^~]\\'")))) -(defun org-attach-reveal (&optional if-exists) - "Show the attachment directory of the current task. +(defun org-attach-reveal () + "Show the attachment directory of the current outline node. This will attempt to use an external program to show the directory." - (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) - (and attach-dir (org-open-file attach-dir)))) + (interactive) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (org-open-file attach-dir) + (error "No attachment directory exist.")))) (defun org-attach-reveal-in-emacs () - "Show the attachment directory of the current task in dired." + "Show the attachment directory of the current outline node in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (dired attach-dir) + (error "No attachment directory exist.")))) (defun org-attach-open (&optional in-emacs) - "Open an attachment of the current task. + "Open an attachment of the current outline node. If there are more than one attachment, you will be prompted for the file name. This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (let* ((files (org-attach-file-list attach-dir)) + (file (if (= (length files) 1) + (car files) + (completing-read "Open attachment: " + (mapcar #'list files) nil t))) + (path (expand-file-name file attach-dir))) + (run-hook-with-args 'org-attach-open-hook path) + (org-open-file path in-emacs)) + (error "No attachment directory exist.")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -616,6 +606,66 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(org-link-set-parameters "attachment" + :follow #'org-attach-open-link + :export #'org-attach-export-link + :complete #'org-attach-complete-link) + +(defun org-attach-open-link (link &optional in-emacs) + "Attachment link type LINK is expanded with the attached directory and opened. + +With optional prefix argument IN-EMACS, Emacs will visit the file. +With a double \\[universal-argument] \\[universal-argument] \ +prefix arg, Org tries to avoid opening in Emacs +and to use an external application to visit the file." + (interactive "P") + (let (line search) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment directory." + (let* ((attached-dir (expand-file-name (org-attach-dir))) + (file (read-file-name "File: " attached-dir)) + (pwd (file-name-as-directory attached-dir)) + (pwd-relative (file-name-as-directory + (abbreviate-file-name attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file) + (concat "attachment:" (match-string 1 file))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (concat "attachment:" (match-string 1 (expand-file-name file)))) + (t (concat "attachment:" file))))) + +(defun org-attach-export-link (link description format) + "Translate attachment LINK from Org mode format to exported FORMAT. +Also includes the DESCRIPTION of the link in the export." + (save-excursion + (let (path desc) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 9cb396fe9..42fe64379 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -263,6 +263,9 @@ Counting starts at 1." (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays 'org-clear-latex-preview "Org 9.3") +(define-obsolete-variable-alias 'org-attach-directory + 'org-attach-id-dir "Org 9.3") + (defun org-in-fixed-width-region-p () "Non-nil if point in a fixed-width region." (save-match-data diff --git a/lisp/org.el b/lisp/org.el index f0e7c3ab8..10b8babe5 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -3849,7 +3849,9 @@ This is needed for font-lock setup.") (beg end)) (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) (declare-function org-agenda-skip "org-agenda" ()) -(declare-function org-attach-reveal "org-attach" (&optional if-exists)) +(declare-function org-attach-expand "org-attach" (file)) +(declare-function org-attach-reveal "org-attach" ()) +(declare-function org-attach-reveal-in-emacs "org-attach" ()) (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) (declare-function org-indent-mode "org-indent" (&optional arg)) (declare-function org-inlinetask-goto-beginning "org-inlinetask" ()) @@ -8647,12 +8649,15 @@ a link." (pcase (org-offer-links-in-entry (current-buffer) (point) arg) (`(nil . ,_) (require 'org-attach) - (org-attach-reveal 'if-exists)) + (message "Opening attachment-dir") + (if (equal arg '(4)) + (org-attach-reveal-in-emacs) + (org-attach-reveal))) (`(,links . ,links-end) (dolist (link (if (stringp links) (list links) links)) (search-forward link nil links-end) (goto-char (match-beginning 0)) - (org-open-at-point)))))) + (org-open-at-point arg)))))) ;; On a footnote reference or at definition's label. ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) @@ -16632,13 +16637,14 @@ boundaries." ;; "file:" links. Also check link abbreviations since ;; some might expand to "file" links. (file-types-re - (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" + (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" (if (not link-abbrevs) "" (concat "\\|" (regexp-opt link-abbrevs)))))) (while (re-search-forward file-types-re end t) (let* ((link (org-element-lineage (save-match-data (org-element-context)) '(link) t)) + (linktype (org-element-property :type link)) (inner-start (match-beginning 1)) (path (cond @@ -16652,7 +16658,8 @@ boundaries." ;; INCLUDE-LINKED is non-nil. ((or (not (org-element-property :contents-begin link)) include-linked) - (and (equal "file" (org-element-property :type link)) + (and (or (equal "file" linktype) + (equal "attachment" linktype)) (org-element-property :path link))) ;; Link with a description. Check if description ;; is a filename. Even if Org doesn't have syntax @@ -16671,7 +16678,11 @@ boundaries." (match-end 0)) (match-string 2))))))) (when (and path (string-match-p file-extension-re path)) - (let ((file (expand-file-name path))) + (let ((file (if (equal "attachment" linktype) + (progn + (require 'org-attach) + (org-attach-expand path)) + (expand-file-name path)))) (when (file-exists-p file) (let ((width ;; Apply `org-image-actual-width' specifications. diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA new file mode 100644 index 000000000..9a0406c0d --- /dev/null +++ b/testing/examples/att1/fileA @@ -0,0 +1 @@ +Text in fileA diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB new file mode 100644 index 000000000..dd2331824 --- /dev/null +++ b/testing/examples/att1/fileB @@ -0,0 +1 @@ +Text in fileB diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC new file mode 100644 index 000000000..2c9a92bfe --- /dev/null +++ b/testing/examples/att2/fileC @@ -0,0 +1 @@ +Text in fileC \ No newline at end of file diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD new file mode 100644 index 000000000..c706556c5 --- /dev/null +++ b/testing/examples/att2/fileD @@ -0,0 +1 @@ +text in fileD diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org new file mode 100644 index 000000000..ab4a4e548 --- /dev/null +++ b/testing/examples/attachments.org @@ -0,0 +1,32 @@ +#+TITLE: Org attach testfile +Used to test and verify the functionality of org-attach. + +* H1 + :PROPERTIES: + :DIR: att1 + :END: +A link to one attachment: [[attachment:fileA]] + +** H1.1 +A link to another attachment: [[attachment:fileB]] + +** H1.2 + :PROPERTIES: + :DIR: att2 + :END: + +* H2 + :PROPERTIES: + :ID: abcd123 + :END: + +* H3 + :PROPERTIES: + :DIR: att1 + :ID: abcd1234 + :END: + +** H3.1 + :PROPERTIES: + :ID: abcd12345 + :END: diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE new file mode 100644 index 000000000..80d337772 --- /dev/null +++ b/testing/examples/data/ab/cd123/fileE @@ -0,0 +1 @@ +peek-a-boo diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el similarity index 93% rename from testing/lisp/test-org-attach-annex.el rename to testing/lisp/test-org-attach-git.el index 7f2792696..8b826b72f 100644 --- a/testing/lisp/test-org-attach-annex.el +++ b/testing/lisp/test-org-attach-git.el @@ -20,19 +20,19 @@ ;;; Code: (org-test-for-executable "git-annex") -(require 'org-attach) +(require 'org-attach-git) (require 'cl-lib) -(defmacro test-org-attach-annex/with-annex (&rest body) +(defmacro test-org-attach-git/with-annex (&rest body) `(let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (shell-command "git annex init") ,@body)))) -(ert-deftest test-org-attach/use-annex () +(ert-deftest test-org-attach-git/use-annex () (test-org-attach-annex/with-annex (let ((org-attach-git-annex-cutoff 1)) (should (org-attach-use-annex))) @@ -44,12 +44,12 @@ (let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (should-not (org-attach-use-annex))) (delete-directory tmpdir 'recursive)))) -(ert-deftest test-org-attach/get-maybe () +(ert-deftest test-org-attach-git/get-maybe () (test-org-attach-annex/with-annex (let ((path (expand-file-name "test-file")) (annex-dup (make-temp-file "org-annex-test" t "/"))) diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el index c2f2be356..02fd05032 100644 --- a/testing/lisp/test-org-attach.el +++ b/testing/lisp/test-org-attach.el @@ -28,6 +28,56 @@ (require 'org-attach) (eval-and-compile (require 'cl-lib)) +(ert-deftest test-org-attach/dir () + "Test `org-attach-get' specifications." + (org-test-in-example-file org-test-attachments-file + ;; Link inside H1 + (org-next-link) + (save-excursion + (org-open-at-point) + (should (equal "Text in fileA\n" (buffer-string)))) + ;; * H1.1 + (org-next-visible-heading 1) + (let ((org-attach-use-inheritance nil)) + (should-not (equal "att1" (org-attach-dir)))) + (let ((org-attach-use-inheritance t)) + (should (equal "att1" (org-attach-dir)))) + ;; Link inside H1.1 + (org-next-link) + (save-excursion + (let ((org-attach-use-inheritance nil)) + (org-open-at-point) + (should-not (equal "Text in fileB\n" (buffer-string))))) + (save-excursion + (let ((org-attach-use-inheritance t)) + (org-open-at-point) + (should (equal "Text in fileB\n" (buffer-string))))) + ;; * H1.2 + (org-next-visible-heading 1) + (should (equal '("fileC" "fileD") (org-attach-file-list (org-attach-dir)))) + ;; * H2 + (org-next-visible-heading 1) + (let ((org-attach-id-dir "data/")) + (should (equal '("fileE") (org-attach-file-list (org-attach-dir)))) + (save-excursion + (org-attach-open-in-emacs) + (should (equal "peek-a-boo\n" (buffer-string))))) + ;; * H3 + (org-next-visible-heading 1) + ;; DIR has priority over ID + (should (equal '("fileA" "fileB") (org-attach-file-list (org-attach-dir)))) + ;; * H3.1 + (org-next-visible-heading 1) + (let ((org-attach-use-inheritance nil)) + (should (equal "data/ab/cd12345" (file-relative-name (org-attach-dir))))) + (let ((org-attach-use-inheritance t)) + ;; This is where it get's a bit sketchy...! DIR always has + ;; priority over ID, even if ID is declared "higher up" in the + ;; tree. This can potentially be revised. But it is also + ;; pretty clean. DIR is always higher in priority than ID right + ;; now, no matter the depth in the tree. + (should (equal '("fileA" "fileB") (org-attach-file-list (org-attach-dir))))))) + (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 () "Attach file at point in dired to subtree." (should diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index d671b5c78..a618da479 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2514,7 +2514,11 @@ Foo Bar (catch :result (cl-letf (((symbol-function 'org-tags-view) (lambda (&rest args) (throw :result t)))) - (org-open-at-point) + ;; When point isn't on a tag it's going to try other things, + ;; possibly trying to open attachments which will return an + ;; error if there isn't an attachment. Supress that error. + (ignore-errors + (org-open-at-point)) nil))))) \f diff --git a/testing/org-test.el b/testing/org-test.el index 6b218fc00..6d216bc28 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.") (defconst org-test-no-heading-file (expand-file-name "no-heading.org" org-test-example-dir)) +(defconst org-test-attachments-file + (expand-file-name "attachments.org" org-test-example-dir)) + (defconst org-test-link-in-heading-file (expand-file-name "link-in-heading.org" org-test-dir)) -- 2.17.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-05-26 23:05 ` Gustav Wikström @ 2019-06-15 13:29 ` Nicolas Goaziou 2019-06-15 15:38 ` Bastien 2019-06-30 6:03 ` Gustav Wikström 0 siblings, 2 replies; 113+ messages in thread From: Nicolas Goaziou @ 2019-06-15 13:29 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien Guerry, emacs-orgmode Hello, Gustav Wikström <gustav@whil.se> writes: > Some updates, and a fresh patch...! Thank you. > > I won't say that much here since the patch speaks for itself (It > contains a chapter to be added to ORG-NEWS). It's patch 0002 that is the > important one. See sidenote below for a comment about patch 0001. > > I have to mention that the patch has grown quite a lot. With the > Additional changes, I've taken the liberty to promote attachments to a > level-1 headline within the documentation! Hmm. I don't think it should be a top-level information. More on this below. > Inheriting ID's for attachments is actually valuable. It makes it possible, > for example, to add attachment-links in subheadings to the node the > attachment is defined on. After having used this for quite some time now it > feels quite natural to have inheritance switched on for attachments. No negative > side-effects at all. OK. > (Sidenote 1; what do I need to do to gain access to the official > git-repository? Would be nice to be able to provide pull requests there!) Pull requests are not the preferred way to interact with the project. However, I think you should have write access to the repository. I'm Cc'ing Bastien about it, as I cannot do it myself. > (Sidenote 2; The first patch is some minor unrelated fixups - it > breaks test-org-export/expand-include as a side-effect. But that's probably > because the test doesn't do what it should! 😲 ) Probably. Yet, we should do something about it. If you cannot fix it, at least please comment it out somehow. > (should > (equal > "1" > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > - (org-entry-get (point) "A" t)))) > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > + (org-entry-get (point-max) "A" t)))) Not that it is wrong, but I don't see the benefit of this change. > (should > (equal > "1" > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" Ditto. > (let ((org-use-property-inheritance t)) > - (org-entry-get (point) "A" 'selective))))) > + (org-entry-get (point-max) "A" 'selective))))) Ditto. > (should-not > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > (let ((org-use-property-inheritance nil)) > - (org-entry-get (point) "A" 'selective)))) > + (org-entry-get (point-max) "A" 'selective)))) Ditto. > (defmacro org-test-with-temp-text-in-file (text &rest body) > - "Run body in a temporary file buffer with Org mode as the active mode." > + "Run body in a temporary file buffer with Org mode as the active mode. > +If the string \"<point>\" appears in TEXT then remove it and > +place the point there before running BODY, otherwise place the > +point at the beginning of the buffer." > (declare (indent 1)) > (let ((results (cl-gensym))) > `(let ((file (make-temp-file "org-test")) > @@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text." > ,results) > (with-temp-file file (insert inside-text)) > (find-file file) > + (when (re-search-forward "<point>" nil t) > + (replace-match "")) > (org-mode) > (setq ,results (progn ,@body)) > (save-buffer) (kill-buffer (current-buffer)) While we're at fixing this macro, we may also wrap stuff within `unwind-protect' so as to properly delete temporary files in any cases. > From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> > Date: Sun, 25 Nov 2018 21:38:44 +0100 > Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, > testing/**/test-org-attach* > > * org-attach.el > > Changed the way attachments deal with property-inheritance. It now > adheres to the =org-use-property-inheritance= setting by default but > it can be customized if needed (I recommend to enable it!). > The property ATTACH_DIR is depricated in favour of the shorter and simpler > property DIR. depricated -> deprecated > * org-manual.org > > Attachments have been promoted into its own top-level node! There are > a lot of goodies to mention here that didn't fit naturally with > "capture" and "archive" before. This is true, but there is not enough information to require a top-level node. Here is a suggestion. Split "Capture, Refile, Archive" into two parts: 1. Refile, Copy and Archiving in one place, because they all relate to moving existing data around 2. Capture, Attachments, RSS Feeds, Protocols in another place, because they all insert external data to the system. WDYT? > +File links and attachment links can contain additional information to Since attachment links are file links, it seems redundant to talk about both everywhere. Just clarify clearly once that attachments links are file links for all purposes. > +It is often useful to associate reference material with an outline > +node/task. I would use "node" only: it is more generic. > +The attachment system has been contributed to Org by John Wiegley. I would drop this reference, since John Wiegley is already mentioned in the Thanks entry. > +** Attachment defaults and dispatcher > +By default, org-attach will use ID properties when adding attachments > +to outline nodes. This makes working with attachments fully > +automated. There is no decision needed for folder-name or location. > +ID-based directories are by default located in the =data/= directory, > +which lives in the same directory where your Org file lives[fn:87]. > +For more control over the setup, see [[*Attachment options]]. > + > +When attachments are made using ~org-attach~ a default tag =ATTACH= is > +added to the node that gets the attachments. Note overly important, but we prefer the active voice whenever possible. > + #+begin_example > + ,* Chapter A ... > + :PROPERTIES: > + :DIR: Chapter A/ > + :END: > + ,** Introduction > + Some text > + > + #+NAME: Image 1 > + [[Attachment:image 1.jpg]] > + #+end_example > + > + Without inheritance one would not be able to resolve the link to image > + 1.jpg, since the link is inside a sub-heading to Chapter A. =1.jpg= ... =Chapter A= > + Inheritance works the same way for both =ID= and =DIR= property. If > + both properties are defined on the same headline then =DIR= takes > + precedance. This is also true if inheritance is enabled. If =DIR= is > + inherited from a parent node in the outline, that property still takes > + precedence over an =ID= property defined on the node itself. > + > +- ~org-attach-method~ :: > + #+vindex: org-attach-method > + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it > + defaults to copying files. The behaviour can be changed by > + customizing ~org-attach-method~. Options are =Copy=, =Move/Rename=, > + =Hard link= or =Symbolic link=. I don't think =...= are warranted here. > +- ~org-attach-preferred-new-method~ :: > + #+vindex: org-attach-preferred-new-method > + This customization lets you choose the default way to attach to > + nodes without existing ID and DIR property. It defaults to =id= but > + can also be set to =dir=, =ask= or =nil=. ~id~, ~dir~ ~ask~ or ~nil~, since those are symbols. > + Do not show the splash buffer with the attach dispatcher when > + ~org-attach-expert~ is set to Non-nil. non-~nil~ > +** Attachment links > +Attached files and folders can be referenced using attachment-links. Why the hyphen in "attachment-links"? I think "attachment links" is perfectly clear. > +This makes it easy to refer to the material added to an outline node. > +Especially if it was attached using the unique ID of the entry! > + > +#+begin_example > +,* TODO Some task > + :PROPERTIES: > + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 > + :END: > +See attached document for more information: [[attachment:info.org]] > +#+end_example > + > +See [[* External Links]] for more information about these links. No need for the space: [[*External Links]] > +** Automatic version-control with git Shouldn't it be "Git"? > +If the directory attached to an outline node is a git repository, Org Ditto. > +can be configured to automatically commit changes to that repository > +when it sees them. > + > +To make org-mode take care of versioning of attachments for you, add To make Org mode... > +(defcustom org-attach-dir-relative nil > + "Choose whether directories in DIR property should be added as relative links or not. > +Defaults to absolute location." First line is too long, maybe: Non-nil means directories in DIR property are added as relative links > -(defcustom org-attach-annex-auto-get 'ask > - "Confirmation preference for automatically getting annex files. > -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." > +(defun org-attach-id-folder-format (id) > + (format "%s/%s" > + (substring id 0 2) > + (substring id 2)) > + ) No dangling parens, please. Also, this function needs a docstring. > +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format > + "The function parsing the ID parameter into a folder-path" Missing full stop. Also: "Function parsing..." > :group 'org-attach > - :package-version '(Org . "9.0") > - :version "26.1" > - :type '(choice > - (const :tag "confirm with `y-or-n-p'" ask) > - (const :tag "always get from annex if necessary" t) > - (const :tag "never get from annex" nil))) > + :package-version '(Org . "9.3") > + :type 'function > + ) See above. > + "Return the directory associated with the current outline node. > +First check for DIR property, then ID property. > +`org-attach-use-inheritance' determines whether inherited > +properties also will be considered. > + > +If an ID property is found the default mechanism using that ID > +will be invoked to access the directory for the current entry. > + > +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' > +is run." > + (if create-if-not-exists-p > + (org-attach-dir-get-create) Could you merge the `if' within the `cond' below? > + (let (attach-dir id) > + (cond > + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) > + (org-attach-check-absolute-path attach-dir)) > + ;; Depricated and removed from documentation, but still Deprecated. Also, please add a FIXME. > + (if attach-dir > + (progn (if (not (file-directory-p attach-dir)) > + (make-directory attach-dir t)) > + (if (file-exists-p attach-dir) > + attach-dir > + (error "Path does not exist: %s." attach-dir))) > + (error "No attachment directory is associated with the current node.")))) (unless attach-dir (error "No attachment ... current node")) (unless (file-directory-p attach-dir) (make-directory ...)) attach-dir Note that error messages never end with a full stop in Emacs. Also, I don't see how the inner error could trigger since you create the directory just before, and it would already have returned an error if that wasn't possible. > - (shell-command (format "rm -fr %s" attach-dir)) > + (when (and attach-dir > + (or force > + (y-or-n-p "Are you sure you want to remove all > attachments of this entry? "))) Maybe the less mouthful: "Really remove all attachments of this entry? " Also, what about using `yes-or-no-p' since this looks a sensitive operation? > + (org-attach-tag (not files)))) > + (when (not attach-dir) > + (org-attach-tag t)))) (unless attach-dir (org-attach-tag t)) > + (interactive) > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (org-open-file attach-dir) > + (error "No attachment directory exist.")))) See above: no full stop at the end of error messages. > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (dired attach-dir) > + (error "No attachment directory exist.")))) Ditto. > > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (let* ((files (org-attach-file-list attach-dir)) > + (file (if (= (length files) 1) > + (car files) > + (completing-read "Open attachment: " > + (mapcar #'list files) nil t))) I think a `pcase' is warranted here: (pcase (org-attach-file-list attach-dir) (`(,file) file) (files (completing-read ...))) > + (path (expand-file-name file attach-dir))) > + (run-hook-with-args 'org-attach-open-hook path) > + (org-open-file path in-emacs)) > + (error "No attachment directory exist.")))) Ahem. :) > diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA Would it be possible to use `org-test-with-temp-text-in file instead of creating files? > +(ert-deftest test-org-attach/dir () > + "Test `org-attach-get' specifications." > + (org-test-in-example-file org-test-attachments-file > + ;; Link inside H1 > + (org-next-link) > + (save-excursion > + (org-open-at-point) > + (should (equal "Text in fileA\n" (buffer-string)))) Please move `should' in the outermost part of the sexp, if possible. It makes debugging easier (i.e., evaluating the sexp without getting `should' in the way). I probably missed a few things, but it keeps the ball rolling. Thank you again for all the hard work. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-06-15 13:29 ` Nicolas Goaziou @ 2019-06-15 15:38 ` Bastien 2019-06-30 6:03 ` Gustav Wikström 1 sibling, 0 replies; 113+ messages in thread From: Bastien @ 2019-06-15 15:38 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode Hi Gustav, thanks a lot for your contribution! Please register as a user on https://code.orgmode.org then send me your username in a private email, I'll then add you to the list of people with push access. Thanks, -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-06-15 13:29 ` Nicolas Goaziou 2019-06-15 15:38 ` Bastien @ 2019-06-30 6:03 ` Gustav Wikström 2019-07-06 21:46 ` Nicolas Goaziou 1 sibling, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-06-30 6:03 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 15614 bytes --] Hi, Thanks! > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 15 juni 2019 15:29 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode <emacs-orgmode@gnu.org>; Bastien Guerry <bzg@gnu.org> > Subject: Re: [RFC] Link-type for attachments, more attach options > > (Sidenote 2; The first patch is some minor unrelated fixups - it > > breaks test-org-export/expand-include as a side-effect. But that's probably > > because the test doesn't do what it should! 😲 ) > > Probably. Yet, we should do something about it. If you cannot fix it, at > least please comment it out somehow. Looked at it a few more minutes. The error comes from the fix of org-test-with-temp-text-in-file, where it previously didn't work with point. It does now, which means the test-specification was wrong. The test should compare to 2 instead of 1 since the inserted node will be one level above the current headline. > > (should > > (equal > > "1" > > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > > - (org-entry-get (point) "A" t)))) > > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > > + (org-entry-get (point-max) "A" t)))) > > Not that it is wrong, but I don't see the benefit of this change. No real benefit except that it now matches other tests that was also defined. I spent a few minutes wondering why some was specified in one way and the others another way. Realized there was no reason and thought to save those minutes for the next person who might wonder the same thing. > > (defmacro org-test-with-temp-text-in-file (text &rest body) > > - "Run body in a temporary file buffer with Org mode as the active mode." > > + "Run body in a temporary file buffer with Org mode as the active mode. > > +If the string \"<point>\" appears in TEXT then remove it and > > +place the point there before running BODY, otherwise place the > > +point at the beginning of the buffer." > > (declare (indent 1)) > > (let ((results (cl-gensym))) > > `(let ((file (make-temp-file "org-test")) > > @@ -207,6 +210,8 @@ otherwise place the point at the beginning of the inserted text." > > ,results) > > (with-temp-file file (insert inside-text)) > > (find-file file) > > + (when (re-search-forward "<point>" nil t) > > + (replace-match "")) > > (org-mode) > > (setq ,results (progn ,@body)) > > (save-buffer) (kill-buffer (current-buffer)) > > While we're at fixing this macro, we may also wrap stuff within > `unwind-protect' so as to properly delete temporary files in any cases. Ok, tried to do that. Maybe added a few to many guardrails but it should work as intended. > > From 0180a900f890b2053d8184116c99c62cfa083055 Mon Sep 17 00:00:00 2001 > > From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> > > Date: Sun, 25 Nov 2018 21:38:44 +0100 > > Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, > > testing/**/test-org-attach* > > > > * org-attach.el > > > > Changed the way attachments deal with property-inheritance. It now > > adheres to the =org-use-property-inheritance= setting by default but > > it can be customized if needed (I recommend to enable it!). > > The property ATTACH_DIR is depricated in favour of the shorter and simpler > > property DIR. > > depricated -> deprecated Whops! Fixed > > * org-manual.org > > > > Attachments have been promoted into its own top-level node! There are > > a lot of goodies to mention here that didn't fit naturally with > > "capture" and "archive" before. > > This is true, but there is not enough information to require a top-level > node. > > Here is a suggestion. Split "Capture, Refile, Archive" into two parts: > > 1. Refile, Copy and Archiving in one place, because they all relate to > moving existing data around > > 2. Capture, Attachments, RSS Feeds, Protocols in another place, because > they all insert external data to the system. > > WDYT? Fair enough. Modified the manual to match that suggestion. > > +File links and attachment links can contain additional information to > > Since attachment links are file links, it seems redundant to talk about > both everywhere. Just clarify clearly once that attachments links are > file links for all purposes. Modified it a bit to make it read better. I do think it's worth having small notes that search options apply also for attachment links. But I agree that we don't need to mention it everywhere. > > +It is often useful to associate reference material with an outline > > +node/task. > > I would use "node" only: it is more generic. Agreed, fixed. > > +The attachment system has been contributed to Org by John Wiegley. > > I would drop this reference, since John Wiegley is already mentioned in > the Thanks entry. Ok, fixed. > > +** Attachment defaults and dispatcher > > +By default, org-attach will use ID properties when adding attachments > > +to outline nodes. This makes working with attachments fully > > +automated. There is no decision needed for folder-name or location. > > +ID-based directories are by default located in the =data/= directory, > > +which lives in the same directory where your Org file lives[fn:87]. > > +For more control over the setup, see [[*Attachment options]]. > > + > > +When attachments are made using ~org-attach~ a default tag =ATTACH= is > > +added to the node that gets the attachments. > > Note overly important, but we prefer the active voice whenever possible. Can't say I really understand what was meant with this. > > + #+begin_example > > + ,* Chapter A ... > > + :PROPERTIES: > > + :DIR: Chapter A/ > > + :END: > > + ,** Introduction > > + Some text > > + > > + #+NAME: Image 1 > > + [[Attachment:image 1.jpg]] > > + #+end_example > > + > > + Without inheritance one would not be able to resolve the link to image > > + 1.jpg, since the link is inside a sub-heading to Chapter A. > > =1.jpg= ... =Chapter A= Fixed. > > + Inheritance works the same way for both =ID= and =DIR= property. If > > + both properties are defined on the same headline then =DIR= takes > > + precedance. This is also true if inheritance is enabled. If =DIR= is > > + inherited from a parent node in the outline, that property still takes > > + precedence over an =ID= property defined on the node itself. > > + > > +- ~org-attach-method~ :: > > + #+vindex: org-attach-method > > + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it > > + defaults to copying files. The behaviour can be changed by > > + customizing ~org-attach-method~. Options are =Copy=, =Move/Rename=, > > + =Hard link= or =Symbolic link=. > > I don't think =...= are warranted here. Ok, fixed. > > > +- ~org-attach-preferred-new-method~ :: > > + #+vindex: org-attach-preferred-new-method > > + This customization lets you choose the default way to attach to > > + nodes without existing ID and DIR property. It defaults to =id= but > > + can also be set to =dir=, =ask= or =nil=. > > ~id~, ~dir~ ~ask~ or ~nil~, since those are symbols. Fixed. > > + Do not show the splash buffer with the attach dispatcher when > > + ~org-attach-expert~ is set to Non-nil. > > non-~nil~ Fixed. > > +** Attachment links > > +Attached files and folders can be referenced using attachment-links. > > Why the hyphen in "attachment-links"? I think "attachment links" is > perfectly clear. Fixed. > > +This makes it easy to refer to the material added to an outline node. > > +Especially if it was attached using the unique ID of the entry! > > + > > +#+begin_example > > +,* TODO Some task > > + :PROPERTIES: > > + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 > > + :END: > > +See attached document for more information: [[attachment:info.org]] > > +#+end_example > > + > > +See [[* External Links]] for more information about these links. > > No need for the space: [[*External Links]] > > > +** Automatic version-control with git > > Shouldn't it be "Git"? Maybe...? Changed now anyways. > > +If the directory attached to an outline node is a git repository, Org > > Ditto. Changed. > > +can be configured to automatically commit changes to that repository > > +when it sees them. > > + > > +To make org-mode take care of versioning of attachments for you, add > > To make Org mode... Fixed. > > +(defcustom org-attach-dir-relative nil > > + "Choose whether directories in DIR property should be added as relative links or not. > > +Defaults to absolute location." > > First line is too long, maybe: > > Non-nil means directories in DIR property are added as relative links > Fixed. > > -(defcustom org-attach-annex-auto-get 'ask > > - "Confirmation preference for automatically getting annex files. > > -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." > > +(defun org-attach-id-folder-format (id) > > + (format "%s/%s" > > + (substring id 0 2) > > + (substring id 2)) > > + ) > > No dangling parens, please. Also, this function needs a docstring. Ah, ofc. > > +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format > > + "The function parsing the ID parameter into a folder-path" > > Missing full stop. Also: "Function parsing..." > > > :group 'org-attach > > - :package-version '(Org . "9.0") > > - :version "26.1" > > - :type '(choice > > - (const :tag "confirm with `y-or-n-p'" ask) > > - (const :tag "always get from annex if necessary" t) > > - (const :tag "never get from annex" nil))) > > + :package-version '(Org . "9.3") > > + :type 'function > > + ) > > See above. Fixed. > > + "Return the directory associated with the current outline node. > > +First check for DIR property, then ID property. > > +`org-attach-use-inheritance' determines whether inherited > > +properties also will be considered. > > + > > +If an ID property is found the default mechanism using that ID > > +will be invoked to access the directory for the current entry. > > + > > +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' > > +is run." > > + (if create-if-not-exists-p > > + (org-attach-dir-get-create) > > Could you merge the `if' within the `cond' below? Done. > > + (let (attach-dir id) > > + (cond > > + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) > > + (org-attach-check-absolute-path attach-dir)) > > + ;; Depricated and removed from documentation, but still > > Deprecated. Also, please add a FIXME. Fixed and added. > > + (if attach-dir > > + (progn (if (not (file-directory-p attach-dir)) > > + (make-directory attach-dir t)) > > + (if (file-exists-p attach-dir) > > + attach-dir > > + (error "Path does not exist: %s." attach-dir))) > > + (error "No attachment directory is associated with the current node.")))) > > (unless attach-dir (error "No attachment ... current node")) > (unless (file-directory-p attach-dir) (make-directory ...)) > attach-dir > > Note that error messages never end with a full stop in Emacs. Also, > I don't see how the inner error could trigger since you create the > directory just before, and it would already have returned an error if > that wasn't possible. Ok, got it. Fixed. Removed inner error as well as I agree with your conclusion. Tried to think of why it was added but couldn't remember any reason. > > - (shell-command (format "rm -fr %s" attach-dir)) > > + (when (and attach-dir > > + (or force > > + (y-or-n-p "Are you sure you want to remove all > > attachments of this entry? "))) > > Maybe the less mouthful: > > "Really remove all attachments of this entry? " > Good suggestion, fixed. > Also, what about using `yes-or-no-p' since this looks a sensitive operation? Agreed! Didn't think of that. > > + (org-attach-tag (not files)))) > > + (when (not attach-dir) > > + (org-attach-tag t)))) > > (unless attach-dir (org-attach-tag t)) Fixed. > > + (interactive) > > + (let ((attach-dir (org-attach-dir))) > > + (if attach-dir > > + (org-open-file attach-dir) > > + (error "No attachment directory exist.")))) > > See above: no full stop at the end of error messages. Fixed. > > + (let ((attach-dir (org-attach-dir))) > > + (if attach-dir > > + (dired attach-dir) > > + (error "No attachment directory exist.")))) > > Ditto. Fixed > > + (let ((attach-dir (org-attach-dir))) > > + (if attach-dir > > + (let* ((files (org-attach-file-list attach-dir)) > > + (file (if (= (length files) 1) > > + (car files) > > + (completing-read "Open attachment: " > > + (mapcar #'list files) nil t))) > > I think a `pcase' is warranted here: > > (pcase (org-attach-file-list attach-dir) > (`(,file) file) > (files (completing-read ...))) > And so I learnt something new. Pattern matching in emacs, didn't think of that. Changed. Can't really say that the code will be easier to understand now. But for those familiar with pcase I'm sure it looks nicer. > > + (path (expand-file-name file attach-dir))) > > + (run-hook-with-args 'org-attach-open-hook path) > > + (org-open-file path in-emacs)) > > + (error "No attachment directory exist.")))) > > Ahem. :) Yeah. Fixed the full stop. > > > diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA > > Would it be possible to use `org-test-with-temp-text-in file instead of > creating files? I couldn't think of a good way since I wanted to test relations between an org-mode document and it's attachments. I would need to dynamically create both org-mode files and it's attachment and link them in the filesystem somehow... That wasn't intuitive for me so I chose this solution instead. > > +(ert-deftest test-org-attach/dir () > > + "Test `org-attach-get' specifications." > > + (org-test-in-example-file org-test-attachments-file > > + ;; Link inside H1 > > + (org-next-link) > > + (save-excursion > > + (org-open-at-point) > > + (should (equal "Text in fileA\n" (buffer-string)))) > > Please move `should' in the outermost part of the sexp, if possible. It > makes debugging easier (i.e., evaluating the sexp without getting > `should' in the way). Ok, did that. I agree - it reads better. To get this to work better I made a slight change in org-test-in-example-file as well. Added to patch 0001 since that change isn't really related to attachments but rather a general improvement. One might also argue that this particular test should be split up. I Agree with that, but would like that to not be a stopper for this first patch. > I probably missed a few things, but it keeps the ball rolling. I've added a few fixes to the patch myself. I haven't kept track of the changes though, since I'm trying to keep the patch together in one commit (well... two in this case). > Thank you again for all the hard work. And thank you for the review. Bastien gave me access to the Git repository. Let me know how you want to proceed with this patch. Kind regards Gustav Wikström [-- Attachment #2: 0002-org-attach-org-org-manual-org-news-testing-test-org-.patch --] [-- Type: application/octet-stream, Size: 106611 bytes --] From ce40b082d106231a8306e60e9509b8be76a0189f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 25 Nov 2018 21:38:44 +0100 Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, testing/**/test-org-attach* * org-attach.el Changed the way attachments deal with property-inheritance. It now adheres to the =org-use-property-inheritance= setting by default but it can be customized if needed (I recommend to enable it!). The property ATTACH_DIR is deprecated in favour of the shorter and simpler property DIR. Added an explicit option to =org-attach= for unsetting attachment-directories (i.e. remove DIR property and deal with the attachments by interaction). Added attachment link type with the prefix "attachment:". Added customizations: - org-attach-dir-relative - org-attach-preferred-new-method - org-attach-use-inheritance - org-attach-id-to-path-function Hooks added: - org-attach-after-change-hook - org-attach-open-hook * Add new linktype "attachment" for attachments A new linktype "attachment" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID and DIR properties. The goal is to make the functionality for attachment links mirror the functionality for file links. * org-attach-git.el New file, existing functionality. Code here has been factored out from org-attach.el and if GIT-functionality is to be used this module needs to be required sepatately. It extends org-attach by use of its hooks. Activating git functionality in org-attach is done by loading org-attach-git from now on, instead of customizing a variable. Naming of both functions and tests has been modified to match the move of functionality into its own module. * org.el Inline images are shown also using attachment-links, exactly the same as it works for file-links today. Make org-open-at-point respect ARG when opening attachment-dir. * org-compat.el org-attach-directory has been deprecated in favour for org-attach-id-dir. The new name matches its purpose better. * org-manual.org The chapter "Refile, Copy, Archive" has been split into two separate chapters. - "Refile, Copy and Archiving" for information related to moving existing data around. - "Capture, Attachments, RSS Feeds and Protocols" for information related to working with external data. The attachment-part has been rewritten and extended to match the changes in this patch. The new attachment link type is mentioned both inside the attachments chapter and in the chapter dealing with links. Documentation related to external links has been improved. * testing/lisp/test-org-attach-annex.el Require org-attach-git instead of org-attach, since this file tests the GIT-functionality. * testing/org-test.el Define a symbol for a file to test attachments with. * testing/examples/* A bunch of new example files and folders are created and are used in testing of org-attach to verify its functionality. --- doc/org-manual.org | 1079 ++++++++++------- etc/ORG-NEWS | 93 ++ lisp/org-attach-git.el | 118 ++ lisp/org-attach.el | 563 +++++---- lisp/org-compat.el | 3 + lisp/org.el | 23 +- testing/examples/att1/fileA | 1 + testing/examples/att1/fileB | 1 + testing/examples/att2/fileC | 1 + testing/examples/att2/fileD | 1 + testing/examples/attachments.org | 32 + testing/examples/data/ab/cd123/fileE | 1 + ...attach-annex.el => test-org-attach-git.el} | 12 +- testing/lisp/test-org-attach.el | 69 ++ testing/lisp/test-org.el | 6 +- testing/org-test.el | 3 + 16 files changed, 1307 insertions(+), 699 deletions(-) create mode 100644 lisp/org-attach-git.el create mode 100644 testing/examples/att1/fileA create mode 100644 testing/examples/att1/fileB create mode 100644 testing/examples/att2/fileC create mode 100644 testing/examples/att2/fileD create mode 100644 testing/examples/attachments.org create mode 100644 testing/examples/data/ab/cd123/fileE rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%) diff --git a/doc/org-manual.org b/doc/org-manual.org index 469e16402..801cca617 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3068,6 +3068,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: attachment links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3079,38 +3080,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. - -| =http://www.astro.uva.nl/=dominik= | on the web | -| =doi:10.1000/182= | DOI for an electronic resource | -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | -| =/home/dominik/images/jupiter.jpg= | same as above | -| =file:papers/last.pdf= | file, relative path | -| =./papers/last.pdf= | same as above | -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | -| =/ssh:me@some.where:papers/last.pdf= | same as above | -| =file:sometextfile::NNN= | file, jump to line number | -| =file:projects.org= | another Org file | -| =file:projects.org::some words= | text search in Org file[fn:27] | -| =file:projects.org::*task title= | heading search in Org file | -| =file+sys:/path/to/file= | open via OS, like double-click | -| =file+emacs:/path/to/file= | force opening by Emacs | -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | -| =news:comp.emacs= | Usenet link | -| =mailto:adent@galaxy.net= | mail link | -| =mhe:folder= | MH-E folder link | -| =mhe:folder#id= | MH-E message link | -| =rmail:folder= | Rmail folder link | -| =rmail:folder#id= | Rmail message link | -| =gnus:group= | Gnus group link | -| =gnus:group#id= | Gnus article link | -| =bbdb:R.*Stallman= | BBDB link (with regexp) | -| =irc:/irc.com/#emacs/bob= | IRC link | -| =info:org#External links= | Info node link | -| =shell:ls *.org= | shell command | -| =elisp:org-agenda= | interactive Elisp command | -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | +the colon. + +Here is the full set of built-in link types: + +- =file= :: + + File links. File name may be remote, absolute, or relative. + + Additionally, you can specify a line number, or a text search. + In Org files, you may link to a headline name, a custom ID, or a + code reference instead. + + As a special case, "file" prefix may be omitted if the file name + is complete, e.g., it starts with =./=, or =/=. + +- =attachment= :: + + Same as file links but for files and folders attached to the current + node (see [[*Attachments]]). Attachment links are intended to behave + exactly as file links but for files relative to the attachment + directory. + +- =bbdb= :: + + Link to a BBDB record, with possible regexp completion. + +- =docview= :: + + Link to a document opened with DocView mode. You may specify a page + number. + +- =doi= :: + + Link to an electronic ressource, through its handle. + +- =elisp= :: + + Execute an Elisp command upon activation. + +- =gnus=, =rmail=, =mhe= :: + + Links to messages or folders from a given Emacs' MUA. + +- =http=, =https= :: + + Web links. + +- =id= :: + + Link to a specific headline by its ID property, in an Org file. + +- =info= :: + + Link to an Info manual, or to a specific node. + +- =irc= :: + + Link to an IRC channel. + +- =mailto= :: + + Link to message composition. + +- =news= :: + + Usenet links. + +- =shell= :: + + Execute a shell command upon activation. + +The following table illustrates the link types above, along with their +options: + +| Link Type | Example | +|------------+----------------------------------------------------------| +| http | =http://www.astro.uva.nl/=dominik= | +| https | =https://orgmode.org/= | +| doi | =doi:10.1000/182= | +| file | =file:/home/dominik/images/jupiter.jpg= | +| | =/home/dominik/images/jupiter.jpg= (same as above) | +| | =file:papers/last.pdf= | +| | =./papers/last.pdf= (same as above) | +| | =file:/ssh:me@some.where:papers/last.pdf= (remote) | +| | =/ssh:me@some.where:papers/last.pdf= (same as above) | +| | =file:sometextfile::NNN= (jump to line number) | +| | =file:projects.org= | +| | =file:projects.org::some words= (text search) [fn:28] | +| | =file:projects.org::*task title= (headline search) | +| | =file:projects.org::#custom-id= (headline search) | +| attachment | =attachment:projects.org= | +| | =attachment:projects.org::some words= (text search) | +| docview | =docview:papers/last.pdf::NNN= | +| id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | +| news | =news:comp.emacs= | +| mailto | =mailto:adent@galaxy.net= | +| mhe | =mhe:folder= (folder link) | +| | =mhe:folder#id= (message link) | +| rmail | =rmail:folder= (folder link) | +| | =rmail:folder#id= (message link) | +| gnus | =gnus:group= (group link) | +| | =gnus:group#id= (article link) | +| bbdb | =bbdb:R.*Stallman= (record with regexp) | +| irc | =irc:/irc.com/#emacs/bob= | +| info | =info:org#External links= | +| shell | =shell:ls *.org= | +| elisp | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) | +| | =elisp:org-agenda= (interactive Elisp command) | #+cindex: VM links #+cindex: Wanderlust links @@ -3462,15 +3539,19 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: attachment links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:34]. For +File links can contain additional information to make Emacs jump to a +particular location in the file when following a link. This can be a +line number or a search option after a double colon[fn:34]. For example, when the command ~org-store-link~ creates a link (see [[*Handling Links]]) to a file, it encodes the words in the current line as a search string that can be used to find this line back later when following the link with {{{kbd(C-c C-o)}}}. +Note that all search options apply for Attachment links in the same +way that they apply for File links. + Here is the syntax of the different ways to attach a search to a file link, together with explanations for each: @@ -3480,6 +3561,7 @@ link, together with explanations for each: [[file:~/xx.org::*My Target]] [[file:~/xx.org::#my-custom-id]] [[file:~/xx.org::/regexp/]] +[[attachment:main.c::255]] #+end_example - =255= :: @@ -6893,163 +6975,420 @@ same commands. continue the old one. This command also removes the timer from the mode line. -* Capture, Refile, Archive -:PROPERTIES: -:DESCRIPTION: The ins and outs for projects. -:END: -#+cindex: capture - -An important part of any organization system is the ability to quickly -capture new ideas and tasks, and to associate reference material with -them. Org does this using a process called /capture/. It also can -store files related to a task (/attachments/) in a special directory. -Once in the system, tasks and projects need to be moved around. -Moving completed project trees to an archive file keeps the system -compact and fast. - -** Capture +* Refile, Copy and Archiving :PROPERTIES: -:DESCRIPTION: Capturing new stuff. +:DESCRIPTION: Moving and copying information with ease. :END: -#+cindex: capture +#+cindex: refiling notes +#+cindex: copying notes +#+cindex: archiving -Capture lets you quickly store notes with little interruption of your -work flow. Org's method for capturing new items is heavily inspired -by John Wiegley's excellent Remember package. +Once information is in the system, it may need to be moved around. +Org provides Refile, Copy and Archive commands for this. Refile and +Copy helps with moving and copying outlines. Archiving helps to keep +the system compact and fast. -*** Setting up capture +** Refile and Copy :PROPERTIES: -:DESCRIPTION: Where notes will be stored. +:DESCRIPTION: Moving/copying a tree from one place to another. :END: +#+cindex: refiling notes +#+cindex: copying notes -The following customization sets a default target file for notes. +When reviewing the captured data, you may want to refile or to copy +some of the entries into a different list, for example into a project. +Cutting, finding the right location, and then pasting the note is +cumbersome. To simplify this process, you can use the following +special command: -#+vindex: org-default-notes-file -#+begin_src emacs-lisp -(setq org-default-notes-file (concat org-directory "/notes.org")) -#+end_src +- {{{kbd(C-c C-w)}}} (~org-refile~) :: -You may also define a global key for capturing new material (see -[[*Activation]]). + #+kindex: C-c C-w + #+findex: org-refile + #+vindex: org-reverse-note-order + #+vindex: org-refile-targets + #+vindex: org-refile-use-outline-path + #+vindex: org-outline-path-complete-in-steps + #+vindex: org-refile-allow-creating-parent-nodes + #+vindex: org-log-refile + Refile the entry or region at point. This command offers possible + locations for refiling the entry and lets you select one with + completion. The item (or all items in the region) is filed below + the target heading as a subitem. Depending on + ~org-reverse-note-order~, it is either the first or last subitem. -*** Using capture -:PROPERTIES: -:DESCRIPTION: Commands to invoke and terminate capture. -:END: + By default, all level 1 headlines in the current buffer are + considered to be targets, but you can have more complex definitions + across a number of files. See the variable ~org-refile-targets~ for + details. If you would like to select a location via + a file-path-like completion along the outline path, see the + variables ~org-refile-use-outline-path~ and + ~org-outline-path-complete-in-steps~. If you would like to be able + to create new nodes as new parents for refiling on the fly, check + the variable ~org-refile-allow-creating-parent-nodes~. When the + variable ~org-log-refile~[fn:88] is set, a timestamp or a note is + recorded whenever an entry is refiled. -- {{{kbd(M-x org-capture)}}} (~org-capture~) :: +- {{{kbd(C-u C-c C-w)}}} :: - #+findex: org-capture - #+cindex: date tree - Display the capture templates menu. If you have templates defined - (see [[*Capture templates]]), it offers these templates for selection or - use a new Org outline node as the default template. It inserts the - template into the target file and switch to an indirect buffer - narrowed to this new node. You may then insert the information you - want. + #+kindex: C-u C-c C-w + Use the refile interface to jump to a heading. -- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: +- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: - #+kindex: C-c C-c @r{(Capture buffer)} - #+findex: org-capture-finalize - Once you have finished entering information into the capture buffer, - {{{kbd(C-c C-c)}}} returns you to the window configuration before - the capture process, so that you can resume your work without - further distraction. When called with a prefix argument, finalize - and then jump to the captured item. + #+kindex: C-u C-u C-c C-w + #+findex: org-refile-goto-last-stored + Jump to the location where ~org-refile~ last moved a tree to. -- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: +- {{{kbd(C-2 C-c C-w)}}} :: - #+kindex: C-c C-w @r{(Capture buffer)} - #+findex: org-capture-refile - Finalize the capture process by refiling the note to a different - place (see [[*Refile and Copy]]). Please realize that this is a normal - refiling command that will be executed---so point position at the - moment you run this command is important. If you have inserted - a tree with a parent and children, first move point back to the - parent. Any prefix argument given to this command is passed on to - the ~org-refile~ command. + #+kindex: C-2 C-c C-w + Refile as the child of the item currently being clocked. -- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: +- {{{kbd(C-3 C-c C-w)}}} :: - #+kindex: C-c C-k @r{(Capture buffer)} - #+findex: org-capture-kill - Abort the capture process and return to the previous state. + #+kindex: C-3 C-c C-w + #+vindex: org-refile-keep + Refile and keep the entry in place. Also see ~org-refile-keep~ to + make this the default behavior, and beware that this may result in + duplicated =ID= properties. -#+kindex: k c @r{(Agenda)} -You can also call ~org-capture~ in a special way from the agenda, -using the {{{kbd(k c)}}} key combination. With this access, any -timestamps inserted by the selected capture template defaults to the -date at point in the agenda, rather than to the current date. +- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: -To find the locations of the last stored capture, use ~org-capture~ -with prefix commands: + #+kindex: C-u C-u C-u C-c C-w + #+kindex: C-0 C-c C-w + #+findex: org-refile-cache-clear + #+vindex: org-refile-use-cache + Clear the target cache. Caching of refile targets can be turned on + by setting ~org-refile-use-cache~. To make the command see new + possible targets, you have to clear the cache with this command. -- {{{kbd(C-u M-x org-capture)}}} :: +- {{{kbd(C-c M-w)}}} (~org-copy~) :: - Visit the target location of a capture template. You get to select - the template in the usual way. + #+kindex: C-c M-w + #+findex: org-copy + Copying works like refiling, except that the original note is not + deleted. -- {{{kbd(C-u C-u M-x org-capture)}}} :: +** Archiving +:PROPERTIES: +:DESCRIPTION: What to do with finished products. +:END: +#+cindex: archiving - Visit the last stored capture item in its buffer. +When a project represented by a (sub)tree is finished, you may want to +move the tree out of the way and to stop it from contributing to the +agenda. Archiving is important to keep your working files compact and +global searches like the construction of agenda views fast. -#+vindex: org-capture-bookmark -#+vindex: org-capture-last-stored -You can also jump to the bookmark ~org-capture-last-stored~, which is -automatically created unless you set ~org-capture-bookmark~ to ~nil~. +- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: -To insert the capture at point in an Org buffer, call ~org-capture~ -with a {{{kbd(C-0)}}} prefix argument. + #+kindex: C-c C-x C-a + #+findex: org-archive-subtree-default + #+vindex: org-archive-default-command + Archive the current entry using the command specified in the + variable ~org-archive-default-command~. -*** Capture templates +*** Moving a tree to an archive file :PROPERTIES: -:DESCRIPTION: Define the outline of different note types. +:DESCRIPTION: Moving a tree to an archive file. +:ALT_TITLE: Moving subtrees :END: -#+cindex: templates, for Capture - -You can use templates for different types of capture items, and for -different target locations. The easiest way to create such templates -is through the customize interface. +#+cindex: external archiving -- {{{kbd(C)}}} :: +The most common archiving action is to move a project tree to another +file, the archive file. - #+kindex: C @r{(Capture menu} - #+vindex: org-capture-templates - Customize the variable ~org-capture-templates~. +- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: -Before we give the formal description of template definitions, let's -look at an example. Say you would like to use one template to create -general TODO entries, and you want to put these entries under the -heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in -the file =journal.org= should capture journal entries. A possible -configuration would look like: + #+kindex: C-c C-x C-s + #+kindex: C-c $ + #+findex: org-archive-subtree + #+vindex: org-archive-location + Archive the subtree starting at point position to the location given + by ~org-archive-location~. -#+begin_src emacs-lisp -(setq org-capture-templates - '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") - "* TODO %?\n %i\n %a") - ("j" "Journal" entry (file+datetree "~/org/journal.org") - "* %?\nEntered on %U\n %i\n %a"))) -#+end_src +- {{{kbd(C-u C-c C-x C-s)}}} :: -If you then press {{{kbd(t)}}} from the capture menu, Org will prepare -the template for you like this: + #+kindex: C-u C-c C-x C-s + Check if any direct children of the current headline could be moved + to the archive. To do this, check each subtree for open TODO + entries. If none is found, the command offers to move it to the + archive location. If point is /not/ on a headline when this command + is invoked, check level 1 trees. -#+begin_example -,* TODO - [[file:LINK TO WHERE YOU INITIATED CAPTURE]] -#+end_example +- {{{kbd(C-u C-u C-c C-x C-s)}}} :: -#+texinfo: @noindent -During expansion of the template, =%a= has been replaced by a link to -the location from where you called the capture command. This can be -extremely useful for deriving tasks from emails, for example. You -fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns -you to the same place where you started the capture process. + #+kindex: C-u C-u C-c C-x C-s + As above, but check subtree for timestamps instead of TODO entries. + The command offers to archive the subtree if it /does/ contain + a timestamp, and that timestamp is in the past. -To define special keys to capture to a particular template without -going through the interactive template selection, you can create your +#+cindex: archive locations +The default archive location is a file in the same directory as the +current file, with the name derived by appending =_archive= to the +current file name. You can also choose what heading to file archived +items under, with the possibility to add them to a datetree in a file. +For information and examples on how to specify the file and the +heading, see the documentation string of the variable +~org-archive-location~. + +There is also an in-buffer option for setting this variable, for +example: + +#+cindex: @samp{ARCHIVE}, keyword +: #+ARCHIVE: %s_done:: + +#+cindex: ARCHIVE, property +If you would like to have a special archive location for a single +entry or a (sub)tree, give the entry an =ARCHIVE= property with the +location as the value (see [[*Properties and Columns]]). + +#+vindex: org-archive-save-context-info +When a subtree is moved, it receives a number of special properties +that record context information like the file from where the entry +came, its outline path the archiving time etc. Configure the variable +~org-archive-save-context-info~ to adjust the amount of information +added. + +*** Internal archiving +:PROPERTIES: +:DESCRIPTION: Switch off a tree but keep it in the file. +:END: + +#+cindex: @samp{ARCHIVE}, tag +If you want to just switch off---for agenda views---certain subtrees +without moving them to a different file, you can use the =ARCHIVE= +tag. + +A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at +its location in the outline tree, but behaves in the following way: + +- + #+vindex: org-cycle-open-archived-trees + It does not open when you attempt to do so with a visibility cycling + command (see [[*Visibility Cycling]]). You can force cycling archived + subtrees with {{{kbd(C-TAB)}}}, or by setting the option + ~org-cycle-open-archived-trees~. Also normal outline commands, like + ~outline-show-all~, open archived subtrees. + +- + #+vindex: org-sparse-tree-open-archived-trees + During sparse tree construction (see [[*Sparse Trees]]), matches in + archived subtrees are not exposed, unless you configure the option + ~org-sparse-tree-open-archived-trees~. + +- + #+vindex: org-agenda-skip-archived-trees + During agenda view construction (see [[*Agenda Views]]), the content of + archived trees is ignored unless you configure the option + ~org-agenda-skip-archived-trees~, in which case these trees are + always included. In the agenda you can press {{{kbd(v a)}}} to get + archives temporarily included. + +- + #+vindex: org-export-with-archived-trees + Archived trees are not exported (see [[*Exporting]]), only the headline + is. Configure the details using the variable + ~org-export-with-archived-trees~. + +- + #+vindex: org-columns-skip-archived-trees + Archived trees are excluded from column view unless the variable + ~org-columns-skip-archived-trees~ is configured to ~nil~. + +The following commands help manage the =ARCHIVE= tag: + +- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: + + #+kindex: C-c C-x a + #+findex: org-toggle-archive-tag + Toggle the archive tag for the current headline. When the tag is + set, the headline changes to a shadowed face, and the subtree below + it is hidden. + +- {{{kbd(C-u C-c C-x a)}}} :: + + #+kindex: C-u C-c C-x a + Check if any direct children of the current headline should be + archived. To do this, check each subtree for open TODO entries. If + none is found, the command offers to set the =ARCHIVE= tag for the + child. If point is /not/ on a headline when this command is + invoked, check the level 1 trees. + +- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: + + #+kindex: C-TAB + Cycle a tree even if it is tagged with =ARCHIVE=. + +- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: + + #+kindex: C-c C-x A + #+findex: org-archive-to-archive-sibling + Move the current entry to the /Archive Sibling/. This is a sibling + of the entry with the heading =Archive= and the archive tag. The + entry becomes a child of that sibling and in this way retains a lot + of its original context, including inherited tags and approximate + position in the outline. + +* Capture, Attachments, RSS Feeds and Protocols +:PROPERTIES: +:DESCRIPTION: Dealing with external data. +:END: +#+cindex: capture +#+cindex: attachments +#+cindex: RSS feeds +#+cindex: Atom feeds +#+cindex: protocols, for external access + +An important part of any organization system is the ability to quickly +capture new ideas and tasks, and to associate reference material with +them. Org does this using a process called /capture/. It also can +store files related to a task (/attachments/) in a special directory. + +** Capture +:PROPERTIES: +:DESCRIPTION: Capturing new stuff. +:END: +#+cindex: capture + +Capture lets you quickly store notes with little interruption of your +work flow. Org's method for capturing new items is heavily inspired +by John Wiegley's excellent Remember package. + +*** Setting up capture +:PROPERTIES: +:DESCRIPTION: Where notes will be stored. +:END: + +The following customization sets a default target file for notes. + +#+vindex: org-default-notes-file +#+begin_src emacs-lisp +(setq org-default-notes-file (concat org-directory "/notes.org")) +#+end_src + +You may also define a global key for capturing new material (see +[[*Activation]]). + +*** Using capture +:PROPERTIES: +:DESCRIPTION: Commands to invoke and terminate capture. +:END: + +- {{{kbd(M-x org-capture)}}} (~org-capture~) :: + + #+findex: org-capture + #+cindex: date tree + Display the capture templates menu. If you have templates defined + (see [[*Capture templates]]), it offers these templates for selection or + use a new Org outline node as the default template. It inserts the + template into the target file and switch to an indirect buffer + narrowed to this new node. You may then insert the information you + want. + +- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: + + #+kindex: C-c C-c @r{(Capture buffer)} + #+findex: org-capture-finalize + Once you have finished entering information into the capture buffer, + {{{kbd(C-c C-c)}}} returns you to the window configuration before + the capture process, so that you can resume your work without + further distraction. When called with a prefix argument, finalize + and then jump to the captured item. + +- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: + + #+kindex: C-c C-w @r{(Capture buffer)} + #+findex: org-capture-refile + Finalize the capture process by refiling the note to a different + place (see [[*Refile and Copy]]). Please realize that this is a normal + refiling command that will be executed---so point position at the + moment you run this command is important. If you have inserted + a tree with a parent and children, first move point back to the + parent. Any prefix argument given to this command is passed on to + the ~org-refile~ command. + +- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: + + #+kindex: C-c C-k @r{(Capture buffer)} + #+findex: org-capture-kill + Abort the capture process and return to the previous state. + +#+kindex: k c @r{(Agenda)} +You can also call ~org-capture~ in a special way from the agenda, +using the {{{kbd(k c)}}} key combination. With this access, any +timestamps inserted by the selected capture template defaults to the +date at point in the agenda, rather than to the current date. + +To find the locations of the last stored capture, use ~org-capture~ +with prefix commands: + +- {{{kbd(C-u M-x org-capture)}}} :: + + Visit the target location of a capture template. You get to select + the template in the usual way. + +- {{{kbd(C-u C-u M-x org-capture)}}} :: + + Visit the last stored capture item in its buffer. + +#+vindex: org-capture-bookmark +#+vindex: org-capture-last-stored +You can also jump to the bookmark ~org-capture-last-stored~, which is +automatically created unless you set ~org-capture-bookmark~ to ~nil~. + +To insert the capture at point in an Org buffer, call ~org-capture~ +with a {{{kbd(C-0)}}} prefix argument. + +*** Capture templates +:PROPERTIES: +:DESCRIPTION: Define the outline of different note types. +:END: +#+cindex: templates, for Capture + +You can use templates for different types of capture items, and for +different target locations. The easiest way to create such templates +is through the customize interface. + +- {{{kbd(C)}}} :: + + #+kindex: C @r{(Capture menu} + #+vindex: org-capture-templates + Customize the variable ~org-capture-templates~. + +Before we give the formal description of template definitions, let's +look at an example. Say you would like to use one template to create +general TODO entries, and you want to put these entries under the +heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in +the file =journal.org= should capture journal entries. A possible +configuration would look like: + +#+begin_src emacs-lisp +(setq org-capture-templates + '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") + "* TODO %?\n %i\n %a") + ("j" "Journal" entry (file+datetree "~/org/journal.org") + "* %?\nEntered on %U\n %i\n %a"))) +#+end_src + +If you then press {{{kbd(t)}}} from the capture menu, Org will prepare +the template for you like this: + +#+begin_example +,* TODO + [[file:LINK TO WHERE YOU INITIATED CAPTURE]] +#+end_example + +#+texinfo: @noindent +During expansion of the template, =%a= has been replaced by a link to +the location from where you called the capture command. This can be +extremely useful for deriving tasks from emails, for example. You +fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns +you to the same place where you started the capture process. + +To define special keys to capture to a particular template without +going through the interactive template selection, you can create your key binding like this: #+begin_src emacs-lisp @@ -7434,28 +7773,30 @@ See the docstring of the variable for more information. ** Attachments :PROPERTIES: -:DESCRIPTION: Add files to tasks. +:DESCRIPTION: Attach files to outlines. :END: #+cindex: attachments -#+vindex: org-attach-directory It is often useful to associate reference material with an outline -node/task. Small chunks of plain text can simply be stored in the -subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish -associations with files that live elsewhere on your computer or in the -cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -=data/= directory which lives in the same directory where your Org -file lives[fn:87]. If you initialize this directory with =git init=, -Org automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. +node. Small chunks of plain text can simply be stored in the subtree +of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations +with files that live elsewhere on your computer or in the cloud, like +emails or source code files belonging to a project. + +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by a unique ID of each entry, or by a =DIR= property. + +*** Attachment defaults and dispatcher +By default, org-attach will use ID properties when adding attachments +to outline nodes. This makes working with attachments fully +automated. There is no decision needed for folder-name or location. +ID-based directories are by default located in the =data/= directory, +which lives in the same directory where your Org file lives[fn:87]. +For more control over the setup, see [[*Attachment options]]. + +When attachments are made using ~org-attach~ a default tag =ATTACH= is +added to the node that gets the attachments. The following commands deal with attachments: @@ -7540,25 +7881,144 @@ The following commands deal with attachments: - {{{kbd(D)}}} (~org-attach-delete-all~) :: - #+kindex: C-c C-a D - Delete all of a task's attachments. A safer way is to open the - directory in Dired and delete from there. + #+kindex: C-c C-a D + Delete all of a task's attachments. A safer way is to open the + directory in Dired and delete from there. + + - {{{kbd(s)}}} (~org-attach-set-directory~) :: + + #+kindex: C-c C-a s + #+cindex: @samp{DIR}, property + Set a specific directory as the entry's attachment directory. + This works by putting the directory path into the =DIR= + property. + + - {{{kbd(S)}}} (~org-attach-unset-directory~) :: + + #+kindex: C-c C-a S + #+cindex: @samp{DIR}, property + Remove the attachment directory. This command removes the =DIR= + property and asks the user to either move content inside that + folder, if an =ID= property is set, delete the content, or to + leave the attachment directory as is but no longer attached to the + outline node. + +*** Attachment options +There are a couple of options for attachments that are worth +mentioning. + +- ~org-attach-id-dir~ :: + #+vindex: org-attach-id-dir + The directory where attachments are stored when =ID= is used as + method. + +- ~org-attach-dir-relative~ :: + #+vindex: org-attach-dir-relative + When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}} + (~org-attach-set-directory~), absolute links are entered by default. + This option changes that to relative links. + +- ~org-attach-use-inheritance~ :: + #+vindex: org-attach-use-inheritance + By default folders attached to an outline node are inherited from + parents according to ~org-use-property-inheritance~. If one instead + want to set inheritance specifically for org-attach that can be done + using ~org-attach-use-inheritance~. Inheriting documents through + the node hierarchy makes a lot of sense in most cases. Especially + since the introduction of [[* Attachment links]]. The following example + shows one use case for attachment inheritance: + + #+begin_example + ,* Chapter A ... + :PROPERTIES: + :DIR: Chapter A/ + :END: + ,** Introduction + Some text + + #+NAME: Image 1 + [[Attachment:image 1.jpg]] + #+end_example + + Without inheritance one would not be able to resolve the link to + image =1.jpg=, since the link is inside a sub-heading to =Chapter + A=. + + Inheritance works the same way for both =ID= and =DIR= property. If + both properties are defined on the same headline then =DIR= takes + precedance. This is also true if inheritance is enabled. If =DIR= + is inherited from a parent node in the outline, that property still + takes precedence over an =ID= property defined on the node itself. + +- ~org-attach-method~ :: + #+vindex: org-attach-method + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it + defaults to copying files. The behaviour can be changed by + customizing ~org-attach-method~. Options are Copy, Move/Rename, + Hard link or Symbolic link. + +- ~org-attach-preferred-new-method~ :: + #+vindex: org-attach-preferred-new-method + This customization lets you choose the default way to attach to + nodes without existing =ID= and =DIR= property. It defaults to ~id~ + but can also be set to ~dir~, ~ask~ or ~nil~. + +- ~org-attach-archive-delete~ :: + #+vindex: org-attach-archive-delete + Configure this to determine if attachments should be deleted or not + when a subtree that has attachments is archived. + +- ~org-attach-auto-tag~ :: + #+vindex: org-attach-auto-tag + When attaching files to a heading it will be assigned a tag + according to what is set here. + +- ~org-attach-id-to-path-function~ :: + #+vindex: org-attach-id-to-path-function + When =ID= is used for attachments, the ID is parsed into a part of a + directory-path. See ~org-attach-id-folder-format~ for the default + function. Define a new one and add it to + ~org-attach-id-to-path-function~ if you want the folder structure + any other way. Note that modifying this makes org-attach dependent + on your function also for opening attachments, not only setting + them! + +- ~org-attach-expert~ :: + #+vindex: org-attach-expert + Do not show the splash buffer with the attach dispatcher when + ~org-attach-expert~ is set to non-~nil~. + +See customization group =Org Attach= if you want to change the +default settings. + +*** Attachment links +Attached files and folders can be referenced using attachment links. +This makes it easy to refer to the material added to an outline node. +Especially if it was attached using the unique ID of the entry! + +#+begin_example +,* TODO Some task + :PROPERTIES: + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 + :END: +See attached document for more information: [[attachment:info.org]] +#+end_example - - {{{kbd(s)}}} (~org-attach-set-directory~) :: +See [[*External Links]] for more information about these links. - #+kindex: C-c C-a s - #+cindex: @samp{ATTACH_DIR}, property - Set a specific directory as the entry's attachment directory. - This works by putting the directory path into the =ATTACH_DIR= - property. +*** Automatic version-control with Git +If the directory attached to an outline node is a Git repository, Org +can be configured to automatically commit changes to that repository +when it sees them. - - {{{kbd(i)}}} (~org-attach-set-inherit~) :: +To make Org mode take care of versioning of attachments for you, add +the following to your Emacs config: - #+kindex: C-c C-a i - #+cindex: @samp{ATTACH_DIR_INHERIT}, property - Set the =ATTACH_DIR_INHERIT= property, so that children use the - same directory for attachments as the parent does. +#+begin_src emacs-lisp + (require 'org-attach-git) +#+end_src +*** Attach from Dired #+cindex: attach from Dired #+findex: org-attach-dired-to-subtree It is possible to attach files to a subtree from a Dired buffer. To @@ -7829,249 +8289,6 @@ valid contents: ~org-protocol-create~ and ~org-protocol-create-for-org~. The latter is of use if you're editing an Org file that is part of a publishing project. -** Refile and Copy -:PROPERTIES: -:DESCRIPTION: Moving/copying a tree from one place to another. -:END: -#+cindex: refiling notes -#+cindex: copying notes - -When reviewing the captured data, you may want to refile or to copy -some of the entries into a different list, for example into a project. -Cutting, finding the right location, and then pasting the note is -cumbersome. To simplify this process, you can use the following -special command: - -- {{{kbd(C-c C-w)}}} (~org-refile~) :: - - #+kindex: C-c C-w - #+findex: org-refile - #+vindex: org-reverse-note-order - #+vindex: org-refile-targets - #+vindex: org-refile-use-outline-path - #+vindex: org-outline-path-complete-in-steps - #+vindex: org-refile-allow-creating-parent-nodes - #+vindex: org-log-refile - Refile the entry or region at point. This command offers possible - locations for refiling the entry and lets you select one with - completion. The item (or all items in the region) is filed below - the target heading as a subitem. Depending on - ~org-reverse-note-order~, it is either the first or last subitem. - - By default, all level 1 headlines in the current buffer are - considered to be targets, but you can have more complex definitions - across a number of files. See the variable ~org-refile-targets~ for - details. If you would like to select a location via - a file-path-like completion along the outline path, see the - variables ~org-refile-use-outline-path~ and - ~org-outline-path-complete-in-steps~. If you would like to be able - to create new nodes as new parents for refiling on the fly, check - the variable ~org-refile-allow-creating-parent-nodes~. When the - variable ~org-log-refile~[fn:88] is set, a timestamp or a note is - recorded whenever an entry is refiled. - -- {{{kbd(C-u C-c C-w)}}} :: - - #+kindex: C-u C-c C-w - Use the refile interface to jump to a heading. - -- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: - - #+kindex: C-u C-u C-c C-w - #+findex: org-refile-goto-last-stored - Jump to the location where ~org-refile~ last moved a tree to. - -- {{{kbd(C-2 C-c C-w)}}} :: - - #+kindex: C-2 C-c C-w - Refile as the child of the item currently being clocked. - -- {{{kbd(C-3 C-c C-w)}}} :: - - #+kindex: C-3 C-c C-w - #+vindex: org-refile-keep - Refile and keep the entry in place. Also see ~org-refile-keep~ to - make this the default behavior, and beware that this may result in - duplicated =ID= properties. - -- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: - - #+kindex: C-u C-u C-u C-c C-w - #+kindex: C-0 C-c C-w - #+findex: org-refile-cache-clear - #+vindex: org-refile-use-cache - Clear the target cache. Caching of refile targets can be turned on - by setting ~org-refile-use-cache~. To make the command see new - possible targets, you have to clear the cache with this command. - -- {{{kbd(C-c M-w)}}} (~org-copy~) :: - - #+kindex: C-c M-w - #+findex: org-copy - Copying works like refiling, except that the original note is not - deleted. - -** Archiving -:PROPERTIES: -:DESCRIPTION: What to do with finished products. -:END: -#+cindex: archiving - -When a project represented by a (sub)tree is finished, you may want to -move the tree out of the way and to stop it from contributing to the -agenda. Archiving is important to keep your working files compact and -global searches like the construction of agenda views fast. - -- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: - - #+kindex: C-c C-x C-a - #+findex: org-archive-subtree-default - #+vindex: org-archive-default-command - Archive the current entry using the command specified in the - variable ~org-archive-default-command~. - -*** Moving a tree to an archive file -:PROPERTIES: -:DESCRIPTION: Moving a tree to an archive file. -:ALT_TITLE: Moving subtrees -:END: -#+cindex: external archiving - -The most common archiving action is to move a project tree to another -file, the archive file. - -- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: - - #+kindex: C-c C-x C-s - #+kindex: C-c $ - #+findex: org-archive-subtree - #+vindex: org-archive-location - Archive the subtree starting at point position to the location given - by ~org-archive-location~. - -- {{{kbd(C-u C-c C-x C-s)}}} :: - - #+kindex: C-u C-c C-x C-s - Check if any direct children of the current headline could be moved - to the archive. To do this, check each subtree for open TODO - entries. If none is found, the command offers to move it to the - archive location. If point is /not/ on a headline when this command - is invoked, check level 1 trees. - -- {{{kbd(C-u C-u C-c C-x C-s)}}} :: - - #+kindex: C-u C-u C-c C-x C-s - As above, but check subtree for timestamps instead of TODO entries. - The command offers to archive the subtree if it /does/ contain - a timestamp, and that timestamp is in the past. - -#+cindex: archive locations -The default archive location is a file in the same directory as the -current file, with the name derived by appending =_archive= to the -current file name. You can also choose what heading to file archived -items under, with the possibility to add them to a datetree in a file. -For information and examples on how to specify the file and the -heading, see the documentation string of the variable -~org-archive-location~. - -There is also an in-buffer option for setting this variable, for -example: - -#+cindex: @samp{ARCHIVE}, keyword -: #+ARCHIVE: %s_done:: - -#+cindex: ARCHIVE, property -If you would like to have a special archive location for a single -entry or a (sub)tree, give the entry an =ARCHIVE= property with the -location as the value (see [[*Properties and Columns]]). - -#+vindex: org-archive-save-context-info -When a subtree is moved, it receives a number of special properties -that record context information like the file from where the entry -came, its outline path the archiving time etc. Configure the variable -~org-archive-save-context-info~ to adjust the amount of information -added. - -*** Internal archiving -:PROPERTIES: -:DESCRIPTION: Switch off a tree but keep it in the file. -:END: - -#+cindex: @samp{ARCHIVE}, tag -If you want to just switch off---for agenda views---certain subtrees -without moving them to a different file, you can use the =ARCHIVE= -tag. - -A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at -its location in the outline tree, but behaves in the following way: - -- - #+vindex: org-cycle-open-archived-trees - It does not open when you attempt to do so with a visibility cycling - command (see [[*Visibility Cycling]]). You can force cycling archived - subtrees with {{{kbd(C-TAB)}}}, or by setting the option - ~org-cycle-open-archived-trees~. Also normal outline commands, like - ~outline-show-all~, open archived subtrees. - -- - #+vindex: org-sparse-tree-open-archived-trees - During sparse tree construction (see [[*Sparse Trees]]), matches in - archived subtrees are not exposed, unless you configure the option - ~org-sparse-tree-open-archived-trees~. - -- - #+vindex: org-agenda-skip-archived-trees - During agenda view construction (see [[*Agenda Views]]), the content of - archived trees is ignored unless you configure the option - ~org-agenda-skip-archived-trees~, in which case these trees are - always included. In the agenda you can press {{{kbd(v a)}}} to get - archives temporarily included. - -- - #+vindex: org-export-with-archived-trees - Archived trees are not exported (see [[*Exporting]]), only the headline - is. Configure the details using the variable - ~org-export-with-archived-trees~. - -- - #+vindex: org-columns-skip-archived-trees - Archived trees are excluded from column view unless the variable - ~org-columns-skip-archived-trees~ is configured to ~nil~. - -The following commands help manage the =ARCHIVE= tag: - -- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: - - #+kindex: C-c C-x a - #+findex: org-toggle-archive-tag - Toggle the archive tag for the current headline. When the tag is - set, the headline changes to a shadowed face, and the subtree below - it is hidden. - -- {{{kbd(C-u C-c C-x a)}}} :: - - #+kindex: C-u C-c C-x a - Check if any direct children of the current headline should be - archived. To do this, check each subtree for open TODO entries. If - none is found, the command offers to set the =ARCHIVE= tag for the - child. If point is /not/ on a headline when this command is - invoked, check the level 1 trees. - -- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: - - #+kindex: C-TAB - Cycle a tree even if it is tagged with =ARCHIVE=. - -- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: - - #+kindex: C-c C-x A - #+findex: org-archive-to-archive-sibling - Move the current entry to the /Archive Sibling/. This is a sibling - of the entry with the heading =Archive= and the archive tag. The - entry becomes a child of that sibling and in this way retains a lot - of its original context, including inherited tags and approximate - position in the outline. - * Agenda Views :PROPERTIES: :DESCRIPTION: Collecting information into views. @@ -21241,7 +21458,7 @@ accessed in capture templates in a similar way. ~org-link-from-user-regexp~. [fn:87] If you move entries or Org files from one directory to -another, you may want to configure ~org-attach-directory~ to contain +another, you may want to configure ~org-attach-id-dir~ to contain an absolute path. [fn:88] Note the corresponding =STARTUP= options =logrefile=, diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 95358ca7b..4d5c11c3c 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI alternative was removed and there is no more a :use-xcolor options since now it's implicitly always true. +*** Org-Attach Git commit +[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality. Not +much, but the following changes are required if you still need to +auto-commit attachments to git: + +- Customization of ~org-attach-annex-auto-get~ needs to be renamed to + ~org-attach-git-annex-auto-get~. + +- Customization of ~org-attach-commit~ is no longer needed. Instead + one need to require the =org-attach-git= module in the startup. + ** New features +*** Org-Attach has been refactored and extended +Org attach has been refactored and the functionality extended. It +should now be easier to understand how it works. A few improvements +and extra options have been added as well. + +From the initial comment in org-attach source-code: + +- Attachments are managed either by using a custom property DIR or by + using property ID from org-id. When DIR is defined, a location in + the filesystem is directly attached to the outline node. When + org-id is used, attachments are stored in a folder named after the + ID, in a location defined by ~org-attach-id-dir~. DIR has + precedence over ID when both parameters are defined for the current + outline node (also when inherited parameters are taken into + account). + +From now on inheritance requires no extra property and will adhere to +~org-attach-use-inheritance~ by default. Inheritance can be +customized to always be activated or never be activated in +~org-attach-use-inheritance~. + +The ATTACH_DIR property is deprecated in favour of the shorter +property DIR. Links to folders inside the DIR property can now be +declared as relative links. This is not enabled by default, but can +be set in ~org-attach-dir-relative~. + +When adding new attachment to the outline node the preferred way of +doing so can be customized. Take a look at +~org-attach-preferred-new-method~. It defaults to using ID since that +was the behaviour before this change. + +If both DIR and ID properties are set on the same node, DIR has +precedence and will be used. + +One can now also choose to build attachment-directory-paths in a +customized way. This is an advanced topic, but in some case it makes +sense to parse an ID in a different way than the default one. Create +your own function and use it is ~org-attach-id-to-path-function~ if +you want to customize the ID-based folder structure. + +If you've used ATTACH_DIR properties to manage attachments, use the +following code to rename that property to DIR which supports the same +functionality. ATTACH_DIR_INHERIT is no longer supported and is +removed. + +#+begin_src emacs-lisp + (defun org-update-attach-properties () + "Change properties for Org-Attach." + (interactive) + (org-with-point-at 1 + (while (outline-next-heading) + (let ((DIR (org--property-local-values "ATTACH_DIR" nil))) + (when DIR + (org-set-property "DIR" (car DIR)) + (org-delete-property "ATTACH_DIR")))) + (org-delete-property-globally "ATTACH_DIR_INHERIT"))) +#+end_src + +For those who hate breaking changes, even though the changes are made +to clean things up; fear not. ATTACH_DIR will still continue to work. +It's just not documented any longer. When you get the chance, run the +code above to clean things up anyways! + +**** New hooks +Two hooks are added to org-attach: +- org-attach-after-change-hook +- org-attach-open-hook + +They are added mostly for internal restructuring purposes, but can +ofc. be used for other things as well. + +*** New link-type: Attachment +Attachment-links are now first-class citizens. They mimick file-links +in everything they do but use the existing attachment-folder as a base +when expanding the links. Both =DIR= and =ID= properties are used to +try to resolve the links, in exactly the same way as Org-Attach uses +those properties. + *** Handle overlay specification for notes in Beamer export This aligns Beamer notes with slide overlays. @@ -244,6 +333,10 @@ dynamic block in ~org-dynamic-block-alist~. *** ~org-babel-set-current-result-hash~ It was unused throughout the code base. +*** ~org-attach-directory~ + +It has been deprecated in favour of ~org-attach-id-dir~ which is less +ambigous given the restructured org-attach. ** Miscellaneous *** LaTeX preview is simplified diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el new file mode 100644 index 000000000..924d04157 --- /dev/null +++ b/lisp/org-attach-git.el @@ -0,0 +1,118 @@ +;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Free Software Foundation, Inc. + +;; Original Author: John Wiegley <johnw@newartisans.com> +;; Restructurer: Gustav Wikström <gustav@whil.se> +;; Keywords: org data git + +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; An extention to org-attach. If the attachment-directory to an +;; outline node (using either DIR or ID) is initialized as a Git +;; repository, then org-attach-git will automatically commit changes +;; when it sees them. + +;;; Code: + +(require 'org-attach) +(require 'vc-git) + +(defcustom org-attach-git-annex-cutoff (* 32 1024) + "If non-nil, files larger than this will be annexed instead of stored." + :group 'org-attach + :version "24.4" + :package-version '(Org . "8.0") + :type '(choice + (const :tag "None" nil) + (integer :tag "Bytes"))) + +(defcustom org-attach-git-annex-auto-get 'ask + "Confirmation preference for automatically getting annex files. +If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." + :group 'org-attach + :package-version '(Org . "9.0") + :version "26.1" + :type '(choice + (const :tag "confirm with `y-or-n-p'" ask) + (const :tag "always get from annex if necessary" t) + (const :tag "never get from annex" nil))) + +(defun org-attach-git-use-annex () + "Return non-nil if git annex can be used." + (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir)))) + (and org-attach-git-annex-cutoff + (or (file-exists-p (expand-file-name "annex" git-dir)) + (file-exists-p (expand-file-name ".git/annex" git-dir)))))) + +(defun org-attach-git-annex-get-maybe (path) + "Call git annex get PATH (via shell) if using git annex. +Signals an error if the file content is not available and it was not retrieved." + (let* ((default-directory (expand-file-name org-attach-id-dir)) + (path-relative (file-relative-name path))) + (when (and (org-attach-git-use-annex) + (not + (string-equal + "found" + (shell-command-to-string + (format "git annex find --format=found --in=here %s" + (shell-quote-argument path-relative)))))) + (let ((should-get + (if (eq org-attach-git-annex-auto-get 'ask) + (y-or-n-p (format "Run git annex get %s? " path-relative)) + org-attach-git-annex-auto-get))) + (if should-get + (progn (message "Running git annex get \"%s\"." path-relative) + (call-process "git" nil nil nil "annex" "get" path-relative)) + (error "File %s stored in git annex but it is not available, and was not retrieved" + path)))))) + +(defun org-attach-git-commit () + "Commit changes to git if `org-attach-id-dir' is properly initialized. +This checks for the existence of a \".git\" directory in that directory." + (let* ((dir (expand-file-name org-attach-id-dir)) + (git-dir (vc-git-root dir)) + (use-annex (org-attach-git-use-annex)) + (changes 0)) + (when (and git-dir (executable-find "git")) + (with-temp-buffer + (cd dir) + (dolist (new-or-modified + (split-string + (shell-command-to-string + "git ls-files -zmo --exclude-standard") "\0" t)) + (if (and use-annex + (>= (file-attribute-size (file-attributes new-or-modified)) + org-attach-git-annex-cutoff)) + (call-process "git" nil nil nil "annex" "add" new-or-modified) + (call-process "git" nil nil nil "add" new-or-modified)) + (cl-incf changes)) + (dolist (deleted + (split-string + (shell-command-to-string "git ls-files -z --deleted") "\0" t)) + (call-process "git" nil nil nil "rm" deleted) + (cl-incf changes)) + (when (> changes 0) + (shell-command "git commit -m 'Synchronized attachments'")))))) + +(add-hook 'org-attach-after-change-hook 'org-attach-git-commit) +(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe) + +(provide 'org-attach-git) + +;;; org-attach-git.el ends here diff --git a/lisp/org-attach.el b/lisp/org-attach.el index de8b2fc96..c4cdb161c 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -1,9 +1,9 @@ -;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*- +;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*- ;; Copyright (C) 2008-2019 Free Software Foundation, Inc. ;; Author: John Wiegley <johnw@newartisans.com> -;; Keywords: org data task +;; Keywords: org data attachment ;; This file is part of GNU Emacs. ;; @@ -24,32 +24,30 @@ ;; See the Org manual for information on how to use it. ;; -;; Attachments are managed in a special directory called "data", which -;; lives in the same directory as the org file itself. If this data -;; directory is initialized as a Git repository, then org-attach will -;; automatically commit changes when it sees them. -;; -;; Attachment directories are identified using a UUID generated for the -;; task which has the attachments. These are added as property to the -;; task when necessary, and should not be deleted or changed by the -;; user, ever. UUIDs are generated by a mechanism defined in the variable -;; `org-id-method'. +;; Attachments are managed either by using a custom property DIR or by +;; using property ID from org-id. When DIR is defined, a location in +;; the filesystem is directly attached to the outline node. When +;; org-id is used, attachments are stored in a folder named after the +;; ID, in a location defined by `org-attach-id-dir'. DIR has +;; precedence over ID when both parameters are defined for the current +;; outline node (also when inherited parameters are taken into +;; account). ;;; Code: (require 'cl-lib) (require 'org) +(require 'ol) (require 'org-id) -(require 'vc-git) (declare-function dired-dwim-target-directory "dired-aux") (defgroup org-attach nil - "Options concerning entry attachments in Org mode." + "Options concerning attachments in Org mode." :tag "Org Attach" :group 'org) -(defcustom org-attach-directory "data/" +(defcustom org-attach-id-dir "data/" "The directory where attachments are stored. If this is a relative path, it will be interpreted relative to the directory where the Org file lives." @@ -57,22 +55,13 @@ where the Org file lives." :type 'directory :safe #'stringp) -(defcustom org-attach-commit t - "If non-nil commit attachments with git. -This is only done if the Org file is in a git repository." +(defcustom org-attach-dir-relative nil + "Non-nil means directories in DIR property are added as relative links. +Defaults to absolute location." :group 'org-attach :type 'boolean - :version "26.1" - :package-version '(Org . "9.0")) - -(defcustom org-attach-git-annex-cutoff (* 32 1024) - "If non-nil, files larger than this will be annexed instead of stored." - :group 'org-attach - :version "24.4" - :package-version '(Org . "8.0") - :type '(choice - (const :tag "None" nil) - (integer :tag "Bytes"))) + :package-version '(Org . "9.3") + :safe #'booleanp) (defcustom org-attach-auto-tag "ATTACH" "Tag that will be triggered automatically when an entry has an attachment." @@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository." (const :tag "None" nil) (string :tag "Tag"))) -(defcustom org-attach-file-list-property "Attachments" - "The property used to keep a list of attachment belonging to this entry. -This is not really needed, so you may set this to nil if you don't want it. -Also, for entries where children inherit the directory, the list of -attachments is not kept in this property." +(defcustom org-attach-preferred-new-method 'id + "Preferred way to attach to nodes without existing ID and DIR property. +This choice is used when adding attachments to nodes without ID +and DIR properties. + +Allowed values are: + +id Create and use an ID parameter +dir Create and use a DIR parameter +ask Ask the user for input of which method to choose +nil Prefer to not create a new parameter + + nil means that ID or DIR has to be created explicitly + before attaching files." :group 'org-attach + :package-version '(org . "9.3") :type '(choice - (const :tag "None" nil) - (string :tag "Tag"))) + (const :tag "ID parameter" id) + (const :tag "DIR parameter" dir) + (const :tag "Ask user" ask) + (const :tag "Don't create" nil))) (defcustom org-attach-method 'cp "The preferred method to attach a file. @@ -113,14 +114,25 @@ lns create a symbol link. Note that this is not supported :group 'org-attach :type 'boolean) -(defcustom org-attach-allow-inheritance t - "Non-nil means allow attachment directories be inherited." +(defcustom org-attach-use-inheritance 'selective + "Attachment inheritance for the outline. + +Enabling inheritance for org-attach implies two things. First, +that attachment links will look through all parent headings until +it finds the linked attachment. Second, that running org-attach +inside a node without attachments will make org-attach operate on +the first parent heading it finds with an attachment. + +Selective means to respect the inheritance setting in +`org-use-property-inheritance'." :group 'org-attach + :type '(choice + (const :tag "Don't use inheritance" nil) + (const :tag "Inherit parent node attachments" t) + (const :tag "Respect org-use-property-inheritance" selective) + ) :type 'boolean) -(defvar org-attach-inherited nil - "Indicates if the last access to the attachment directory was inherited.") - (defcustom org-attach-store-link-p nil "Non-nil means store a link to a file when attaching it." :group 'org-attach @@ -141,16 +153,28 @@ When set to `query', ask the user instead." (const :tag "Always delete attachments" t) (const :tag "Query the user" query))) -(defcustom org-attach-annex-auto-get 'ask - "Confirmation preference for automatically getting annex files. -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." +(defun org-attach-id-folder-format (id) + "Translate an ID into a folder-path. +Default format for how Org translates ID properties to a path for +attachments." + (format "%s/%s" + (substring id 0 2) + (substring id 2))) + +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format + "Function parsing the ID parameter into a folder-path." :group 'org-attach - :package-version '(Org . "9.0") - :version "26.1" - :type '(choice - (const :tag "confirm with `y-or-n-p'" ask) - (const :tag "always get from annex if necessary" t) - (const :tag "never get from annex" nil))) + :package-version '(Org . "9.3") + :type 'function) + +(defvar org-attach-after-change-hook nil + "Hook to be called when files have been added or removed to the attachment folder.") + +(defvar org-attach-open-hook nil + "Hook that is invoked by `org-attach-open'. + +Created mostly to be compatible with org-attach-git after removing +git-funtionality from this file.") (defcustom org-attach-commands '(((?a ?\C-a) org-attach-attach @@ -186,9 +210,9 @@ you added attachments yourself.\n") "Delete all of a task's attachments. A safer way is\n to open the \ directory in dired and delete from there.\n") ((?s ?\C-s) org-attach-set-directory - "Set a specific attachment directory for this entry or reset to default.") - ((?i ?\C-i) org-attach-set-inherit - "Make children of the current entry inherit its attachment directory.\n") + "Set a specific attachment directory for this entry. Sets DIR property.") + ((?S ?\C-S) org-attach-unset-directory + "Unset the attachment directory for this entry. Removes DIR property.") ((?q) (lambda () (interactive) (message "Abort")) "Abort.")) "The list of commands for the attachment dispatcher. Each entry in this list is a list of three elements: @@ -210,39 +234,42 @@ Each entry in this list is a list of three elements: "The dispatcher for attachment commands. Shows a list of commands and prompts for another key to execute a command." (interactive) - (let (c marker) + (let (c marker attachment) (when (eq major-mode 'org-agenda-mode) (setq marker (or (get-text-property (point) 'org-hd-marker) (get-text-property (point) 'org-marker))) (unless marker - (error "No task in current line"))) + (error "No item in current line"))) (save-excursion (when marker (set-buffer (marker-buffer marker)) (goto-char marker)) (org-back-to-heading t) + (setq attachment (or (org-attach-dir) + (quote "Can't find an existing attachment-folder"))) (save-excursion (save-window-excursion (unless org-attach-expert (with-output-to-temp-buffer "*Org Attach*" - (princ - (format "Select an Attachment Command:\n\n%s" - (mapconcat - (lambda (entry) - (pcase entry - (`((,key . ,_) ,_ ,docstring) - (format "%c %s" - key - (replace-regexp-in-string "\n\\([\t ]*\\)" - " " - docstring - nil nil 1))) - (_ - (user-error - "Invalid `org-attach-commands' item: %S" - entry)))) - org-attach-commands - "\n"))))) + (princ + (concat "Attachment folder:\n" attachment "\n\n" + (format "Select an Attachment Command:\n\n%s" + (mapconcat + (lambda (entry) + (pcase entry + (`((,key . ,_) ,_ ,docstring) + (format "%c %s" + key + (replace-regexp-in-string "\n\\([\t ]*\\)" + " " + docstring + nil nil 1))) + (_ + (user-error + "Invalid `org-attach-commands' item: %S" + entry)))) + org-attach-commands + "\n")))))) (org-fit-window-to-buffer (get-buffer-window "*Org Attach*")) (message "Select command: [%s]" (concat (mapcar #'caar org-attach-commands))) @@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command." (error "No such attachment command: %c" c)))))) (defun org-attach-dir (&optional create-if-not-exists-p) - "Return the directory associated with the current entry. -This first checks for a local property ATTACH_DIR, and then for an inherited -property ATTACH_DIR_INHERIT. If neither exists, the default mechanism -using the entry ID will be invoked to access the unique directory for the -current entry. -If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, -the directory and (if necessary) the corresponding ID will be created." - (let (attach-dir uuid) - (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) + "Return the directory associated with the current outline node. +First check for DIR property, then ID property. +`org-attach-use-inheritance' determines whether inherited +properties also will be considered. + +If an ID property is found the default mechanism using that ID +will be invoked to access the directory for the current entry. + +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' +is run." + (let (attach-dir id) (cond - ((setq attach-dir (org-entry-get nil "ATTACH_DIR")) + (create-if-not-exists-p + (setq attach-dir (org-attach-dir-get-create))) + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) (org-attach-check-absolute-path attach-dir)) - ((and org-attach-allow-inheritance - (org-entry-get nil "ATTACH_DIR_INHERIT" t)) - (setq attach-dir - (org-with-wide-buffer - (if (marker-position org-entry-property-inherited-from) - (goto-char org-entry-property-inherited-from) - (org-back-to-heading t)) - (let (org-attach-allow-inheritance) - (org-attach-dir create-if-not-exists-p)))) - (org-attach-check-absolute-path attach-dir) - (setq org-attach-inherited t)) - (t ; use the ID + ;; Deprecated and removed from documentation, but still + ;; works. FIXME: Remove after major nr change. + ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance)) + (org-attach-check-absolute-path attach-dir)) + ((setq id (org-entry-get nil "ID" org-attach-use-inheritance)) (org-attach-check-absolute-path nil) - (setq uuid (org-id-get (point) create-if-not-exists-p)) - (when (or uuid create-if-not-exists-p) - (unless uuid (error "ID retrieval/creation failed")) - (setq attach-dir (expand-file-name - (format "%s/%s" - (substring uuid 0 2) - (substring uuid 2)) - (expand-file-name org-attach-directory)))))) - (when attach-dir - (if (and create-if-not-exists-p - (not (file-directory-p attach-dir))) - (make-directory attach-dir t)) - (and (file-exists-p attach-dir) - attach-dir)))) + (setq attach-dir (org-attach-dir-from-id id)))) + attach-dir)) + +(defun org-attach-dir-get-create () + "Return existing or new directory associated with the current outline node. + +`org-attach-preferred-new-method' decides how to attach +new directory." + (interactive) + (let ((attach-dir (org-attach-dir))) + (unless attach-dir + (let (answer) + (when (eq org-attach-preferred-new-method 'ask) + (message "Create new ID [1] property or DIR [2] property for attachments?") + (setq answer (read-char-exclusive))) + (cond + ((or (eq org-attach-preferred-new-method 'id) (eq answer ?1)) + (setq attach-dir (org-attach-dir-from-id (org-id-get nil t)))) + ((or (eq org-attach-preferred-new-method 'dir) (eq answer ?2)) + (setq attach-dir (org-attach-set-directory))) + ((eq org-attach-preferred-new-method 'nil) + (error "No existing directory. DIR or ID property has to be explicitly created"))))) + (if attach-dir + (progn (if (not (file-directory-p attach-dir)) + (make-directory attach-dir t)) + attach-dir) + (error "No attachment directory is associated with the current node")))) + +(defun org-attach-dir-from-id (id) + "Creates a path based on `org-attach-id-dir' and ID." + (expand-file-name + (funcall org-attach-id-to-path-function id) + (expand-file-name org-attach-id-dir))) (defun org-attach-check-absolute-path (dir) "Check if we have enough information to root the attachment directory. When DIR is given, check also if it is already absolute. Otherwise, -assume that it will be relative, and check if `org-attach-directory' is +assume that it will be relative, and check if `org-attach-id-dir' is absolute, or if at least the current buffer has a file name. Throw an error if we cannot root the directory." (or (and dir (file-name-absolute-p dir)) - (file-name-absolute-p org-attach-directory) + (file-name-absolute-p org-attach-id-dir) (buffer-file-name (buffer-base-buffer)) - (error "Need absolute `org-attach-directory' to attach in buffers without filename"))) + (error "Need absolute `org-attach-id-dir' to attach in buffers without filename"))) -(defun org-attach-set-directory (&optional arg) - "Set the ATTACH_DIR node property and ask to move files there. +(defun org-attach-set-directory () + "Set the DIR node property and ask to move files there. The property defines the directory that is used for attachments -of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." - (interactive "P") +of the entry. Creates relative links if `org-attach-dir-relative' +is t. + +Return the directory." + (interactive) (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (new + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil "DIR"))) + (current-dir (file-name-directory (or default-directory + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (org-entry-put nil "DIR" (if org-attach-dir-relative + attach-dir-relative + attach-dir)) + attach-dir))) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") + (copy-directory old new t t t)) + (when (yes-or-no-p (concat "Delete " old)) + (delete-directory old t))) + new)) + +(defun org-attach-unset-directory () + "Removes DIR node property. +If attachment folder is changed due to removal of DIR-property +ask to move attachments to new location and ask to delete old +attachment-folder. + +Change of attachment-folder due to unset might be if an ID +property is set on the node, or if a separate inherited +DIR-property exists (that is different than the unset one)." + (interactive) + (let ((old (org-attach-dir)) + (new + (progn + (org-entry-delete nil "DIR") + ;; ATTACH-DIR is deprecated and removed from documentation, + ;; but still works. Remove code for it after major nr change. + (org-entry-delete nil "ATTACH_DIR") + (org-attach-dir)))) + (unless (or (string= old new) + (not old)) + (when (and new (yes-or-no-p "Copy over attachments from old directory? ")) (copy-directory old new t nil t)) (when (yes-or-no-p (concat "Delete " old)) (delete-directory old t))))) -(defun org-attach-set-inherit () - "Set the ATTACH_DIR_INHERIT property of the current entry. -The property defines the directory that is used for attachments -of the entry and any children that do not explicitly define (by setting -the ATTACH_DIR property) their own attachment directory." - (interactive) - (org-entry-put nil "ATTACH_DIR_INHERIT" "t") - (message "Children will inherit attachment directory")) - -(defun org-attach-use-annex () - "Return non-nil if git annex can be used." - (let ((git-dir (vc-git-root (expand-file-name org-attach-directory)))) - (and org-attach-git-annex-cutoff - (or (file-exists-p (expand-file-name "annex" git-dir)) - (file-exists-p (expand-file-name ".git/annex" git-dir)))))) - -(defun org-attach-annex-get-maybe (path) - "Call git annex get PATH (via shell) if using git annex. -Signals an error if the file content is not available and it was not retrieved." - (let* ((default-directory (expand-file-name org-attach-directory)) - (path-relative (file-relative-name path))) - (when (and (org-attach-use-annex) - (not - (string-equal - "found" - (shell-command-to-string - (format "git annex find --format=found --in=here %s" - (shell-quote-argument path-relative)))))) - (let ((should-get - (if (eq org-attach-annex-auto-get 'ask) - (y-or-n-p (format "Run git annex get %s? " path-relative)) - org-attach-annex-auto-get))) - (if should-get - (progn (message "Running git annex get \"%s\"." path-relative) - (call-process "git" nil nil nil "annex" "get" path-relative)) - (error "File %s stored in git annex but it is not available, and was not retrieved" - path)))))) - -(defun org-attach-commit () - "Commit changes to git if `org-attach-directory' is properly initialized. -This checks for the existence of a \".git\" directory in that directory." - (let* ((dir (expand-file-name org-attach-directory)) - (git-dir (vc-git-root dir)) - (use-annex (org-attach-use-annex)) - (changes 0)) - (when (and git-dir (executable-find "git")) - (with-temp-buffer - (cd dir) - (dolist (new-or-modified - (split-string - (shell-command-to-string - "git ls-files -zmo --exclude-standard") "\0" t)) - (if (and use-annex - (>= (file-attribute-size (file-attributes new-or-modified)) - org-attach-git-annex-cutoff)) - (call-process "git" nil nil nil "annex" "add" new-or-modified) - (call-process "git" nil nil nil "add" new-or-modified)) - (cl-incf changes)) - (dolist (deleted - (split-string - (shell-command-to-string "git ls-files -z --deleted") "\0" t)) - (call-process "git" nil nil nil "rm" deleted) - (cl-incf changes)) - (when (> changes 0) - (shell-command "git commit -m 'Synchronized attachments'")))))) - (defun org-attach-tag (&optional off) "Turn the autotag on or (if OFF is set) off." (when org-attach-auto-tag @@ -422,22 +427,21 @@ Only do this when `org-attach-store-link-p' is non-nil." (org-attach-attach url)) (defun org-attach-buffer (buffer-name) - "Attach BUFFER-NAME's contents to current task. + "Attach BUFFER-NAME's contents to current outline node. BUFFER-NAME is a string. Signals a `file-already-exists' error if it would overwrite an existing filename." (interactive "bBuffer whose contents should be attached: ") - (let ((output (expand-file-name buffer-name (org-attach-dir t)))) + (let* ((attach-dir (org-attach-dir 'get-create)) + (output (expand-file-name buffer-name attach-dir))) (when (file-exists-p output) (signal 'file-already-exists (list "File exists" output))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property buffer-name)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (with-temp-file output (insert-buffer-substring buffer-name)))) (defun org-attach-attach (file &optional visit-dir method) - "Move/copy/link FILE into the attachment directory of the current task. + "Move/copy/link FILE into the attachment directory of the current outline node. If VISIT-DIR is non-nil, visit the directory with dired. METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from `org-attach-method'." @@ -452,10 +456,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from nil)) (setq method (or method org-attach-method)) (let ((basename (file-name-nondirectory file))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property basename)) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir 'get-create)) (fname (expand-file-name basename attach-dir))) (cond ((eq method 'mv) (rename-file file fname)) @@ -463,8 +464,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from ((eq method 'ln) (add-name-to-file file fname)) ((eq method 'lns) (make-symbolic-link file fname)) ((eq method 'url) (url-copy-file file fname))) - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (cond ((eq org-attach-store-link-p 'attached) (org-attach-store-link fname)) @@ -472,7 +472,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from (org-attach-store-link file))) (if visit-dir (dired attach-dir) - (message "File %S is now a task attachment." basename))))) + (message "File %S is now an attachment." basename))))) (defun org-attach-attach-cp () "Attach a file by copying it." @@ -497,13 +497,10 @@ On some systems, this apparently does copy the file instead." (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) (defun org-attach-new (file) - "Create a new attachment FILE for the current task. + "Create a new attachment FILE for the current outline node. The attachment is created as an Emacs buffer." (interactive "sCreate attachment named: ") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)) - (let ((attach-dir (org-attach-dir t))) + (let ((attach-dir (org-attach-dir 'get-create))) (org-attach-tag) (find-file (expand-file-name file attach-dir)) (message "New attachment %s" file))) @@ -511,7 +508,7 @@ The attachment is created as an Emacs buffer." (defun org-attach-delete-one (&optional file) "Delete a single attachment." (interactive) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir)) (files (org-attach-file-list attach-dir)) (file (or file (completing-read @@ -523,44 +520,32 @@ The attachment is created as an Emacs buffer." (unless (file-exists-p file) (error "No such attachment: %s" file)) (delete-file file) - (when org-attach-commit - (org-attach-commit)))) + (run-hook-with-args 'org-attach-after-change-hook attach-dir))) (defun org-attach-delete-all (&optional force) - "Delete all attachments from the current task. + "Delete all attachments from the current outline node. This actually deletes the entire attachment directory. A safer way is to open the directory in dired and delete from there." (interactive "P") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) - (when - (and attach-dir - (or force - (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) - (shell-command (format "rm -fr %s" attach-dir)) + (when (and attach-dir + (or force + (yes-or-no-p "Really remove all attachments of this entry? "))) + (delete-directory attach-dir (yes-or-no-p "Recursive?") t) (message "Attachment directory removed") - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-untag)))) (defun org-attach-sync () - "Synchronize the current tasks with its attachments. + "Synchronize the current outline node with its attachments. This can be used after files have been added externally." (interactive) - (when org-attach-commit - (org-attach-commit)) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) (when attach-dir + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (let ((files (org-attach-file-list attach-dir))) - (org-attach-tag (not files)) - (when org-attach-file-list-property - (dolist (file files) - (unless (string-match "^\\.\\.?\\'" file) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)))))))) + (org-attach-tag (not files)))) + (unless attach-dir (org-attach-tag t)))) (defun org-attach-file-list (dir) "Return a list of files in the attachment directory. @@ -569,35 +554,40 @@ This ignores files ending in \"~\"." (mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x)) (directory-files dir nil "[^~]\\'")))) -(defun org-attach-reveal (&optional if-exists) - "Show the attachment directory of the current task. +(defun org-attach-reveal () + "Show the attachment directory of the current outline node. This will attempt to use an external program to show the directory." - (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) - (and attach-dir (org-open-file attach-dir)))) + (interactive) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (org-open-file attach-dir) + (error "No attachment directory exist")))) (defun org-attach-reveal-in-emacs () - "Show the attachment directory of the current task in dired." + "Show the attachment directory of the current outline node in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (dired attach-dir) + (error "No attachment directory exist")))) (defun org-attach-open (&optional in-emacs) - "Open an attachment of the current task. + "Open an attachment of the current outline node. If there are more than one attachment, you will be prompted for the file name. This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (let* ((file (pcase (org-attach-file-list attach-dir) + (`(,file) file) + (files (completing-read "Open attachment: " + (mapcar #'list files) nil t)))) + (path (expand-file-name file attach-dir))) + (run-hook-with-args 'org-attach-open-hook path) + (org-open-file path in-emacs)) + (error "No attachment directory exist")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -616,6 +606,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(org-link-set-parameters "attachment" + :follow #'org-attach-open-link + :export #'org-attach-export-link + :complete #'org-attach-complete-link) + +(defun org-attach-open-link (link &optional in-emacs) + "Attachment link type LINK is expanded with the attached directory and opened. + +With optional prefix argument IN-EMACS, Emacs will visit the file. +With a double \\[universal-argument] \\[universal-argument] \ +prefix arg, Org tries to avoid opening in Emacs +and to use an external application to visit the file." + (interactive "P") + (let (line search) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment directory." + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (let* ((attached-dir (expand-file-name attach-dir)) + (file (read-file-name "File: " attached-dir)) + (pwd (file-name-as-directory attached-dir)) + (pwd-relative (file-name-as-directory + (abbreviate-file-name attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file) + (concat "attachment:" (match-string 1 file))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (concat "attachment:" (match-string 1 (expand-file-name file)))) + (t (concat "attachment:" file)))) + (error "No attachment directory exist")))) + +(defun org-attach-export-link (link description format) + "Translate attachment LINK from Org mode format to exported FORMAT. +Also includes the DESCRIPTION of the link in the export." + (save-excursion + (let (path desc) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option @@ -643,7 +696,7 @@ Idea taken from `gnus-dired-attach'." (interactive (list (dired-get-marked-files))) (unless (eq major-mode 'dired-mode) - (user-error "This command must be triggered in a dired buffer.")) + (user-error "This command must be triggered in a dired buffer")) (let ((start-win (selected-window)) (other-win (get-window-with-predicate diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 9cb396fe9..42fe64379 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -263,6 +263,9 @@ Counting starts at 1." (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays 'org-clear-latex-preview "Org 9.3") +(define-obsolete-variable-alias 'org-attach-directory + 'org-attach-id-dir "Org 9.3") + (defun org-in-fixed-width-region-p () "Non-nil if point in a fixed-width region." (save-match-data diff --git a/lisp/org.el b/lisp/org.el index b19a30f38..255b94e8d 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -3849,7 +3849,9 @@ This is needed for font-lock setup.") (beg end)) (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) (declare-function org-agenda-skip "org-agenda" ()) -(declare-function org-attach-reveal "org-attach" (&optional if-exists)) +(declare-function org-attach-expand "org-attach" (file)) +(declare-function org-attach-reveal "org-attach" ()) +(declare-function org-attach-reveal-in-emacs "org-attach" ()) (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) (declare-function org-indent-mode "org-indent" (&optional arg)) (declare-function org-inlinetask-goto-beginning "org-inlinetask" ()) @@ -8647,12 +8649,15 @@ a link." (pcase (org-offer-links-in-entry (current-buffer) (point) arg) (`(nil . ,_) (require 'org-attach) - (org-attach-reveal 'if-exists)) + (message "Opening attachment-dir") + (if (equal arg '(4)) + (org-attach-reveal-in-emacs) + (org-attach-reveal))) (`(,links . ,links-end) (dolist (link (if (stringp links) (list links) links)) (search-forward link nil links-end) (goto-char (match-beginning 0)) - (org-open-at-point)))))) + (org-open-at-point arg)))))) ;; On a footnote reference or at definition's label. ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) @@ -16632,13 +16637,14 @@ boundaries." ;; "file:" links. Also check link abbreviations since ;; some might expand to "file" links. (file-types-re - (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" + (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" (if (not link-abbrevs) "" (concat "\\|" (regexp-opt link-abbrevs)))))) (while (re-search-forward file-types-re end t) (let* ((link (org-element-lineage (save-match-data (org-element-context)) '(link) t)) + (linktype (org-element-property :type link)) (inner-start (match-beginning 1)) (path (cond @@ -16652,7 +16658,8 @@ boundaries." ;; INCLUDE-LINKED is non-nil. ((or (not (org-element-property :contents-begin link)) include-linked) - (and (equal "file" (org-element-property :type link)) + (and (or (equal "file" linktype) + (equal "attachment" linktype)) (org-element-property :path link))) ;; Link with a description. Check if description ;; is a filename. Even if Org doesn't have syntax @@ -16671,7 +16678,11 @@ boundaries." (match-end 0)) (match-string 2))))))) (when (and path (string-match-p file-extension-re path)) - (let ((file (expand-file-name path))) + (let ((file (if (equal "attachment" linktype) + (progn + (require 'org-attach) + (org-attach-expand path)) + (expand-file-name path)))) (when (file-exists-p file) (let ((width ;; Apply `org-image-actual-width' specifications. diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA new file mode 100644 index 000000000..9a0406c0d --- /dev/null +++ b/testing/examples/att1/fileA @@ -0,0 +1 @@ +Text in fileA diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB new file mode 100644 index 000000000..dd2331824 --- /dev/null +++ b/testing/examples/att1/fileB @@ -0,0 +1 @@ +Text in fileB diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC new file mode 100644 index 000000000..2c9a92bfe --- /dev/null +++ b/testing/examples/att2/fileC @@ -0,0 +1 @@ +Text in fileC \ No newline at end of file diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD new file mode 100644 index 000000000..c706556c5 --- /dev/null +++ b/testing/examples/att2/fileD @@ -0,0 +1 @@ +text in fileD diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org new file mode 100644 index 000000000..ab4a4e548 --- /dev/null +++ b/testing/examples/attachments.org @@ -0,0 +1,32 @@ +#+TITLE: Org attach testfile +Used to test and verify the functionality of org-attach. + +* H1 + :PROPERTIES: + :DIR: att1 + :END: +A link to one attachment: [[attachment:fileA]] + +** H1.1 +A link to another attachment: [[attachment:fileB]] + +** H1.2 + :PROPERTIES: + :DIR: att2 + :END: + +* H2 + :PROPERTIES: + :ID: abcd123 + :END: + +* H3 + :PROPERTIES: + :DIR: att1 + :ID: abcd1234 + :END: + +** H3.1 + :PROPERTIES: + :ID: abcd12345 + :END: diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE new file mode 100644 index 000000000..80d337772 --- /dev/null +++ b/testing/examples/data/ab/cd123/fileE @@ -0,0 +1 @@ +peek-a-boo diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el similarity index 93% rename from testing/lisp/test-org-attach-annex.el rename to testing/lisp/test-org-attach-git.el index 7f2792696..8b826b72f 100644 --- a/testing/lisp/test-org-attach-annex.el +++ b/testing/lisp/test-org-attach-git.el @@ -20,19 +20,19 @@ ;;; Code: (org-test-for-executable "git-annex") -(require 'org-attach) +(require 'org-attach-git) (require 'cl-lib) -(defmacro test-org-attach-annex/with-annex (&rest body) +(defmacro test-org-attach-git/with-annex (&rest body) `(let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (shell-command "git annex init") ,@body)))) -(ert-deftest test-org-attach/use-annex () +(ert-deftest test-org-attach-git/use-annex () (test-org-attach-annex/with-annex (let ((org-attach-git-annex-cutoff 1)) (should (org-attach-use-annex))) @@ -44,12 +44,12 @@ (let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (should-not (org-attach-use-annex))) (delete-directory tmpdir 'recursive)))) -(ert-deftest test-org-attach/get-maybe () +(ert-deftest test-org-attach-git/get-maybe () (test-org-attach-annex/with-annex (let ((path (expand-file-name "test-file")) (annex-dup (make-temp-file "org-annex-test" t "/"))) diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el index c2f2be356..5bcfe86fd 100644 --- a/testing/lisp/test-org-attach.el +++ b/testing/lisp/test-org-attach.el @@ -28,6 +28,75 @@ (require 'org-attach) (eval-and-compile (require 'cl-lib)) +(ert-deftest test-org-attach/dir () + "Test `org-attach-get' specifications." + (should (equal "Text in fileA\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 157) ;; First attachment link + (org-open-at-point) + (buffer-string)))) + (should-not (equal "Text in fileB\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 219) ;; Second attachment link + (let ((org-attach-use-inheritance nil)) + (org-open-at-point) + (buffer-string))))) + (should (equal "Text in fileB\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 219) ;; Second attachment link + (let ((org-attach-use-inheritance t)) + (org-open-at-point) + (buffer-string))))) + (should-not (equal "att1" + (org-test-in-example-file org-test-attachments-file + (goto-char 179) ;; H1.1 + (let ((org-attach-use-inheritance nil)) + (org-attach-dir))))) + (should (equal "att1" + (org-test-in-example-file org-test-attachments-file + (goto-char 179) ;; H1.1 + (let ((org-attach-use-inheritance t)) + (org-attach-dir))))) + (should (equal '("fileC" "fileD") + (org-test-in-example-file org-test-attachments-file + (goto-char 239) ;; H1.2 + (org-attach-file-list (org-attach-dir))))) + (should (equal '("fileC" "fileD") + (org-test-in-example-file org-test-attachments-file + (goto-char 239) ;; H1.2 + (org-attach-file-list (org-attach-dir))))) + (should (equal '("fileE") + (org-test-in-example-file org-test-attachments-file + (goto-char 289) ;; H2 + (let ((org-attach-id-dir "data/")) + (org-attach-file-list (org-attach-dir)))))) + (should (equal "peek-a-boo\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 289) ;; H2 + (let ((org-attach-id-dir "data/")) + (org-attach-open-in-emacs) + (buffer-string))))) + (should (equal '("fileA" "fileB") + (org-test-in-example-file org-test-attachments-file + (goto-char 336) ;; H3 + (org-attach-file-list (org-attach-dir))))) + (should (equal "data/ab/cd12345" + (org-test-in-example-file org-test-attachments-file + (goto-char 401) ;; H3.1 + (let ((org-attach-use-inheritance nil) + (org-attach-id-dir "data/")) + (file-relative-name (org-attach-dir)))))) + (should (equal '("fileA" "fileB") + (org-test-in-example-file org-test-attachments-file + (goto-char 401) ;; H3.1 + (let ((org-attach-use-inheritance t)) + ;; This is where it get's a bit sketchy...! DIR always has + ;; priority over ID, even if ID is declared "higher up" in the + ;; tree. This can potentially be revised. But it is also + ;; pretty clean. DIR is always higher in priority than ID right + ;; now, no matter the depth in the tree. + (org-attach-file-list (org-attach-dir))))))) + (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 () "Attach file at point in dired to subtree." (should diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index d671b5c78..a618da479 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2514,7 +2514,11 @@ Foo Bar (catch :result (cl-letf (((symbol-function 'org-tags-view) (lambda (&rest args) (throw :result t)))) - (org-open-at-point) + ;; When point isn't on a tag it's going to try other things, + ;; possibly trying to open attachments which will return an + ;; error if there isn't an attachment. Supress that error. + (ignore-errors + (org-open-at-point)) nil))))) \f diff --git a/testing/org-test.el b/testing/org-test.el index 295df1919..c3e21eb30 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.") (defconst org-test-no-heading-file (expand-file-name "no-heading.org" org-test-example-dir)) +(defconst org-test-attachments-file + (expand-file-name "attachments.org" org-test-example-dir)) + (defconst org-test-link-in-heading-file (expand-file-name "link-in-heading.org" org-test-dir)) -- 2.17.1 [-- Attachment #3: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --] [-- Type: application/octet-stream, Size: 8578 bytes --] From 8bdf0c4d9e0308d32bee18613e530a2c497a4611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 26 May 2019 03:34:34 +0200 Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox, test-property-inheritance * org-test.el: Fix org-test-with-temp-text-in-file. Make it work with <point>, as some tests already expect it to do! Also make it fail more gracefully by still removing temporary buffers and files. Improve org-test-in-example-file. Make it behave similar to org-test-with-temp-text and org-test-with-temp-text-in-file, in that it will return the last evaluated expression. * testing/lisp/test-org-element.el Fix a temp-text strings so that it doesn't have an initial newline. * testing/lisp/test-org.el Minor cleanup to align code-structure with other tests. Nothing changes in the test execpt style. * testing/lisp/test-ox.el Fix a couple of temp-text strings so that they don't have initial newlines. ** test-org-export/expand-include Test specification was wrong, due to org-test-with-temp-text-in-file not previously working with <point>. Since that is fixed in this patch the test needed to be updated to match the expected outcome. * testing/lisp/test-property-inheritance.el Fix wrong file-header and file-ending. --- testing/lisp/test-org-element.el | 4 +-- testing/lisp/test-org.el | 12 +++---- testing/lisp/test-ox.el | 30 ++++++++-------- testing/lisp/test-property-inheritance.el | 4 +-- testing/org-test.el | 44 ++++++++++++++--------- 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 8b4081ee2..4c1e4d181 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -3250,8 +3250,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu (ert-deftest test-org-element/granularity () "Test granularity impact on buffer parsing." - (org-test-with-temp-text " -* Head 1 + (org-test-with-temp-text + "* Head 1 ** Head 2 #+BEGIN_CENTER Centered paragraph. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index abc004689..d671b5c78 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -5060,18 +5060,18 @@ Paragraph<point>" (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" - (org-entry-get (point) "A" t)))) + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" + (org-entry-get (point-max) "A" t)))) (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance t)) - (org-entry-get (point) "A" 'selective))))) + (org-entry-get (point-max) "A" 'selective))))) (should-not - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance nil)) - (org-entry-get (point) "A" 'selective)))) + (org-entry-get (point-max) "A" 'selective)))) (should (equal "1 2" diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 2c2778f82..b8c507e0b 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote] org-test-dir) (narrow-to-region (point) (point-max)) (org-export-expand-include-keyword) - (eq 1 (org-current-level)))) + (eq 2 (org-current-level)))) ;; If :minlevel is present do not alter it. (should (org-test-with-temp-text @@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after comments removal." (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment # Comment @@ -2012,15 +2012,15 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2029,8 +2029,8 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2040,24 +2040,24 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "- item 1\n\n- item 2\n" - (org-test-with-temp-text " -- item 1 + (org-test-with-temp-text + "- item 1 # Comment diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el index 0f803e5f7..1d0dcfbe1 100644 --- a/testing/lisp/test-property-inheritance.el +++ b/testing/lisp/test-property-inheritance.el @@ -1,4 +1,4 @@ -;;; test-ob-R.el --- tests for ob-R.el +;;; test-property-inheritance.el --- tests for property-inheritance.el ;; Copyright (c) 2011-2014, 2019 Eric Schulte ;; Authors: Eric Schulte @@ -47,4 +47,4 @@ (provide 'test-ob-R) -;;; test-ob-R.el ends here +;;; test-property-inheritance.el ends here diff --git a/testing/org-test.el b/testing/org-test.el index 39c346410..295df1919 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -146,7 +146,8 @@ currently executed.") (declare (indent 1)) `(let* ((my-file (or ,file org-test-file)) (visited-p (get-file-buffer my-file)) - to-be-removed) + to-be-removed + results) (save-window-excursion (save-match-data (find-file my-file) @@ -160,9 +161,10 @@ currently executed.") (org-show-subtree) (org-show-all '(blocks))) (error nil)) - (save-restriction ,@body))) + (setq results (save-restriction ,@body)))) (unless visited-p - (kill-buffer to-be-removed)))) + (kill-buffer to-be-removed)) + results)) (def-edebug-spec org-test-in-example-file (form body)) (defmacro org-test-at-marker (file marker &rest body) @@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text." (def-edebug-spec org-test-with-temp-text (form body)) (defmacro org-test-with-temp-text-in-file (text &rest body) - "Run body in a temporary file buffer with Org mode as the active mode." + "Run body in a temporary file buffer with Org mode as the active mode. +If the string \"<point>\" appears in TEXT then remove it and +place the point there before running BODY, otherwise place the +point at the beginning of the buffer." (declare (indent 1)) - (let ((results (cl-gensym))) - `(let ((file (make-temp-file "org-test")) - (kill-buffer-query-functions nil) - (inside-text (if (stringp ,text) ,text (eval ,text))) - ,results) - (with-temp-file file (insert inside-text)) - (find-file file) - (org-mode) - (setq ,results (progn ,@body)) - (save-buffer) (kill-buffer (current-buffer)) - (delete-file file) - ,results))) + `(let ((file (make-temp-file "org-test")) + (inside-text (if (stringp ,text) ,text (eval ,text))) + buffer) + (with-temp-file file (insert inside-text)) + (unwind-protect + (progn + (setq buffer (find-file file)) + (when (re-search-forward "<point>" nil t) + (replace-match "")) + (org-mode) + (progn ,@body)) + (let ((kill-buffer-query-functions nil)) + (when buffer + (set-buffer buffer) + ;; Ignore changes, we're deleting the file in the next step + ;; anyways. + (set-buffer-modified-p nil) + (kill-buffer)) + (delete-file file))))) (def-edebug-spec org-test-with-temp-text-in-file (form body)) (defun org-test-table-target-expect (target &optional expect laps -- 2.17.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-06-30 6:03 ` Gustav Wikström @ 2019-07-06 21:46 ` Nicolas Goaziou 2019-07-07 18:38 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2019-07-06 21:46 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > + (if should-get > + (progn (message "Running git annex get \"%s\"." path-relative) > + (call-process "git" nil nil nil "annex" "get" path-relative)) > + (error "File %s stored in git annex but it is not available, and was not retrieved" > + path)))))) Nitpick: (unless should-get (error "File %S stored in git annex but unavailable" path)) (message "Running git annex get %S." path-relative) (call-process ...) > +Selective means to respect the inheritance setting in > +`org-use-property-inheritance'." > :group 'org-attach > + :type '(choice > + (const :tag "Don't use inheritance" nil) > + (const :tag "Inherit parent node attachments" t) > + (const :tag "Respect org-use-property-inheritance" selective) > + ) Dangling paren spotted. > + (setq attachment (or (org-attach-dir) > + (quote "Can't find an existing attachment-folder"))) You forgot to remove that weird quote. Maybe you meant `error'? > + (if attach-dir > + (progn (if (not (file-directory-p attach-dir)) > + (make-directory attach-dir t)) > + attach-dir) > + (error "No attachment directory is associated with the current node")))) Same nitpick as above: (unless attach-dir (error "No attachment ...")) (if (file-directory-p attach-dir) attach-dir (make-directory attach-dir)) > +(defun org-attach-dir-from-id (id) > + "Creates a path based on `org-attach-id-dir' and ID." > + (expand-file-name > + (funcall org-attach-id-to-path-function id) > + (expand-file-name org-attach-id-dir))) Creates path -> Return a file name. > +of the entry. Creates relative links if `org-attach-dir-relative' > +is t. Nitpick: is t -> is non-nil. If tests pass, feel free to apply the patches in master. Thank you! Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-06 21:46 ` Nicolas Goaziou @ 2019-07-07 18:38 ` Gustav Wikström 2019-07-08 10:47 ` Marco Wahl ` (2 more replies) 0 siblings, 3 replies; 113+ messages in thread From: Gustav Wikström @ 2019-07-07 18:38 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 3167 bytes --] Hi! > > + (if should-get > > + (progn (message "Running git annex get \"%s\"." path-relative) > > + (call-process "git" nil nil nil "annex" "get" path-relative)) > > + (error "File %s stored in git annex but it is not available, and was not > retrieved" > > + path)))))) > > Nitpick: > > (unless should-get > (error "File %S stored in git annex but unavailable" path)) > (message "Running git annex get %S." path-relative) > (call-process ...) Ok, fixed. > > +Selective means to respect the inheritance setting in > > +`org-use-property-inheritance'." > > :group 'org-attach > > + :type '(choice > > + (const :tag "Don't use inheritance" nil) > > + (const :tag "Inherit parent node attachments" t) > > + (const :tag "Respect org-use-property-inheritance" selective) > > + ) > > Dangling paren spotted. Fixed. > > + (setq attachment (or (org-attach-dir) > > + (quote "Can't find an existing attachment-folder"))) > > You forgot to remove that weird quote. Maybe you meant `error'? Hmm, actually no. But the code is pretty bad so I've refactored it a bit. The purpose of the change is for org-attach to give an indication of the active attachment path, or to signal that there is none. But for that I don't really need a separate variable. Thus it's slightly refactored for code-clarity. > > + (if attach-dir > > + (progn (if (not (file-directory-p attach-dir)) > > + (make-directory attach-dir t)) > > + attach-dir) > > + (error "No attachment directory is associated with the current node")))) > > Same nitpick as above: > > (unless attach-dir > (error "No attachment ...")) > (if (file-directory-p attach-dir) attach-dir > (make-directory attach-dir)) Ok, fixed. > > +(defun org-attach-dir-from-id (id) > > + "Creates a path based on `org-attach-id-dir' and ID." > > + (expand-file-name > > + (funcall org-attach-id-to-path-function id) > > + (expand-file-name org-attach-id-dir))) > > Creates path -> Return a file name. Fixed. > > +of the entry. Creates relative links if `org-attach-dir-relative' > > +is t. > > Nitpick: > > is t -> is non-nil. Ah, true. Fixed. > If tests pass, feel free to apply the patches in master. Thank you! Got it. Aaand one test failure. That test is unrelated to my changes though, and fails also on master. Test-org-table/copy-down. So I'll try to apply my patch asap regardless of that one test failing. Just one more thing - a few days back I added a row to lisp/ox-html.el regarding inline-images. I'm including that change as well since it relates 100% to the new attachment link. I looked in the other export-backends too but didn't add anything due to lack of time for testing. Maybe the additions for other backends is as trivial as for html. So someone who regularly export to those backends might want to suggest patches for them to make attachment links to images actually display as images? 😊 Final patches attached for full disclosure before applying them. > > Regards, > > -- > Nicolas Goaziou [-- Attachment #2: 0001-org-test-test-org-element-test-org-test-ox-test-prop.patch --] [-- Type: application/octet-stream, Size: 8578 bytes --] From 3cbe356b0a9d1a98848df0fa09ba306392995b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 26 May 2019 03:34:34 +0200 Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox, test-property-inheritance * org-test.el: Fix org-test-with-temp-text-in-file. Make it work with <point>, as some tests already expect it to do! Also make it fail more gracefully by still removing temporary buffers and files. Improve org-test-in-example-file. Make it behave similar to org-test-with-temp-text and org-test-with-temp-text-in-file, in that it will return the last evaluated expression. * testing/lisp/test-org-element.el Fix a temp-text strings so that it doesn't have an initial newline. * testing/lisp/test-org.el Minor cleanup to align code-structure with other tests. Nothing changes in the test execpt style. * testing/lisp/test-ox.el Fix a couple of temp-text strings so that they don't have initial newlines. ** test-org-export/expand-include Test specification was wrong, due to org-test-with-temp-text-in-file not previously working with <point>. Since that is fixed in this patch the test needed to be updated to match the expected outcome. * testing/lisp/test-property-inheritance.el Fix wrong file-header and file-ending. --- testing/lisp/test-org-element.el | 4 +-- testing/lisp/test-org.el | 12 +++---- testing/lisp/test-ox.el | 30 ++++++++-------- testing/lisp/test-property-inheritance.el | 4 +-- testing/org-test.el | 44 ++++++++++++++--------- 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 04f97f97a..f2ab38031 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -3264,8 +3264,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu (ert-deftest test-org-element/granularity () "Test granularity impact on buffer parsing." - (org-test-with-temp-text " -* Head 1 + (org-test-with-temp-text + "* Head 1 ** Head 2 #+BEGIN_CENTER Centered paragraph. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index abc004689..d671b5c78 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -5060,18 +5060,18 @@ Paragraph<point>" (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" - (org-entry-get (point) "A" t)))) + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" + (org-entry-get (point-max) "A" t)))) (should (equal "1" - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance t)) - (org-entry-get (point) "A" 'selective))))) + (org-entry-get (point-max) "A" 'selective))))) (should-not - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" (let ((org-use-property-inheritance nil)) - (org-entry-get (point) "A" 'selective)))) + (org-entry-get (point-max) "A" 'selective)))) (should (equal "1 2" diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 2c2778f82..b8c507e0b 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote] org-test-dir) (narrow-to-region (point) (point-max)) (org-export-expand-include-keyword) - (eq 1 (org-current-level)))) + (eq 2 (org-current-level)))) ;; If :minlevel is present do not alter it. (should (org-test-with-temp-text @@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after comments removal." (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment # Comment @@ -2012,15 +2012,15 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "Para1\n\nPara2\n" - (org-test-with-temp-text " -Para1 + (org-test-with-temp-text + "Para1 # Comment Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2029,8 +2029,8 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition @@ -2040,24 +2040,24 @@ Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "[fn:1] Para1\n\nPara2\n" - (org-test-with-temp-text " -\[fn:1] Para1 + (org-test-with-temp-text + "[fn:1] Para1 # Inside definition Para2" (org-export-as (org-test-default-backend))))) (should (equal "- item 1\n\n- item 2\n" - (org-test-with-temp-text " -- item 1 + (org-test-with-temp-text + "- item 1 # Comment diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el index 0f803e5f7..1d0dcfbe1 100644 --- a/testing/lisp/test-property-inheritance.el +++ b/testing/lisp/test-property-inheritance.el @@ -1,4 +1,4 @@ -;;; test-ob-R.el --- tests for ob-R.el +;;; test-property-inheritance.el --- tests for property-inheritance.el ;; Copyright (c) 2011-2014, 2019 Eric Schulte ;; Authors: Eric Schulte @@ -47,4 +47,4 @@ (provide 'test-ob-R) -;;; test-ob-R.el ends here +;;; test-property-inheritance.el ends here diff --git a/testing/org-test.el b/testing/org-test.el index 39c346410..295df1919 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -146,7 +146,8 @@ currently executed.") (declare (indent 1)) `(let* ((my-file (or ,file org-test-file)) (visited-p (get-file-buffer my-file)) - to-be-removed) + to-be-removed + results) (save-window-excursion (save-match-data (find-file my-file) @@ -160,9 +161,10 @@ currently executed.") (org-show-subtree) (org-show-all '(blocks))) (error nil)) - (save-restriction ,@body))) + (setq results (save-restriction ,@body)))) (unless visited-p - (kill-buffer to-be-removed)))) + (kill-buffer to-be-removed)) + results)) (def-edebug-spec org-test-in-example-file (form body)) (defmacro org-test-at-marker (file marker &rest body) @@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text." (def-edebug-spec org-test-with-temp-text (form body)) (defmacro org-test-with-temp-text-in-file (text &rest body) - "Run body in a temporary file buffer with Org mode as the active mode." + "Run body in a temporary file buffer with Org mode as the active mode. +If the string \"<point>\" appears in TEXT then remove it and +place the point there before running BODY, otherwise place the +point at the beginning of the buffer." (declare (indent 1)) - (let ((results (cl-gensym))) - `(let ((file (make-temp-file "org-test")) - (kill-buffer-query-functions nil) - (inside-text (if (stringp ,text) ,text (eval ,text))) - ,results) - (with-temp-file file (insert inside-text)) - (find-file file) - (org-mode) - (setq ,results (progn ,@body)) - (save-buffer) (kill-buffer (current-buffer)) - (delete-file file) - ,results))) + `(let ((file (make-temp-file "org-test")) + (inside-text (if (stringp ,text) ,text (eval ,text))) + buffer) + (with-temp-file file (insert inside-text)) + (unwind-protect + (progn + (setq buffer (find-file file)) + (when (re-search-forward "<point>" nil t) + (replace-match "")) + (org-mode) + (progn ,@body)) + (let ((kill-buffer-query-functions nil)) + (when buffer + (set-buffer buffer) + ;; Ignore changes, we're deleting the file in the next step + ;; anyways. + (set-buffer-modified-p nil) + (kill-buffer)) + (delete-file file))))) (def-edebug-spec org-test-with-temp-text-in-file (form body)) (defun org-test-table-target-expect (target &optional expect laps -- 2.17.1 [-- Attachment #3: 0002-org-attach-org-org-manual-org-news-ox-html-testing.patch --] [-- Type: application/octet-stream, Size: 107223 bytes --] From ae9cd4370b4daaaca7bc53923d5e438c08955e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> Date: Sun, 25 Nov 2018 21:38:44 +0100 Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, ox-html, testing/* * lisp/org-attach.el Changed the way attachments deal with property-inheritance. It now adheres to the =org-use-property-inheritance= setting by default but it can be customized if needed (I recommend to enable it!). The property ATTACH_DIR is deprecated in favour of the shorter and simpler property DIR. Added an explicit option to =org-attach= for unsetting attachment-directories (i.e. remove DIR property and deal with the attachments by interaction). Added attachment link type with the prefix "attachment:". Added customizations: - org-attach-dir-relative - org-attach-preferred-new-method - org-attach-use-inheritance - org-attach-id-to-path-function Hooks added: - org-attach-after-change-hook - org-attach-open-hook A new linktype "attachment" is added in order to reduce link-duplication when wanting to link to files in attached folders of nodes. This works for both ID and DIR properties. The goal is to make the functionality for attachment links mirror the functionality for file links. * lisp/org-attach-git.el New file, existing functionality. Code here has been factored out from org-attach.el and if GIT-functionality is to be used this module needs to be required sepatately. It extends org-attach by use of its hooks. Activating git functionality in org-attach is done by loading org-attach-git from now on, instead of customizing a variable. Naming of both functions and tests has been modified to match the move of functionality into its own module. * lisp/org.el Inline images are shown also using attachment-links, exactly the same as it works for file-links today. Make org-open-at-point respect ARG when opening attachment-dir. * lisp/org-compat.el org-attach-directory has been deprecated in favour for org-attach-id-dir. The new name matches its purpose better. * lisp/ox-html.el Export attachment links to images as inline images, in the same way as file links work today. * etc/ORG-NEWS Mention the changes in this patch. * doc/org-manual.org The chapter "Refile, Copy, Archive" has been split into two separate chapters. - "Refile, Copy and Archiving" for information related to moving existing data around. - "Capture, Attachments, RSS Feeds and Protocols" for information related to working with external data. The attachment-part has been rewritten and extended to match the changes in this patch. The new attachment link type is mentioned both inside the attachments chapter and in the chapter dealing with links. Documentation related to external links has been improved. * testing/lisp/test-org-attach-annex.el Require org-attach-git instead of org-attach, since this file tests the GIT-functionality. * testing/lisp/test-org-attach.el Add tests for org-attach. * testing/org-test.el Define a symbol for a file to test attachments with. * testing/examples/* A bunch of new example files and folders are created and are used in testing of org-attach to verify its functionality. --- doc/org-manual.org | 1079 ++++++++++------- etc/ORG-NEWS | 94 ++ lisp/org-attach-git.el | 117 ++ lisp/org-attach.el | 561 +++++---- lisp/org-compat.el | 3 + lisp/org.el | 23 +- lisp/ox-html.el | 1 + testing/examples/att1/fileA | 1 + testing/examples/att1/fileB | 1 + testing/examples/att2/fileC | 1 + testing/examples/att2/fileD | 1 + testing/examples/attachments.org | 32 + testing/examples/data/ab/cd123/fileE | 1 + ...attach-annex.el => test-org-attach-git.el} | 12 +- testing/lisp/test-org-attach.el | 69 ++ testing/lisp/test-org.el | 6 +- testing/org-test.el | 3 + 17 files changed, 1307 insertions(+), 698 deletions(-) create mode 100644 lisp/org-attach-git.el create mode 100644 testing/examples/att1/fileA create mode 100644 testing/examples/att1/fileB create mode 100644 testing/examples/att2/fileC create mode 100644 testing/examples/att2/fileD create mode 100644 testing/examples/attachments.org create mode 100644 testing/examples/data/ab/cd123/fileE rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%) diff --git a/doc/org-manual.org b/doc/org-manual.org index 8318e7cdc..e81b76f14 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -3071,6 +3071,7 @@ point on or at a target. #+cindex: irc links #+cindex: URL links #+cindex: file links +#+cindex: attachment links #+cindex: Rmail links #+cindex: MH-E links #+cindex: Usenet links @@ -3082,38 +3083,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB database entries and links to both IRC conversations and their logs. External links are URL-like locators. They start with a short identifying string followed by a colon. There can be no space after -the colon. The following list shows examples for each link type. - -| =https://staff.science.uva.nl/c.dominik/= | on the web | -| =doi:10.1000/182= | DOI for an electronic resource | -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | -| =/home/dominik/images/jupiter.jpg= | same as above | -| =file:papers/last.pdf= | file, relative path | -| =./papers/last.pdf= | same as above | -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | -| =/ssh:me@some.where:papers/last.pdf= | same as above | -| =file:sometextfile::NNN= | file, jump to line number | -| =file:projects.org= | another Org file | -| =file:projects.org::some words= | text search in Org file[fn:27] | -| =file:projects.org::*task title= | heading search in Org file | -| =file+sys:/path/to/file= | open via OS, like double-click | -| =file+emacs:/path/to/file= | force opening by Emacs | -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | -| =news:comp.emacs= | Usenet link | -| =mailto:adent@galaxy.net= | mail link | -| =mhe:folder= | MH-E folder link | -| =mhe:folder#id= | MH-E message link | -| =rmail:folder= | Rmail folder link | -| =rmail:folder#id= | Rmail message link | -| =gnus:group= | Gnus group link | -| =gnus:group#id= | Gnus article link | -| =bbdb:R.*Stallman= | BBDB link (with regexp) | -| =irc:/irc.com/#emacs/bob= | IRC link | -| =info:org#External links= | Info node link | -| =shell:ls *.org= | shell command | -| =elisp:org-agenda= | interactive Elisp command | -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | +the colon. + +Here is the full set of built-in link types: + +- =file= :: + + File links. File name may be remote, absolute, or relative. + + Additionally, you can specify a line number, or a text search. + In Org files, you may link to a headline name, a custom ID, or a + code reference instead. + + As a special case, "file" prefix may be omitted if the file name + is complete, e.g., it starts with =./=, or =/=. + +- =attachment= :: + + Same as file links but for files and folders attached to the current + node (see [[*Attachments]]). Attachment links are intended to behave + exactly as file links but for files relative to the attachment + directory. + +- =bbdb= :: + + Link to a BBDB record, with possible regexp completion. + +- =docview= :: + + Link to a document opened with DocView mode. You may specify a page + number. + +- =doi= :: + + Link to an electronic ressource, through its handle. + +- =elisp= :: + + Execute an Elisp command upon activation. + +- =gnus=, =rmail=, =mhe= :: + + Links to messages or folders from a given Emacs' MUA. + +- =http=, =https= :: + + Web links. + +- =id= :: + + Link to a specific headline by its ID property, in an Org file. + +- =info= :: + + Link to an Info manual, or to a specific node. + +- =irc= :: + + Link to an IRC channel. + +- =mailto= :: + + Link to message composition. + +- =news= :: + + Usenet links. + +- =shell= :: + + Execute a shell command upon activation. + +The following table illustrates the link types above, along with their +options: + +| Link Type | Example | +|------------+----------------------------------------------------------| +| http | =http://staff.science.uva.nl/c.dominik/= | +| https | =https://orgmode.org/= | +| doi | =doi:10.1000/182= | +| file | =file:/home/dominik/images/jupiter.jpg= | +| | =/home/dominik/images/jupiter.jpg= (same as above) | +| | =file:papers/last.pdf= | +| | =./papers/last.pdf= (same as above) | +| | =file:/ssh:me@some.where:papers/last.pdf= (remote) | +| | =/ssh:me@some.where:papers/last.pdf= (same as above) | +| | =file:sometextfile::NNN= (jump to line number) | +| | =file:projects.org= | +| | =file:projects.org::some words= (text search) [fn:28] | +| | =file:projects.org::*task title= (headline search) | +| | =file:projects.org::#custom-id= (headline search) | +| attachment | =attachment:projects.org= | +| | =attachment:projects.org::some words= (text search) | +| docview | =docview:papers/last.pdf::NNN= | +| id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | +| news | =news:comp.emacs= | +| mailto | =mailto:adent@galaxy.net= | +| mhe | =mhe:folder= (folder link) | +| | =mhe:folder#id= (message link) | +| rmail | =rmail:folder= (folder link) | +| | =rmail:folder#id= (message link) | +| gnus | =gnus:group= (group link) | +| | =gnus:group#id= (article link) | +| bbdb | =bbdb:R.*Stallman= (record with regexp) | +| irc | =irc:/irc.com/#emacs/bob= | +| info | =info:org#External links= | +| shell | =shell:ls *.org= | +| elisp | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) | +| | =elisp:org-agenda= (interactive Elisp command) | #+cindex: VM links #+cindex: Wanderlust links @@ -3465,15 +3542,19 @@ the link completion function like this: :END: #+cindex: search option in file links #+cindex: file links, searching +#+cindex: attachment links, searching -File links can contain additional information to make Emacs jump to -a particular location in the file when following a link. This can be -a line number or a search option after a double colon[fn:34]. For +File links can contain additional information to make Emacs jump to a +particular location in the file when following a link. This can be a +line number or a search option after a double colon[fn:34]. For example, when the command ~org-store-link~ creates a link (see [[*Handling Links]]) to a file, it encodes the words in the current line as a search string that can be used to find this line back later when following the link with {{{kbd(C-c C-o)}}}. +Note that all search options apply for Attachment links in the same +way that they apply for File links. + Here is the syntax of the different ways to attach a search to a file link, together with explanations for each: @@ -3483,6 +3564,7 @@ link, together with explanations for each: [[file:~/xx.org::*My Target]] [[file:~/xx.org::#my-custom-id]] [[file:~/xx.org::/regexp/]] +[[attachment:main.c::255]] #+end_example - =255= :: @@ -6896,163 +6978,420 @@ same commands. continue the old one. This command also removes the timer from the mode line. -* Capture, Refile, Archive -:PROPERTIES: -:DESCRIPTION: The ins and outs for projects. -:END: -#+cindex: capture - -An important part of any organization system is the ability to quickly -capture new ideas and tasks, and to associate reference material with -them. Org does this using a process called /capture/. It also can -store files related to a task (/attachments/) in a special directory. -Once in the system, tasks and projects need to be moved around. -Moving completed project trees to an archive file keeps the system -compact and fast. - -** Capture +* Refile, Copy and Archiving :PROPERTIES: -:DESCRIPTION: Capturing new stuff. +:DESCRIPTION: Moving and copying information with ease. :END: -#+cindex: capture +#+cindex: refiling notes +#+cindex: copying notes +#+cindex: archiving -Capture lets you quickly store notes with little interruption of your -work flow. Org's method for capturing new items is heavily inspired -by John Wiegley's excellent Remember package. +Once information is in the system, it may need to be moved around. +Org provides Refile, Copy and Archive commands for this. Refile and +Copy helps with moving and copying outlines. Archiving helps to keep +the system compact and fast. -*** Setting up capture +** Refile and Copy :PROPERTIES: -:DESCRIPTION: Where notes will be stored. +:DESCRIPTION: Moving/copying a tree from one place to another. :END: +#+cindex: refiling notes +#+cindex: copying notes -The following customization sets a default target file for notes. +When reviewing the captured data, you may want to refile or to copy +some of the entries into a different list, for example into a project. +Cutting, finding the right location, and then pasting the note is +cumbersome. To simplify this process, you can use the following +special command: -#+vindex: org-default-notes-file -#+begin_src emacs-lisp -(setq org-default-notes-file (concat org-directory "/notes.org")) -#+end_src +- {{{kbd(C-c C-w)}}} (~org-refile~) :: -You may also define a global key for capturing new material (see -[[*Activation]]). + #+kindex: C-c C-w + #+findex: org-refile + #+vindex: org-reverse-note-order + #+vindex: org-refile-targets + #+vindex: org-refile-use-outline-path + #+vindex: org-outline-path-complete-in-steps + #+vindex: org-refile-allow-creating-parent-nodes + #+vindex: org-log-refile + Refile the entry or region at point. This command offers possible + locations for refiling the entry and lets you select one with + completion. The item (or all items in the region) is filed below + the target heading as a subitem. Depending on + ~org-reverse-note-order~, it is either the first or last subitem. -*** Using capture -:PROPERTIES: -:DESCRIPTION: Commands to invoke and terminate capture. -:END: + By default, all level 1 headlines in the current buffer are + considered to be targets, but you can have more complex definitions + across a number of files. See the variable ~org-refile-targets~ for + details. If you would like to select a location via + a file-path-like completion along the outline path, see the + variables ~org-refile-use-outline-path~ and + ~org-outline-path-complete-in-steps~. If you would like to be able + to create new nodes as new parents for refiling on the fly, check + the variable ~org-refile-allow-creating-parent-nodes~. When the + variable ~org-log-refile~[fn:88] is set, a timestamp or a note is + recorded whenever an entry is refiled. -- {{{kbd(M-x org-capture)}}} (~org-capture~) :: +- {{{kbd(C-u C-c C-w)}}} :: - #+findex: org-capture - #+cindex: date tree - Display the capture templates menu. If you have templates defined - (see [[*Capture templates]]), it offers these templates for selection or - use a new Org outline node as the default template. It inserts the - template into the target file and switch to an indirect buffer - narrowed to this new node. You may then insert the information you - want. + #+kindex: C-u C-c C-w + Use the refile interface to jump to a heading. -- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: +- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: - #+kindex: C-c C-c @r{(Capture buffer)} - #+findex: org-capture-finalize - Once you have finished entering information into the capture buffer, - {{{kbd(C-c C-c)}}} returns you to the window configuration before - the capture process, so that you can resume your work without - further distraction. When called with a prefix argument, finalize - and then jump to the captured item. + #+kindex: C-u C-u C-c C-w + #+findex: org-refile-goto-last-stored + Jump to the location where ~org-refile~ last moved a tree to. -- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: +- {{{kbd(C-2 C-c C-w)}}} :: - #+kindex: C-c C-w @r{(Capture buffer)} - #+findex: org-capture-refile - Finalize the capture process by refiling the note to a different - place (see [[*Refile and Copy]]). Please realize that this is a normal - refiling command that will be executed---so point position at the - moment you run this command is important. If you have inserted - a tree with a parent and children, first move point back to the - parent. Any prefix argument given to this command is passed on to - the ~org-refile~ command. + #+kindex: C-2 C-c C-w + Refile as the child of the item currently being clocked. -- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: +- {{{kbd(C-3 C-c C-w)}}} :: - #+kindex: C-c C-k @r{(Capture buffer)} - #+findex: org-capture-kill - Abort the capture process and return to the previous state. + #+kindex: C-3 C-c C-w + #+vindex: org-refile-keep + Refile and keep the entry in place. Also see ~org-refile-keep~ to + make this the default behavior, and beware that this may result in + duplicated =ID= properties. -#+kindex: k c @r{(Agenda)} -You can also call ~org-capture~ in a special way from the agenda, -using the {{{kbd(k c)}}} key combination. With this access, any -timestamps inserted by the selected capture template defaults to the -date at point in the agenda, rather than to the current date. +- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: -To find the locations of the last stored capture, use ~org-capture~ -with prefix commands: + #+kindex: C-u C-u C-u C-c C-w + #+kindex: C-0 C-c C-w + #+findex: org-refile-cache-clear + #+vindex: org-refile-use-cache + Clear the target cache. Caching of refile targets can be turned on + by setting ~org-refile-use-cache~. To make the command see new + possible targets, you have to clear the cache with this command. -- {{{kbd(C-u M-x org-capture)}}} :: +- {{{kbd(C-c M-w)}}} (~org-copy~) :: - Visit the target location of a capture template. You get to select - the template in the usual way. + #+kindex: C-c M-w + #+findex: org-copy + Copying works like refiling, except that the original note is not + deleted. -- {{{kbd(C-u C-u M-x org-capture)}}} :: +** Archiving +:PROPERTIES: +:DESCRIPTION: What to do with finished products. +:END: +#+cindex: archiving - Visit the last stored capture item in its buffer. +When a project represented by a (sub)tree is finished, you may want to +move the tree out of the way and to stop it from contributing to the +agenda. Archiving is important to keep your working files compact and +global searches like the construction of agenda views fast. -#+vindex: org-capture-bookmark -#+vindex: org-capture-last-stored -You can also jump to the bookmark ~org-capture-last-stored~, which is -automatically created unless you set ~org-capture-bookmark~ to ~nil~. +- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: -To insert the capture at point in an Org buffer, call ~org-capture~ -with a {{{kbd(C-0)}}} prefix argument. + #+kindex: C-c C-x C-a + #+findex: org-archive-subtree-default + #+vindex: org-archive-default-command + Archive the current entry using the command specified in the + variable ~org-archive-default-command~. -*** Capture templates +*** Moving a tree to an archive file :PROPERTIES: -:DESCRIPTION: Define the outline of different note types. +:DESCRIPTION: Moving a tree to an archive file. +:ALT_TITLE: Moving subtrees :END: -#+cindex: templates, for Capture - -You can use templates for different types of capture items, and for -different target locations. The easiest way to create such templates -is through the customize interface. +#+cindex: external archiving -- {{{kbd(C)}}} :: +The most common archiving action is to move a project tree to another +file, the archive file. - #+kindex: C @r{(Capture menu} - #+vindex: org-capture-templates - Customize the variable ~org-capture-templates~. +- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: -Before we give the formal description of template definitions, let's -look at an example. Say you would like to use one template to create -general TODO entries, and you want to put these entries under the -heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in -the file =journal.org= should capture journal entries. A possible -configuration would look like: + #+kindex: C-c C-x C-s + #+kindex: C-c $ + #+findex: org-archive-subtree + #+vindex: org-archive-location + Archive the subtree starting at point position to the location given + by ~org-archive-location~. -#+begin_src emacs-lisp -(setq org-capture-templates - '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") - "* TODO %?\n %i\n %a") - ("j" "Journal" entry (file+datetree "~/org/journal.org") - "* %?\nEntered on %U\n %i\n %a"))) -#+end_src +- {{{kbd(C-u C-c C-x C-s)}}} :: -If you then press {{{kbd(t)}}} from the capture menu, Org will prepare -the template for you like this: + #+kindex: C-u C-c C-x C-s + Check if any direct children of the current headline could be moved + to the archive. To do this, check each subtree for open TODO + entries. If none is found, the command offers to move it to the + archive location. If point is /not/ on a headline when this command + is invoked, check level 1 trees. -#+begin_example -,* TODO - [[file:LINK TO WHERE YOU INITIATED CAPTURE]] -#+end_example +- {{{kbd(C-u C-u C-c C-x C-s)}}} :: -#+texinfo: @noindent -During expansion of the template, =%a= has been replaced by a link to -the location from where you called the capture command. This can be -extremely useful for deriving tasks from emails, for example. You -fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns -you to the same place where you started the capture process. + #+kindex: C-u C-u C-c C-x C-s + As above, but check subtree for timestamps instead of TODO entries. + The command offers to archive the subtree if it /does/ contain + a timestamp, and that timestamp is in the past. -To define special keys to capture to a particular template without -going through the interactive template selection, you can create your +#+cindex: archive locations +The default archive location is a file in the same directory as the +current file, with the name derived by appending =_archive= to the +current file name. You can also choose what heading to file archived +items under, with the possibility to add them to a datetree in a file. +For information and examples on how to specify the file and the +heading, see the documentation string of the variable +~org-archive-location~. + +There is also an in-buffer option for setting this variable, for +example: + +#+cindex: @samp{ARCHIVE}, keyword +: #+ARCHIVE: %s_done:: + +#+cindex: ARCHIVE, property +If you would like to have a special archive location for a single +entry or a (sub)tree, give the entry an =ARCHIVE= property with the +location as the value (see [[*Properties and Columns]]). + +#+vindex: org-archive-save-context-info +When a subtree is moved, it receives a number of special properties +that record context information like the file from where the entry +came, its outline path the archiving time etc. Configure the variable +~org-archive-save-context-info~ to adjust the amount of information +added. + +*** Internal archiving +:PROPERTIES: +:DESCRIPTION: Switch off a tree but keep it in the file. +:END: + +#+cindex: @samp{ARCHIVE}, tag +If you want to just switch off---for agenda views---certain subtrees +without moving them to a different file, you can use the =ARCHIVE= +tag. + +A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at +its location in the outline tree, but behaves in the following way: + +- + #+vindex: org-cycle-open-archived-trees + It does not open when you attempt to do so with a visibility cycling + command (see [[*Visibility Cycling]]). You can force cycling archived + subtrees with {{{kbd(C-TAB)}}}, or by setting the option + ~org-cycle-open-archived-trees~. Also normal outline commands, like + ~outline-show-all~, open archived subtrees. + +- + #+vindex: org-sparse-tree-open-archived-trees + During sparse tree construction (see [[*Sparse Trees]]), matches in + archived subtrees are not exposed, unless you configure the option + ~org-sparse-tree-open-archived-trees~. + +- + #+vindex: org-agenda-skip-archived-trees + During agenda view construction (see [[*Agenda Views]]), the content of + archived trees is ignored unless you configure the option + ~org-agenda-skip-archived-trees~, in which case these trees are + always included. In the agenda you can press {{{kbd(v a)}}} to get + archives temporarily included. + +- + #+vindex: org-export-with-archived-trees + Archived trees are not exported (see [[*Exporting]]), only the headline + is. Configure the details using the variable + ~org-export-with-archived-trees~. + +- + #+vindex: org-columns-skip-archived-trees + Archived trees are excluded from column view unless the variable + ~org-columns-skip-archived-trees~ is configured to ~nil~. + +The following commands help manage the =ARCHIVE= tag: + +- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: + + #+kindex: C-c C-x a + #+findex: org-toggle-archive-tag + Toggle the archive tag for the current headline. When the tag is + set, the headline changes to a shadowed face, and the subtree below + it is hidden. + +- {{{kbd(C-u C-c C-x a)}}} :: + + #+kindex: C-u C-c C-x a + Check if any direct children of the current headline should be + archived. To do this, check each subtree for open TODO entries. If + none is found, the command offers to set the =ARCHIVE= tag for the + child. If point is /not/ on a headline when this command is + invoked, check the level 1 trees. + +- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: + + #+kindex: C-TAB + Cycle a tree even if it is tagged with =ARCHIVE=. + +- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: + + #+kindex: C-c C-x A + #+findex: org-archive-to-archive-sibling + Move the current entry to the /Archive Sibling/. This is a sibling + of the entry with the heading =Archive= and the archive tag. The + entry becomes a child of that sibling and in this way retains a lot + of its original context, including inherited tags and approximate + position in the outline. + +* Capture, Attachments, RSS Feeds and Protocols +:PROPERTIES: +:DESCRIPTION: Dealing with external data. +:END: +#+cindex: capture +#+cindex: attachments +#+cindex: RSS feeds +#+cindex: Atom feeds +#+cindex: protocols, for external access + +An important part of any organization system is the ability to quickly +capture new ideas and tasks, and to associate reference material with +them. Org does this using a process called /capture/. It also can +store files related to a task (/attachments/) in a special directory. + +** Capture +:PROPERTIES: +:DESCRIPTION: Capturing new stuff. +:END: +#+cindex: capture + +Capture lets you quickly store notes with little interruption of your +work flow. Org's method for capturing new items is heavily inspired +by John Wiegley's excellent Remember package. + +*** Setting up capture +:PROPERTIES: +:DESCRIPTION: Where notes will be stored. +:END: + +The following customization sets a default target file for notes. + +#+vindex: org-default-notes-file +#+begin_src emacs-lisp +(setq org-default-notes-file (concat org-directory "/notes.org")) +#+end_src + +You may also define a global key for capturing new material (see +[[*Activation]]). + +*** Using capture +:PROPERTIES: +:DESCRIPTION: Commands to invoke and terminate capture. +:END: + +- {{{kbd(M-x org-capture)}}} (~org-capture~) :: + + #+findex: org-capture + #+cindex: date tree + Display the capture templates menu. If you have templates defined + (see [[*Capture templates]]), it offers these templates for selection or + use a new Org outline node as the default template. It inserts the + template into the target file and switch to an indirect buffer + narrowed to this new node. You may then insert the information you + want. + +- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: + + #+kindex: C-c C-c @r{(Capture buffer)} + #+findex: org-capture-finalize + Once you have finished entering information into the capture buffer, + {{{kbd(C-c C-c)}}} returns you to the window configuration before + the capture process, so that you can resume your work without + further distraction. When called with a prefix argument, finalize + and then jump to the captured item. + +- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: + + #+kindex: C-c C-w @r{(Capture buffer)} + #+findex: org-capture-refile + Finalize the capture process by refiling the note to a different + place (see [[*Refile and Copy]]). Please realize that this is a normal + refiling command that will be executed---so point position at the + moment you run this command is important. If you have inserted + a tree with a parent and children, first move point back to the + parent. Any prefix argument given to this command is passed on to + the ~org-refile~ command. + +- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: + + #+kindex: C-c C-k @r{(Capture buffer)} + #+findex: org-capture-kill + Abort the capture process and return to the previous state. + +#+kindex: k c @r{(Agenda)} +You can also call ~org-capture~ in a special way from the agenda, +using the {{{kbd(k c)}}} key combination. With this access, any +timestamps inserted by the selected capture template defaults to the +date at point in the agenda, rather than to the current date. + +To find the locations of the last stored capture, use ~org-capture~ +with prefix commands: + +- {{{kbd(C-u M-x org-capture)}}} :: + + Visit the target location of a capture template. You get to select + the template in the usual way. + +- {{{kbd(C-u C-u M-x org-capture)}}} :: + + Visit the last stored capture item in its buffer. + +#+vindex: org-capture-bookmark +#+vindex: org-capture-last-stored +You can also jump to the bookmark ~org-capture-last-stored~, which is +automatically created unless you set ~org-capture-bookmark~ to ~nil~. + +To insert the capture at point in an Org buffer, call ~org-capture~ +with a {{{kbd(C-0)}}} prefix argument. + +*** Capture templates +:PROPERTIES: +:DESCRIPTION: Define the outline of different note types. +:END: +#+cindex: templates, for Capture + +You can use templates for different types of capture items, and for +different target locations. The easiest way to create such templates +is through the customize interface. + +- {{{kbd(C)}}} :: + + #+kindex: C @r{(Capture menu} + #+vindex: org-capture-templates + Customize the variable ~org-capture-templates~. + +Before we give the formal description of template definitions, let's +look at an example. Say you would like to use one template to create +general TODO entries, and you want to put these entries under the +heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in +the file =journal.org= should capture journal entries. A possible +configuration would look like: + +#+begin_src emacs-lisp +(setq org-capture-templates + '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") + "* TODO %?\n %i\n %a") + ("j" "Journal" entry (file+datetree "~/org/journal.org") + "* %?\nEntered on %U\n %i\n %a"))) +#+end_src + +If you then press {{{kbd(t)}}} from the capture menu, Org will prepare +the template for you like this: + +#+begin_example +,* TODO + [[file:LINK TO WHERE YOU INITIATED CAPTURE]] +#+end_example + +#+texinfo: @noindent +During expansion of the template, =%a= has been replaced by a link to +the location from where you called the capture command. This can be +extremely useful for deriving tasks from emails, for example. You +fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns +you to the same place where you started the capture process. + +To define special keys to capture to a particular template without +going through the interactive template selection, you can create your key binding like this: #+begin_src emacs-lisp @@ -7437,28 +7776,30 @@ See the docstring of the variable for more information. ** Attachments :PROPERTIES: -:DESCRIPTION: Add files to tasks. +:DESCRIPTION: Attach files to outlines. :END: #+cindex: attachments -#+vindex: org-attach-directory It is often useful to associate reference material with an outline -node/task. Small chunks of plain text can simply be stored in the -subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish -associations with files that live elsewhere on your computer or in the -cloud, like emails or source code files belonging to a project. -Another method is /attachments/, which are files located in -a directory belonging to an outline node. Org uses directories named -by the unique ID of each entry. These directories are located in the -=data/= directory which lives in the same directory where your Org -file lives[fn:87]. If you initialize this directory with =git init=, -Org automatically commits changes when it sees them. The attachment -system has been contributed to Org by John Wiegley. - -In cases where it seems better to do so, you can attach a directory of -your choice to an entry. You can also make children inherit the -attachment directory from a parent, so that an entire subtree uses the -same attached directory. +node. Small chunks of plain text can simply be stored in the subtree +of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations +with files that live elsewhere on your computer or in the cloud, like +emails or source code files belonging to a project. + +Another method is /attachments/, which are files located in a +directory belonging to an outline node. Org uses directories either +named by a unique ID of each entry, or by a =DIR= property. + +*** Attachment defaults and dispatcher +By default, org-attach will use ID properties when adding attachments +to outline nodes. This makes working with attachments fully +automated. There is no decision needed for folder-name or location. +ID-based directories are by default located in the =data/= directory, +which lives in the same directory where your Org file lives[fn:87]. +For more control over the setup, see [[*Attachment options]]. + +When attachments are made using ~org-attach~ a default tag =ATTACH= is +added to the node that gets the attachments. The following commands deal with attachments: @@ -7543,25 +7884,144 @@ The following commands deal with attachments: - {{{kbd(D)}}} (~org-attach-delete-all~) :: - #+kindex: C-c C-a D - Delete all of a task's attachments. A safer way is to open the - directory in Dired and delete from there. + #+kindex: C-c C-a D + Delete all of a task's attachments. A safer way is to open the + directory in Dired and delete from there. + + - {{{kbd(s)}}} (~org-attach-set-directory~) :: + + #+kindex: C-c C-a s + #+cindex: @samp{DIR}, property + Set a specific directory as the entry's attachment directory. + This works by putting the directory path into the =DIR= + property. + + - {{{kbd(S)}}} (~org-attach-unset-directory~) :: + + #+kindex: C-c C-a S + #+cindex: @samp{DIR}, property + Remove the attachment directory. This command removes the =DIR= + property and asks the user to either move content inside that + folder, if an =ID= property is set, delete the content, or to + leave the attachment directory as is but no longer attached to the + outline node. + +*** Attachment options +There are a couple of options for attachments that are worth +mentioning. + +- ~org-attach-id-dir~ :: + #+vindex: org-attach-id-dir + The directory where attachments are stored when =ID= is used as + method. + +- ~org-attach-dir-relative~ :: + #+vindex: org-attach-dir-relative + When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}} + (~org-attach-set-directory~), absolute links are entered by default. + This option changes that to relative links. + +- ~org-attach-use-inheritance~ :: + #+vindex: org-attach-use-inheritance + By default folders attached to an outline node are inherited from + parents according to ~org-use-property-inheritance~. If one instead + want to set inheritance specifically for org-attach that can be done + using ~org-attach-use-inheritance~. Inheriting documents through + the node hierarchy makes a lot of sense in most cases. Especially + since the introduction of [[* Attachment links]]. The following example + shows one use case for attachment inheritance: + + #+begin_example + ,* Chapter A ... + :PROPERTIES: + :DIR: Chapter A/ + :END: + ,** Introduction + Some text + + #+NAME: Image 1 + [[Attachment:image 1.jpg]] + #+end_example + + Without inheritance one would not be able to resolve the link to + image =1.jpg=, since the link is inside a sub-heading to =Chapter + A=. + + Inheritance works the same way for both =ID= and =DIR= property. If + both properties are defined on the same headline then =DIR= takes + precedance. This is also true if inheritance is enabled. If =DIR= + is inherited from a parent node in the outline, that property still + takes precedence over an =ID= property defined on the node itself. + +- ~org-attach-method~ :: + #+vindex: org-attach-method + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it + defaults to copying files. The behaviour can be changed by + customizing ~org-attach-method~. Options are Copy, Move/Rename, + Hard link or Symbolic link. + +- ~org-attach-preferred-new-method~ :: + #+vindex: org-attach-preferred-new-method + This customization lets you choose the default way to attach to + nodes without existing =ID= and =DIR= property. It defaults to ~id~ + but can also be set to ~dir~, ~ask~ or ~nil~. + +- ~org-attach-archive-delete~ :: + #+vindex: org-attach-archive-delete + Configure this to determine if attachments should be deleted or not + when a subtree that has attachments is archived. + +- ~org-attach-auto-tag~ :: + #+vindex: org-attach-auto-tag + When attaching files to a heading it will be assigned a tag + according to what is set here. + +- ~org-attach-id-to-path-function~ :: + #+vindex: org-attach-id-to-path-function + When =ID= is used for attachments, the ID is parsed into a part of a + directory-path. See ~org-attach-id-folder-format~ for the default + function. Define a new one and add it to + ~org-attach-id-to-path-function~ if you want the folder structure + any other way. Note that modifying this makes org-attach dependent + on your function also for opening attachments, not only setting + them! + +- ~org-attach-expert~ :: + #+vindex: org-attach-expert + Do not show the splash buffer with the attach dispatcher when + ~org-attach-expert~ is set to non-~nil~. + +See customization group =Org Attach= if you want to change the +default settings. + +*** Attachment links +Attached files and folders can be referenced using attachment links. +This makes it easy to refer to the material added to an outline node. +Especially if it was attached using the unique ID of the entry! + +#+begin_example +,* TODO Some task + :PROPERTIES: + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 + :END: +See attached document for more information: [[attachment:info.org]] +#+end_example - - {{{kbd(s)}}} (~org-attach-set-directory~) :: +See [[*External Links]] for more information about these links. - #+kindex: C-c C-a s - #+cindex: @samp{ATTACH_DIR}, property - Set a specific directory as the entry's attachment directory. - This works by putting the directory path into the =ATTACH_DIR= - property. +*** Automatic version-control with Git +If the directory attached to an outline node is a Git repository, Org +can be configured to automatically commit changes to that repository +when it sees them. - - {{{kbd(i)}}} (~org-attach-set-inherit~) :: +To make Org mode take care of versioning of attachments for you, add +the following to your Emacs config: - #+kindex: C-c C-a i - #+cindex: @samp{ATTACH_DIR_INHERIT}, property - Set the =ATTACH_DIR_INHERIT= property, so that children use the - same directory for attachments as the parent does. +#+begin_src emacs-lisp + (require 'org-attach-git) +#+end_src +*** Attach from Dired #+cindex: attach from Dired #+findex: org-attach-dired-to-subtree It is possible to attach files to a subtree from a Dired buffer. To @@ -7832,249 +8292,6 @@ valid contents: ~org-protocol-create~ and ~org-protocol-create-for-org~. The latter is of use if you're editing an Org file that is part of a publishing project. -** Refile and Copy -:PROPERTIES: -:DESCRIPTION: Moving/copying a tree from one place to another. -:END: -#+cindex: refiling notes -#+cindex: copying notes - -When reviewing the captured data, you may want to refile or to copy -some of the entries into a different list, for example into a project. -Cutting, finding the right location, and then pasting the note is -cumbersome. To simplify this process, you can use the following -special command: - -- {{{kbd(C-c C-w)}}} (~org-refile~) :: - - #+kindex: C-c C-w - #+findex: org-refile - #+vindex: org-reverse-note-order - #+vindex: org-refile-targets - #+vindex: org-refile-use-outline-path - #+vindex: org-outline-path-complete-in-steps - #+vindex: org-refile-allow-creating-parent-nodes - #+vindex: org-log-refile - Refile the entry or region at point. This command offers possible - locations for refiling the entry and lets you select one with - completion. The item (or all items in the region) is filed below - the target heading as a subitem. Depending on - ~org-reverse-note-order~, it is either the first or last subitem. - - By default, all level 1 headlines in the current buffer are - considered to be targets, but you can have more complex definitions - across a number of files. See the variable ~org-refile-targets~ for - details. If you would like to select a location via - a file-path-like completion along the outline path, see the - variables ~org-refile-use-outline-path~ and - ~org-outline-path-complete-in-steps~. If you would like to be able - to create new nodes as new parents for refiling on the fly, check - the variable ~org-refile-allow-creating-parent-nodes~. When the - variable ~org-log-refile~[fn:88] is set, a timestamp or a note is - recorded whenever an entry is refiled. - -- {{{kbd(C-u C-c C-w)}}} :: - - #+kindex: C-u C-c C-w - Use the refile interface to jump to a heading. - -- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: - - #+kindex: C-u C-u C-c C-w - #+findex: org-refile-goto-last-stored - Jump to the location where ~org-refile~ last moved a tree to. - -- {{{kbd(C-2 C-c C-w)}}} :: - - #+kindex: C-2 C-c C-w - Refile as the child of the item currently being clocked. - -- {{{kbd(C-3 C-c C-w)}}} :: - - #+kindex: C-3 C-c C-w - #+vindex: org-refile-keep - Refile and keep the entry in place. Also see ~org-refile-keep~ to - make this the default behavior, and beware that this may result in - duplicated =ID= properties. - -- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: - - #+kindex: C-u C-u C-u C-c C-w - #+kindex: C-0 C-c C-w - #+findex: org-refile-cache-clear - #+vindex: org-refile-use-cache - Clear the target cache. Caching of refile targets can be turned on - by setting ~org-refile-use-cache~. To make the command see new - possible targets, you have to clear the cache with this command. - -- {{{kbd(C-c M-w)}}} (~org-copy~) :: - - #+kindex: C-c M-w - #+findex: org-copy - Copying works like refiling, except that the original note is not - deleted. - -** Archiving -:PROPERTIES: -:DESCRIPTION: What to do with finished products. -:END: -#+cindex: archiving - -When a project represented by a (sub)tree is finished, you may want to -move the tree out of the way and to stop it from contributing to the -agenda. Archiving is important to keep your working files compact and -global searches like the construction of agenda views fast. - -- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: - - #+kindex: C-c C-x C-a - #+findex: org-archive-subtree-default - #+vindex: org-archive-default-command - Archive the current entry using the command specified in the - variable ~org-archive-default-command~. - -*** Moving a tree to an archive file -:PROPERTIES: -:DESCRIPTION: Moving a tree to an archive file. -:ALT_TITLE: Moving subtrees -:END: -#+cindex: external archiving - -The most common archiving action is to move a project tree to another -file, the archive file. - -- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: - - #+kindex: C-c C-x C-s - #+kindex: C-c $ - #+findex: org-archive-subtree - #+vindex: org-archive-location - Archive the subtree starting at point position to the location given - by ~org-archive-location~. - -- {{{kbd(C-u C-c C-x C-s)}}} :: - - #+kindex: C-u C-c C-x C-s - Check if any direct children of the current headline could be moved - to the archive. To do this, check each subtree for open TODO - entries. If none is found, the command offers to move it to the - archive location. If point is /not/ on a headline when this command - is invoked, check level 1 trees. - -- {{{kbd(C-u C-u C-c C-x C-s)}}} :: - - #+kindex: C-u C-u C-c C-x C-s - As above, but check subtree for timestamps instead of TODO entries. - The command offers to archive the subtree if it /does/ contain - a timestamp, and that timestamp is in the past. - -#+cindex: archive locations -The default archive location is a file in the same directory as the -current file, with the name derived by appending =_archive= to the -current file name. You can also choose what heading to file archived -items under, with the possibility to add them to a datetree in a file. -For information and examples on how to specify the file and the -heading, see the documentation string of the variable -~org-archive-location~. - -There is also an in-buffer option for setting this variable, for -example: - -#+cindex: @samp{ARCHIVE}, keyword -: #+ARCHIVE: %s_done:: - -#+cindex: ARCHIVE, property -If you would like to have a special archive location for a single -entry or a (sub)tree, give the entry an =ARCHIVE= property with the -location as the value (see [[*Properties and Columns]]). - -#+vindex: org-archive-save-context-info -When a subtree is moved, it receives a number of special properties -that record context information like the file from where the entry -came, its outline path the archiving time etc. Configure the variable -~org-archive-save-context-info~ to adjust the amount of information -added. - -*** Internal archiving -:PROPERTIES: -:DESCRIPTION: Switch off a tree but keep it in the file. -:END: - -#+cindex: @samp{ARCHIVE}, tag -If you want to just switch off---for agenda views---certain subtrees -without moving them to a different file, you can use the =ARCHIVE= -tag. - -A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at -its location in the outline tree, but behaves in the following way: - -- - #+vindex: org-cycle-open-archived-trees - It does not open when you attempt to do so with a visibility cycling - command (see [[*Visibility Cycling]]). You can force cycling archived - subtrees with {{{kbd(C-TAB)}}}, or by setting the option - ~org-cycle-open-archived-trees~. Also normal outline commands, like - ~outline-show-all~, open archived subtrees. - -- - #+vindex: org-sparse-tree-open-archived-trees - During sparse tree construction (see [[*Sparse Trees]]), matches in - archived subtrees are not exposed, unless you configure the option - ~org-sparse-tree-open-archived-trees~. - -- - #+vindex: org-agenda-skip-archived-trees - During agenda view construction (see [[*Agenda Views]]), the content of - archived trees is ignored unless you configure the option - ~org-agenda-skip-archived-trees~, in which case these trees are - always included. In the agenda you can press {{{kbd(v a)}}} to get - archives temporarily included. - -- - #+vindex: org-export-with-archived-trees - Archived trees are not exported (see [[*Exporting]]), only the headline - is. Configure the details using the variable - ~org-export-with-archived-trees~. - -- - #+vindex: org-columns-skip-archived-trees - Archived trees are excluded from column view unless the variable - ~org-columns-skip-archived-trees~ is configured to ~nil~. - -The following commands help manage the =ARCHIVE= tag: - -- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: - - #+kindex: C-c C-x a - #+findex: org-toggle-archive-tag - Toggle the archive tag for the current headline. When the tag is - set, the headline changes to a shadowed face, and the subtree below - it is hidden. - -- {{{kbd(C-u C-c C-x a)}}} :: - - #+kindex: C-u C-c C-x a - Check if any direct children of the current headline should be - archived. To do this, check each subtree for open TODO entries. If - none is found, the command offers to set the =ARCHIVE= tag for the - child. If point is /not/ on a headline when this command is - invoked, check the level 1 trees. - -- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: - - #+kindex: C-TAB - Cycle a tree even if it is tagged with =ARCHIVE=. - -- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: - - #+kindex: C-c C-x A - #+findex: org-archive-to-archive-sibling - Move the current entry to the /Archive Sibling/. This is a sibling - of the entry with the heading =Archive= and the archive tag. The - entry becomes a child of that sibling and in this way retains a lot - of its original context, including inherited tags and approximate - position in the outline. - * Agenda Views :PROPERTIES: :DESCRIPTION: Collecting information into views. @@ -21244,7 +21461,7 @@ accessed in capture templates in a similar way. ~org-link-from-user-regexp~. [fn:87] If you move entries or Org files from one directory to -another, you may want to configure ~org-attach-directory~ to contain +another, you may want to configure ~org-attach-id-dir~ to contain an absolute path. [fn:88] Note the corresponding =STARTUP= options =logrefile=, diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 4abecdfbc..bbd9dc975 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI alternative was removed and there is no more a :use-xcolor options since now it's implicitly always true. +*** Org-Attach Git commit +[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality. Not +much, but the following changes are required if you still need to +auto-commit attachments to git: + +- Customization of ~org-attach-annex-auto-get~ needs to be renamed to + ~org-attach-git-annex-auto-get~. + +- Customization of ~org-attach-commit~ is no longer needed. Instead + one need to require the =org-attach-git= module in the startup. + ** New features +*** Org-Attach has been refactored and extended +Org attach has been refactored and the functionality extended. It +should now be easier to understand how it works. A few improvements +and extra options have been added as well. + +From the initial comment in org-attach source-code: + +- Attachments are managed either by using a custom property DIR or by + using property ID from org-id. When DIR is defined, a location in + the filesystem is directly attached to the outline node. When + org-id is used, attachments are stored in a folder named after the + ID, in a location defined by ~org-attach-id-dir~. DIR has + precedence over ID when both parameters are defined for the current + outline node (also when inherited parameters are taken into + account). + +From now on inheritance requires no extra property and will adhere to +~org-attach-use-inheritance~ by default. Inheritance can be +customized to always be activated or never be activated in +~org-attach-use-inheritance~. + +The ATTACH_DIR property is deprecated in favour of the shorter +property DIR. Links to folders inside the DIR property can now be +declared as relative links. This is not enabled by default, but can +be set in ~org-attach-dir-relative~. + +When adding new attachment to the outline node the preferred way of +doing so can be customized. Take a look at +~org-attach-preferred-new-method~. It defaults to using ID since that +was the behaviour before this change. + +If both DIR and ID properties are set on the same node, DIR has +precedence and will be used. + +One can now also choose to build attachment-directory-paths in a +customized way. This is an advanced topic, but in some case it makes +sense to parse an ID in a different way than the default one. Create +your own function and use it is ~org-attach-id-to-path-function~ if +you want to customize the ID-based folder structure. + +If you've used ATTACH_DIR properties to manage attachments, use the +following code to rename that property to DIR which supports the same +functionality. ATTACH_DIR_INHERIT is no longer supported and is +removed. + +#+begin_src emacs-lisp + (defun org-update-attach-properties () + "Change properties for Org-Attach." + (interactive) + (org-with-point-at 1 + (while (outline-next-heading) + (let ((DIR (org--property-local-values "ATTACH_DIR" nil))) + (when DIR + (org-set-property "DIR" (car DIR)) + (org-delete-property "ATTACH_DIR")))) + (org-delete-property-globally "ATTACH_DIR_INHERIT"))) +#+end_src + +For those who hate breaking changes, even though the changes are made +to clean things up; fear not. ATTACH_DIR will still continue to work. +It's just not documented any longer. When you get the chance, run the +code above to clean things up anyways! + +**** New hooks +Two hooks are added to org-attach: +- org-attach-after-change-hook +- org-attach-open-hook + +They are added mostly for internal restructuring purposes, but can +ofc. be used for other things as well. + +*** New link-type: Attachment +Attachment-links are now first-class citizens. They mimick file-links +in everything they do but use the existing attachment-folder as a base +when expanding the links. Both =DIR= and =ID= properties are used to +try to resolve the links, in exactly the same way as Org-Attach uses +those properties. + *** Handle overlay specification for notes in Beamer export This aligns Beamer notes with slide overlays. @@ -243,6 +332,11 @@ dynamic block in ~org-dynamic-block-alist~. ** Removed functions *** ~org-babel-set-current-result-hash~ *** ~org-capture-insert-template-here~ +*** ~org-attach-directory~ + +It has been deprecated in favour of ~org-attach-id-dir~ which is less +ambigous given the restructured org-attach. + ** Miscellaneous *** Change signature for ~org-list-to-subtree~ The function now accepts the level of the subtree as an optional diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el new file mode 100644 index 000000000..f40eb966d --- /dev/null +++ b/lisp/org-attach-git.el @@ -0,0 +1,117 @@ +;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Free Software Foundation, Inc. + +;; Original Author: John Wiegley <johnw@newartisans.com> +;; Restructurer: Gustav Wikström <gustav@whil.se> +;; Keywords: org data git + +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; An extention to org-attach. If the attachment-directory to an +;; outline node (using either DIR or ID) is initialized as a Git +;; repository, then org-attach-git will automatically commit changes +;; when it sees them. + +;;; Code: + +(require 'org-attach) +(require 'vc-git) + +(defcustom org-attach-git-annex-cutoff (* 32 1024) + "If non-nil, files larger than this will be annexed instead of stored." + :group 'org-attach + :version "24.4" + :package-version '(Org . "8.0") + :type '(choice + (const :tag "None" nil) + (integer :tag "Bytes"))) + +(defcustom org-attach-git-annex-auto-get 'ask + "Confirmation preference for automatically getting annex files. +If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." + :group 'org-attach + :package-version '(Org . "9.0") + :version "26.1" + :type '(choice + (const :tag "confirm with `y-or-n-p'" ask) + (const :tag "always get from annex if necessary" t) + (const :tag "never get from annex" nil))) + +(defun org-attach-git-use-annex () + "Return non-nil if git annex can be used." + (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir)))) + (and org-attach-git-annex-cutoff + (or (file-exists-p (expand-file-name "annex" git-dir)) + (file-exists-p (expand-file-name ".git/annex" git-dir)))))) + +(defun org-attach-git-annex-get-maybe (path) + "Call git annex get PATH (via shell) if using git annex. +Signals an error if the file content is not available and it was not retrieved." + (let* ((default-directory (expand-file-name org-attach-id-dir)) + (path-relative (file-relative-name path))) + (when (and (org-attach-git-use-annex) + (not + (string-equal + "found" + (shell-command-to-string + (format "git annex find --format=found --in=here %s" + (shell-quote-argument path-relative)))))) + (let ((should-get + (if (eq org-attach-git-annex-auto-get 'ask) + (y-or-n-p (format "Run git annex get %s? " path-relative)) + org-attach-git-annex-auto-get))) + (unless should-get + (error "File %s stored in git annex but unavailable" path)) + (message "Running git annex get \"%s\"." path-relative) + (call-process "git" nil nil nil "annex" "get" path-relative))))) + +(defun org-attach-git-commit () + "Commit changes to git if `org-attach-id-dir' is properly initialized. +This checks for the existence of a \".git\" directory in that directory." + (let* ((dir (expand-file-name org-attach-id-dir)) + (git-dir (vc-git-root dir)) + (use-annex (org-attach-git-use-annex)) + (changes 0)) + (when (and git-dir (executable-find "git")) + (with-temp-buffer + (cd dir) + (dolist (new-or-modified + (split-string + (shell-command-to-string + "git ls-files -zmo --exclude-standard") "\0" t)) + (if (and use-annex + (>= (file-attribute-size (file-attributes new-or-modified)) + org-attach-git-annex-cutoff)) + (call-process "git" nil nil nil "annex" "add" new-or-modified) + (call-process "git" nil nil nil "add" new-or-modified)) + (cl-incf changes)) + (dolist (deleted + (split-string + (shell-command-to-string "git ls-files -z --deleted") "\0" t)) + (call-process "git" nil nil nil "rm" deleted) + (cl-incf changes)) + (when (> changes 0) + (shell-command "git commit -m 'Synchronized attachments'")))))) + +(add-hook 'org-attach-after-change-hook 'org-attach-git-commit) +(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe) + +(provide 'org-attach-git) + +;;; org-attach-git.el ends here diff --git a/lisp/org-attach.el b/lisp/org-attach.el index a715c89e9..726085014 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -1,9 +1,9 @@ -;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*- +;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*- ;; Copyright (C) 2008-2019 Free Software Foundation, Inc. ;; Author: John Wiegley <johnw@newartisans.com> -;; Keywords: org data task +;; Keywords: org data attachment ;; This file is part of GNU Emacs. ;; @@ -24,32 +24,30 @@ ;; See the Org manual for information on how to use it. ;; -;; Attachments are managed in a special directory called "data", which -;; lives in the same directory as the org file itself. If this data -;; directory is initialized as a Git repository, then org-attach will -;; automatically commit changes when it sees them. -;; -;; Attachment directories are identified using a UUID generated for the -;; task which has the attachments. These are added as property to the -;; task when necessary, and should not be deleted or changed by the -;; user, ever. UUIDs are generated by a mechanism defined in the variable -;; `org-id-method'. +;; Attachments are managed either by using a custom property DIR or by +;; using property ID from org-id. When DIR is defined, a location in +;; the filesystem is directly attached to the outline node. When +;; org-id is used, attachments are stored in a folder named after the +;; ID, in a location defined by `org-attach-id-dir'. DIR has +;; precedence over ID when both parameters are defined for the current +;; outline node (also when inherited parameters are taken into +;; account). ;;; Code: (require 'cl-lib) (require 'org) +(require 'ol) (require 'org-id) -(require 'vc-git) (declare-function dired-dwim-target-directory "dired-aux") (defgroup org-attach nil - "Options concerning entry attachments in Org mode." + "Options concerning attachments in Org mode." :tag "Org Attach" :group 'org) -(defcustom org-attach-directory "data/" +(defcustom org-attach-id-dir "data/" "The directory where attachments are stored. If this is a relative path, it will be interpreted relative to the directory where the Org file lives." @@ -57,22 +55,13 @@ where the Org file lives." :type 'directory :safe #'stringp) -(defcustom org-attach-commit t - "If non-nil commit attachments with git. -This is only done if the Org file is in a git repository." +(defcustom org-attach-dir-relative nil + "Non-nil means directories in DIR property are added as relative links. +Defaults to absolute location." :group 'org-attach :type 'boolean - :version "26.1" - :package-version '(Org . "9.0")) - -(defcustom org-attach-git-annex-cutoff (* 32 1024) - "If non-nil, files larger than this will be annexed instead of stored." - :group 'org-attach - :version "24.4" - :package-version '(Org . "8.0") - :type '(choice - (const :tag "None" nil) - (integer :tag "Bytes"))) + :package-version '(Org . "9.3") + :safe #'booleanp) (defcustom org-attach-auto-tag "ATTACH" "Tag that will be triggered automatically when an entry has an attachment." @@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository." (const :tag "None" nil) (string :tag "Tag"))) -(defcustom org-attach-file-list-property "Attachments" - "The property used to keep a list of attachment belonging to this entry. -This is not really needed, so you may set this to nil if you don't want it. -Also, for entries where children inherit the directory, the list of -attachments is not kept in this property." +(defcustom org-attach-preferred-new-method 'id + "Preferred way to attach to nodes without existing ID and DIR property. +This choice is used when adding attachments to nodes without ID +and DIR properties. + +Allowed values are: + +id Create and use an ID parameter +dir Create and use a DIR parameter +ask Ask the user for input of which method to choose +nil Prefer to not create a new parameter + + nil means that ID or DIR has to be created explicitly + before attaching files." :group 'org-attach + :package-version '(org . "9.3") :type '(choice - (const :tag "None" nil) - (string :tag "Tag"))) + (const :tag "ID parameter" id) + (const :tag "DIR parameter" dir) + (const :tag "Ask user" ask) + (const :tag "Don't create" nil))) (defcustom org-attach-method 'cp "The preferred method to attach a file. @@ -113,14 +114,24 @@ lns create a symbol link. Note that this is not supported :group 'org-attach :type 'boolean) -(defcustom org-attach-allow-inheritance t - "Non-nil means allow attachment directories be inherited." +(defcustom org-attach-use-inheritance 'selective + "Attachment inheritance for the outline. + +Enabling inheritance for org-attach implies two things. First, +that attachment links will look through all parent headings until +it finds the linked attachment. Second, that running org-attach +inside a node without attachments will make org-attach operate on +the first parent heading it finds with an attachment. + +Selective means to respect the inheritance setting in +`org-use-property-inheritance'." :group 'org-attach + :type '(choice + (const :tag "Don't use inheritance" nil) + (const :tag "Inherit parent node attachments" t) + (const :tag "Respect org-use-property-inheritance" selective)) :type 'boolean) -(defvar org-attach-inherited nil - "Indicates if the last access to the attachment directory was inherited.") - (defcustom org-attach-store-link-p nil "Non-nil means store a link to a file when attaching it." :group 'org-attach @@ -141,16 +152,28 @@ When set to `query', ask the user instead." (const :tag "Always delete attachments" t) (const :tag "Query the user" query))) -(defcustom org-attach-annex-auto-get 'ask - "Confirmation preference for automatically getting annex files. -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." +(defun org-attach-id-folder-format (id) + "Translate an ID into a folder-path. +Default format for how Org translates ID properties to a path for +attachments." + (format "%s/%s" + (substring id 0 2) + (substring id 2))) + +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format + "Function parsing the ID parameter into a folder-path." :group 'org-attach - :package-version '(Org . "9.0") - :version "26.1" - :type '(choice - (const :tag "confirm with `y-or-n-p'" ask) - (const :tag "always get from annex if necessary" t) - (const :tag "never get from annex" nil))) + :package-version '(Org . "9.3") + :type 'function) + +(defvar org-attach-after-change-hook nil + "Hook to be called when files have been added or removed to the attachment folder.") + +(defvar org-attach-open-hook nil + "Hook that is invoked by `org-attach-open'. + +Created mostly to be compatible with org-attach-git after removing +git-funtionality from this file.") (defcustom org-attach-commands '(((?a ?\C-a) org-attach-attach @@ -186,9 +209,9 @@ you added attachments yourself.\n") "Delete all of a task's attachments. A safer way is\n to open the \ directory in dired and delete from there.\n") ((?s ?\C-s) org-attach-set-directory - "Set a specific attachment directory for this entry or reset to default.") - ((?i ?\C-i) org-attach-set-inherit - "Make children of the current entry inherit its attachment directory.\n") + "Set a specific attachment directory for this entry. Sets DIR property.") + ((?S ?\C-S) org-attach-unset-directory + "Unset the attachment directory for this entry. Removes DIR property.") ((?q) (lambda () (interactive) (message "Abort")) "Abort.")) "The list of commands for the attachment dispatcher. Each entry in this list is a list of three elements: @@ -215,7 +238,7 @@ Shows a list of commands and prompts for another key to execute a command." (setq marker (or (get-text-property (point) 'org-hd-marker) (get-text-property (point) 'org-marker))) (unless marker - (error "No task in current line"))) + (error "No item in current line"))) (save-excursion (when marker (set-buffer (marker-buffer marker)) @@ -225,24 +248,28 @@ Shows a list of commands and prompts for another key to execute a command." (save-window-excursion (unless org-attach-expert (with-output-to-temp-buffer "*Org Attach*" - (princ - (format "Select an Attachment Command:\n\n%s" - (mapconcat - (lambda (entry) - (pcase entry - (`((,key . ,_) ,_ ,docstring) - (format "%c %s" - key - (replace-regexp-in-string "\n\\([\t ]*\\)" - " " - docstring - nil nil 1))) - (_ - (user-error - "Invalid `org-attach-commands' item: %S" - entry)))) - org-attach-commands - "\n"))))) + (princ + (concat "Attachment folder:\n" + (or (org-attach-dir) + "Can't find an existing attachment-folder") + "\n\n" + (format "Select an Attachment Command:\n\n%s" + (mapconcat + (lambda (entry) + (pcase entry + (`((,key . ,_) ,_ ,docstring) + (format "%c %s" + key + (replace-regexp-in-string "\n\\([\t ]*\\)" + " " + docstring + nil nil 1))) + (_ + (user-error + "Invalid `org-attach-commands' item: %S" + entry)))) + org-attach-commands + "\n")))))) (org-fit-window-to-buffer (get-buffer-window "*Org Attach*")) (message "Select command: [%s]" (concat (mapcar #'caar org-attach-commands))) @@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command." (error "No such attachment command: %c" c)))))) (defun org-attach-dir (&optional create-if-not-exists-p) - "Return the directory associated with the current entry. -This first checks for a local property ATTACH_DIR, and then for an inherited -property ATTACH_DIR_INHERIT. If neither exists, the default mechanism -using the entry ID will be invoked to access the unique directory for the -current entry. -If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, -the directory and (if necessary) the corresponding ID will be created." - (let (attach-dir uuid) - (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) + "Return the directory associated with the current outline node. +First check for DIR property, then ID property. +`org-attach-use-inheritance' determines whether inherited +properties also will be considered. + +If an ID property is found the default mechanism using that ID +will be invoked to access the directory for the current entry. + +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' +is run." + (let (attach-dir id) (cond - ((setq attach-dir (org-entry-get nil "ATTACH_DIR")) + (create-if-not-exists-p + (setq attach-dir (org-attach-dir-get-create))) + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) (org-attach-check-absolute-path attach-dir)) - ((and org-attach-allow-inheritance - (org-entry-get nil "ATTACH_DIR_INHERIT" t)) - (setq attach-dir - (org-with-wide-buffer - (if (marker-position org-entry-property-inherited-from) - (goto-char org-entry-property-inherited-from) - (org-back-to-heading t)) - (let (org-attach-allow-inheritance) - (org-attach-dir create-if-not-exists-p)))) - (org-attach-check-absolute-path attach-dir) - (setq org-attach-inherited t)) - (t ; use the ID + ;; Deprecated and removed from documentation, but still + ;; works. FIXME: Remove after major nr change. + ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance)) + (org-attach-check-absolute-path attach-dir)) + ((setq id (org-entry-get nil "ID" org-attach-use-inheritance)) (org-attach-check-absolute-path nil) - (setq uuid (org-id-get (point) create-if-not-exists-p)) - (when (or uuid create-if-not-exists-p) - (unless uuid (error "ID retrieval/creation failed")) - (setq attach-dir (expand-file-name - (format "%s/%s" - (substring uuid 0 2) - (substring uuid 2)) - (expand-file-name org-attach-directory)))))) - (when attach-dir - (if (and create-if-not-exists-p - (not (file-directory-p attach-dir))) - (make-directory attach-dir t)) - (and (file-exists-p attach-dir) - attach-dir)))) + (setq attach-dir (org-attach-dir-from-id id)))) + attach-dir)) + +(defun org-attach-dir-get-create () + "Return existing or new directory associated with the current outline node. + +`org-attach-preferred-new-method' decides how to attach +new directory." + (interactive) + (let ((attach-dir (org-attach-dir))) + (unless attach-dir + (let (answer) + (when (eq org-attach-preferred-new-method 'ask) + (message "Create new ID [1] property or DIR [2] property for attachments?") + (setq answer (read-char-exclusive))) + (cond + ((or (eq org-attach-preferred-new-method 'id) (eq answer ?1)) + (setq attach-dir (org-attach-dir-from-id (org-id-get nil t)))) + ((or (eq org-attach-preferred-new-method 'dir) (eq answer ?2)) + (setq attach-dir (org-attach-set-directory))) + ((eq org-attach-preferred-new-method 'nil) + (error "No existing directory. DIR or ID property has to be explicitly created"))))) + (unless attach-dir + (error "No attachment directory is associated with the current node")) + (unless (file-directory-p attach-dir) + (make-directory attach-dir t)) + attach-dir)) + +(defun org-attach-dir-from-id (id) + "Returns a file name based on `org-attach-id-dir' and ID." + (expand-file-name + (funcall org-attach-id-to-path-function id) + (expand-file-name org-attach-id-dir))) (defun org-attach-check-absolute-path (dir) "Check if we have enough information to root the attachment directory. When DIR is given, check also if it is already absolute. Otherwise, -assume that it will be relative, and check if `org-attach-directory' is +assume that it will be relative, and check if `org-attach-id-dir' is absolute, or if at least the current buffer has a file name. Throw an error if we cannot root the directory." (or (and dir (file-name-absolute-p dir)) - (file-name-absolute-p org-attach-directory) + (file-name-absolute-p org-attach-id-dir) (buffer-file-name (buffer-base-buffer)) - (error "Need absolute `org-attach-directory' to attach in buffers without filename"))) + (error "Need absolute `org-attach-id-dir' to attach in buffers without filename"))) -(defun org-attach-set-directory (&optional arg) - "Set the ATTACH_DIR node property and ask to move files there. +(defun org-attach-set-directory () + "Set the DIR node property and ask to move files there. The property defines the directory that is used for attachments -of the entry. When called with `\\[universal-argument]', reset \ -the directory to -the default ID based one." - (interactive "P") +of the entry. Creates relative links if `org-attach-dir-relative' +is non-nil. + +Return the directory." + (interactive) (let ((old (org-attach-dir)) - (new - (progn - (if arg (org-entry-delete nil "ATTACH_DIR") - (let ((dir (read-directory-name - "Attachment directory: " - (org-entry-get nil - "ATTACH_DIR" - (and org-attach-allow-inheritance t))))) - (org-entry-put nil "ATTACH_DIR" dir))) - (org-attach-dir t)))) + (new + (let* ((attach-dir (read-directory-name + "Attachment directory: " + (org-entry-get nil "DIR"))) + (current-dir (file-name-directory (or default-directory + buffer-file-name))) + (attach-dir-relative (file-relative-name attach-dir current-dir))) + (org-entry-put nil "DIR" (if org-attach-dir-relative + attach-dir-relative + attach-dir)) + attach-dir))) (unless (or (string= old new) (not old)) (when (yes-or-no-p "Copy over attachments from old directory? ") + (copy-directory old new t t t)) + (when (yes-or-no-p (concat "Delete " old)) + (delete-directory old t))) + new)) + +(defun org-attach-unset-directory () + "Removes DIR node property. +If attachment folder is changed due to removal of DIR-property +ask to move attachments to new location and ask to delete old +attachment-folder. + +Change of attachment-folder due to unset might be if an ID +property is set on the node, or if a separate inherited +DIR-property exists (that is different than the unset one)." + (interactive) + (let ((old (org-attach-dir)) + (new + (progn + (org-entry-delete nil "DIR") + ;; ATTACH-DIR is deprecated and removed from documentation, + ;; but still works. Remove code for it after major nr change. + (org-entry-delete nil "ATTACH_DIR") + (org-attach-dir)))) + (unless (or (string= old new) + (not old)) + (when (and new (yes-or-no-p "Copy over attachments from old directory? ")) (copy-directory old new t nil t)) (when (yes-or-no-p (concat "Delete " old)) (delete-directory old t))))) -(defun org-attach-set-inherit () - "Set the ATTACH_DIR_INHERIT property of the current entry. -The property defines the directory that is used for attachments -of the entry and any children that do not explicitly define (by setting -the ATTACH_DIR property) their own attachment directory." - (interactive) - (org-entry-put nil "ATTACH_DIR_INHERIT" "t") - (message "Children will inherit attachment directory")) - -(defun org-attach-use-annex () - "Return non-nil if git annex can be used." - (let ((git-dir (vc-git-root (expand-file-name org-attach-directory)))) - (and org-attach-git-annex-cutoff - (or (file-exists-p (expand-file-name "annex" git-dir)) - (file-exists-p (expand-file-name ".git/annex" git-dir)))))) - -(defun org-attach-annex-get-maybe (path) - "Call git annex get PATH (via shell) if using git annex. -Signals an error if the file content is not available and it was not retrieved." - (let* ((default-directory (expand-file-name org-attach-directory)) - (path-relative (file-relative-name path))) - (when (and (org-attach-use-annex) - (not - (string-equal - "found" - (shell-command-to-string - (format "git annex find --format=found --in=here %s" - (shell-quote-argument path-relative)))))) - (let ((should-get - (if (eq org-attach-annex-auto-get 'ask) - (y-or-n-p (format "Run git annex get %s? " path-relative)) - org-attach-annex-auto-get))) - (if should-get - (progn (message "Running git annex get \"%s\"." path-relative) - (call-process "git" nil nil nil "annex" "get" path-relative)) - (error "File %s stored in git annex but it is not available, and was not retrieved" - path)))))) - -(defun org-attach-commit () - "Commit changes to git if `org-attach-directory' is properly initialized. -This checks for the existence of a \".git\" directory in that directory." - (let* ((dir (expand-file-name org-attach-directory)) - (git-dir (vc-git-root dir)) - (use-annex (org-attach-use-annex)) - (changes 0)) - (when (and git-dir (executable-find "git")) - (with-temp-buffer - (cd dir) - (dolist (new-or-modified - (split-string - (shell-command-to-string - "git ls-files -zmo --exclude-standard") "\0" t)) - (if (and use-annex - (>= (file-attribute-size (file-attributes new-or-modified)) - org-attach-git-annex-cutoff)) - (call-process "git" nil nil nil "annex" "add" new-or-modified) - (call-process "git" nil nil nil "add" new-or-modified)) - (cl-incf changes)) - (dolist (deleted - (split-string - (shell-command-to-string "git ls-files -z --deleted") "\0" t)) - (call-process "git" nil nil nil "rm" deleted) - (cl-incf changes)) - (when (> changes 0) - (shell-command "git commit -m 'Synchronized attachments'")))))) - (defun org-attach-tag (&optional off) "Turn the autotag on or (if OFF is set) off." (when org-attach-auto-tag @@ -423,22 +428,21 @@ Only do this when `org-attach-store-link-p' is non-nil." (org-attach-attach url))) (defun org-attach-buffer (buffer-name) - "Attach BUFFER-NAME's contents to current task. + "Attach BUFFER-NAME's contents to current outline node. BUFFER-NAME is a string. Signals a `file-already-exists' error if it would overwrite an existing filename." (interactive "bBuffer whose contents should be attached: ") - (let ((output (expand-file-name buffer-name (org-attach-dir t)))) + (let* ((attach-dir (org-attach-dir 'get-create)) + (output (expand-file-name buffer-name attach-dir))) (when (file-exists-p output) (signal 'file-already-exists (list "File exists" output))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property buffer-name)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (with-temp-file output (insert-buffer-substring buffer-name)))) (defun org-attach-attach (file &optional visit-dir method) - "Move/copy/link FILE into the attachment directory of the current task. + "Move/copy/link FILE into the attachment directory of the current outline node. If VISIT-DIR is non-nil, visit the directory with dired. METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from `org-attach-method'." @@ -453,10 +457,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from nil)) (setq method (or method org-attach-method)) (let ((basename (file-name-nondirectory file))) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property basename)) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir 'get-create)) (fname (expand-file-name basename attach-dir))) (cond ((eq method 'mv) (rename-file file fname)) @@ -464,8 +465,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from ((eq method 'ln) (add-name-to-file file fname)) ((eq method 'lns) (make-symbolic-link file fname)) ((eq method 'url) (url-copy-file file fname))) - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (cond ((eq org-attach-store-link-p 'attached) (org-attach-store-link fname)) @@ -473,7 +473,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from (org-attach-store-link file))) (if visit-dir (dired attach-dir) - (message "File %S is now a task attachment." basename))))) + (message "File %S is now an attachment." basename))))) (defun org-attach-attach-cp () "Attach a file by copying it." @@ -498,13 +498,10 @@ On some systems, this apparently does copy the file instead." (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) (defun org-attach-new (file) - "Create a new attachment FILE for the current task. + "Create a new attachment FILE for the current outline node. The attachment is created as an Emacs buffer." (interactive "sCreate attachment named: ") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)) - (let ((attach-dir (org-attach-dir t))) + (let ((attach-dir (org-attach-dir 'get-create))) (org-attach-tag) (find-file (expand-file-name file attach-dir)) (message "New attachment %s" file))) @@ -512,7 +509,7 @@ The attachment is created as an Emacs buffer." (defun org-attach-delete-one (&optional file) "Delete a single attachment." (interactive) - (let* ((attach-dir (org-attach-dir t)) + (let* ((attach-dir (org-attach-dir)) (files (org-attach-file-list attach-dir)) (file (or file (completing-read @@ -524,44 +521,32 @@ The attachment is created as an Emacs buffer." (unless (file-exists-p file) (error "No such attachment: %s" file)) (delete-file file) - (when org-attach-commit - (org-attach-commit)))) + (run-hook-with-args 'org-attach-after-change-hook attach-dir))) (defun org-attach-delete-all (&optional force) - "Delete all attachments from the current task. + "Delete all attachments from the current outline node. This actually deletes the entire attachment directory. A safer way is to open the directory in dired and delete from there." (interactive "P") - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) - (when - (and attach-dir - (or force - (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) - (shell-command (format "rm -fr %s" attach-dir)) + (when (and attach-dir + (or force + (yes-or-no-p "Really remove all attachments of this entry? "))) + (delete-directory attach-dir (yes-or-no-p "Recursive?") t) (message "Attachment directory removed") - (when org-attach-commit - (org-attach-commit)) + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-untag)))) (defun org-attach-sync () - "Synchronize the current tasks with its attachments. + "Synchronize the current outline node with its attachments. This can be used after files have been added externally." (interactive) - (when org-attach-commit - (org-attach-commit)) - (when (and org-attach-file-list-property (not org-attach-inherited)) - (org-entry-delete (point) org-attach-file-list-property)) (let ((attach-dir (org-attach-dir))) (when attach-dir + (run-hook-with-args 'org-attach-after-change-hook attach-dir) (let ((files (org-attach-file-list attach-dir))) - (org-attach-tag (not files)) - (when org-attach-file-list-property - (dolist (file files) - (unless (string-match "^\\.\\.?\\'" file) - (org-entry-add-to-multivalued-property - (point) org-attach-file-list-property file)))))))) + (org-attach-tag (not files)))) + (unless attach-dir (org-attach-tag t)))) (defun org-attach-file-list (dir) "Return a list of files in the attachment directory. @@ -570,35 +555,40 @@ This ignores files ending in \"~\"." (mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x)) (directory-files dir nil "[^~]\\'")))) -(defun org-attach-reveal (&optional if-exists) - "Show the attachment directory of the current task. +(defun org-attach-reveal () + "Show the attachment directory of the current outline node. This will attempt to use an external program to show the directory." - (interactive "P") - (let ((attach-dir (org-attach-dir (not if-exists)))) - (and attach-dir (org-open-file attach-dir)))) + (interactive) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (org-open-file attach-dir) + (error "No attachment directory exist")))) (defun org-attach-reveal-in-emacs () - "Show the attachment directory of the current task in dired." + "Show the attachment directory of the current outline node in dired." (interactive) - (let ((attach-dir (org-attach-dir t))) - (dired attach-dir))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (dired attach-dir) + (error "No attachment directory exist")))) (defun org-attach-open (&optional in-emacs) - "Open an attachment of the current task. + "Open an attachment of the current outline node. If there are more than one attachment, you will be prompted for the file name. This command will open the file using the settings in `org-file-apps' and in the system-specific variants of this variable. If IN-EMACS is non-nil, force opening in Emacs." (interactive "P") - (let* ((attach-dir (org-attach-dir t)) - (files (org-attach-file-list attach-dir)) - (file (if (= (length files) 1) - (car files) - (completing-read "Open attachment: " - (mapcar #'list files) nil t))) - (path (expand-file-name file attach-dir))) - (org-attach-annex-get-maybe path) - (org-open-file path in-emacs))) + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (let* ((file (pcase (org-attach-file-list attach-dir) + (`(,file) file) + (files (completing-read "Open attachment: " + (mapcar #'list files) nil t)))) + (path (expand-file-name file attach-dir))) + (run-hook-with-args 'org-attach-open-hook path) + (org-open-file path in-emacs)) + (error "No attachment directory exist")))) (defun org-attach-open-in-emacs () "Open attachment, force opening in Emacs. @@ -617,6 +607,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\" prefix." (concat "file:" (org-attach-expand file))) +(org-link-set-parameters "attachment" + :follow #'org-attach-open-link + :export #'org-attach-export-link + :complete #'org-attach-complete-link) + +(defun org-attach-open-link (link &optional in-emacs) + "Attachment link type LINK is expanded with the attached directory and opened. + +With optional prefix argument IN-EMACS, Emacs will visit the file. +With a double \\[universal-argument] \\[universal-argument] \ +prefix arg, Org tries to avoid opening in Emacs +and to use an external application to visit the file." + (interactive "P") + (let (line search) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq line (string-to-number (match-string 1 link)) + link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq search (match-string 1 link) + link (substring link 0 (match-beginning 0))))) + (if (string-match "[*?{]" (file-name-nondirectory link)) + (dired (org-attach-expand link)) + (org-open-file (org-attach-expand link) in-emacs line search)))) + +(defun org-attach-complete-link () + "Advise the user with the available files in the attachment directory." + (let ((attach-dir (org-attach-dir))) + (if attach-dir + (let* ((attached-dir (expand-file-name attach-dir)) + (file (read-file-name "File: " attached-dir)) + (pwd (file-name-as-directory attached-dir)) + (pwd-relative (file-name-as-directory + (abbreviate-file-name attached-dir)))) + (cond + ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file) + (concat "attachment:" (match-string 1 file))) + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") + (expand-file-name file)) + (concat "attachment:" (match-string 1 (expand-file-name file)))) + (t (concat "attachment:" file)))) + (error "No attachment directory exist")))) + +(defun org-attach-export-link (link description format) + "Translate attachment LINK from Org mode format to exported FORMAT. +Also includes the DESCRIPTION of the link in the export." + (save-excursion + (let (path desc) + (cond + ((string-match "::\\([0-9]+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0)))) + ((string-match "::\\(.+\\)\\'" link) + (setq link (substring link 0 (match-beginning 0))))) + (setq path (file-relative-name (org-attach-expand link)) + desc (or description link)) + (pcase format + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) + (`latex (format "\\href{%s}{%s}" path desc)) + (`texinfo (format "@uref{%s,%s}" path desc)) + (`ascii (format "%s (%s)" desc path)) + (`md (format "[%s](%s)" desc path)) + (_ path))))) + (defun org-attach-archive-delete-maybe () "Maybe delete subtree attachments when archiving. This function is called by `org-archive-hook'. The option @@ -644,7 +697,7 @@ Idea taken from `gnus-dired-attach'." (interactive (list (dired-get-marked-files))) (unless (eq major-mode 'dired-mode) - (user-error "This command must be triggered in a dired buffer.")) + (user-error "This command must be triggered in a dired buffer")) (let ((start-win (selected-window)) (other-win (get-window-with-predicate diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 9cb396fe9..42fe64379 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -263,6 +263,9 @@ Counting starts at 1." (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays 'org-clear-latex-preview "Org 9.3") +(define-obsolete-variable-alias 'org-attach-directory + 'org-attach-id-dir "Org 9.3") + (defun org-in-fixed-width-region-p () "Non-nil if point in a fixed-width region." (save-match-data diff --git a/lisp/org.el b/lisp/org.el index 9601ecf2e..5d6cc757d 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -3847,7 +3847,9 @@ This is needed for font-lock setup.") (beg end)) (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) (declare-function org-agenda-skip "org-agenda" ()) -(declare-function org-attach-reveal "org-attach" (&optional if-exists)) +(declare-function org-attach-expand "org-attach" (file)) +(declare-function org-attach-reveal "org-attach" ()) +(declare-function org-attach-reveal-in-emacs "org-attach" ()) (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) (declare-function org-indent-mode "org-indent" (&optional arg)) (declare-function org-inlinetask-goto-beginning "org-inlinetask" ()) @@ -8645,12 +8647,15 @@ a link." (pcase (org-offer-links-in-entry (current-buffer) (point) arg) (`(nil . ,_) (require 'org-attach) - (org-attach-reveal 'if-exists)) + (message "Opening attachment-dir") + (if (equal arg '(4)) + (org-attach-reveal-in-emacs) + (org-attach-reveal))) (`(,links . ,links-end) (dolist (link (if (stringp links) (list links) links)) (search-forward link nil links-end) (goto-char (match-beginning 0)) - (org-open-at-point)))))) + (org-open-at-point arg)))))) ;; On a footnote reference or at definition's label. ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) @@ -16630,13 +16635,14 @@ boundaries." ;; "file:" links. Also check link abbreviations since ;; some might expand to "file" links. (file-types-re - (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" + (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" (if (not link-abbrevs) "" (concat "\\|" (regexp-opt link-abbrevs)))))) (while (re-search-forward file-types-re end t) (let* ((link (org-element-lineage (save-match-data (org-element-context)) '(link) t)) + (linktype (org-element-property :type link)) (inner-start (match-beginning 1)) (path (cond @@ -16650,7 +16656,8 @@ boundaries." ;; INCLUDE-LINKED is non-nil. ((or (not (org-element-property :contents-begin link)) include-linked) - (and (equal "file" (org-element-property :type link)) + (and (or (equal "file" linktype) + (equal "attachment" linktype)) (org-element-property :path link))) ;; Link with a description. Check if description ;; is a filename. Even if Org doesn't have syntax @@ -16669,7 +16676,11 @@ boundaries." (match-end 0)) (match-string 2))))))) (when (and path (string-match-p file-extension-re path)) - (let ((file (expand-file-name path))) + (let ((file (if (equal "attachment" linktype) + (progn + (require 'org-attach) + (org-attach-expand path)) + (expand-file-name path)))) (when (file-exists-p file) (let ((width ;; Apply `org-image-actual-width' specifications. diff --git a/lisp/ox-html.el b/lisp/ox-html.el index f1c06e069..757006321 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -884,6 +884,7 @@ link to the image." (defcustom org-html-inline-image-rules '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") + ("attachment" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")) "Rules characterizing image files that can be inlined into HTML. diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA new file mode 100644 index 000000000..9a0406c0d --- /dev/null +++ b/testing/examples/att1/fileA @@ -0,0 +1 @@ +Text in fileA diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB new file mode 100644 index 000000000..dd2331824 --- /dev/null +++ b/testing/examples/att1/fileB @@ -0,0 +1 @@ +Text in fileB diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC new file mode 100644 index 000000000..2c9a92bfe --- /dev/null +++ b/testing/examples/att2/fileC @@ -0,0 +1 @@ +Text in fileC \ No newline at end of file diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD new file mode 100644 index 000000000..c706556c5 --- /dev/null +++ b/testing/examples/att2/fileD @@ -0,0 +1 @@ +text in fileD diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org new file mode 100644 index 000000000..ab4a4e548 --- /dev/null +++ b/testing/examples/attachments.org @@ -0,0 +1,32 @@ +#+TITLE: Org attach testfile +Used to test and verify the functionality of org-attach. + +* H1 + :PROPERTIES: + :DIR: att1 + :END: +A link to one attachment: [[attachment:fileA]] + +** H1.1 +A link to another attachment: [[attachment:fileB]] + +** H1.2 + :PROPERTIES: + :DIR: att2 + :END: + +* H2 + :PROPERTIES: + :ID: abcd123 + :END: + +* H3 + :PROPERTIES: + :DIR: att1 + :ID: abcd1234 + :END: + +** H3.1 + :PROPERTIES: + :ID: abcd12345 + :END: diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE new file mode 100644 index 000000000..80d337772 --- /dev/null +++ b/testing/examples/data/ab/cd123/fileE @@ -0,0 +1 @@ +peek-a-boo diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el similarity index 93% rename from testing/lisp/test-org-attach-annex.el rename to testing/lisp/test-org-attach-git.el index 7f2792696..8b826b72f 100644 --- a/testing/lisp/test-org-attach-annex.el +++ b/testing/lisp/test-org-attach-git.el @@ -20,19 +20,19 @@ ;;; Code: (org-test-for-executable "git-annex") -(require 'org-attach) +(require 'org-attach-git) (require 'cl-lib) -(defmacro test-org-attach-annex/with-annex (&rest body) +(defmacro test-org-attach-git/with-annex (&rest body) `(let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (shell-command "git annex init") ,@body)))) -(ert-deftest test-org-attach/use-annex () +(ert-deftest test-org-attach-git/use-annex () (test-org-attach-annex/with-annex (let ((org-attach-git-annex-cutoff 1)) (should (org-attach-use-annex))) @@ -44,12 +44,12 @@ (let ((tmpdir (make-temp-file "org-annex-test" t "/"))) (unwind-protect (let ((default-directory tmpdir) - (org-attach-directory tmpdir)) + (org-attach-id-dir tmpdir)) (shell-command "git init") (should-not (org-attach-use-annex))) (delete-directory tmpdir 'recursive)))) -(ert-deftest test-org-attach/get-maybe () +(ert-deftest test-org-attach-git/get-maybe () (test-org-attach-annex/with-annex (let ((path (expand-file-name "test-file")) (annex-dup (make-temp-file "org-annex-test" t "/"))) diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el index c2f2be356..5bcfe86fd 100644 --- a/testing/lisp/test-org-attach.el +++ b/testing/lisp/test-org-attach.el @@ -28,6 +28,75 @@ (require 'org-attach) (eval-and-compile (require 'cl-lib)) +(ert-deftest test-org-attach/dir () + "Test `org-attach-get' specifications." + (should (equal "Text in fileA\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 157) ;; First attachment link + (org-open-at-point) + (buffer-string)))) + (should-not (equal "Text in fileB\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 219) ;; Second attachment link + (let ((org-attach-use-inheritance nil)) + (org-open-at-point) + (buffer-string))))) + (should (equal "Text in fileB\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 219) ;; Second attachment link + (let ((org-attach-use-inheritance t)) + (org-open-at-point) + (buffer-string))))) + (should-not (equal "att1" + (org-test-in-example-file org-test-attachments-file + (goto-char 179) ;; H1.1 + (let ((org-attach-use-inheritance nil)) + (org-attach-dir))))) + (should (equal "att1" + (org-test-in-example-file org-test-attachments-file + (goto-char 179) ;; H1.1 + (let ((org-attach-use-inheritance t)) + (org-attach-dir))))) + (should (equal '("fileC" "fileD") + (org-test-in-example-file org-test-attachments-file + (goto-char 239) ;; H1.2 + (org-attach-file-list (org-attach-dir))))) + (should (equal '("fileC" "fileD") + (org-test-in-example-file org-test-attachments-file + (goto-char 239) ;; H1.2 + (org-attach-file-list (org-attach-dir))))) + (should (equal '("fileE") + (org-test-in-example-file org-test-attachments-file + (goto-char 289) ;; H2 + (let ((org-attach-id-dir "data/")) + (org-attach-file-list (org-attach-dir)))))) + (should (equal "peek-a-boo\n" + (org-test-in-example-file org-test-attachments-file + (goto-char 289) ;; H2 + (let ((org-attach-id-dir "data/")) + (org-attach-open-in-emacs) + (buffer-string))))) + (should (equal '("fileA" "fileB") + (org-test-in-example-file org-test-attachments-file + (goto-char 336) ;; H3 + (org-attach-file-list (org-attach-dir))))) + (should (equal "data/ab/cd12345" + (org-test-in-example-file org-test-attachments-file + (goto-char 401) ;; H3.1 + (let ((org-attach-use-inheritance nil) + (org-attach-id-dir "data/")) + (file-relative-name (org-attach-dir)))))) + (should (equal '("fileA" "fileB") + (org-test-in-example-file org-test-attachments-file + (goto-char 401) ;; H3.1 + (let ((org-attach-use-inheritance t)) + ;; This is where it get's a bit sketchy...! DIR always has + ;; priority over ID, even if ID is declared "higher up" in the + ;; tree. This can potentially be revised. But it is also + ;; pretty clean. DIR is always higher in priority than ID right + ;; now, no matter the depth in the tree. + (org-attach-file-list (org-attach-dir))))))) + (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 () "Attach file at point in dired to subtree." (should diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index d671b5c78..a618da479 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2514,7 +2514,11 @@ Foo Bar (catch :result (cl-letf (((symbol-function 'org-tags-view) (lambda (&rest args) (throw :result t)))) - (org-open-at-point) + ;; When point isn't on a tag it's going to try other things, + ;; possibly trying to open attachments which will return an + ;; error if there isn't an attachment. Supress that error. + (ignore-errors + (org-open-at-point)) nil))))) \f diff --git a/testing/org-test.el b/testing/org-test.el index 295df1919..c3e21eb30 100644 --- a/testing/org-test.el +++ b/testing/org-test.el @@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.") (defconst org-test-no-heading-file (expand-file-name "no-heading.org" org-test-example-dir)) +(defconst org-test-attachments-file + (expand-file-name "attachments.org" org-test-example-dir)) + (defconst org-test-link-in-heading-file (expand-file-name "link-in-heading.org" org-test-dir)) -- 2.17.1 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-07 18:38 ` Gustav Wikström @ 2019-07-08 10:47 ` Marco Wahl 2019-07-09 10:16 ` Nicolas Goaziou 2019-07-27 14:56 ` Ihor Radchenko 2 siblings, 0 replies; 113+ messages in thread From: Marco Wahl @ 2019-07-08 10:47 UTC (permalink / raw) To: emacs-orgmode Hi Gustav and all, Thanks for the refreshment of the org attach universe. In particular I like the new attachment type for links. I'd like to express my favorability to use the name "att" opposed to "attachment" to specify that type. Thanks for reading, best regards, Marco ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-07 18:38 ` Gustav Wikström 2019-07-08 10:47 ` Marco Wahl @ 2019-07-09 10:16 ` Nicolas Goaziou 2019-07-27 14:56 ` Ihor Radchenko 2 siblings, 0 replies; 113+ messages in thread From: Nicolas Goaziou @ 2019-07-09 10:16 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Final patches attached for full disclosure before applying them. I see you applied your patches. Thank you. Just some remarks: - "Capture, Attachments, RSS Feeds and Protocols" is too long: we ought to find a shorter title, - Sub-nodes behind "Attachments" have no description. The should have one, unless they are not meant to appear in the toc, in which case, you should set "UNNUMBERED" property to "notoc". Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-07 18:38 ` Gustav Wikström 2019-07-08 10:47 ` Marco Wahl 2019-07-09 10:16 ` Nicolas Goaziou @ 2019-07-27 14:56 ` Ihor Radchenko 2019-07-28 20:39 ` Gustav Wikström 2 siblings, 1 reply; 113+ messages in thread From: Ihor Radchenko @ 2019-07-27 14:56 UTC (permalink / raw) To: Gustav Wikström, Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi, > ATTACH_DIR_INHERIT is no longer supported and is +removed. I just found that removing ATTACH_DIR_INHERIT broke my current configuration. I do not use ATTACH_DIR property - all the attachment folders are created using ID. Also, I use ID property to store links to entries. Therefore, inheriting ATTACH_DIR does nothing for me and inheriting ID always gives the current entry's id value. At the end, I cannot make a common attachment directory for the whole subtree, like I was able to do with ATTACH_DIR_INHERIT. Regards, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi! > >> > + (if should-get >> > + (progn (message "Running git annex get \"%s\"." path-relative) >> > + (call-process "git" nil nil nil "annex" "get" path-relative)) >> > + (error "File %s stored in git annex but it is not available, and was not >> retrieved" >> > + path)))))) >> >> Nitpick: >> >> (unless should-get >> (error "File %S stored in git annex but unavailable" path)) >> (message "Running git annex get %S." path-relative) >> (call-process ...) > > Ok, fixed. > >> > +Selective means to respect the inheritance setting in >> > +`org-use-property-inheritance'." >> > :group 'org-attach >> > + :type '(choice >> > + (const :tag "Don't use inheritance" nil) >> > + (const :tag "Inherit parent node attachments" t) >> > + (const :tag "Respect org-use-property-inheritance" selective) >> > + ) >> >> Dangling paren spotted. > > Fixed. > >> > + (setq attachment (or (org-attach-dir) >> > + (quote "Can't find an existing attachment-folder"))) >> >> You forgot to remove that weird quote. Maybe you meant `error'? > > Hmm, actually no. But the code is pretty bad so I've refactored it a > bit. The purpose of the change is for org-attach to give an indication > of the active attachment path, or to signal that there is none. But > for that I don't really need a separate variable. Thus it's slightly > refactored for code-clarity. > >> > + (if attach-dir >> > + (progn (if (not (file-directory-p attach-dir)) >> > + (make-directory attach-dir t)) >> > + attach-dir) >> > + (error "No attachment directory is associated with the current node")))) >> >> Same nitpick as above: >> >> (unless attach-dir >> (error "No attachment ...")) >> (if (file-directory-p attach-dir) attach-dir >> (make-directory attach-dir)) > > Ok, fixed. > >> > +(defun org-attach-dir-from-id (id) >> > + "Creates a path based on `org-attach-id-dir' and ID." >> > + (expand-file-name >> > + (funcall org-attach-id-to-path-function id) >> > + (expand-file-name org-attach-id-dir))) >> >> Creates path -> Return a file name. > > Fixed. > >> > +of the entry. Creates relative links if `org-attach-dir-relative' >> > +is t. >> >> Nitpick: >> >> is t -> is non-nil. > > Ah, true. Fixed. > >> If tests pass, feel free to apply the patches in master. Thank you! > > Got it. Aaand one test failure. That test is unrelated to my changes > though, and fails also on master. Test-org-table/copy-down. So I'll > try to apply my patch asap regardless of that one test failing. > > Just one more thing - a few days back I added a row to lisp/ox-html.el > regarding inline-images. I'm including that change as well since it > relates 100% to the new attachment link. I looked in the other > export-backends too but didn't add anything due to lack of time for > testing. Maybe the additions for other backends is as trivial as for > html. So someone who regularly export to those backends might want to > suggest patches for them to make attachment links to images actually > display as images? > > Final patches attached for full disclosure before applying them. > >> >> Regards, >> >> -- >> Nicolas Goaziou > From 3cbe356b0a9d1a98848df0fa09ba306392995b88 Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> > Date: Sun, 26 May 2019 03:34:34 +0200 > Subject: [PATCH 1/2] org-test, test-org-element, test-org, test-ox, > test-property-inheritance > > * org-test.el: > > Fix org-test-with-temp-text-in-file. Make it work with <point>, as > some tests already expect it to do! Also make it fail more gracefully > by still removing temporary buffers and files. > > Improve org-test-in-example-file. Make it behave similar to > org-test-with-temp-text and org-test-with-temp-text-in-file, in that > it will return the last evaluated expression. > > * testing/lisp/test-org-element.el > > Fix a temp-text strings so that it doesn't have an initial newline. > > * testing/lisp/test-org.el > > Minor cleanup to align code-structure with other tests. Nothing > changes in the test execpt style. > > * testing/lisp/test-ox.el > > Fix a couple of temp-text strings so that they don't have initial > newlines. > > ** test-org-export/expand-include > > Test specification was wrong, due to org-test-with-temp-text-in-file > not previously working with <point>. Since that is fixed in this > patch the test needed to be updated to match the expected outcome. > > * testing/lisp/test-property-inheritance.el > > Fix wrong file-header and file-ending. > --- > testing/lisp/test-org-element.el | 4 +-- > testing/lisp/test-org.el | 12 +++---- > testing/lisp/test-ox.el | 30 ++++++++-------- > testing/lisp/test-property-inheritance.el | 4 +-- > testing/org-test.el | 44 ++++++++++++++--------- > 5 files changed, 53 insertions(+), 41 deletions(-) > > diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el > index 04f97f97a..f2ab38031 100644 > --- a/testing/lisp/test-org-element.el > +++ b/testing/lisp/test-org-element.el > @@ -3264,8 +3264,8 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu > > (ert-deftest test-org-element/granularity () > "Test granularity impact on buffer parsing." > - (org-test-with-temp-text " > -* Head 1 > + (org-test-with-temp-text > + "* Head 1 > ** Head 2 > #+BEGIN_CENTER > Centered paragraph. > diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el > index abc004689..d671b5c78 100644 > --- a/testing/lisp/test-org.el > +++ b/testing/lisp/test-org.el > @@ -5060,18 +5060,18 @@ Paragraph<point>" > (should > (equal > "1" > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > - (org-entry-get (point) "A" t)))) > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > + (org-entry-get (point-max) "A" t)))) > (should > (equal > "1" > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > (let ((org-use-property-inheritance t)) > - (org-entry-get (point) "A" 'selective))))) > + (org-entry-get (point-max) "A" 'selective))))) > (should-not > - (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** <point>H2" > + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:\n** H2" > (let ((org-use-property-inheritance nil)) > - (org-entry-get (point) "A" 'selective)))) > + (org-entry-get (point-max) "A" 'selective)))) > (should > (equal > "1 2" > diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el > index 2c2778f82..b8c507e0b 100644 > --- a/testing/lisp/test-ox.el > +++ b/testing/lisp/test-ox.el > @@ -1352,7 +1352,7 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote] > org-test-dir) > (narrow-to-region (point) (point-max)) > (org-export-expand-include-keyword) > - (eq 1 (org-current-level)))) > + (eq 2 (org-current-level)))) > ;; If :minlevel is present do not alter it. > (should > (org-test-with-temp-text > @@ -2003,8 +2003,8 @@ In particular, structure of the document mustn't be altered after > comments removal." > (should > (equal "Para1\n\nPara2\n" > - (org-test-with-temp-text " > -Para1 > + (org-test-with-temp-text > + "Para1 > # Comment > > # Comment > @@ -2012,15 +2012,15 @@ Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "Para1\n\nPara2\n" > - (org-test-with-temp-text " > -Para1 > + (org-test-with-temp-text > + "Para1 > # Comment > Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "[fn:1] Para1\n\n\nPara2\n" > - (org-test-with-temp-text " > -\[fn:1] Para1 > + (org-test-with-temp-text > + "[fn:1] Para1 > # Inside definition > > > @@ -2029,8 +2029,8 @@ Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "[fn:1] Para1\n\nPara2\n" > - (org-test-with-temp-text " > -\[fn:1] Para1 > + (org-test-with-temp-text > + "[fn:1] Para1 > > # Inside definition > > @@ -2040,24 +2040,24 @@ Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "[fn:1] Para1\n\nPara2\n" > - (org-test-with-temp-text " > -\[fn:1] Para1 > + (org-test-with-temp-text > + "[fn:1] Para1 > # Inside definition > > Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "[fn:1] Para1\n\nPara2\n" > - (org-test-with-temp-text " > -\[fn:1] Para1 > + (org-test-with-temp-text > + "[fn:1] Para1 > > # Inside definition > Para2" > (org-export-as (org-test-default-backend))))) > (should > (equal "- item 1\n\n- item 2\n" > - (org-test-with-temp-text " > -- item 1 > + (org-test-with-temp-text > + "- item 1 > > # Comment > > diff --git a/testing/lisp/test-property-inheritance.el b/testing/lisp/test-property-inheritance.el > index 0f803e5f7..1d0dcfbe1 100644 > --- a/testing/lisp/test-property-inheritance.el > +++ b/testing/lisp/test-property-inheritance.el > @@ -1,4 +1,4 @@ > -;;; test-ob-R.el --- tests for ob-R.el > +;;; test-property-inheritance.el --- tests for property-inheritance.el > > ;; Copyright (c) 2011-2014, 2019 Eric Schulte > ;; Authors: Eric Schulte > @@ -47,4 +47,4 @@ > > (provide 'test-ob-R) > > -;;; test-ob-R.el ends here > +;;; test-property-inheritance.el ends here > diff --git a/testing/org-test.el b/testing/org-test.el > index 39c346410..295df1919 100644 > --- a/testing/org-test.el > +++ b/testing/org-test.el > @@ -146,7 +146,8 @@ currently executed.") > (declare (indent 1)) > `(let* ((my-file (or ,file org-test-file)) > (visited-p (get-file-buffer my-file)) > - to-be-removed) > + to-be-removed > + results) > (save-window-excursion > (save-match-data > (find-file my-file) > @@ -160,9 +161,10 @@ currently executed.") > (org-show-subtree) > (org-show-all '(blocks))) > (error nil)) > - (save-restriction ,@body))) > + (setq results (save-restriction ,@body)))) > (unless visited-p > - (kill-buffer to-be-removed)))) > + (kill-buffer to-be-removed)) > + results)) > (def-edebug-spec org-test-in-example-file (form body)) > > (defmacro org-test-at-marker (file marker &rest body) > @@ -198,20 +200,30 @@ otherwise place the point at the beginning of the inserted text." > (def-edebug-spec org-test-with-temp-text (form body)) > > (defmacro org-test-with-temp-text-in-file (text &rest body) > - "Run body in a temporary file buffer with Org mode as the active mode." > + "Run body in a temporary file buffer with Org mode as the active mode. > +If the string \"<point>\" appears in TEXT then remove it and > +place the point there before running BODY, otherwise place the > +point at the beginning of the buffer." > (declare (indent 1)) > - (let ((results (cl-gensym))) > - `(let ((file (make-temp-file "org-test")) > - (kill-buffer-query-functions nil) > - (inside-text (if (stringp ,text) ,text (eval ,text))) > - ,results) > - (with-temp-file file (insert inside-text)) > - (find-file file) > - (org-mode) > - (setq ,results (progn ,@body)) > - (save-buffer) (kill-buffer (current-buffer)) > - (delete-file file) > - ,results))) > + `(let ((file (make-temp-file "org-test")) > + (inside-text (if (stringp ,text) ,text (eval ,text))) > + buffer) > + (with-temp-file file (insert inside-text)) > + (unwind-protect > + (progn > + (setq buffer (find-file file)) > + (when (re-search-forward "<point>" nil t) > + (replace-match "")) > + (org-mode) > + (progn ,@body)) > + (let ((kill-buffer-query-functions nil)) > + (when buffer > + (set-buffer buffer) > + ;; Ignore changes, we're deleting the file in the next step > + ;; anyways. > + (set-buffer-modified-p nil) > + (kill-buffer)) > + (delete-file file))))) > (def-edebug-spec org-test-with-temp-text-in-file (form body)) > > (defun org-test-table-target-expect (target &optional expect laps > -- > 2.17.1 > > From ae9cd4370b4daaaca7bc53923d5e438c08955e48 Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Gustav=20Wikstr=C3=B6m?= <gustav@whil.se> > Date: Sun, 25 Nov 2018 21:38:44 +0100 > Subject: [PATCH 2/2] org-attach*, org, org-manual, org-news, ox-html, > testing/* > > * lisp/org-attach.el > > Changed the way attachments deal with property-inheritance. It now > adheres to the =org-use-property-inheritance= setting by default but > it can be customized if needed (I recommend to enable it!). > The property ATTACH_DIR is deprecated in favour of the shorter and simpler > property DIR. > > Added an explicit option to =org-attach= for unsetting > attachment-directories (i.e. remove DIR property and deal with the > attachments by interaction). > > Added attachment link type with the prefix "attachment:". > > Added customizations: > - org-attach-dir-relative > - org-attach-preferred-new-method > - org-attach-use-inheritance > - org-attach-id-to-path-function > > Hooks added: > - org-attach-after-change-hook > - org-attach-open-hook > > A new linktype "attachment" is added in order to reduce > link-duplication when wanting to link to files in attached folders of > nodes. This works for both ID and DIR properties. The goal is to > make the functionality for attachment links mirror the functionality > for file links. > > * lisp/org-attach-git.el > > New file, existing functionality. Code here has been factored out > from org-attach.el and if GIT-functionality is to be used this module > needs to be required sepatately. It extends org-attach by use of its > hooks. > > Activating git functionality in org-attach is done by loading > org-attach-git from now on, instead of customizing a variable. > > Naming of both functions and tests has been modified to match the move > of functionality into its own module. > > * lisp/org.el > > Inline images are shown also using attachment-links, exactly the same > as it works for file-links today. > > Make org-open-at-point respect ARG when opening attachment-dir. > > * lisp/org-compat.el > > org-attach-directory has been deprecated in favour for > org-attach-id-dir. The new name matches its purpose better. > > * lisp/ox-html.el > > Export attachment links to images as inline images, in the same way as > file links work today. > > * etc/ORG-NEWS > > Mention the changes in this patch. > > * doc/org-manual.org > > The chapter "Refile, Copy, Archive" has been split into two separate > chapters. > - "Refile, Copy and Archiving" for information related to moving > existing data around. > > - "Capture, Attachments, RSS Feeds and Protocols" for information > related to working with external data. > > The attachment-part has been rewritten and extended to match the > changes in this patch. > > The new attachment link type is mentioned both inside the attachments > chapter and in the chapter dealing with links. > > Documentation related to external links has been improved. > > * testing/lisp/test-org-attach-annex.el > > Require org-attach-git instead of org-attach, since this file tests > the GIT-functionality. > > * testing/lisp/test-org-attach.el > > Add tests for org-attach. > > * testing/org-test.el > > Define a symbol for a file to test attachments with. > > * testing/examples/* > > A bunch of new example files and folders are created and are used in > testing of org-attach to verify its functionality. > --- > doc/org-manual.org | 1079 ++++++++++------- > etc/ORG-NEWS | 94 ++ > lisp/org-attach-git.el | 117 ++ > lisp/org-attach.el | 561 +++++---- > lisp/org-compat.el | 3 + > lisp/org.el | 23 +- > lisp/ox-html.el | 1 + > testing/examples/att1/fileA | 1 + > testing/examples/att1/fileB | 1 + > testing/examples/att2/fileC | 1 + > testing/examples/att2/fileD | 1 + > testing/examples/attachments.org | 32 + > testing/examples/data/ab/cd123/fileE | 1 + > ...attach-annex.el => test-org-attach-git.el} | 12 +- > testing/lisp/test-org-attach.el | 69 ++ > testing/lisp/test-org.el | 6 +- > testing/org-test.el | 3 + > 17 files changed, 1307 insertions(+), 698 deletions(-) > create mode 100644 lisp/org-attach-git.el > create mode 100644 testing/examples/att1/fileA > create mode 100644 testing/examples/att1/fileB > create mode 100644 testing/examples/att2/fileC > create mode 100644 testing/examples/att2/fileD > create mode 100644 testing/examples/attachments.org > create mode 100644 testing/examples/data/ab/cd123/fileE > rename testing/lisp/{test-org-attach-annex.el => test-org-attach-git.el} (93%) > > diff --git a/doc/org-manual.org b/doc/org-manual.org > index 8318e7cdc..e81b76f14 100644 > --- a/doc/org-manual.org > +++ b/doc/org-manual.org > @@ -3071,6 +3071,7 @@ point on or at a target. > #+cindex: irc links > #+cindex: URL links > #+cindex: file links > +#+cindex: attachment links > #+cindex: Rmail links > #+cindex: MH-E links > #+cindex: Usenet links > @@ -3082,38 +3083,114 @@ Org supports links to files, websites, Usenet and email messages, BBDB > database entries and links to both IRC conversations and their logs. > External links are URL-like locators. They start with a short > identifying string followed by a colon. There can be no space after > -the colon. The following list shows examples for each link type. > - > -| =https://staff.science.uva.nl/c.dominik/= | on the web | > -| =doi:10.1000/182= | DOI for an electronic resource | > -| =file:/home/dominik/images/jupiter.jpg= | file, absolute path | > -| =/home/dominik/images/jupiter.jpg= | same as above | > -| =file:papers/last.pdf= | file, relative path | > -| =./papers/last.pdf= | same as above | > -| =file:/ssh:me@some.where:papers/last.pdf= | file, path on remote machine | > -| =/ssh:me@some.where:papers/last.pdf= | same as above | > -| =file:sometextfile::NNN= | file, jump to line number | > -| =file:projects.org= | another Org file | > -| =file:projects.org::some words= | text search in Org file[fn:27] | > -| =file:projects.org::*task title= | heading search in Org file | > -| =file+sys:/path/to/file= | open via OS, like double-click | > -| =file+emacs:/path/to/file= | force opening by Emacs | > -| =docview:papers/last.pdf::NNN= | open in doc-view mode at page | > -| =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | link to heading by ID | > -| =news:comp.emacs= | Usenet link | > -| =mailto:adent@galaxy.net= | mail link | > -| =mhe:folder= | MH-E folder link | > -| =mhe:folder#id= | MH-E message link | > -| =rmail:folder= | Rmail folder link | > -| =rmail:folder#id= | Rmail message link | > -| =gnus:group= | Gnus group link | > -| =gnus:group#id= | Gnus article link | > -| =bbdb:R.*Stallman= | BBDB link (with regexp) | > -| =irc:/irc.com/#emacs/bob= | IRC link | > -| =info:org#External links= | Info node link | > -| =shell:ls *.org= | shell command | > -| =elisp:org-agenda= | interactive Elisp command | > -| =elisp:(find-file "Elisp.org")= | Elisp form to evaluate | > +the colon. > + > +Here is the full set of built-in link types: > + > +- =file= :: > + > + File links. File name may be remote, absolute, or relative. > + > + Additionally, you can specify a line number, or a text search. > + In Org files, you may link to a headline name, a custom ID, or a > + code reference instead. > + > + As a special case, "file" prefix may be omitted if the file name > + is complete, e.g., it starts with =./=, or =/=. > + > +- =attachment= :: > + > + Same as file links but for files and folders attached to the current > + node (see [[*Attachments]]). Attachment links are intended to behave > + exactly as file links but for files relative to the attachment > + directory. > + > +- =bbdb= :: > + > + Link to a BBDB record, with possible regexp completion. > + > +- =docview= :: > + > + Link to a document opened with DocView mode. You may specify a page > + number. > + > +- =doi= :: > + > + Link to an electronic ressource, through its handle. > + > +- =elisp= :: > + > + Execute an Elisp command upon activation. > + > +- =gnus=, =rmail=, =mhe= :: > + > + Links to messages or folders from a given Emacs' MUA. > + > +- =http=, =https= :: > + > + Web links. > + > +- =id= :: > + > + Link to a specific headline by its ID property, in an Org file. > + > +- =info= :: > + > + Link to an Info manual, or to a specific node. > + > +- =irc= :: > + > + Link to an IRC channel. > + > +- =mailto= :: > + > + Link to message composition. > + > +- =news= :: > + > + Usenet links. > + > +- =shell= :: > + > + Execute a shell command upon activation. > + > +The following table illustrates the link types above, along with their > +options: > + > +| Link Type | Example | > +|------------+----------------------------------------------------------| > +| http | =http://staff.science.uva.nl/c.dominik/= | > +| https | =https://orgmode.org/= | > +| doi | =doi:10.1000/182= | > +| file | =file:/home/dominik/images/jupiter.jpg= | > +| | =/home/dominik/images/jupiter.jpg= (same as above) | > +| | =file:papers/last.pdf= | > +| | =./papers/last.pdf= (same as above) | > +| | =file:/ssh:me@some.where:papers/last.pdf= (remote) | > +| | =/ssh:me@some.where:papers/last.pdf= (same as above) | > +| | =file:sometextfile::NNN= (jump to line number) | > +| | =file:projects.org= | > +| | =file:projects.org::some words= (text search) [fn:28] | > +| | =file:projects.org::*task title= (headline search) | > +| | =file:projects.org::#custom-id= (headline search) | > +| attachment | =attachment:projects.org= | > +| | =attachment:projects.org::some words= (text search) | > +| docview | =docview:papers/last.pdf::NNN= | > +| id | =id:B7423F4D-2E8A-471B-8810-C40F074717E9= | > +| news | =news:comp.emacs= | > +| mailto | =mailto:adent@galaxy.net= | > +| mhe | =mhe:folder= (folder link) | > +| | =mhe:folder#id= (message link) | > +| rmail | =rmail:folder= (folder link) | > +| | =rmail:folder#id= (message link) | > +| gnus | =gnus:group= (group link) | > +| | =gnus:group#id= (article link) | > +| bbdb | =bbdb:R.*Stallman= (record with regexp) | > +| irc | =irc:/irc.com/#emacs/bob= | > +| info | =info:org#External links= | > +| shell | =shell:ls *.org= | > +| elisp | =elisp:(find-file "Elisp.org")= (Elisp form to evaluate) | > +| | =elisp:org-agenda= (interactive Elisp command) | > > #+cindex: VM links > #+cindex: Wanderlust links > @@ -3465,15 +3542,19 @@ the link completion function like this: > :END: > #+cindex: search option in file links > #+cindex: file links, searching > +#+cindex: attachment links, searching > > -File links can contain additional information to make Emacs jump to > -a particular location in the file when following a link. This can be > -a line number or a search option after a double colon[fn:34]. For > +File links can contain additional information to make Emacs jump to a > +particular location in the file when following a link. This can be a > +line number or a search option after a double colon[fn:34]. For > example, when the command ~org-store-link~ creates a link (see > [[*Handling Links]]) to a file, it encodes the words in the current line > as a search string that can be used to find this line back later when > following the link with {{{kbd(C-c C-o)}}}. > > +Note that all search options apply for Attachment links in the same > +way that they apply for File links. > + > Here is the syntax of the different ways to attach a search to a file > link, together with explanations for each: > > @@ -3483,6 +3564,7 @@ link, together with explanations for each: > [[file:~/xx.org::*My Target]] > [[file:~/xx.org::#my-custom-id]] > [[file:~/xx.org::/regexp/]] > +[[attachment:main.c::255]] > #+end_example > > - =255= :: > @@ -6896,163 +6978,420 @@ same commands. > continue the old one. This command also removes the timer from the > mode line. > > -* Capture, Refile, Archive > -:PROPERTIES: > -:DESCRIPTION: The ins and outs for projects. > -:END: > -#+cindex: capture > - > -An important part of any organization system is the ability to quickly > -capture new ideas and tasks, and to associate reference material with > -them. Org does this using a process called /capture/. It also can > -store files related to a task (/attachments/) in a special directory. > -Once in the system, tasks and projects need to be moved around. > -Moving completed project trees to an archive file keeps the system > -compact and fast. > - > -** Capture > +* Refile, Copy and Archiving > :PROPERTIES: > -:DESCRIPTION: Capturing new stuff. > +:DESCRIPTION: Moving and copying information with ease. > :END: > -#+cindex: capture > +#+cindex: refiling notes > +#+cindex: copying notes > +#+cindex: archiving > > -Capture lets you quickly store notes with little interruption of your > -work flow. Org's method for capturing new items is heavily inspired > -by John Wiegley's excellent Remember package. > +Once information is in the system, it may need to be moved around. > +Org provides Refile, Copy and Archive commands for this. Refile and > +Copy helps with moving and copying outlines. Archiving helps to keep > +the system compact and fast. > > -*** Setting up capture > +** Refile and Copy > :PROPERTIES: > -:DESCRIPTION: Where notes will be stored. > +:DESCRIPTION: Moving/copying a tree from one place to another. > :END: > +#+cindex: refiling notes > +#+cindex: copying notes > > -The following customization sets a default target file for notes. > +When reviewing the captured data, you may want to refile or to copy > +some of the entries into a different list, for example into a project. > +Cutting, finding the right location, and then pasting the note is > +cumbersome. To simplify this process, you can use the following > +special command: > > -#+vindex: org-default-notes-file > -#+begin_src emacs-lisp > -(setq org-default-notes-file (concat org-directory "/notes.org")) > -#+end_src > +- {{{kbd(C-c C-w)}}} (~org-refile~) :: > > -You may also define a global key for capturing new material (see > -[[*Activation]]). > + #+kindex: C-c C-w > + #+findex: org-refile > + #+vindex: org-reverse-note-order > + #+vindex: org-refile-targets > + #+vindex: org-refile-use-outline-path > + #+vindex: org-outline-path-complete-in-steps > + #+vindex: org-refile-allow-creating-parent-nodes > + #+vindex: org-log-refile > + Refile the entry or region at point. This command offers possible > + locations for refiling the entry and lets you select one with > + completion. The item (or all items in the region) is filed below > + the target heading as a subitem. Depending on > + ~org-reverse-note-order~, it is either the first or last subitem. > > -*** Using capture > -:PROPERTIES: > -:DESCRIPTION: Commands to invoke and terminate capture. > -:END: > + By default, all level 1 headlines in the current buffer are > + considered to be targets, but you can have more complex definitions > + across a number of files. See the variable ~org-refile-targets~ for > + details. If you would like to select a location via > + a file-path-like completion along the outline path, see the > + variables ~org-refile-use-outline-path~ and > + ~org-outline-path-complete-in-steps~. If you would like to be able > + to create new nodes as new parents for refiling on the fly, check > + the variable ~org-refile-allow-creating-parent-nodes~. When the > + variable ~org-log-refile~[fn:88] is set, a timestamp or a note is > + recorded whenever an entry is refiled. > > -- {{{kbd(M-x org-capture)}}} (~org-capture~) :: > +- {{{kbd(C-u C-c C-w)}}} :: > > - #+findex: org-capture > - #+cindex: date tree > - Display the capture templates menu. If you have templates defined > - (see [[*Capture templates]]), it offers these templates for selection or > - use a new Org outline node as the default template. It inserts the > - template into the target file and switch to an indirect buffer > - narrowed to this new node. You may then insert the information you > - want. > + #+kindex: C-u C-c C-w > + Use the refile interface to jump to a heading. > > -- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: > +- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: > > - #+kindex: C-c C-c @r{(Capture buffer)} > - #+findex: org-capture-finalize > - Once you have finished entering information into the capture buffer, > - {{{kbd(C-c C-c)}}} returns you to the window configuration before > - the capture process, so that you can resume your work without > - further distraction. When called with a prefix argument, finalize > - and then jump to the captured item. > + #+kindex: C-u C-u C-c C-w > + #+findex: org-refile-goto-last-stored > + Jump to the location where ~org-refile~ last moved a tree to. > > -- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: > +- {{{kbd(C-2 C-c C-w)}}} :: > > - #+kindex: C-c C-w @r{(Capture buffer)} > - #+findex: org-capture-refile > - Finalize the capture process by refiling the note to a different > - place (see [[*Refile and Copy]]). Please realize that this is a normal > - refiling command that will be executed---so point position at the > - moment you run this command is important. If you have inserted > - a tree with a parent and children, first move point back to the > - parent. Any prefix argument given to this command is passed on to > - the ~org-refile~ command. > + #+kindex: C-2 C-c C-w > + Refile as the child of the item currently being clocked. > > -- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: > +- {{{kbd(C-3 C-c C-w)}}} :: > > - #+kindex: C-c C-k @r{(Capture buffer)} > - #+findex: org-capture-kill > - Abort the capture process and return to the previous state. > + #+kindex: C-3 C-c C-w > + #+vindex: org-refile-keep > + Refile and keep the entry in place. Also see ~org-refile-keep~ to > + make this the default behavior, and beware that this may result in > + duplicated =ID= properties. > > -#+kindex: k c @r{(Agenda)} > -You can also call ~org-capture~ in a special way from the agenda, > -using the {{{kbd(k c)}}} key combination. With this access, any > -timestamps inserted by the selected capture template defaults to the > -date at point in the agenda, rather than to the current date. > +- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: > > -To find the locations of the last stored capture, use ~org-capture~ > -with prefix commands: > + #+kindex: C-u C-u C-u C-c C-w > + #+kindex: C-0 C-c C-w > + #+findex: org-refile-cache-clear > + #+vindex: org-refile-use-cache > + Clear the target cache. Caching of refile targets can be turned on > + by setting ~org-refile-use-cache~. To make the command see new > + possible targets, you have to clear the cache with this command. > > -- {{{kbd(C-u M-x org-capture)}}} :: > +- {{{kbd(C-c M-w)}}} (~org-copy~) :: > > - Visit the target location of a capture template. You get to select > - the template in the usual way. > + #+kindex: C-c M-w > + #+findex: org-copy > + Copying works like refiling, except that the original note is not > + deleted. > > -- {{{kbd(C-u C-u M-x org-capture)}}} :: > +** Archiving > +:PROPERTIES: > +:DESCRIPTION: What to do with finished products. > +:END: > +#+cindex: archiving > > - Visit the last stored capture item in its buffer. > +When a project represented by a (sub)tree is finished, you may want to > +move the tree out of the way and to stop it from contributing to the > +agenda. Archiving is important to keep your working files compact and > +global searches like the construction of agenda views fast. > > -#+vindex: org-capture-bookmark > -#+vindex: org-capture-last-stored > -You can also jump to the bookmark ~org-capture-last-stored~, which is > -automatically created unless you set ~org-capture-bookmark~ to ~nil~. > +- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: > > -To insert the capture at point in an Org buffer, call ~org-capture~ > -with a {{{kbd(C-0)}}} prefix argument. > + #+kindex: C-c C-x C-a > + #+findex: org-archive-subtree-default > + #+vindex: org-archive-default-command > + Archive the current entry using the command specified in the > + variable ~org-archive-default-command~. > > -*** Capture templates > +*** Moving a tree to an archive file > :PROPERTIES: > -:DESCRIPTION: Define the outline of different note types. > +:DESCRIPTION: Moving a tree to an archive file. > +:ALT_TITLE: Moving subtrees > :END: > -#+cindex: templates, for Capture > - > -You can use templates for different types of capture items, and for > -different target locations. The easiest way to create such templates > -is through the customize interface. > +#+cindex: external archiving > > -- {{{kbd(C)}}} :: > +The most common archiving action is to move a project tree to another > +file, the archive file. > > - #+kindex: C @r{(Capture menu} > - #+vindex: org-capture-templates > - Customize the variable ~org-capture-templates~. > +- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: > > -Before we give the formal description of template definitions, let's > -look at an example. Say you would like to use one template to create > -general TODO entries, and you want to put these entries under the > -heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in > -the file =journal.org= should capture journal entries. A possible > -configuration would look like: > + #+kindex: C-c C-x C-s > + #+kindex: C-c $ > + #+findex: org-archive-subtree > + #+vindex: org-archive-location > + Archive the subtree starting at point position to the location given > + by ~org-archive-location~. > > -#+begin_src emacs-lisp > -(setq org-capture-templates > - '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") > - "* TODO %?\n %i\n %a") > - ("j" "Journal" entry (file+datetree "~/org/journal.org") > - "* %?\nEntered on %U\n %i\n %a"))) > -#+end_src > +- {{{kbd(C-u C-c C-x C-s)}}} :: > > -If you then press {{{kbd(t)}}} from the capture menu, Org will prepare > -the template for you like this: > + #+kindex: C-u C-c C-x C-s > + Check if any direct children of the current headline could be moved > + to the archive. To do this, check each subtree for open TODO > + entries. If none is found, the command offers to move it to the > + archive location. If point is /not/ on a headline when this command > + is invoked, check level 1 trees. > > -#+begin_example > -,* TODO > - [[file:LINK TO WHERE YOU INITIATED CAPTURE]] > -#+end_example > +- {{{kbd(C-u C-u C-c C-x C-s)}}} :: > > -#+texinfo: @noindent > -During expansion of the template, =%a= has been replaced by a link to > -the location from where you called the capture command. This can be > -extremely useful for deriving tasks from emails, for example. You > -fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns > -you to the same place where you started the capture process. > + #+kindex: C-u C-u C-c C-x C-s > + As above, but check subtree for timestamps instead of TODO entries. > + The command offers to archive the subtree if it /does/ contain > + a timestamp, and that timestamp is in the past. > > -To define special keys to capture to a particular template without > -going through the interactive template selection, you can create your > +#+cindex: archive locations > +The default archive location is a file in the same directory as the > +current file, with the name derived by appending =_archive= to the > +current file name. You can also choose what heading to file archived > +items under, with the possibility to add them to a datetree in a file. > +For information and examples on how to specify the file and the > +heading, see the documentation string of the variable > +~org-archive-location~. > + > +There is also an in-buffer option for setting this variable, for > +example: > + > +#+cindex: @samp{ARCHIVE}, keyword > +: #+ARCHIVE: %s_done:: > + > +#+cindex: ARCHIVE, property > +If you would like to have a special archive location for a single > +entry or a (sub)tree, give the entry an =ARCHIVE= property with the > +location as the value (see [[*Properties and Columns]]). > + > +#+vindex: org-archive-save-context-info > +When a subtree is moved, it receives a number of special properties > +that record context information like the file from where the entry > +came, its outline path the archiving time etc. Configure the variable > +~org-archive-save-context-info~ to adjust the amount of information > +added. > + > +*** Internal archiving > +:PROPERTIES: > +:DESCRIPTION: Switch off a tree but keep it in the file. > +:END: > + > +#+cindex: @samp{ARCHIVE}, tag > +If you want to just switch off---for agenda views---certain subtrees > +without moving them to a different file, you can use the =ARCHIVE= > +tag. > + > +A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at > +its location in the outline tree, but behaves in the following way: > + > +- > + #+vindex: org-cycle-open-archived-trees > + It does not open when you attempt to do so with a visibility cycling > + command (see [[*Visibility Cycling]]). You can force cycling archived > + subtrees with {{{kbd(C-TAB)}}}, or by setting the option > + ~org-cycle-open-archived-trees~. Also normal outline commands, like > + ~outline-show-all~, open archived subtrees. > + > +- > + #+vindex: org-sparse-tree-open-archived-trees > + During sparse tree construction (see [[*Sparse Trees]]), matches in > + archived subtrees are not exposed, unless you configure the option > + ~org-sparse-tree-open-archived-trees~. > + > +- > + #+vindex: org-agenda-skip-archived-trees > + During agenda view construction (see [[*Agenda Views]]), the content of > + archived trees is ignored unless you configure the option > + ~org-agenda-skip-archived-trees~, in which case these trees are > + always included. In the agenda you can press {{{kbd(v a)}}} to get > + archives temporarily included. > + > +- > + #+vindex: org-export-with-archived-trees > + Archived trees are not exported (see [[*Exporting]]), only the headline > + is. Configure the details using the variable > + ~org-export-with-archived-trees~. > + > +- > + #+vindex: org-columns-skip-archived-trees > + Archived trees are excluded from column view unless the variable > + ~org-columns-skip-archived-trees~ is configured to ~nil~. > + > +The following commands help manage the =ARCHIVE= tag: > + > +- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: > + > + #+kindex: C-c C-x a > + #+findex: org-toggle-archive-tag > + Toggle the archive tag for the current headline. When the tag is > + set, the headline changes to a shadowed face, and the subtree below > + it is hidden. > + > +- {{{kbd(C-u C-c C-x a)}}} :: > + > + #+kindex: C-u C-c C-x a > + Check if any direct children of the current headline should be > + archived. To do this, check each subtree for open TODO entries. If > + none is found, the command offers to set the =ARCHIVE= tag for the > + child. If point is /not/ on a headline when this command is > + invoked, check the level 1 trees. > + > +- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: > + > + #+kindex: C-TAB > + Cycle a tree even if it is tagged with =ARCHIVE=. > + > +- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: > + > + #+kindex: C-c C-x A > + #+findex: org-archive-to-archive-sibling > + Move the current entry to the /Archive Sibling/. This is a sibling > + of the entry with the heading =Archive= and the archive tag. The > + entry becomes a child of that sibling and in this way retains a lot > + of its original context, including inherited tags and approximate > + position in the outline. > + > +* Capture, Attachments, RSS Feeds and Protocols > +:PROPERTIES: > +:DESCRIPTION: Dealing with external data. > +:END: > +#+cindex: capture > +#+cindex: attachments > +#+cindex: RSS feeds > +#+cindex: Atom feeds > +#+cindex: protocols, for external access > + > +An important part of any organization system is the ability to quickly > +capture new ideas and tasks, and to associate reference material with > +them. Org does this using a process called /capture/. It also can > +store files related to a task (/attachments/) in a special directory. > + > +** Capture > +:PROPERTIES: > +:DESCRIPTION: Capturing new stuff. > +:END: > +#+cindex: capture > + > +Capture lets you quickly store notes with little interruption of your > +work flow. Org's method for capturing new items is heavily inspired > +by John Wiegley's excellent Remember package. > + > +*** Setting up capture > +:PROPERTIES: > +:DESCRIPTION: Where notes will be stored. > +:END: > + > +The following customization sets a default target file for notes. > + > +#+vindex: org-default-notes-file > +#+begin_src emacs-lisp > +(setq org-default-notes-file (concat org-directory "/notes.org")) > +#+end_src > + > +You may also define a global key for capturing new material (see > +[[*Activation]]). > + > +*** Using capture > +:PROPERTIES: > +:DESCRIPTION: Commands to invoke and terminate capture. > +:END: > + > +- {{{kbd(M-x org-capture)}}} (~org-capture~) :: > + > + #+findex: org-capture > + #+cindex: date tree > + Display the capture templates menu. If you have templates defined > + (see [[*Capture templates]]), it offers these templates for selection or > + use a new Org outline node as the default template. It inserts the > + template into the target file and switch to an indirect buffer > + narrowed to this new node. You may then insert the information you > + want. > + > +- {{{kbd(C-c C-c)}}} (~org-capture-finalize~) :: > + > + #+kindex: C-c C-c @r{(Capture buffer)} > + #+findex: org-capture-finalize > + Once you have finished entering information into the capture buffer, > + {{{kbd(C-c C-c)}}} returns you to the window configuration before > + the capture process, so that you can resume your work without > + further distraction. When called with a prefix argument, finalize > + and then jump to the captured item. > + > +- {{{kbd(C-c C-w)}}} (~org-capture-refile~) :: > + > + #+kindex: C-c C-w @r{(Capture buffer)} > + #+findex: org-capture-refile > + Finalize the capture process by refiling the note to a different > + place (see [[*Refile and Copy]]). Please realize that this is a normal > + refiling command that will be executed---so point position at the > + moment you run this command is important. If you have inserted > + a tree with a parent and children, first move point back to the > + parent. Any prefix argument given to this command is passed on to > + the ~org-refile~ command. > + > +- {{{kbd(C-c C-k)}}} (~org-capture-kill~) :: > + > + #+kindex: C-c C-k @r{(Capture buffer)} > + #+findex: org-capture-kill > + Abort the capture process and return to the previous state. > + > +#+kindex: k c @r{(Agenda)} > +You can also call ~org-capture~ in a special way from the agenda, > +using the {{{kbd(k c)}}} key combination. With this access, any > +timestamps inserted by the selected capture template defaults to the > +date at point in the agenda, rather than to the current date. > + > +To find the locations of the last stored capture, use ~org-capture~ > +with prefix commands: > + > +- {{{kbd(C-u M-x org-capture)}}} :: > + > + Visit the target location of a capture template. You get to select > + the template in the usual way. > + > +- {{{kbd(C-u C-u M-x org-capture)}}} :: > + > + Visit the last stored capture item in its buffer. > + > +#+vindex: org-capture-bookmark > +#+vindex: org-capture-last-stored > +You can also jump to the bookmark ~org-capture-last-stored~, which is > +automatically created unless you set ~org-capture-bookmark~ to ~nil~. > + > +To insert the capture at point in an Org buffer, call ~org-capture~ > +with a {{{kbd(C-0)}}} prefix argument. > + > +*** Capture templates > +:PROPERTIES: > +:DESCRIPTION: Define the outline of different note types. > +:END: > +#+cindex: templates, for Capture > + > +You can use templates for different types of capture items, and for > +different target locations. The easiest way to create such templates > +is through the customize interface. > + > +- {{{kbd(C)}}} :: > + > + #+kindex: C @r{(Capture menu} > + #+vindex: org-capture-templates > + Customize the variable ~org-capture-templates~. > + > +Before we give the formal description of template definitions, let's > +look at an example. Say you would like to use one template to create > +general TODO entries, and you want to put these entries under the > +heading =Tasks= in your file =~/org/gtd.org=. Also, a date tree in > +the file =journal.org= should capture journal entries. A possible > +configuration would look like: > + > +#+begin_src emacs-lisp > +(setq org-capture-templates > + '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") > + "* TODO %?\n %i\n %a") > + ("j" "Journal" entry (file+datetree "~/org/journal.org") > + "* %?\nEntered on %U\n %i\n %a"))) > +#+end_src > + > +If you then press {{{kbd(t)}}} from the capture menu, Org will prepare > +the template for you like this: > + > +#+begin_example > +,* TODO > + [[file:LINK TO WHERE YOU INITIATED CAPTURE]] > +#+end_example > + > +#+texinfo: @noindent > +During expansion of the template, =%a= has been replaced by a link to > +the location from where you called the capture command. This can be > +extremely useful for deriving tasks from emails, for example. You > +fill in the task definition, press {{{kbd(C-c C-c)}}} and Org returns > +you to the same place where you started the capture process. > + > +To define special keys to capture to a particular template without > +going through the interactive template selection, you can create your > key binding like this: > > #+begin_src emacs-lisp > @@ -7437,28 +7776,30 @@ See the docstring of the variable for more information. > > ** Attachments > :PROPERTIES: > -:DESCRIPTION: Add files to tasks. > +:DESCRIPTION: Attach files to outlines. > :END: > #+cindex: attachments > -#+vindex: org-attach-directory > > It is often useful to associate reference material with an outline > -node/task. Small chunks of plain text can simply be stored in the > -subtree of a project. Hyperlinks (see [[*Hyperlinks]]) can establish > -associations with files that live elsewhere on your computer or in the > -cloud, like emails or source code files belonging to a project. > -Another method is /attachments/, which are files located in > -a directory belonging to an outline node. Org uses directories named > -by the unique ID of each entry. These directories are located in the > -=data/= directory which lives in the same directory where your Org > -file lives[fn:87]. If you initialize this directory with =git init=, > -Org automatically commits changes when it sees them. The attachment > -system has been contributed to Org by John Wiegley. > - > -In cases where it seems better to do so, you can attach a directory of > -your choice to an entry. You can also make children inherit the > -attachment directory from a parent, so that an entire subtree uses the > -same attached directory. > +node. Small chunks of plain text can simply be stored in the subtree > +of a project. Hyperlinks (see [[*Hyperlinks]]) can establish associations > +with files that live elsewhere on your computer or in the cloud, like > +emails or source code files belonging to a project. > + > +Another method is /attachments/, which are files located in a > +directory belonging to an outline node. Org uses directories either > +named by a unique ID of each entry, or by a =DIR= property. > + > +*** Attachment defaults and dispatcher > +By default, org-attach will use ID properties when adding attachments > +to outline nodes. This makes working with attachments fully > +automated. There is no decision needed for folder-name or location. > +ID-based directories are by default located in the =data/= directory, > +which lives in the same directory where your Org file lives[fn:87]. > +For more control over the setup, see [[*Attachment options]]. > + > +When attachments are made using ~org-attach~ a default tag =ATTACH= is > +added to the node that gets the attachments. > > The following commands deal with attachments: > > @@ -7543,25 +7884,144 @@ The following commands deal with attachments: > > - {{{kbd(D)}}} (~org-attach-delete-all~) :: > > - #+kindex: C-c C-a D > - Delete all of a task's attachments. A safer way is to open the > - directory in Dired and delete from there. > + #+kindex: C-c C-a D > + Delete all of a task's attachments. A safer way is to open the > + directory in Dired and delete from there. > + > + - {{{kbd(s)}}} (~org-attach-set-directory~) :: > + > + #+kindex: C-c C-a s > + #+cindex: @samp{DIR}, property > + Set a specific directory as the entry's attachment directory. > + This works by putting the directory path into the =DIR= > + property. > + > + - {{{kbd(S)}}} (~org-attach-unset-directory~) :: > + > + #+kindex: C-c C-a S > + #+cindex: @samp{DIR}, property > + Remove the attachment directory. This command removes the =DIR= > + property and asks the user to either move content inside that > + folder, if an =ID= property is set, delete the content, or to > + leave the attachment directory as is but no longer attached to the > + outline node. > + > +*** Attachment options > +There are a couple of options for attachments that are worth > +mentioning. > + > +- ~org-attach-id-dir~ :: > + #+vindex: org-attach-id-dir > + The directory where attachments are stored when =ID= is used as > + method. > + > +- ~org-attach-dir-relative~ :: > + #+vindex: org-attach-dir-relative > + When setting the =DIR= property on a node using {{{kbd(C-c C-a s)}}} > + (~org-attach-set-directory~), absolute links are entered by default. > + This option changes that to relative links. > + > +- ~org-attach-use-inheritance~ :: > + #+vindex: org-attach-use-inheritance > + By default folders attached to an outline node are inherited from > + parents according to ~org-use-property-inheritance~. If one instead > + want to set inheritance specifically for org-attach that can be done > + using ~org-attach-use-inheritance~. Inheriting documents through > + the node hierarchy makes a lot of sense in most cases. Especially > + since the introduction of [[* Attachment links]]. The following example > + shows one use case for attachment inheritance: > + > + #+begin_example > + ,* Chapter A ... > + :PROPERTIES: > + :DIR: Chapter A/ > + :END: > + ,** Introduction > + Some text > + > + #+NAME: Image 1 > + [[Attachment:image 1.jpg]] > + #+end_example > + > + Without inheritance one would not be able to resolve the link to > + image =1.jpg=, since the link is inside a sub-heading to =Chapter > + A=. > + > + Inheritance works the same way for both =ID= and =DIR= property. If > + both properties are defined on the same headline then =DIR= takes > + precedance. This is also true if inheritance is enabled. If =DIR= > + is inherited from a parent node in the outline, that property still > + takes precedence over an =ID= property defined on the node itself. > + > +- ~org-attach-method~ :: > + #+vindex: org-attach-method > + When attaching files using the dispatcher {{{kbd(C-c C-a)}}} it > + defaults to copying files. The behaviour can be changed by > + customizing ~org-attach-method~. Options are Copy, Move/Rename, > + Hard link or Symbolic link. > + > +- ~org-attach-preferred-new-method~ :: > + #+vindex: org-attach-preferred-new-method > + This customization lets you choose the default way to attach to > + nodes without existing =ID= and =DIR= property. It defaults to ~id~ > + but can also be set to ~dir~, ~ask~ or ~nil~. > + > +- ~org-attach-archive-delete~ :: > + #+vindex: org-attach-archive-delete > + Configure this to determine if attachments should be deleted or not > + when a subtree that has attachments is archived. > + > +- ~org-attach-auto-tag~ :: > + #+vindex: org-attach-auto-tag > + When attaching files to a heading it will be assigned a tag > + according to what is set here. > + > +- ~org-attach-id-to-path-function~ :: > + #+vindex: org-attach-id-to-path-function > + When =ID= is used for attachments, the ID is parsed into a part of a > + directory-path. See ~org-attach-id-folder-format~ for the default > + function. Define a new one and add it to > + ~org-attach-id-to-path-function~ if you want the folder structure > + any other way. Note that modifying this makes org-attach dependent > + on your function also for opening attachments, not only setting > + them! > + > +- ~org-attach-expert~ :: > + #+vindex: org-attach-expert > + Do not show the splash buffer with the attach dispatcher when > + ~org-attach-expert~ is set to non-~nil~. > + > +See customization group =Org Attach= if you want to change the > +default settings. > + > +*** Attachment links > +Attached files and folders can be referenced using attachment links. > +This makes it easy to refer to the material added to an outline node. > +Especially if it was attached using the unique ID of the entry! > + > +#+begin_example > +,* TODO Some task > + :PROPERTIES: > + :ID: 95d50008-c12e-479f-a4f2-cc0238205319 > + :END: > +See attached document for more information: [[attachment:info.org]] > +#+end_example > > - - {{{kbd(s)}}} (~org-attach-set-directory~) :: > +See [[*External Links]] for more information about these links. > > - #+kindex: C-c C-a s > - #+cindex: @samp{ATTACH_DIR}, property > - Set a specific directory as the entry's attachment directory. > - This works by putting the directory path into the =ATTACH_DIR= > - property. > +*** Automatic version-control with Git > +If the directory attached to an outline node is a Git repository, Org > +can be configured to automatically commit changes to that repository > +when it sees them. > > - - {{{kbd(i)}}} (~org-attach-set-inherit~) :: > +To make Org mode take care of versioning of attachments for you, add > +the following to your Emacs config: > > - #+kindex: C-c C-a i > - #+cindex: @samp{ATTACH_DIR_INHERIT}, property > - Set the =ATTACH_DIR_INHERIT= property, so that children use the > - same directory for attachments as the parent does. > +#+begin_src emacs-lisp > + (require 'org-attach-git) > +#+end_src > > +*** Attach from Dired > #+cindex: attach from Dired > #+findex: org-attach-dired-to-subtree > It is possible to attach files to a subtree from a Dired buffer. To > @@ -7832,249 +8292,6 @@ valid contents: ~org-protocol-create~ and > ~org-protocol-create-for-org~. The latter is of use if you're editing > an Org file that is part of a publishing project. > > -** Refile and Copy > -:PROPERTIES: > -:DESCRIPTION: Moving/copying a tree from one place to another. > -:END: > -#+cindex: refiling notes > -#+cindex: copying notes > - > -When reviewing the captured data, you may want to refile or to copy > -some of the entries into a different list, for example into a project. > -Cutting, finding the right location, and then pasting the note is > -cumbersome. To simplify this process, you can use the following > -special command: > - > -- {{{kbd(C-c C-w)}}} (~org-refile~) :: > - > - #+kindex: C-c C-w > - #+findex: org-refile > - #+vindex: org-reverse-note-order > - #+vindex: org-refile-targets > - #+vindex: org-refile-use-outline-path > - #+vindex: org-outline-path-complete-in-steps > - #+vindex: org-refile-allow-creating-parent-nodes > - #+vindex: org-log-refile > - Refile the entry or region at point. This command offers possible > - locations for refiling the entry and lets you select one with > - completion. The item (or all items in the region) is filed below > - the target heading as a subitem. Depending on > - ~org-reverse-note-order~, it is either the first or last subitem. > - > - By default, all level 1 headlines in the current buffer are > - considered to be targets, but you can have more complex definitions > - across a number of files. See the variable ~org-refile-targets~ for > - details. If you would like to select a location via > - a file-path-like completion along the outline path, see the > - variables ~org-refile-use-outline-path~ and > - ~org-outline-path-complete-in-steps~. If you would like to be able > - to create new nodes as new parents for refiling on the fly, check > - the variable ~org-refile-allow-creating-parent-nodes~. When the > - variable ~org-log-refile~[fn:88] is set, a timestamp or a note is > - recorded whenever an entry is refiled. > - > -- {{{kbd(C-u C-c C-w)}}} :: > - > - #+kindex: C-u C-c C-w > - Use the refile interface to jump to a heading. > - > -- {{{kbd(C-u C-u C-c C-w)}}} (~org-refile-goto-last-stored~) :: > - > - #+kindex: C-u C-u C-c C-w > - #+findex: org-refile-goto-last-stored > - Jump to the location where ~org-refile~ last moved a tree to. > - > -- {{{kbd(C-2 C-c C-w)}}} :: > - > - #+kindex: C-2 C-c C-w > - Refile as the child of the item currently being clocked. > - > -- {{{kbd(C-3 C-c C-w)}}} :: > - > - #+kindex: C-3 C-c C-w > - #+vindex: org-refile-keep > - Refile and keep the entry in place. Also see ~org-refile-keep~ to > - make this the default behavior, and beware that this may result in > - duplicated =ID= properties. > - > -- {{{kbd(C-0 C-c C-w)}}} or {{{kbd(C-u C-u C-u C-c C-w)}}} (~org-refile-cache-clear~) :: > - > - #+kindex: C-u C-u C-u C-c C-w > - #+kindex: C-0 C-c C-w > - #+findex: org-refile-cache-clear > - #+vindex: org-refile-use-cache > - Clear the target cache. Caching of refile targets can be turned on > - by setting ~org-refile-use-cache~. To make the command see new > - possible targets, you have to clear the cache with this command. > - > -- {{{kbd(C-c M-w)}}} (~org-copy~) :: > - > - #+kindex: C-c M-w > - #+findex: org-copy > - Copying works like refiling, except that the original note is not > - deleted. > - > -** Archiving > -:PROPERTIES: > -:DESCRIPTION: What to do with finished products. > -:END: > -#+cindex: archiving > - > -When a project represented by a (sub)tree is finished, you may want to > -move the tree out of the way and to stop it from contributing to the > -agenda. Archiving is important to keep your working files compact and > -global searches like the construction of agenda views fast. > - > -- {{{kbd(C-c C-x C-a)}}} (~org-archive-subtree-default~) :: > - > - #+kindex: C-c C-x C-a > - #+findex: org-archive-subtree-default > - #+vindex: org-archive-default-command > - Archive the current entry using the command specified in the > - variable ~org-archive-default-command~. > - > -*** Moving a tree to an archive file > -:PROPERTIES: > -:DESCRIPTION: Moving a tree to an archive file. > -:ALT_TITLE: Moving subtrees > -:END: > -#+cindex: external archiving > - > -The most common archiving action is to move a project tree to another > -file, the archive file. > - > -- {{{kbd(C-c C-x C-s)}}} or short {{{kbd(C-c $)}}} (~org-archive-subtree~) :: > - > - #+kindex: C-c C-x C-s > - #+kindex: C-c $ > - #+findex: org-archive-subtree > - #+vindex: org-archive-location > - Archive the subtree starting at point position to the location given > - by ~org-archive-location~. > - > -- {{{kbd(C-u C-c C-x C-s)}}} :: > - > - #+kindex: C-u C-c C-x C-s > - Check if any direct children of the current headline could be moved > - to the archive. To do this, check each subtree for open TODO > - entries. If none is found, the command offers to move it to the > - archive location. If point is /not/ on a headline when this command > - is invoked, check level 1 trees. > - > -- {{{kbd(C-u C-u C-c C-x C-s)}}} :: > - > - #+kindex: C-u C-u C-c C-x C-s > - As above, but check subtree for timestamps instead of TODO entries. > - The command offers to archive the subtree if it /does/ contain > - a timestamp, and that timestamp is in the past. > - > -#+cindex: archive locations > -The default archive location is a file in the same directory as the > -current file, with the name derived by appending =_archive= to the > -current file name. You can also choose what heading to file archived > -items under, with the possibility to add them to a datetree in a file. > -For information and examples on how to specify the file and the > -heading, see the documentation string of the variable > -~org-archive-location~. > - > -There is also an in-buffer option for setting this variable, for > -example: > - > -#+cindex: @samp{ARCHIVE}, keyword > -: #+ARCHIVE: %s_done:: > - > -#+cindex: ARCHIVE, property > -If you would like to have a special archive location for a single > -entry or a (sub)tree, give the entry an =ARCHIVE= property with the > -location as the value (see [[*Properties and Columns]]). > - > -#+vindex: org-archive-save-context-info > -When a subtree is moved, it receives a number of special properties > -that record context information like the file from where the entry > -came, its outline path the archiving time etc. Configure the variable > -~org-archive-save-context-info~ to adjust the amount of information > -added. > - > -*** Internal archiving > -:PROPERTIES: > -:DESCRIPTION: Switch off a tree but keep it in the file. > -:END: > - > -#+cindex: @samp{ARCHIVE}, tag > -If you want to just switch off---for agenda views---certain subtrees > -without moving them to a different file, you can use the =ARCHIVE= > -tag. > - > -A headline that is marked with the =ARCHIVE= tag (see [[*Tags]]) stays at > -its location in the outline tree, but behaves in the following way: > - > -- > - #+vindex: org-cycle-open-archived-trees > - It does not open when you attempt to do so with a visibility cycling > - command (see [[*Visibility Cycling]]). You can force cycling archived > - subtrees with {{{kbd(C-TAB)}}}, or by setting the option > - ~org-cycle-open-archived-trees~. Also normal outline commands, like > - ~outline-show-all~, open archived subtrees. > - > -- > - #+vindex: org-sparse-tree-open-archived-trees > - During sparse tree construction (see [[*Sparse Trees]]), matches in > - archived subtrees are not exposed, unless you configure the option > - ~org-sparse-tree-open-archived-trees~. > - > -- > - #+vindex: org-agenda-skip-archived-trees > - During agenda view construction (see [[*Agenda Views]]), the content of > - archived trees is ignored unless you configure the option > - ~org-agenda-skip-archived-trees~, in which case these trees are > - always included. In the agenda you can press {{{kbd(v a)}}} to get > - archives temporarily included. > - > -- > - #+vindex: org-export-with-archived-trees > - Archived trees are not exported (see [[*Exporting]]), only the headline > - is. Configure the details using the variable > - ~org-export-with-archived-trees~. > - > -- > - #+vindex: org-columns-skip-archived-trees > - Archived trees are excluded from column view unless the variable > - ~org-columns-skip-archived-trees~ is configured to ~nil~. > - > -The following commands help manage the =ARCHIVE= tag: > - > -- {{{kbd(C-c C-x a)}}} (~org-toggle-archive-tag~) :: > - > - #+kindex: C-c C-x a > - #+findex: org-toggle-archive-tag > - Toggle the archive tag for the current headline. When the tag is > - set, the headline changes to a shadowed face, and the subtree below > - it is hidden. > - > -- {{{kbd(C-u C-c C-x a)}}} :: > - > - #+kindex: C-u C-c C-x a > - Check if any direct children of the current headline should be > - archived. To do this, check each subtree for open TODO entries. If > - none is found, the command offers to set the =ARCHIVE= tag for the > - child. If point is /not/ on a headline when this command is > - invoked, check the level 1 trees. > - > -- {{{kbd(C-TAB)}}} (~org-force-cycle-archived~) :: > - > - #+kindex: C-TAB > - Cycle a tree even if it is tagged with =ARCHIVE=. > - > -- {{{kbd(C-c C-x A)}}} (~org-archive-to-archive-sibling~) :: > - > - #+kindex: C-c C-x A > - #+findex: org-archive-to-archive-sibling > - Move the current entry to the /Archive Sibling/. This is a sibling > - of the entry with the heading =Archive= and the archive tag. The > - entry becomes a child of that sibling and in this way retains a lot > - of its original context, including inherited tags and approximate > - position in the outline. > - > * Agenda Views > :PROPERTIES: > :DESCRIPTION: Collecting information into views. > @@ -21244,7 +21461,7 @@ accessed in capture templates in a similar way. > ~org-link-from-user-regexp~. > > [fn:87] If you move entries or Org files from one directory to > -another, you may want to configure ~org-attach-directory~ to contain > +another, you may want to configure ~org-attach-id-dir~ to contain > an absolute path. > > [fn:88] Note the corresponding =STARTUP= options =logrefile=, > diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS > index 4abecdfbc..bbd9dc975 100644 > --- a/etc/ORG-NEWS > +++ b/etc/ORG-NEWS > @@ -111,7 +111,96 @@ every other backend was already using xcolor to set fg and bg, the CLI > alternative was removed and there is no more a :use-xcolor options > since now it's implicitly always true. > > +*** Org-Attach Git commit > +[[*Org-Attach has been refactored and extended][Refactoring of Org-Attach]] affected the Git commit functionality. Not > +much, but the following changes are required if you still need to > +auto-commit attachments to git: > + > +- Customization of ~org-attach-annex-auto-get~ needs to be renamed to > + ~org-attach-git-annex-auto-get~. > + > +- Customization of ~org-attach-commit~ is no longer needed. Instead > + one need to require the =org-attach-git= module in the startup. > + > ** New features > +*** Org-Attach has been refactored and extended > +Org attach has been refactored and the functionality extended. It > +should now be easier to understand how it works. A few improvements > +and extra options have been added as well. > + > +From the initial comment in org-attach source-code: > + > +- Attachments are managed either by using a custom property DIR or by > + using property ID from org-id. When DIR is defined, a location in > + the filesystem is directly attached to the outline node. When > + org-id is used, attachments are stored in a folder named after the > + ID, in a location defined by ~org-attach-id-dir~. DIR has > + precedence over ID when both parameters are defined for the current > + outline node (also when inherited parameters are taken into > + account). > + > +From now on inheritance requires no extra property and will adhere to > +~org-attach-use-inheritance~ by default. Inheritance can be > +customized to always be activated or never be activated in > +~org-attach-use-inheritance~. > + > +The ATTACH_DIR property is deprecated in favour of the shorter > +property DIR. Links to folders inside the DIR property can now be > +declared as relative links. This is not enabled by default, but can > +be set in ~org-attach-dir-relative~. > + > +When adding new attachment to the outline node the preferred way of > +doing so can be customized. Take a look at > +~org-attach-preferred-new-method~. It defaults to using ID since that > +was the behaviour before this change. > + > +If both DIR and ID properties are set on the same node, DIR has > +precedence and will be used. > + > +One can now also choose to build attachment-directory-paths in a > +customized way. This is an advanced topic, but in some case it makes > +sense to parse an ID in a different way than the default one. Create > +your own function and use it is ~org-attach-id-to-path-function~ if > +you want to customize the ID-based folder structure. > + > +If you've used ATTACH_DIR properties to manage attachments, use the > +following code to rename that property to DIR which supports the same > +functionality. ATTACH_DIR_INHERIT is no longer supported and is > +removed. > + > +#+begin_src emacs-lisp > + (defun org-update-attach-properties () > + "Change properties for Org-Attach." > + (interactive) > + (org-with-point-at 1 > + (while (outline-next-heading) > + (let ((DIR (org--property-local-values "ATTACH_DIR" nil))) > + (when DIR > + (org-set-property "DIR" (car DIR)) > + (org-delete-property "ATTACH_DIR")))) > + (org-delete-property-globally "ATTACH_DIR_INHERIT"))) > +#+end_src > + > +For those who hate breaking changes, even though the changes are made > +to clean things up; fear not. ATTACH_DIR will still continue to work. > +It's just not documented any longer. When you get the chance, run the > +code above to clean things up anyways! > + > +**** New hooks > +Two hooks are added to org-attach: > +- org-attach-after-change-hook > +- org-attach-open-hook > + > +They are added mostly for internal restructuring purposes, but can > +ofc. be used for other things as well. > + > +*** New link-type: Attachment > +Attachment-links are now first-class citizens. They mimick file-links > +in everything they do but use the existing attachment-folder as a base > +when expanding the links. Both =DIR= and =ID= properties are used to > +try to resolve the links, in exactly the same way as Org-Attach uses > +those properties. > + > *** Handle overlay specification for notes in Beamer export > > This aligns Beamer notes with slide overlays. > @@ -243,6 +332,11 @@ dynamic block in ~org-dynamic-block-alist~. > ** Removed functions > *** ~org-babel-set-current-result-hash~ > *** ~org-capture-insert-template-here~ > +*** ~org-attach-directory~ > + > +It has been deprecated in favour of ~org-attach-id-dir~ which is less > +ambigous given the restructured org-attach. > + > ** Miscellaneous > *** Change signature for ~org-list-to-subtree~ > The function now accepts the level of the subtree as an optional > diff --git a/lisp/org-attach-git.el b/lisp/org-attach-git.el > new file mode 100644 > index 000000000..f40eb966d > --- /dev/null > +++ b/lisp/org-attach-git.el > @@ -0,0 +1,117 @@ > +;;; org-attach-git.el --- Automatic git commit extention to org-attach -*- lexical-binding: t; -*- > + > +;; Copyright (C) 2019 Free Software Foundation, Inc. > + > +;; Original Author: John Wiegley <johnw@newartisans.com> > +;; Restructurer: Gustav Wikstr¶m <gustav@whil.se> > +;; Keywords: org data git > + > +;; This file is part of GNU Emacs. > +;; > +;; GNU Emacs is free software: you can redistribute it and/or modify > +;; it under the terms of the GNU General Public License as published by > +;; the Free Software Foundation, either version 3 of the License, or > +;; (at your option) any later version. > + > +;; GNU Emacs is distributed in the hope that it will be useful, > +;; but WITHOUT ANY WARRANTY; without even the implied warranty of > +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +;; GNU General Public License for more details. > + > +;; You should have received a copy of the GNU General Public License > +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. > + > +;;; Commentary: > + > +;; An extention to org-attach. If the attachment-directory to an > +;; outline node (using either DIR or ID) is initialized as a Git > +;; repository, then org-attach-git will automatically commit changes > +;; when it sees them. > + > +;;; Code: > + > +(require 'org-attach) > +(require 'vc-git) > + > +(defcustom org-attach-git-annex-cutoff (* 32 1024) > + "If non-nil, files larger than this will be annexed instead of stored." > + :group 'org-attach > + :version "24.4" > + :package-version '(Org . "8.0") > + :type '(choice > + (const :tag "None" nil) > + (integer :tag "Bytes"))) > + > +(defcustom org-attach-git-annex-auto-get 'ask > + "Confirmation preference for automatically getting annex files. > +If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." > + :group 'org-attach > + :package-version '(Org . "9.0") > + :version "26.1" > + :type '(choice > + (const :tag "confirm with `y-or-n-p'" ask) > + (const :tag "always get from annex if necessary" t) > + (const :tag "never get from annex" nil))) > + > +(defun org-attach-git-use-annex () > + "Return non-nil if git annex can be used." > + (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir)))) > + (and org-attach-git-annex-cutoff > + (or (file-exists-p (expand-file-name "annex" git-dir)) > + (file-exists-p (expand-file-name ".git/annex" git-dir)))))) > + > +(defun org-attach-git-annex-get-maybe (path) > + "Call git annex get PATH (via shell) if using git annex. > +Signals an error if the file content is not available and it was not retrieved." > + (let* ((default-directory (expand-file-name org-attach-id-dir)) > + (path-relative (file-relative-name path))) > + (when (and (org-attach-git-use-annex) > + (not > + (string-equal > + "found" > + (shell-command-to-string > + (format "git annex find --format=found --in=here %s" > + (shell-quote-argument path-relative)))))) > + (let ((should-get > + (if (eq org-attach-git-annex-auto-get 'ask) > + (y-or-n-p (format "Run git annex get %s? " path-relative)) > + org-attach-git-annex-auto-get))) > + (unless should-get > + (error "File %s stored in git annex but unavailable" path)) > + (message "Running git annex get \"%s\"." path-relative) > + (call-process "git" nil nil nil "annex" "get" path-relative))))) > + > +(defun org-attach-git-commit () > + "Commit changes to git if `org-attach-id-dir' is properly initialized. > +This checks for the existence of a \".git\" directory in that directory." > + (let* ((dir (expand-file-name org-attach-id-dir)) > + (git-dir (vc-git-root dir)) > + (use-annex (org-attach-git-use-annex)) > + (changes 0)) > + (when (and git-dir (executable-find "git")) > + (with-temp-buffer > + (cd dir) > + (dolist (new-or-modified > + (split-string > + (shell-command-to-string > + "git ls-files -zmo --exclude-standard") "\0" t)) > + (if (and use-annex > + (>= (file-attribute-size (file-attributes new-or-modified)) > + org-attach-git-annex-cutoff)) > + (call-process "git" nil nil nil "annex" "add" new-or-modified) > + (call-process "git" nil nil nil "add" new-or-modified)) > + (cl-incf changes)) > + (dolist (deleted > + (split-string > + (shell-command-to-string "git ls-files -z --deleted") "\0" t)) > + (call-process "git" nil nil nil "rm" deleted) > + (cl-incf changes)) > + (when (> changes 0) > + (shell-command "git commit -m 'Synchronized attachments'")))))) > + > +(add-hook 'org-attach-after-change-hook 'org-attach-git-commit) > +(add-hook 'org-attach-open-hook 'org-attach-git-annex-get-maybe) > + > +(provide 'org-attach-git) > + > +;;; org-attach-git.el ends here > diff --git a/lisp/org-attach.el b/lisp/org-attach.el > index a715c89e9..726085014 100644 > --- a/lisp/org-attach.el > +++ b/lisp/org-attach.el > @@ -1,9 +1,9 @@ > -;;; org-attach.el --- Manage file attachments to Org tasks -*- lexical-binding: t; -*- > +;;; org-attach.el --- Manage file attachments to Org outlines -*- lexical-binding: t; -*- > > ;; Copyright (C) 2008-2019 Free Software Foundation, Inc. > > ;; Author: John Wiegley <johnw@newartisans.com> > -;; Keywords: org data task > +;; Keywords: org data attachment > > ;; This file is part of GNU Emacs. > ;; > @@ -24,32 +24,30 @@ > > ;; See the Org manual for information on how to use it. > ;; > -;; Attachments are managed in a special directory called "data", which > -;; lives in the same directory as the org file itself. If this data > -;; directory is initialized as a Git repository, then org-attach will > -;; automatically commit changes when it sees them. > -;; > -;; Attachment directories are identified using a UUID generated for the > -;; task which has the attachments. These are added as property to the > -;; task when necessary, and should not be deleted or changed by the > -;; user, ever. UUIDs are generated by a mechanism defined in the variable > -;; `org-id-method'. > +;; Attachments are managed either by using a custom property DIR or by > +;; using property ID from org-id. When DIR is defined, a location in > +;; the filesystem is directly attached to the outline node. When > +;; org-id is used, attachments are stored in a folder named after the > +;; ID, in a location defined by `org-attach-id-dir'. DIR has > +;; precedence over ID when both parameters are defined for the current > +;; outline node (also when inherited parameters are taken into > +;; account). > > ;;; Code: > > (require 'cl-lib) > (require 'org) > +(require 'ol) > (require 'org-id) > -(require 'vc-git) > > (declare-function dired-dwim-target-directory "dired-aux") > > (defgroup org-attach nil > - "Options concerning entry attachments in Org mode." > + "Options concerning attachments in Org mode." > :tag "Org Attach" > :group 'org) > > -(defcustom org-attach-directory "data/" > +(defcustom org-attach-id-dir "data/" > "The directory where attachments are stored. > If this is a relative path, it will be interpreted relative to the directory > where the Org file lives." > @@ -57,22 +55,13 @@ where the Org file lives." > :type 'directory > :safe #'stringp) > > -(defcustom org-attach-commit t > - "If non-nil commit attachments with git. > -This is only done if the Org file is in a git repository." > +(defcustom org-attach-dir-relative nil > + "Non-nil means directories in DIR property are added as relative links. > +Defaults to absolute location." > :group 'org-attach > :type 'boolean > - :version "26.1" > - :package-version '(Org . "9.0")) > - > -(defcustom org-attach-git-annex-cutoff (* 32 1024) > - "If non-nil, files larger than this will be annexed instead of stored." > - :group 'org-attach > - :version "24.4" > - :package-version '(Org . "8.0") > - :type '(choice > - (const :tag "None" nil) > - (integer :tag "Bytes"))) > + :package-version '(Org . "9.3") > + :safe #'booleanp) > > (defcustom org-attach-auto-tag "ATTACH" > "Tag that will be triggered automatically when an entry has an attachment." > @@ -81,15 +70,27 @@ This is only done if the Org file is in a git repository." > (const :tag "None" nil) > (string :tag "Tag"))) > > -(defcustom org-attach-file-list-property "Attachments" > - "The property used to keep a list of attachment belonging to this entry. > -This is not really needed, so you may set this to nil if you don't want it. > -Also, for entries where children inherit the directory, the list of > -attachments is not kept in this property." > +(defcustom org-attach-preferred-new-method 'id > + "Preferred way to attach to nodes without existing ID and DIR property. > +This choice is used when adding attachments to nodes without ID > +and DIR properties. > + > +Allowed values are: > + > +id Create and use an ID parameter > +dir Create and use a DIR parameter > +ask Ask the user for input of which method to choose > +nil Prefer to not create a new parameter > + > + nil means that ID or DIR has to be created explicitly > + before attaching files." > :group 'org-attach > + :package-version '(org . "9.3") > :type '(choice > - (const :tag "None" nil) > - (string :tag "Tag"))) > + (const :tag "ID parameter" id) > + (const :tag "DIR parameter" dir) > + (const :tag "Ask user" ask) > + (const :tag "Don't create" nil))) > > (defcustom org-attach-method 'cp > "The preferred method to attach a file. > @@ -113,14 +114,24 @@ lns create a symbol link. Note that this is not supported > :group 'org-attach > :type 'boolean) > > -(defcustom org-attach-allow-inheritance t > - "Non-nil means allow attachment directories be inherited." > +(defcustom org-attach-use-inheritance 'selective > + "Attachment inheritance for the outline. > + > +Enabling inheritance for org-attach implies two things. First, > +that attachment links will look through all parent headings until > +it finds the linked attachment. Second, that running org-attach > +inside a node without attachments will make org-attach operate on > +the first parent heading it finds with an attachment. > + > +Selective means to respect the inheritance setting in > +`org-use-property-inheritance'." > :group 'org-attach > + :type '(choice > + (const :tag "Don't use inheritance" nil) > + (const :tag "Inherit parent node attachments" t) > + (const :tag "Respect org-use-property-inheritance" selective)) > :type 'boolean) > > -(defvar org-attach-inherited nil > - "Indicates if the last access to the attachment directory was inherited.") > - > (defcustom org-attach-store-link-p nil > "Non-nil means store a link to a file when attaching it." > :group 'org-attach > @@ -141,16 +152,28 @@ When set to `query', ask the user instead." > (const :tag "Always delete attachments" t) > (const :tag "Query the user" query))) > > -(defcustom org-attach-annex-auto-get 'ask > - "Confirmation preference for automatically getting annex files. > -If \\='ask, prompt using `y-or-n-p'. If t, always get. If nil, never get." > +(defun org-attach-id-folder-format (id) > + "Translate an ID into a folder-path. > +Default format for how Org translates ID properties to a path for > +attachments." > + (format "%s/%s" > + (substring id 0 2) > + (substring id 2))) > + > +(defcustom org-attach-id-to-path-function #'org-attach-id-folder-format > + "Function parsing the ID parameter into a folder-path." > :group 'org-attach > - :package-version '(Org . "9.0") > - :version "26.1" > - :type '(choice > - (const :tag "confirm with `y-or-n-p'" ask) > - (const :tag "always get from annex if necessary" t) > - (const :tag "never get from annex" nil))) > + :package-version '(Org . "9.3") > + :type 'function) > + > +(defvar org-attach-after-change-hook nil > + "Hook to be called when files have been added or removed to the attachment folder.") > + > +(defvar org-attach-open-hook nil > + "Hook that is invoked by `org-attach-open'. > + > +Created mostly to be compatible with org-attach-git after removing > +git-funtionality from this file.") > > (defcustom org-attach-commands > '(((?a ?\C-a) org-attach-attach > @@ -186,9 +209,9 @@ you added attachments yourself.\n") > "Delete all of a task's attachments. A safer way is\n to open the \ > directory in dired and delete from there.\n") > ((?s ?\C-s) org-attach-set-directory > - "Set a specific attachment directory for this entry or reset to default.") > - ((?i ?\C-i) org-attach-set-inherit > - "Make children of the current entry inherit its attachment directory.\n") > + "Set a specific attachment directory for this entry. Sets DIR property.") > + ((?S ?\C-S) org-attach-unset-directory > + "Unset the attachment directory for this entry. Removes DIR property.") > ((?q) (lambda () (interactive) (message "Abort")) "Abort.")) > "The list of commands for the attachment dispatcher. > Each entry in this list is a list of three elements: > @@ -215,7 +238,7 @@ Shows a list of commands and prompts for another key to execute a command." > (setq marker (or (get-text-property (point) 'org-hd-marker) > (get-text-property (point) 'org-marker))) > (unless marker > - (error "No task in current line"))) > + (error "No item in current line"))) > (save-excursion > (when marker > (set-buffer (marker-buffer marker)) > @@ -225,24 +248,28 @@ Shows a list of commands and prompts for another key to execute a command." > (save-window-excursion > (unless org-attach-expert > (with-output-to-temp-buffer "*Org Attach*" > - (princ > - (format "Select an Attachment Command:\n\n%s" > - (mapconcat > - (lambda (entry) > - (pcase entry > - (`((,key . ,_) ,_ ,docstring) > - (format "%c %s" > - key > - (replace-regexp-in-string "\n\\([\t ]*\\)" > - " " > - docstring > - nil nil 1))) > - (_ > - (user-error > - "Invalid `org-attach-commands' item: %S" > - entry)))) > - org-attach-commands > - "\n"))))) > + (princ > + (concat "Attachment folder:\n" > + (or (org-attach-dir) > + "Can't find an existing attachment-folder") > + "\n\n" > + (format "Select an Attachment Command:\n\n%s" > + (mapconcat > + (lambda (entry) > + (pcase entry > + (`((,key . ,_) ,_ ,docstring) > + (format "%c %s" > + key > + (replace-regexp-in-string "\n\\([\t ]*\\)" > + " " > + docstring > + nil nil 1))) > + (_ > + (user-error > + "Invalid `org-attach-commands' item: %S" > + entry)))) > + org-attach-commands > + "\n")))))) > (org-fit-window-to-buffer (get-buffer-window "*Org Attach*")) > (message "Select command: [%s]" > (concat (mapcar #'caar org-attach-commands))) > @@ -256,148 +283,126 @@ Shows a list of commands and prompts for another key to execute a command." > (error "No such attachment command: %c" c)))))) > > (defun org-attach-dir (&optional create-if-not-exists-p) > - "Return the directory associated with the current entry. > -This first checks for a local property ATTACH_DIR, and then for an inherited > -property ATTACH_DIR_INHERIT. If neither exists, the default mechanism > -using the entry ID will be invoked to access the unique directory for the > -current entry. > -If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, > -the directory and (if necessary) the corresponding ID will be created." > - (let (attach-dir uuid) > - (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) > + "Return the directory associated with the current outline node. > +First check for DIR property, then ID property. > +`org-attach-use-inheritance' determines whether inherited > +properties also will be considered. > + > +If an ID property is found the default mechanism using that ID > +will be invoked to access the directory for the current entry. > + > +If CREATE-IF-NOT-EXIST-P is non-nil, `org-attach-dir-get-create' > +is run." > + (let (attach-dir id) > (cond > - ((setq attach-dir (org-entry-get nil "ATTACH_DIR")) > + (create-if-not-exists-p > + (setq attach-dir (org-attach-dir-get-create))) > + ((setq attach-dir (org-entry-get nil "DIR" org-attach-use-inheritance)) > (org-attach-check-absolute-path attach-dir)) > - ((and org-attach-allow-inheritance > - (org-entry-get nil "ATTACH_DIR_INHERIT" t)) > - (setq attach-dir > - (org-with-wide-buffer > - (if (marker-position org-entry-property-inherited-from) > - (goto-char org-entry-property-inherited-from) > - (org-back-to-heading t)) > - (let (org-attach-allow-inheritance) > - (org-attach-dir create-if-not-exists-p)))) > - (org-attach-check-absolute-path attach-dir) > - (setq org-attach-inherited t)) > - (t ; use the ID > + ;; Deprecated and removed from documentation, but still > + ;; works. FIXME: Remove after major nr change. > + ((setq attach-dir (org-entry-get nil "ATTACH_DIR" org-attach-use-inheritance)) > + (org-attach-check-absolute-path attach-dir)) > + ((setq id (org-entry-get nil "ID" org-attach-use-inheritance)) > (org-attach-check-absolute-path nil) > - (setq uuid (org-id-get (point) create-if-not-exists-p)) > - (when (or uuid create-if-not-exists-p) > - (unless uuid (error "ID retrieval/creation failed")) > - (setq attach-dir (expand-file-name > - (format "%s/%s" > - (substring uuid 0 2) > - (substring uuid 2)) > - (expand-file-name org-attach-directory)))))) > - (when attach-dir > - (if (and create-if-not-exists-p > - (not (file-directory-p attach-dir))) > - (make-directory attach-dir t)) > - (and (file-exists-p attach-dir) > - attach-dir)))) > + (setq attach-dir (org-attach-dir-from-id id)))) > + attach-dir)) > + > +(defun org-attach-dir-get-create () > + "Return existing or new directory associated with the current outline node. > + > +`org-attach-preferred-new-method' decides how to attach > +new directory." > + (interactive) > + (let ((attach-dir (org-attach-dir))) > + (unless attach-dir > + (let (answer) > + (when (eq org-attach-preferred-new-method 'ask) > + (message "Create new ID [1] property or DIR [2] property for attachments?") > + (setq answer (read-char-exclusive))) > + (cond > + ((or (eq org-attach-preferred-new-method 'id) (eq answer ?1)) > + (setq attach-dir (org-attach-dir-from-id (org-id-get nil t)))) > + ((or (eq org-attach-preferred-new-method 'dir) (eq answer ?2)) > + (setq attach-dir (org-attach-set-directory))) > + ((eq org-attach-preferred-new-method 'nil) > + (error "No existing directory. DIR or ID property has to be explicitly created"))))) > + (unless attach-dir > + (error "No attachment directory is associated with the current node")) > + (unless (file-directory-p attach-dir) > + (make-directory attach-dir t)) > + attach-dir)) > + > +(defun org-attach-dir-from-id (id) > + "Returns a file name based on `org-attach-id-dir' and ID." > + (expand-file-name > + (funcall org-attach-id-to-path-function id) > + (expand-file-name org-attach-id-dir))) > > (defun org-attach-check-absolute-path (dir) > "Check if we have enough information to root the attachment directory. > When DIR is given, check also if it is already absolute. Otherwise, > -assume that it will be relative, and check if `org-attach-directory' is > +assume that it will be relative, and check if `org-attach-id-dir' is > absolute, or if at least the current buffer has a file name. > Throw an error if we cannot root the directory." > (or (and dir (file-name-absolute-p dir)) > - (file-name-absolute-p org-attach-directory) > + (file-name-absolute-p org-attach-id-dir) > (buffer-file-name (buffer-base-buffer)) > - (error "Need absolute `org-attach-directory' to attach in buffers without filename"))) > + (error "Need absolute `org-attach-id-dir' to attach in buffers without filename"))) > > -(defun org-attach-set-directory (&optional arg) > - "Set the ATTACH_DIR node property and ask to move files there. > +(defun org-attach-set-directory () > + "Set the DIR node property and ask to move files there. > The property defines the directory that is used for attachments > -of the entry. When called with `\\[universal-argument]', reset \ > -the directory to > -the default ID based one." > - (interactive "P") > +of the entry. Creates relative links if `org-attach-dir-relative' > +is non-nil. > + > +Return the directory." > + (interactive) > (let ((old (org-attach-dir)) > - (new > - (progn > - (if arg (org-entry-delete nil "ATTACH_DIR") > - (let ((dir (read-directory-name > - "Attachment directory: " > - (org-entry-get nil > - "ATTACH_DIR" > - (and org-attach-allow-inheritance t))))) > - (org-entry-put nil "ATTACH_DIR" dir))) > - (org-attach-dir t)))) > + (new > + (let* ((attach-dir (read-directory-name > + "Attachment directory: " > + (org-entry-get nil "DIR"))) > + (current-dir (file-name-directory (or default-directory > + buffer-file-name))) > + (attach-dir-relative (file-relative-name attach-dir current-dir))) > + (org-entry-put nil "DIR" (if org-attach-dir-relative > + attach-dir-relative > + attach-dir)) > + attach-dir))) > (unless (or (string= old new) > (not old)) > (when (yes-or-no-p "Copy over attachments from old directory? ") > + (copy-directory old new t t t)) > + (when (yes-or-no-p (concat "Delete " old)) > + (delete-directory old t))) > + new)) > + > +(defun org-attach-unset-directory () > + "Removes DIR node property. > +If attachment folder is changed due to removal of DIR-property > +ask to move attachments to new location and ask to delete old > +attachment-folder. > + > +Change of attachment-folder due to unset might be if an ID > +property is set on the node, or if a separate inherited > +DIR-property exists (that is different than the unset one)." > + (interactive) > + (let ((old (org-attach-dir)) > + (new > + (progn > + (org-entry-delete nil "DIR") > + ;; ATTACH-DIR is deprecated and removed from documentation, > + ;; but still works. Remove code for it after major nr change. > + (org-entry-delete nil "ATTACH_DIR") > + (org-attach-dir)))) > + (unless (or (string= old new) > + (not old)) > + (when (and new (yes-or-no-p "Copy over attachments from old directory? ")) > (copy-directory old new t nil t)) > (when (yes-or-no-p (concat "Delete " old)) > (delete-directory old t))))) > > -(defun org-attach-set-inherit () > - "Set the ATTACH_DIR_INHERIT property of the current entry. > -The property defines the directory that is used for attachments > -of the entry and any children that do not explicitly define (by setting > -the ATTACH_DIR property) their own attachment directory." > - (interactive) > - (org-entry-put nil "ATTACH_DIR_INHERIT" "t") > - (message "Children will inherit attachment directory")) > - > -(defun org-attach-use-annex () > - "Return non-nil if git annex can be used." > - (let ((git-dir (vc-git-root (expand-file-name org-attach-directory)))) > - (and org-attach-git-annex-cutoff > - (or (file-exists-p (expand-file-name "annex" git-dir)) > - (file-exists-p (expand-file-name ".git/annex" git-dir)))))) > - > -(defun org-attach-annex-get-maybe (path) > - "Call git annex get PATH (via shell) if using git annex. > -Signals an error if the file content is not available and it was not retrieved." > - (let* ((default-directory (expand-file-name org-attach-directory)) > - (path-relative (file-relative-name path))) > - (when (and (org-attach-use-annex) > - (not > - (string-equal > - "found" > - (shell-command-to-string > - (format "git annex find --format=found --in=here %s" > - (shell-quote-argument path-relative)))))) > - (let ((should-get > - (if (eq org-attach-annex-auto-get 'ask) > - (y-or-n-p (format "Run git annex get %s? " path-relative)) > - org-attach-annex-auto-get))) > - (if should-get > - (progn (message "Running git annex get \"%s\"." path-relative) > - (call-process "git" nil nil nil "annex" "get" path-relative)) > - (error "File %s stored in git annex but it is not available, and was not retrieved" > - path)))))) > - > -(defun org-attach-commit () > - "Commit changes to git if `org-attach-directory' is properly initialized. > -This checks for the existence of a \".git\" directory in that directory." > - (let* ((dir (expand-file-name org-attach-directory)) > - (git-dir (vc-git-root dir)) > - (use-annex (org-attach-use-annex)) > - (changes 0)) > - (when (and git-dir (executable-find "git")) > - (with-temp-buffer > - (cd dir) > - (dolist (new-or-modified > - (split-string > - (shell-command-to-string > - "git ls-files -zmo --exclude-standard") "\0" t)) > - (if (and use-annex > - (>= (file-attribute-size (file-attributes new-or-modified)) > - org-attach-git-annex-cutoff)) > - (call-process "git" nil nil nil "annex" "add" new-or-modified) > - (call-process "git" nil nil nil "add" new-or-modified)) > - (cl-incf changes)) > - (dolist (deleted > - (split-string > - (shell-command-to-string "git ls-files -z --deleted") "\0" t)) > - (call-process "git" nil nil nil "rm" deleted) > - (cl-incf changes)) > - (when (> changes 0) > - (shell-command "git commit -m 'Synchronized attachments'")))))) > - > (defun org-attach-tag (&optional off) > "Turn the autotag on or (if OFF is set) off." > (when org-attach-auto-tag > @@ -423,22 +428,21 @@ Only do this when `org-attach-store-link-p' is non-nil." > (org-attach-attach url))) > > (defun org-attach-buffer (buffer-name) > - "Attach BUFFER-NAME's contents to current task. > + "Attach BUFFER-NAME's contents to current outline node. > BUFFER-NAME is a string. Signals a `file-already-exists' error > if it would overwrite an existing filename." > (interactive "bBuffer whose contents should be attached: ") > - (let ((output (expand-file-name buffer-name (org-attach-dir t)))) > + (let* ((attach-dir (org-attach-dir 'get-create)) > + (output (expand-file-name buffer-name attach-dir))) > (when (file-exists-p output) > (signal 'file-already-exists (list "File exists" output))) > - (when (and org-attach-file-list-property (not org-attach-inherited)) > - (org-entry-add-to-multivalued-property > - (point) org-attach-file-list-property buffer-name)) > + (run-hook-with-args 'org-attach-after-change-hook attach-dir) > (org-attach-tag) > (with-temp-file output > (insert-buffer-substring buffer-name)))) > > (defun org-attach-attach (file &optional visit-dir method) > - "Move/copy/link FILE into the attachment directory of the current task. > + "Move/copy/link FILE into the attachment directory of the current outline node. > If VISIT-DIR is non-nil, visit the directory with dired. > METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from > `org-attach-method'." > @@ -453,10 +457,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from > nil)) > (setq method (or method org-attach-method)) > (let ((basename (file-name-nondirectory file))) > - (when (and org-attach-file-list-property (not org-attach-inherited)) > - (org-entry-add-to-multivalued-property > - (point) org-attach-file-list-property basename)) > - (let* ((attach-dir (org-attach-dir t)) > + (let* ((attach-dir (org-attach-dir 'get-create)) > (fname (expand-file-name basename attach-dir))) > (cond > ((eq method 'mv) (rename-file file fname)) > @@ -464,8 +465,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from > ((eq method 'ln) (add-name-to-file file fname)) > ((eq method 'lns) (make-symbolic-link file fname)) > ((eq method 'url) (url-copy-file file fname))) > - (when org-attach-commit > - (org-attach-commit)) > + (run-hook-with-args 'org-attach-after-change-hook attach-dir) > (org-attach-tag) > (cond ((eq org-attach-store-link-p 'attached) > (org-attach-store-link fname)) > @@ -473,7 +473,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from > (org-attach-store-link file))) > (if visit-dir > (dired attach-dir) > - (message "File %S is now a task attachment." basename))))) > + (message "File %S is now an attachment." basename))))) > > (defun org-attach-attach-cp () > "Attach a file by copying it." > @@ -498,13 +498,10 @@ On some systems, this apparently does copy the file instead." > (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) > > (defun org-attach-new (file) > - "Create a new attachment FILE for the current task. > + "Create a new attachment FILE for the current outline node. > The attachment is created as an Emacs buffer." > (interactive "sCreate attachment named: ") > - (when (and org-attach-file-list-property (not org-attach-inherited)) > - (org-entry-add-to-multivalued-property > - (point) org-attach-file-list-property file)) > - (let ((attach-dir (org-attach-dir t))) > + (let ((attach-dir (org-attach-dir 'get-create))) > (org-attach-tag) > (find-file (expand-file-name file attach-dir)) > (message "New attachment %s" file))) > @@ -512,7 +509,7 @@ The attachment is created as an Emacs buffer." > (defun org-attach-delete-one (&optional file) > "Delete a single attachment." > (interactive) > - (let* ((attach-dir (org-attach-dir t)) > + (let* ((attach-dir (org-attach-dir)) > (files (org-attach-file-list attach-dir)) > (file (or file > (completing-read > @@ -524,44 +521,32 @@ The attachment is created as an Emacs buffer." > (unless (file-exists-p file) > (error "No such attachment: %s" file)) > (delete-file file) > - (when org-attach-commit > - (org-attach-commit)))) > + (run-hook-with-args 'org-attach-after-change-hook attach-dir))) > > (defun org-attach-delete-all (&optional force) > - "Delete all attachments from the current task. > + "Delete all attachments from the current outline node. > This actually deletes the entire attachment directory. > A safer way is to open the directory in dired and delete from there." > (interactive "P") > - (when (and org-attach-file-list-property (not org-attach-inherited)) > - (org-entry-delete (point) org-attach-file-list-property)) > (let ((attach-dir (org-attach-dir))) > - (when > - (and attach-dir > - (or force > - (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) > - (shell-command (format "rm -fr %s" attach-dir)) > + (when (and attach-dir > + (or force > + (yes-or-no-p "Really remove all attachments of this entry? "))) > + (delete-directory attach-dir (yes-or-no-p "Recursive?") t) > (message "Attachment directory removed") > - (when org-attach-commit > - (org-attach-commit)) > + (run-hook-with-args 'org-attach-after-change-hook attach-dir) > (org-attach-untag)))) > > (defun org-attach-sync () > - "Synchronize the current tasks with its attachments. > + "Synchronize the current outline node with its attachments. > This can be used after files have been added externally." > (interactive) > - (when org-attach-commit > - (org-attach-commit)) > - (when (and org-attach-file-list-property (not org-attach-inherited)) > - (org-entry-delete (point) org-attach-file-list-property)) > (let ((attach-dir (org-attach-dir))) > (when attach-dir > + (run-hook-with-args 'org-attach-after-change-hook attach-dir) > (let ((files (org-attach-file-list attach-dir))) > - (org-attach-tag (not files)) > - (when org-attach-file-list-property > - (dolist (file files) > - (unless (string-match "^\\.\\.?\\'" file) > - (org-entry-add-to-multivalued-property > - (point) org-attach-file-list-property file)))))))) > + (org-attach-tag (not files)))) > + (unless attach-dir (org-attach-tag t)))) > > (defun org-attach-file-list (dir) > "Return a list of files in the attachment directory. > @@ -570,35 +555,40 @@ This ignores files ending in \"~\"." > (mapcar (lambda (x) (if (string-match "^\\.\\.?\\'" x) nil x)) > (directory-files dir nil "[^~]\\'")))) > > -(defun org-attach-reveal (&optional if-exists) > - "Show the attachment directory of the current task. > +(defun org-attach-reveal () > + "Show the attachment directory of the current outline node. > This will attempt to use an external program to show the directory." > - (interactive "P") > - (let ((attach-dir (org-attach-dir (not if-exists)))) > - (and attach-dir (org-open-file attach-dir)))) > + (interactive) > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (org-open-file attach-dir) > + (error "No attachment directory exist")))) > > (defun org-attach-reveal-in-emacs () > - "Show the attachment directory of the current task in dired." > + "Show the attachment directory of the current outline node in dired." > (interactive) > - (let ((attach-dir (org-attach-dir t))) > - (dired attach-dir))) > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (dired attach-dir) > + (error "No attachment directory exist")))) > > (defun org-attach-open (&optional in-emacs) > - "Open an attachment of the current task. > + "Open an attachment of the current outline node. > If there are more than one attachment, you will be prompted for the file name. > This command will open the file using the settings in `org-file-apps' > and in the system-specific variants of this variable. > If IN-EMACS is non-nil, force opening in Emacs." > (interactive "P") > - (let* ((attach-dir (org-attach-dir t)) > - (files (org-attach-file-list attach-dir)) > - (file (if (= (length files) 1) > - (car files) > - (completing-read "Open attachment: " > - (mapcar #'list files) nil t))) > - (path (expand-file-name file attach-dir))) > - (org-attach-annex-get-maybe path) > - (org-open-file path in-emacs))) > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (let* ((file (pcase (org-attach-file-list attach-dir) > + (`(,file) file) > + (files (completing-read "Open attachment: " > + (mapcar #'list files) nil t)))) > + (path (expand-file-name file attach-dir))) > + (run-hook-with-args 'org-attach-open-hook path) > + (org-open-file path in-emacs)) > + (error "No attachment directory exist")))) > > (defun org-attach-open-in-emacs () > "Open attachment, force opening in Emacs. > @@ -617,6 +607,69 @@ Basically, this adds the path to the attachment directory, and a \"file:\" > prefix." > (concat "file:" (org-attach-expand file))) > > +(org-link-set-parameters "attachment" > + :follow #'org-attach-open-link > + :export #'org-attach-export-link > + :complete #'org-attach-complete-link) > + > +(defun org-attach-open-link (link &optional in-emacs) > + "Attachment link type LINK is expanded with the attached directory and opened. > + > +With optional prefix argument IN-EMACS, Emacs will visit the file. > +With a double \\[universal-argument] \\[universal-argument] \ > +prefix arg, Org tries to avoid opening in Emacs > +and to use an external application to visit the file." > + (interactive "P") > + (let (line search) > + (cond > + ((string-match "::\\([0-9]+\\)\\'" link) > + (setq line (string-to-number (match-string 1 link)) > + link (substring link 0 (match-beginning 0)))) > + ((string-match "::\\(.+\\)\\'" link) > + (setq search (match-string 1 link) > + link (substring link 0 (match-beginning 0))))) > + (if (string-match "[*?{]" (file-name-nondirectory link)) > + (dired (org-attach-expand link)) > + (org-open-file (org-attach-expand link) in-emacs line search)))) > + > +(defun org-attach-complete-link () > + "Advise the user with the available files in the attachment directory." > + (let ((attach-dir (org-attach-dir))) > + (if attach-dir > + (let* ((attached-dir (expand-file-name attach-dir)) > + (file (read-file-name "File: " attached-dir)) > + (pwd (file-name-as-directory attached-dir)) > + (pwd-relative (file-name-as-directory > + (abbreviate-file-name attached-dir)))) > + (cond > + ((string-match (concat "^" (regexp-quote pwd-relative) "\\(.+\\)") file) > + (concat "attachment:" (match-string 1 file))) > + ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") > + (expand-file-name file)) > + (concat "attachment:" (match-string 1 (expand-file-name file)))) > + (t (concat "attachment:" file)))) > + (error "No attachment directory exist")))) > + > +(defun org-attach-export-link (link description format) > + "Translate attachment LINK from Org mode format to exported FORMAT. > +Also includes the DESCRIPTION of the link in the export." > + (save-excursion > + (let (path desc) > + (cond > + ((string-match "::\\([0-9]+\\)\\'" link) > + (setq link (substring link 0 (match-beginning 0)))) > + ((string-match "::\\(.+\\)\\'" link) > + (setq link (substring link 0 (match-beginning 0))))) > + (setq path (file-relative-name (org-attach-expand link)) > + desc (or description link)) > + (pcase format > + (`html (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc)) > + (`latex (format "\\href{%s}{%s}" path desc)) > + (`texinfo (format "@uref{%s,%s}" path desc)) > + (`ascii (format "%s (%s)" desc path)) > + (`md (format "[%s](%s)" desc path)) > + (_ path))))) > + > (defun org-attach-archive-delete-maybe () > "Maybe delete subtree attachments when archiving. > This function is called by `org-archive-hook'. The option > @@ -644,7 +697,7 @@ Idea taken from `gnus-dired-attach'." > (interactive > (list (dired-get-marked-files))) > (unless (eq major-mode 'dired-mode) > - (user-error "This command must be triggered in a dired buffer.")) > + (user-error "This command must be triggered in a dired buffer")) > (let ((start-win (selected-window)) > (other-win > (get-window-with-predicate > diff --git a/lisp/org-compat.el b/lisp/org-compat.el > index 9cb396fe9..42fe64379 100644 > --- a/lisp/org-compat.el > +++ b/lisp/org-compat.el > @@ -263,6 +263,9 @@ Counting starts at 1." > (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays > 'org-clear-latex-preview "Org 9.3") > > +(define-obsolete-variable-alias 'org-attach-directory > + 'org-attach-id-dir "Org 9.3") > + > (defun org-in-fixed-width-region-p () > "Non-nil if point in a fixed-width region." > (save-match-data > diff --git a/lisp/org.el b/lisp/org.el > index 9601ecf2e..5d6cc757d 100644 > --- a/lisp/org.el > +++ b/lisp/org.el > @@ -3847,7 +3847,9 @@ This is needed for font-lock setup.") > (beg end)) > (declare-function org-agenda-set-restriction-lock "org-agenda" (&optional type)) > (declare-function org-agenda-skip "org-agenda" ()) > -(declare-function org-attach-reveal "org-attach" (&optional if-exists)) > +(declare-function org-attach-expand "org-attach" (file)) > +(declare-function org-attach-reveal "org-attach" ()) > +(declare-function org-attach-reveal-in-emacs "org-attach" ()) > (declare-function org-gnus-follow-link "org-gnus" (&optional group article)) > (declare-function org-indent-mode "org-indent" (&optional arg)) > (declare-function org-inlinetask-goto-beginning "org-inlinetask" ()) > @@ -8645,12 +8647,15 @@ a link." > (pcase (org-offer-links-in-entry (current-buffer) (point) arg) > (`(nil . ,_) > (require 'org-attach) > - (org-attach-reveal 'if-exists)) > + (message "Opening attachment-dir") > + (if (equal arg '(4)) > + (org-attach-reveal-in-emacs) > + (org-attach-reveal))) > (`(,links . ,links-end) > (dolist (link (if (stringp links) (list links) links)) > (search-forward link nil links-end) > (goto-char (match-beginning 0)) > - (org-open-at-point)))))) > + (org-open-at-point arg)))))) > ;; On a footnote reference or at definition's label. > ((or (eq type 'footnote-reference) > (and (eq type 'footnote-definition) > @@ -16630,13 +16635,14 @@ boundaries." > ;; "file:" links. Also check link abbreviations since > ;; some might expand to "file" links. > (file-types-re > - (format "\\[\\[\\(?:file%s:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" > + (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)" > (if (not link-abbrevs) "" > (concat "\\|" (regexp-opt link-abbrevs)))))) > (while (re-search-forward file-types-re end t) > (let* ((link (org-element-lineage > (save-match-data (org-element-context)) > '(link) t)) > + (linktype (org-element-property :type link)) > (inner-start (match-beginning 1)) > (path > (cond > @@ -16650,7 +16656,8 @@ boundaries." > ;; INCLUDE-LINKED is non-nil. > ((or (not (org-element-property :contents-begin link)) > include-linked) > - (and (equal "file" (org-element-property :type link)) > + (and (or (equal "file" linktype) > + (equal "attachment" linktype)) > (org-element-property :path link))) > ;; Link with a description. Check if description > ;; is a filename. Even if Org doesn't have syntax > @@ -16669,7 +16676,11 @@ boundaries." > (match-end 0)) > (match-string 2))))))) > (when (and path (string-match-p file-extension-re path)) > - (let ((file (expand-file-name path))) > + (let ((file (if (equal "attachment" linktype) > + (progn > + (require 'org-attach) > + (org-attach-expand path)) > + (expand-file-name path)))) > (when (file-exists-p file) > (let ((width > ;; Apply `org-image-actual-width' specifications. > diff --git a/lisp/ox-html.el b/lisp/ox-html.el > index f1c06e069..757006321 100644 > --- a/lisp/ox-html.el > +++ b/lisp/ox-html.el > @@ -884,6 +884,7 @@ link to the image." > > (defcustom org-html-inline-image-rules > '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") > + ("attachment" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") > ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'") > ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")) > "Rules characterizing image files that can be inlined into HTML. > diff --git a/testing/examples/att1/fileA b/testing/examples/att1/fileA > new file mode 100644 > index 000000000..9a0406c0d > --- /dev/null > +++ b/testing/examples/att1/fileA > @@ -0,0 +1 @@ > +Text in fileA > diff --git a/testing/examples/att1/fileB b/testing/examples/att1/fileB > new file mode 100644 > index 000000000..dd2331824 > --- /dev/null > +++ b/testing/examples/att1/fileB > @@ -0,0 +1 @@ > +Text in fileB > diff --git a/testing/examples/att2/fileC b/testing/examples/att2/fileC > new file mode 100644 > index 000000000..2c9a92bfe > --- /dev/null > +++ b/testing/examples/att2/fileC > @@ -0,0 +1 @@ > +Text in fileC > \ No newline at end of file > diff --git a/testing/examples/att2/fileD b/testing/examples/att2/fileD > new file mode 100644 > index 000000000..c706556c5 > --- /dev/null > +++ b/testing/examples/att2/fileD > @@ -0,0 +1 @@ > +text in fileD > diff --git a/testing/examples/attachments.org b/testing/examples/attachments.org > new file mode 100644 > index 000000000..ab4a4e548 > --- /dev/null > +++ b/testing/examples/attachments.org > @@ -0,0 +1,32 @@ > +#+TITLE: Org attach testfile > +Used to test and verify the functionality of org-attach. > + > +* H1 > + :PROPERTIES: > + :DIR: att1 > + :END: > +A link to one attachment: [[attachment:fileA]] > + > +** H1.1 > +A link to another attachment: [[attachment:fileB]] > + > +** H1.2 > + :PROPERTIES: > + :DIR: att2 > + :END: > + > +* H2 > + :PROPERTIES: > + :ID: abcd123 > + :END: > + > +* H3 > + :PROPERTIES: > + :DIR: att1 > + :ID: abcd1234 > + :END: > + > +** H3.1 > + :PROPERTIES: > + :ID: abcd12345 > + :END: > diff --git a/testing/examples/data/ab/cd123/fileE b/testing/examples/data/ab/cd123/fileE > new file mode 100644 > index 000000000..80d337772 > --- /dev/null > +++ b/testing/examples/data/ab/cd123/fileE > @@ -0,0 +1 @@ > +peek-a-boo > diff --git a/testing/lisp/test-org-attach-annex.el b/testing/lisp/test-org-attach-git.el > similarity index 93% > rename from testing/lisp/test-org-attach-annex.el > rename to testing/lisp/test-org-attach-git.el > index 7f2792696..8b826b72f 100644 > --- a/testing/lisp/test-org-attach-annex.el > +++ b/testing/lisp/test-org-attach-git.el > @@ -20,19 +20,19 @@ > > ;;; Code: > (org-test-for-executable "git-annex") > -(require 'org-attach) > +(require 'org-attach-git) > (require 'cl-lib) > > -(defmacro test-org-attach-annex/with-annex (&rest body) > +(defmacro test-org-attach-git/with-annex (&rest body) > `(let ((tmpdir (make-temp-file "org-annex-test" t "/"))) > (unwind-protect > (let ((default-directory tmpdir) > - (org-attach-directory tmpdir)) > + (org-attach-id-dir tmpdir)) > (shell-command "git init") > (shell-command "git annex init") > ,@body)))) > > -(ert-deftest test-org-attach/use-annex () > +(ert-deftest test-org-attach-git/use-annex () > (test-org-attach-annex/with-annex > (let ((org-attach-git-annex-cutoff 1)) > (should (org-attach-use-annex))) > @@ -44,12 +44,12 @@ > (let ((tmpdir (make-temp-file "org-annex-test" t "/"))) > (unwind-protect > (let ((default-directory tmpdir) > - (org-attach-directory tmpdir)) > + (org-attach-id-dir tmpdir)) > (shell-command "git init") > (should-not (org-attach-use-annex))) > (delete-directory tmpdir 'recursive)))) > > -(ert-deftest test-org-attach/get-maybe () > +(ert-deftest test-org-attach-git/get-maybe () > (test-org-attach-annex/with-annex > (let ((path (expand-file-name "test-file")) > (annex-dup (make-temp-file "org-annex-test" t "/"))) > diff --git a/testing/lisp/test-org-attach.el b/testing/lisp/test-org-attach.el > index c2f2be356..5bcfe86fd 100644 > --- a/testing/lisp/test-org-attach.el > +++ b/testing/lisp/test-org-attach.el > @@ -28,6 +28,75 @@ > (require 'org-attach) > (eval-and-compile (require 'cl-lib)) > > +(ert-deftest test-org-attach/dir () > + "Test `org-attach-get' specifications." > + (should (equal "Text in fileA\n" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 157) ;; First attachment link > + (org-open-at-point) > + (buffer-string)))) > + (should-not (equal "Text in fileB\n" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 219) ;; Second attachment link > + (let ((org-attach-use-inheritance nil)) > + (org-open-at-point) > + (buffer-string))))) > + (should (equal "Text in fileB\n" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 219) ;; Second attachment link > + (let ((org-attach-use-inheritance t)) > + (org-open-at-point) > + (buffer-string))))) > + (should-not (equal "att1" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 179) ;; H1.1 > + (let ((org-attach-use-inheritance nil)) > + (org-attach-dir))))) > + (should (equal "att1" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 179) ;; H1.1 > + (let ((org-attach-use-inheritance t)) > + (org-attach-dir))))) > + (should (equal '("fileC" "fileD") > + (org-test-in-example-file org-test-attachments-file > + (goto-char 239) ;; H1.2 > + (org-attach-file-list (org-attach-dir))))) > + (should (equal '("fileC" "fileD") > + (org-test-in-example-file org-test-attachments-file > + (goto-char 239) ;; H1.2 > + (org-attach-file-list (org-attach-dir))))) > + (should (equal '("fileE") > + (org-test-in-example-file org-test-attachments-file > + (goto-char 289) ;; H2 > + (let ((org-attach-id-dir "data/")) > + (org-attach-file-list (org-attach-dir)))))) > + (should (equal "peek-a-boo\n" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 289) ;; H2 > + (let ((org-attach-id-dir "data/")) > + (org-attach-open-in-emacs) > + (buffer-string))))) > + (should (equal '("fileA" "fileB") > + (org-test-in-example-file org-test-attachments-file > + (goto-char 336) ;; H3 > + (org-attach-file-list (org-attach-dir))))) > + (should (equal "data/ab/cd12345" > + (org-test-in-example-file org-test-attachments-file > + (goto-char 401) ;; H3.1 > + (let ((org-attach-use-inheritance nil) > + (org-attach-id-dir "data/")) > + (file-relative-name (org-attach-dir)))))) > + (should (equal '("fileA" "fileB") > + (org-test-in-example-file org-test-attachments-file > + (goto-char 401) ;; H3.1 > + (let ((org-attach-use-inheritance t)) > + ;; This is where it get's a bit sketchy...! DIR always has > + ;; priority over ID, even if ID is declared "higher up" in the > + ;; tree. This can potentially be revised. But it is also > + ;; pretty clean. DIR is always higher in priority than ID right > + ;; now, no matter the depth in the tree. > + (org-attach-file-list (org-attach-dir))))))) > + > (ert-deftest test-org-attach/dired-attach-to-next-best-subtree/1 () > "Attach file at point in dired to subtree." > (should > diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el > index d671b5c78..a618da479 100644 > --- a/testing/lisp/test-org.el > +++ b/testing/lisp/test-org.el > @@ -2514,7 +2514,11 @@ Foo Bar > (catch :result > (cl-letf (((symbol-function 'org-tags-view) > (lambda (&rest args) (throw :result t)))) > - (org-open-at-point) > + ;; When point isn't on a tag it's going to try other things, > + ;; possibly trying to open attachments which will return an > + ;; error if there isn't an attachment. Supress that error. > + (ignore-errors > + (org-open-at-point)) > nil))))) > > \f > diff --git a/testing/org-test.el b/testing/org-test.el > index 295df1919..c3e21eb30 100644 > --- a/testing/org-test.el > +++ b/testing/org-test.el > @@ -87,6 +87,9 @@ org-test searches this directory up the directory tree.") > (defconst org-test-no-heading-file > (expand-file-name "no-heading.org" org-test-example-dir)) > > +(defconst org-test-attachments-file > + (expand-file-name "attachments.org" org-test-example-dir)) > + > (defconst org-test-link-in-heading-file > (expand-file-name "link-in-heading.org" org-test-dir)) > > -- > 2.17.1 > ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-27 14:56 ` Ihor Radchenko @ 2019-07-28 20:39 ` Gustav Wikström 2019-07-28 23:20 ` Ihor Radchenko 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-07-28 20:39 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-orgmode@gnu.org, Nicolas Goaziou Hi Ihor, > -----Original Message----- > From: Ihor Radchenko <yantar92@gmail.com> > Sent: den 27 juli 2019 16:56 > To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou <mail@nicolasgoaziou.fr> > Cc: emacs-orgmode@gnu.org > Subject: Re: [O] [RFC] Link-type for attachments, more attach options > I just found that removing ATTACH_DIR_INHERIT broke my current > configuration. I do not use ATTACH_DIR property - all the attachment > folders are created using ID. Also, I use ID property to store links to > entries. Therefore, inheriting ATTACH_DIR does nothing for me and > inheriting ID always gives the current entry's id value. At the end, I > cannot make a common attachment directory for the whole subtree, like I > was able to do with ATTACH_DIR_INHERIT. Ah, yes. That is an unfortunate side effect of ID properties having other use-cases outside of attachments. I thought about that for some time during the development but didn't get to implement any solution for it. The way I thought to do it was to create an algorithm that looks through the outline hierarchy at successively lower hierarchy for an ID property that has a corresponding attachment folder. If no folder exist for the ID attribute at the given level, the inherit functionality would continue to look at a lower level until a folder was found. I imagined the algorithm to look for both ID and DIR properties at each level and stop at the first property that had an existing attachment folder, with DIR taking precedence at each level if for some reason both ID and DIR based folders existed. Adding such functionality means going outside the scope of current property inheritance in Org mode. It adds some complexity but maybe it's warranted to do so here? But, as mentioned, I only got to the point of thinking about it, I didn't implement it. If someone wants to take up the challenge of implementing it then the starting point should be to modify org-attach-dir, replacing org-entry-get with something similar to the algorithm mentioned above. I might get to it at some point as well, but my motivation lies elsewhere right now (document-level stuff... see other threads by me). Kind regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [RFC] Link-type for attachments, more attach options 2019-07-28 20:39 ` Gustav Wikström @ 2019-07-28 23:20 ` Ihor Radchenko 0 siblings, 0 replies; 113+ messages in thread From: Ihor Radchenko @ 2019-07-28 23:20 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org, Nicolas Goaziou Dear Gustav, Thanks for the update. For now, I fixed the problem for me with the following advice: #+begin_src emacs-lisp (define-advice org-attach-dir (:filter-return (dir) yant/org-attach-use-attach-dir-inheritance -100) "Use :ATTACH_DIR_INHERIT: property." (let ((attach-dir-inherited (and (org-entry-get-with-inheritance "ATTACH_DIR_INHERIT") (not (org-entry-get (point) "ATTACH_DIR_INHERIT" nil)) (org-with-point-at org-entry-property-inherited-from (org-attach-dir))))) (or attach-dir-inherited dir))) #+end_src Regards, Ihor Gustav Wikström <gustav@whil.se> writes: > Hi Ihor, > >> -----Original Message----- >> From: Ihor Radchenko <yantar92@gmail.com> >> Sent: den 27 juli 2019 16:56 >> To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou <mail@nicolasgoaziou.fr> >> Cc: emacs-orgmode@gnu.org >> Subject: Re: [O] [RFC] Link-type for attachments, more attach options > >> I just found that removing ATTACH_DIR_INHERIT broke my current >> configuration. I do not use ATTACH_DIR property - all the attachment >> folders are created using ID. Also, I use ID property to store links to >> entries. Therefore, inheriting ATTACH_DIR does nothing for me and >> inheriting ID always gives the current entry's id value. At the end, I >> cannot make a common attachment directory for the whole subtree, like I >> was able to do with ATTACH_DIR_INHERIT. > > Ah, yes. That is an unfortunate side effect of ID properties having > other use-cases outside of attachments. I thought about that for some > time during the development but didn't get to implement any solution > for it. The way I thought to do it was to create an algorithm that > looks through the outline hierarchy at successively lower hierarchy > for an ID property that has a corresponding attachment folder. If no > folder exist for the ID attribute at the given level, the inherit > functionality would continue to look at a lower level until a folder > was found. I imagined the algorithm to look for both ID and DIR > properties at each level and stop at the first property that had an > existing attachment folder, with DIR taking precedence at each level > if for some reason both ID and DIR based folders existed. > > Adding such functionality means going outside the scope of current > property inheritance in Org mode. It adds some complexity but maybe > it's warranted to do so here? But, as mentioned, I only got to the > point of thinking about it, I didn't implement it. > > If someone wants to take up the challenge of implementing it then the > starting point should be to modify org-attach-dir, replacing > org-entry-get with something similar to the algorithm mentioned above. > > I might get to it at some point as well, but my motivation lies > elsewhere right now (document-level stuff... see other threads by > me). > > Kind regards > Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (2 preceding siblings ...) 2018-11-04 22:37 ` Nicolas Goaziou @ 2019-01-04 12:21 ` Feng Shu 2019-05-26 23:15 ` Gustav Wikström 2019-12-12 5:21 ` stardiviner ` (4 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: Feng Shu @ 2019-01-04 12:21 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: I like this feature very much! > Hi, > > > > I’ve attached a patch with some suggested additions to org-attach. Patch comments below. Please review. > > > > Kind regards > > Gustav > > ___ > > Patch comments: > > * Add new linktype "attached" for attachments > > > > A new linktype "attached" is added in order to reduce link-duplication > > when wanting to link to files in attached folders of nodes. This works > > for both ID-based attachments and ATTACH_DIR. Inline images will > > trigger also for attachments, as well as search-decorations in the > > links. The goal is to make the functionality for attached-links > > mirror file-links. > > > > * Add further options for ATTACH_DIR > > > > When working with ATTACH_DIR there are now a couple of new options available: > > - org-attach-dir-inherit-by-default > > - org-attach-dir-create-if-not-exist > > - org-attach-dir-relative > > > > Descriptions of them can be found in the commit for each new customization. > > > > * Documentation in org-manual > > > > Org-manual is updated with the new link-type as well as some minor > > cleanup in the documentation related to external links and attachments. > -- ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-01-04 12:21 ` FW: " Feng Shu @ 2019-05-26 23:15 ` Gustav Wikström 0 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2019-05-26 23:15 UTC (permalink / raw) To: Feng Shu; +Cc: emacs-orgmode@gnu.org Hi Feng Shu, > -----Original Message----- > From: Feng Shu <tumashu@163.com> > Sent: den 4 januari 2019 13:22 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > I like this feature very much! I'm glad! I've just now sent an updated patch to the mailing-list. It contains quite substantial changes. Maybe you care to review it as well? Best Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (3 preceding siblings ...) 2019-01-04 12:21 ` FW: " Feng Shu @ 2019-12-12 5:21 ` stardiviner 2019-12-12 6:12 ` Gustav Wikström 2019-12-16 11:21 ` stardiviner ` (3 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-12 5:21 UTC (permalink / raw) To: emacs-orgmode Hi Gustav, I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will auto in completion list. It will be convenient for user. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-12 5:21 ` stardiviner @ 2019-12-12 6:12 ` Gustav Wikström 2019-12-12 9:52 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-12-12 6:12 UTC (permalink / raw) To: numbchild@gmail.com, emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 998 bytes --] Hi stardiviner, It is my belief that =[Ctrl-C Ctrl-l]= already is supported. You will only get suggestions for attachments if there are any attachments on the outline node you're in. Or in any of its parents if inheritance is configured. Regards Gustav ________________________________ From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com> Sent: Thursday, December 12, 2019 6:21:30 AM To: emacs-orgmode@gnu.org <emacs-orgmode@gnu.org> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options Hi Gustav, I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will auto in completion list. It will be convenient for user. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 [-- Attachment #2: Type: text/html, Size: 2135 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-12 6:12 ` Gustav Wikström @ 2019-12-12 9:52 ` stardiviner 2019-12-12 19:42 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-12 9:52 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi stardiviner, > > It is my belief that =[Ctrl-C Ctrl-l]= already is supported. You will only get suggestions for attachments if there are any attachments on the outline node you're in. Or in any of its parents if inheritance is configured. > For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c Ctrl-l]= (~org-insert-link~) to insert link which will show a list of completions which are all link types prefix like ~attachment:~, and =file:data/a2/..../attachFile.png=. I mean the second link. it is already in completion list, but ~attchment:~ does not have this support. > Regards Gustav > ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com> > Sent: Thursday, December 12, 2019 6:21:30 AM > To: emacs-orgmode@gnu.org <emacs-orgmode@gnu.org> > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > > Hi Gustav, > > I suggest to add support for =[Ctrl-C Ctrl-l]= like ~file:~ link type. which will > auto in completion list. It will be convenient for user. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2019-12-12 9:52 ` stardiviner @ 2019-12-12 19:42 ` Gustav Wikström 2019-12-13 13:38 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-12-12 19:42 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 12 december 2019 10:53 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > ... > > For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c > Ctrl-l]= (~org-insert-link~) to insert link which will show a list of > completions > which are all link types prefix like ~attachment:~, and > =file:data/a2/..../attachFile.png=. I mean the second link. it is already in > completion list, but ~attchment:~ does not have this support. Hmm, I'm not sure I follow. Is it in the same suggestion list for link type prefixes that you also get the file-link to the newly attached file? I tried to reproduce that using emacs -q just now but couldn't... Is there a customization that you've enabled? Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-12 19:42 ` Gustav Wikström @ 2019-12-13 13:38 ` stardiviner 2019-12-13 21:37 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-13 13:38 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: stardiviner <numbchild@gmail.com> >> Sent: den 12 december 2019 10:53 >> To: Gustav Wikström <gustav@whil.se> >> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> ... >> >> For example, I press =[Ctrl-c Ctrl-a]= to attach a file. Then I press =[Ctrl-c >> Ctrl-l]= (~org-insert-link~) to insert link which will show a list of >> completions >> which are all link types prefix like ~attachment:~, and >> =file:data/a2/..../attachFile.png=. I mean the second link. it is already in >> completion list, but ~attchment:~ does not have this support. > > Hmm, I'm not sure I follow. Is it in the same suggestion list for link type prefixes > that you also get the file-link to the newly attached file? Yes. > I tried to reproduce that using emacs -q just now but couldn't... Is there a > customization that you've enabled? Aha, seems yes. I checked my config. I have option enabled: #+begin_src emacs-lisp (setq org-attach-store-link-p 'attached) #+end_src About this feature, WDYT? > > Regards > Gustav -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2019-12-13 13:38 ` stardiviner @ 2019-12-13 21:37 ` Gustav Wikström 2019-12-13 22:15 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-12-13 21:37 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 13 december 2019 14:39 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > ... > > I tried to reproduce that using emacs -q just now but couldn't... Is there a > > customization that you've enabled? > > Aha, seems yes. I checked my config. I have option enabled: > > #+begin_src emacs-lisp > (setq org-attach-store-link-p 'attached) > #+end_src > > About this feature, WDYT? Ah, yes of course. What you propose make sense. More sense than the current functionality! If no one objects I'll change the link that is stored for the 'attached option to be an attachment link instead of a file link. Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2019-12-13 21:37 ` Gustav Wikström @ 2019-12-13 22:15 ` Gustav Wikström 2019-12-15 4:14 ` stardiviner 2019-12-15 9:29 ` stardiviner 0 siblings, 2 replies; 113+ messages in thread From: Gustav Wikström @ 2019-12-13 22:15 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org FYI, pushed to master. Commit 26ace9004 /Gustav > -----Original Message----- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On Behalf > Of Gustav Wikström > Sent: den 13 december 2019 22:37 > To: numbchild@gmail.com > Cc: emacs-orgmode@gnu.org > Subject: RE: [O] FW: [RFC] Link-type for attachments, more attach options > > Hi, > > > -----Original Message----- > > From: stardiviner <numbchild@gmail.com> > > Sent: den 13 december 2019 14:39 > > To: Gustav Wikström <gustav@whil.se> > > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > > > ... > > > I tried to reproduce that using emacs -q just now but couldn't... Is there > a > > > customization that you've enabled? > > > > Aha, seems yes. I checked my config. I have option enabled: > > > > #+begin_src emacs-lisp > > (setq org-attach-store-link-p 'attached) > > #+end_src > > > > About this feature, WDYT? > > Ah, yes of course. What you propose make sense. More sense than the current > functionality! > > If no one objects I'll change the link that is stored for the 'attached option > to be an > attachment link instead of a file link. > > Regards > Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-13 22:15 ` Gustav Wikström @ 2019-12-15 4:14 ` stardiviner 2019-12-15 9:29 ` stardiviner 1 sibling, 0 replies; 113+ messages in thread From: stardiviner @ 2019-12-15 4:14 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > FYI, pushed to master. Commit 26ace9004 Thanks -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-13 22:15 ` Gustav Wikström 2019-12-15 4:14 ` stardiviner @ 2019-12-15 9:29 ` stardiviner 2019-12-15 10:06 ` Gustav Wikström 1 sibling, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-15 9:29 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > FYI, pushed to master. Commit 26ace9004 > After update, I found the new attachment link type can't display inline image now. Maybe should keep *both* original ~file:~ link type and new ~attachment:~ link type in stored link? WDYT, Gustav? -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2019-12-15 9:29 ` stardiviner @ 2019-12-15 10:06 ` Gustav Wikström 2019-12-15 14:26 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-12-15 10:06 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hmm, inline images work for attachment links on my side on Org mode master. I considered keeping the file link option but ruled against it in the end. I could remove some complexity from the code in the end due to it. Don't know why attachments aren’t expanded as images for you... /G > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 15 december 2019 10:29 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > > Gustav Wikström <gustav@whil.se> writes: > > > FYI, pushed to master. Commit 26ace9004 > > > > After update, I found the new attachment link type can't display inline > image now. Maybe should keep *both* original ~file:~ link type and new > ~attachment:~ link type in stored link? WDYT, Gustav? > > -- > [ stardiviner ] > I try to make every word tell the meaning what I want to express. > > Blog: https://stardiviner.github.io/ > IRC(freenode): stardiviner, Matrix: stardiviner > GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 > ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-15 10:06 ` Gustav Wikström @ 2019-12-15 14:26 ` stardiviner 2019-12-15 20:41 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-15 14:26 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hmm, inline images work for attachment links on my side on Org mode master. > > I considered keeping the file link option but ruled against it in the end. I could remove some complexity from the code in the end due to it. > > Don't know why attachments aren’t expanded as images for you... > I figured out why on my side inline image does not work. When have link with description, the inline image does not work. When has no link description, inline image works. Here is an example: #+begin_src org # link work for inline image [[attachment:screenshot.png]] # inline image does not work [[attachment:screenshot.png][description]] #+end_src I tested by EMC, found this is caused by some option. I will figure it out. Thanks! -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2019-12-15 14:26 ` stardiviner @ 2019-12-15 20:41 ` Gustav Wikström 2019-12-16 3:38 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2019-12-15 20:41 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org > -----Original Message----- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On > Behalf Of stardiviner > Sent: den 15 december 2019 15:26 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > ... > > I figured out why on my side inline image does not work. > > When have link with description, the inline image does not work. When has > no link description, inline image works. > > Here is an example: > > #+begin_src org > # link work for inline image > [[attachment:screenshot.png]] > > # inline image does not work > [[attachment:screenshot.png][description]] > #+end_src > > I tested by EMC, found this is caused by some option. I will figure it > out. Thanks! FWIW, I see the same behavior as you do when I add descriptions. The same seems to apply for file-links. I haven't looked it up to see if that's intended though. Just wanted to share how it works for me, if you're scratching you're head over this! Actually... Not wanting to push the "Send" button without looking into the manual, I found the following in the "Images" section: "An image is a link to an image file(1) that does not have a description part" See [[info:org#Images]] Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-15 20:41 ` Gustav Wikström @ 2019-12-16 3:38 ` stardiviner 0 siblings, 0 replies; 113+ messages in thread From: stardiviner @ 2019-12-16 3:38 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: >> -----Original Message----- >> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On >> Behalf Of stardiviner >> Sent: den 15 december 2019 15:26 >> To: Gustav Wikström <gustav@whil.se> >> Cc: emacs-orgmode@gnu.org >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> ... >> >> I figured out why on my side inline image does not work. >> >> When have link with description, the inline image does not work. When has >> no link description, inline image works. >> >> Here is an example: >> >> #+begin_src org >> # link work for inline image >> [[attachment:screenshot.png]] >> >> # inline image does not work >> [[attachment:screenshot.png][description]] >> #+end_src >> >> I tested by EMC, found this is caused by some option. I will figure it >> out. Thanks! > > FWIW, I see the same behavior as you do when I add descriptions. The same seems to > apply for file-links. I haven't looked it up to see if that's intended though. Just > wanted to share how it works for me, if you're scratching you're head over this! > > Actually... Not wanting to push the "Send" button without looking into the manual, I > found the following in the "Images" section: > > "An image is a link to an image file(1) that does not have a description part" > > See [[info:org#Images]] > > Regards > Gustav I read Org Info manual before, forgot most things, just put memory into usual behavior now..... I will read Org Info manual again. :) glade you figure out my wrong point, thanks. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (4 preceding siblings ...) 2019-12-12 5:21 ` stardiviner @ 2019-12-16 11:21 ` stardiviner 2019-12-17 4:27 ` stardiviner 2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner ` (2 subsequent siblings) 8 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2019-12-16 11:21 UTC (permalink / raw) To: emacs-orgmode I found another problem, =[C-c C-a d]= does not give out delete available attachment files. Maybe other places is affected, suggest you check out other places. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2019-12-16 11:21 ` stardiviner @ 2019-12-17 4:27 ` stardiviner 0 siblings, 0 replies; 113+ messages in thread From: stardiviner @ 2019-12-17 4:27 UTC (permalink / raw) To: emacs-orgmode stardiviner <numbchild@gmail.com> writes: > I found another problem, =[C-c C-a d]= does not give out delete available > attachment files. Maybe other places is affected, suggest you check out other > places. Ehh, sorry, today I found I can use this again. Weird that yesterday I got nothing. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (5 preceding siblings ...) 2019-12-16 11:21 ` stardiviner @ 2020-01-13 12:24 ` stardiviner 2020-01-14 3:27 ` Gustav Wikström 2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner 2020-01-17 7:39 ` Missing `org-attach-set-inherit' function stardiviner 8 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-13 12:24 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 1050 bytes --] When I export with =[C-c C-e h o]=, I found attached inline image links are not displayed in HTML page. Here is Org content: #+begin_src org ,****** Strings are not Lists, but Anyway… :PROPERTIES: :ID: 2fd354f3-ac7a-499d-9fe4-a76626bbdb38 :END: In Calva Paredit, strings are treated in much the same way as lists are. Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow Selection. [[attachment:string-as-list.gif]] #+end_src The email attachment contains the screenshot of HTML page. I used Edebug on functions, track down to the error function ~(org-attach-dir)~, it returns ~nil~ when in exporting to HTML, but when I evaluate ~(org-attach-dir)~ interactively under the headline, it works correctly. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 [-- Attachment #2: screenshot --] [-- Type: image/png, Size: 96983 bytes --] ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner @ 2020-01-14 3:27 ` Gustav Wikström 2020-01-14 5:04 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-14 3:27 UTC (permalink / raw) To: emacs-orgmode@gnu.org, numbchild@gmail.com Hi! Thanks for reporting this! The code is updated on the master branch to make the exporters aware of how to deal with attachment links. Commit d70db54db for the curious. Basically, attachment links are expanded into file-links by the exporters now, before further processing into links in the respective markup language. Regards Gustav ________________________________________ From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> on behalf of stardiviner <numbchild@gmail.com> Sent: Monday, January 13, 2020 13:24 To: emacs-orgmode@gnu.org Subject: Re: attachment: link type export to HTML invalid attach dir When I export with =[C-c C-e h o]=, I found attached inline image links are not displayed in HTML page. Here is Org content: #+begin_src org ,****** Strings are not Lists, but Anyway… :PROPERTIES: :ID: 2fd354f3-ac7a-499d-9fe4-a76626bbdb38 :END: In Calva Paredit, strings are treated in much the same way as lists are. Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow Selection. [[attachment:string-as-list.gif]] #+end_src The email attachment contains the screenshot of HTML page. I used Edebug on functions, track down to the error function ~(org-attach-dir)~, it returns ~nil~ when in exporting to HTML, but when I evaluate ~(org-attach-dir)~ interactively under the headline, it works correctly. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-14 3:27 ` Gustav Wikström @ 2020-01-14 5:04 ` stardiviner 2020-01-14 20:58 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-14 5:04 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi! > > Thanks for reporting this! > > The code is updated on the master branch to make the exporters aware of how to deal with attachment links. Commit d70db54db for the curious. Basically, attachment links are expanded into file-links by the exporters now, before further processing into links in the respective markup language. > > Regards > Gustav Many thanks for really quick patching. I tested out the new patch, still does not work. #+begin_src org ,****** Strings are not Lists, but Anyway… :PROPERTIES: :ID: 2fd354f3-ac7a-499d-9fe4-a76626bbdb38 :END: In Calva Paredit, strings are treated in much the same way as lists are. Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow Selection. [[attachment:string-as-list.gif]] #+end_src The upper org content is exported as this (HTML page): #+begin_example Strings are not Lists, but Anyway… In Calva Paredit, strings are treated in much the same way as lists are. Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow Selection. file:///home/stardiviner/Org/Wiki/Computer Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif #+end_example You can see: 1. the link still does not contains the attach directory from ~(org-attach-dir)~. 2. image links are not exported as inline image displayed with ~<img src="...">~. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-14 5:04 ` stardiviner @ 2020-01-14 20:58 ` Gustav Wikström 2020-01-15 5:53 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-14 20:58 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi again, > -----Original Message----- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On > Behalf Of stardiviner > Sent: den 14 januari 2020 06:04 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > [...] > > Many thanks for really quick patching. > > I tested out the new patch, still does not work. > > #+begin_src org > ,****** Strings are not Lists, but Anyway… > :PROPERTIES: > :ID: 2fd354f3-ac7a-499d-9fe4-a76626bbdb38 > :END: > > In Calva Paredit, strings are treated in much the same way as lists are. > Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow > Selection. > > [[attachment:string-as-list.gif]] > > #+end_src > > The upper org content is exported as this (HTML page): > > #+begin_example > Strings are not Lists, but Anyway… > > In Calva Paredit, strings are treated in much the same way as lists are. > Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow > Selection. > > file:///home/stardiviner/Org/Wiki/Computer > Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif > #+end_example > > You can see: > > 1. the link still does not contains the attach directory from ~(org- > attach-dir)~. > 2. image links are not exported as inline image displayed with ~<img > src="...">~. Ah, you're right. I missed a few things. Should be fixed now in master. Care to verify from your end again? Thanks Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-14 20:58 ` Gustav Wikström @ 2020-01-15 5:53 ` stardiviner 2020-01-15 19:48 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-15 5:53 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi again, > >> -----Original Message----- >> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On >> Behalf Of stardiviner >> Sent: den 14 januari 2020 06:04 >> To: Gustav Wikström <gustav@whil.se> >> Cc: emacs-orgmode@gnu.org >> Subject: Re: attachment: link type export to HTML invalid attach dir >> >> [...] >> >> Many thanks for really quick patching. >> >> I tested out the new patch, still does not work. >> >> #+begin_src org >> ,****** Strings are not Lists, but Anyway… >> :PROPERTIES: >> :ID: 2fd354f3-ac7a-499d-9fe4-a76626bbdb38 >> :END: >> >> In Calva Paredit, strings are treated in much the same way as lists are. >> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow >> Selection. >> >> [[attachment:string-as-list.gif]] >> >> #+end_src >> >> The upper org content is exported as this (HTML page): >> >> #+begin_example >> Strings are not Lists, but Anyway… >> >> In Calva Paredit, strings are treated in much the same way as lists are. >> Here’s an example showing Slurp and Barf, Forward/Backward List, and Grow >> Selection. >> >> file:///home/stardiviner/Org/Wiki/Computer >> Technology/Programming/Emacs/Data/Emacs Packages/string-as-list.gif >> #+end_example >> >> You can see: >> >> 1. the link still does not contains the attach directory from ~(org- >> attach-dir)~. >> 2. image links are not exported as inline image displayed with ~<img >> src="...">~. > > Ah, you're right. I missed a few things. Should be fixed now in master. Care to verify from your end again? > > Thanks > Gustav I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved. But the ~(org-attach-dir)~ still not work. The exported ~<img src="">~ inline image still does not contains the attach directory. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-15 5:53 ` stardiviner @ 2020-01-15 19:48 ` Gustav Wikström 2020-01-16 11:06 ` stardiviner 2020-01-16 13:18 ` Nicolas Goaziou 0 siblings, 2 replies; 113+ messages in thread From: Gustav Wikström @ 2020-01-15 19:48 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 15 januari 2020 06:53 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > [...] > > I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved. > But the ~(org-attach-dir)~ still not work. The exported ~<img src="">~ > inline image still does not contains the attach directory. Ah yes. Found the culprit for this issue. Hopefully the last one. The exporter doesn't actually move the point in the buffer during the export. So org-attach-expand tried to expand from the first character in the buffer. This should be fixed from a few minutes ago. Crossing fingers for this to work properly now! Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-15 19:48 ` Gustav Wikström @ 2020-01-16 11:06 ` stardiviner 2020-01-16 13:18 ` Nicolas Goaziou 1 sibling, 0 replies; 113+ messages in thread From: stardiviner @ 2020-01-16 11:06 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: stardiviner <numbchild@gmail.com> >> Sent: den 15 januari 2020 06:53 >> To: Gustav Wikström <gustav@whil.se> >> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >> Subject: Re: attachment: link type export to HTML invalid attach dir >> >> [...] >> >> I checked out the latest commit "0ac6a9e1f", The ~<img>~ tag is solved. >> But the ~(org-attach-dir)~ still not work. The exported ~<img src="">~ >> inline image still does not contains the attach directory. > > Ah yes. Found the culprit for this issue. Hopefully the last one. The exporter doesn't actually move the point in the buffer during the export. So org-attach-expand tried to expand from the first character in the buffer. This should be fixed from a few minutes ago. Aha, wow!!! thanks for great patch. It worked now. Thanks really. :) > > Crossing fingers for this to work properly now! > > Regards > Gustav > -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-15 19:48 ` Gustav Wikström 2020-01-16 11:06 ` stardiviner @ 2020-01-16 13:18 ` Nicolas Goaziou 2020-01-16 21:42 ` Gustav Wikström 1 sibling, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-01-16 13:18 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Ah yes. Found the culprit for this issue. Hopefully the last one. The > exporter doesn't actually move the point in the buffer during the > export. So org-attach-expand tried to expand from the first character > in the buffer. This should be fixed from a few minutes ago. I'm not sure hard-coding attachment links in exporters in the best way forward. For example, exporters in the wild may not cope with them before a long time, if ever. There is some code duplication, too. If attachments links are similar to file links from an export point of view, then I suggest to add a phase in ox.el to expand the former into the latter, before even using export back-ends. This way, there is no change required in the exporters, shipped in or not. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-16 13:18 ` Nicolas Goaziou @ 2020-01-16 21:42 ` Gustav Wikström 2020-01-16 23:07 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-16 21:42 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi Nicolas, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 16 januari 2020 14:18 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > Ah yes. Found the culprit for this issue. Hopefully the last one. The > > exporter doesn't actually move the point in the buffer during the > > export. So org-attach-expand tried to expand from the first character > > in the buffer. This should be fixed from a few minutes ago. > > I'm not sure hard-coding attachment links in exporters in the best way > forward. For example, exporters in the wild may not cope with them before > a long time, if ever. There is some code duplication, too. Yes indeed, duplicated functionality for all export backends as it stands. > > If attachments links are similar to file links from an export point of > view, then I suggest to add a phase in ox.el to expand the former into the > latter, before even using export back-ends. This way, there is no change > required in the exporters, shipped in or not. Yeah, I do think attachment links should be treated as file links when exported. And I like this suggestion, although that means I probably have to dig into the ox.el code. Not an easy task. I suspect you'd guide me to adding logic inside org-export-as for this. I'll have a look starting from there. But wouldn't mind some further insights here! Regards Gustav > > Regards, > > -- > Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-16 21:42 ` Gustav Wikström @ 2020-01-16 23:07 ` Gustav Wikström 2020-01-17 0:39 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-16 23:07 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi again, > -----Original Message----- > From: Gustav Wikström > Sent: den 16 januari 2020 22:42 > To: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: RE: attachment: link type export to HTML invalid attach dir > > Hi Nicolas, > > > -----Original Message----- > > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > > Sent: den 16 januari 2020 14:18 > > To: Gustav Wikström <gustav@whil.se> > > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > > Subject: Re: attachment: link type export to HTML invalid attach dir > > > > Hello, > > > > Gustav Wikström <gustav@whil.se> writes: > > > > > Ah yes. Found the culprit for this issue. Hopefully the last one. > > > The exporter doesn't actually move the point in the buffer during > > > the export. So org-attach-expand tried to expand from the first > > > character in the buffer. This should be fixed from a few minutes ago. > > > > I'm not sure hard-coding attachment links in exporters in the best way > > forward. For example, exporters in the wild may not cope with them > > before a long time, if ever. There is some code duplication, too. > > Yes indeed, duplicated functionality for all export backends as it stands. > > > > > If attachments links are similar to file links from an export point of > > view, then I suggest to add a phase in ox.el to expand the former into > > the latter, before even using export back-ends. This way, there is no > > change required in the exporters, shipped in or not. > > Yeah, I do think attachment links should be treated as file links when > exported. And I like this suggestion, although that means I probably have > to dig into the ox.el code. Not an easy task. I suspect you'd guide me to > adding logic inside org-export-as for this. I'll have a look starting from > there. But wouldn't mind some further insights here! After thinking a while I'm leaning towards thinking this should be handled already in the element link parser and interpreter. Need a bit more metadata for that though, to be able to deconstruct and reconstruct the link properly while still providing the correct paths. Hardcoding the translation of attachment-links into file-links in an in-between layer (ox.el - that is somewhat complicated as well) is not transparent and I think best to avoid. Even if an attachment link is /very/ similar to a file link it may be best still to treat them for what they are. If some export back-ends out in the wild don't work with attachment-links today then so be it. But let's at least make it easy to fix! So I'll try to remove the hard coding of org-attach invocation and instead make the attachment-path when parsed by org-element return a path that is an actual file-system path out of the box. I'll see what I figure out in terms of code I suppose...! What do you say? > > Regards > Gustav > > > > > Regards, > > > > -- > > Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-16 23:07 ` Gustav Wikström @ 2020-01-17 0:39 ` Nicolas Goaziou 2020-01-17 14:29 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-01-17 0:39 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hardcoding the translation of attachment-links into file-links in an > in-between layer (ox.el - that is somewhat complicated as well) is not > transparent and I think best to avoid. Even if an attachment link is > /very/ similar to a file link it may be best still to treat them for > what they are. If some export back-ends out in the wild don't work > with attachment-links today then so be it. But let's at least make it > easy to fix! So I'll try to remove the hard coding of org-attach > invocation and instead make the attachment-path when parsed by > org-element return a path that is an actual file-system path out of > the box. I'll see what I figure out in terms of code I suppose...! > > What do you say? It is true that Element library expands link abbreviations right before parsing a link, and an attachment is similar to a local link abbreviation. This is not great because some information is lost in the process: interpreting the parse tree will not bring the abbreviation back, only its expanded form. Actually, `org-link-expand-abbrev' is called so that the parser knows what is the true type of the link, since abbreviations could expand to anything. OTOH, attachments can only expand to a "file" link, so the motivation for expansion doesn't hold. Besides, there's no good reason to store redundant, or even remote, information in the parse tree. The parser needs to be as low level as possible. Moreover, the issue encountered here is specific to export, so it makes sense to solve at the export level, i.e., in "ox.el". This is not trivial though, as it needs to be done very early, much link footnotes. Indeed, since the meaning of the link is position dependent, including parts of a document, or executing arbitrary code can mess it up. IOW expansion should happen in `org-export--prepare-file-contents', i.e., within every included piece of text, and in `org-export-as', somewhere after `org-export-expand-include-keyword' call, but before Babel code execution. HTH, Regards, ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-17 0:39 ` Nicolas Goaziou @ 2020-01-17 14:29 ` Gustav Wikström 2020-01-17 18:36 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-17 14:29 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 17 januari 2020 01:40 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > > Hardcoding the translation of attachment-links into file-links in an > > in-between layer (ox.el - that is somewhat complicated as well) is not > > transparent and I think best to avoid. Even if an attachment link is > > /very/ similar to a file link it may be best still to treat them for > > what they are. If some export back-ends out in the wild don't work > > with attachment-links today then so be it. But let's at least make it > > easy to fix! So I'll try to remove the hard coding of org-attach > > invocation and instead make the attachment-path when parsed by > > org-element return a path that is an actual file-system path out of > > the box. I'll see what I figure out in terms of code I suppose...! > > > > What do you say? > > It is true that Element library expands link abbreviations right before > parsing a link, and an attachment is similar to a local link abbreviation. > This is not great because some information is lost in the > process: interpreting the parse tree will not bring the abbreviation back, > only its expanded form. Actually, `org-link-expand-abbrev' is called so > that the parser knows what is the true type of the link, since > abbreviations could expand to anything. OTOH, attachments can only expand > to a "file" link, so the motivation for expansion doesn't hold. Hmm, interesting... And are we sure the destructive behavior is something we want to maintain? I for one would vote for the parsers ability to provide information that can reconstruct the source... Is it really worth the space saving in the parse tree to do that destruction? I feel inclined here to add a :link and :raw-path property to the output from the link parser for example. That would allow those links that expand to be stored in the parse tree in both expanded and non-expanded form. Reasons against? > Besides, there's no good reason to store redundant, or even remote, > information in the parse tree. The parser needs to be as low level as > possible. Yes, this is a reason against... But big enough? I humbly question that a bit. Also, would it be feasible to store the original "raw" form only if it differs from the expanded form? It may complicate the interpreters work though... They would have to have a bit more insight into when the original form will be needed. Not sure of the better design decision here. > Moreover, the issue encountered here is specific to export, so it makes > sense to solve at the export level, i.e., in "ox.el". This is not trivial > though, as it needs to be done very early, much link footnotes. > Indeed, since the meaning of the link is position dependent, including > parts of a document, or executing arbitrary code can mess it up. IOW > expansion should happen in `org-export--prepare-file-contents', i.e., > within every included piece of text, and in `org-export-as', somewhere > after `org-export-expand-include-keyword' call, but before Babel code > execution. It's actually not only specific to exporting. Opening attachment links show a similar issue (org-link-open). Because the current way to open files and attachments differ. And it shouldn't have to! That as well would be solved if the link parser would take care of the path expansion. One example of the difference today is that attachment links cannot abide to any prefix argument. As a user I would expect the prefix arguments that work for files to also work for attachments. Something I think we can fix here, by making the parser do a little bit more work. I'd be happy to apply a patch. Kind regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-17 14:29 ` Gustav Wikström @ 2020-01-17 18:36 ` Gustav Wikström 2020-01-18 1:13 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-17 18:36 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi again, > -----Original Message----- > From: Gustav Wikström > Sent: den 17 januari 2020 15:30 > To: 'Nicolas Goaziou' <mail@nicolasgoaziou.fr> > Cc: emacs-orgmode@gnu.org > Subject: RE: attachment: link type export to HTML invalid attach dir > > Hi, > > [...] > > > > > It is true that Element library expands link abbreviations right > > before parsing a link, and an attachment is similar to a local link > abbreviation. > > This is not great because some information is lost in the > > process: interpreting the parse tree will not bring the abbreviation > > back, only its expanded form. Actually, `org-link-expand-abbrev' is > > called so that the parser knows what is the true type of the link, > > since abbreviations could expand to anything. OTOH, attachments can > > only expand to a "file" link, so the motivation for expansion doesn't > hold. > > Hmm, interesting... And are we sure the destructive behavior is something > we want to maintain? I for one would vote for the parsers ability to > provide information that can reconstruct the source... Is it really worth > the space saving in the parse tree to do that destruction? I feel inclined > here to add a :link and :raw-path property to the output from the link > parser for example. That would allow those links that expand to be stored > in the parse tree in both expanded and non-expanded form. > > Reasons against? Hmm, I'm actually kind of going full circle here, back to think that the logic currently implemented is in its right place... Either that, or to just decorate the link in the parse-tree with some auxiliary information that can be specific for the type of link. For attachment links that auxiliary information would be attachment-path-prefix (or something shorter but possibly less clear). For abbreviated links possibly the auxiliary information would be it's unexpanded form. But I'm not sure of the necessity or need for that, except from allowing interpreters to reconstruct the original link. > > [...] > Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-17 18:36 ` Gustav Wikström @ 2020-01-18 1:13 ` Gustav Wikström 2020-01-18 11:34 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-18 1:13 UTC (permalink / raw) To: Nicolas Goaziou, emacs-orgmode@gnu.org Ok, so change pushed... Where org-element-link-parser now sets one extra property only for attachment links. The exporters and org-link-open use this additional information when exporting and opening attachment links. Feature parity with file links should now be complete. Note that exporters outside of the Org mode repo need to be aware of the attachment link type if the path expansion is to be correct. They aren't translated in between into file-links. Not doing that translation is the proper think in my opinion. No magic hiding of the attachment link type. Who knows - maybe some exporters in the future need the link as is, without expansion!?. Making an exporter in the wild aware of attachment links can be done using org-element-property and the new property :attachment-path created by the parser only for attachment links. Regards Gustav > -----Original Message----- > From: Gustav Wikström > Sent: den 17 januari 2020 19:36 > To: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Cc: emacs-orgmode@gnu.org > Subject: RE: attachment: link type export to HTML invalid attach dir > > Hi again, > > > -----Original Message----- > > From: Gustav Wikström > > Sent: den 17 januari 2020 15:30 > > To: 'Nicolas Goaziou' <mail@nicolasgoaziou.fr> > > Cc: emacs-orgmode@gnu.org > > Subject: RE: attachment: link type export to HTML invalid attach dir > > > > Hi, > > > > [...] > > > > > > > > It is true that Element library expands link abbreviations right > > > before parsing a link, and an attachment is similar to a local link > > abbreviation. > > > This is not great because some information is lost in the > > > process: interpreting the parse tree will not bring the abbreviation > > > back, only its expanded form. Actually, `org-link-expand-abbrev' is > > > called so that the parser knows what is the true type of the link, > > > since abbreviations could expand to anything. OTOH, attachments can > > > only expand to a "file" link, so the motivation for expansion > > > doesn't > > hold. > > > > Hmm, interesting... And are we sure the destructive behavior is > > something we want to maintain? I for one would vote for the parsers > > ability to provide information that can reconstruct the source... Is > > it really worth the space saving in the parse tree to do that > > destruction? I feel inclined here to add a :link and :raw-path > > property to the output from the link parser for example. That would > > allow those links that expand to be stored in the parse tree in both > expanded and non-expanded form. > > > > Reasons against? > > Hmm, I'm actually kind of going full circle here, back to think that the > logic currently implemented is in its right place... Either that, or to > just decorate the link in the parse-tree with some auxiliary information > that can be specific for the type of link. For attachment links that > auxiliary information would be attachment-path-prefix (or something > shorter but possibly less clear). For abbreviated links possibly the > auxiliary information would be it's unexpanded form. But I'm not sure of > the necessity or need for that, except from allowing interpreters to > reconstruct the original link. > > > > > [...] > > > > Regards > Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-18 1:13 ` Gustav Wikström @ 2020-01-18 11:34 ` Nicolas Goaziou 2020-01-18 15:14 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-01-18 11:34 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Ok, so change pushed... I'm sorry, but this is going too fast. We're discussing core design here (the parser), and I couldn't even answer your proposal. Let's at least reach an agreement on the change to make. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-18 11:34 ` Nicolas Goaziou @ 2020-01-18 15:14 ` Gustav Wikström 2020-01-19 21:12 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-18 15:14 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 18 januari 2020 12:34 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > Ok, so change pushed... > > I'm sorry, but this is going too fast. We're discussing core design here > (the parser), and I couldn't even answer your proposal. Let's at least > reach an agreement on the change to make. Yes, agreed, it was a bit fast. The final changes was done to not stop "in the middle" so to say, with something both you and me think is suboptimal. Functionally it's in a good (and maintainable) state right now, in my opinion. But I do understand that the contextual attribute added to the parser may require some discussion. If the decision is to not allow contextual attributes in the parser I'm prepared to revert and change again. No stress though. Just to add a note about the trail of my thoughts regarding this... And why I thought the contextual attribute was a good option here: I argue that the attachment folder is a part of the attachment link, even though the information is found at a different location in the document (i.e. as a property to nodes in the document hierarchy). Parsing an attachment link would then be incomplete if that information is discarded. One option to adding an attribute could be to modify existing properties by adding the attachment folder to, for example, the path property. But that means to remove information about what was written as path in the original link. So I argue to keep path as the original path. But that means extra information is needed to also make it work in the filesystem. If we would translate an attachment link to a file link in ox.el that means we remove the option for exporters to decide for themselves what to do with the link. And I think the exporter should have that option. :) Right now the ASCII exporter for example outputs attachment links as attachment:expanded_path instead of file:expanded_path. Since the link type actually is attachment. And for a solemnly textual export the exported information should be kept as close to source as possible. So either we explicitly and always say attachment-links *are* file-links in disguise (i.e. even change type in the parser), or we don't say that, and then don't say that all the way to the edge of the system. And let the uses of the link type decide themselves what to do. Which is what I propose. But with the addition of a bit of extra information contextual for the attachment links. Whoops long paragraph, sorry... I'm just trying to explain my current way of looking at this. Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-18 15:14 ` Gustav Wikström @ 2020-01-19 21:12 ` Nicolas Goaziou 2020-01-19 23:29 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-01-19 21:12 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Functionally it's in a good (and maintainable) state right now, in my > opinion. But I do understand that the contextual attribute added to > the parser may require some discussion. This is not my main gripe here, although I'm not convinced that extra attribute is warranted. My concern is that you hard-code "attachment" type in the parser. I don't think this is the correct way to handle the situation. Some link types specifically handle files, e.g., "docview", yet do not need a special treatment in the parser. Note that "file" links have a good reason to be treated specially there, besides their obvious importance, as their type can be omitted. E.g., [[~/file.org]]. OTOH, I see no strong reason to handle "attachments" in here, since they behave like any other link type. Worse, the parser is more or less the definition of the Org syntax. Therefore, including "attachment" in the parser is a signal meaning that in order to fully implement Org syntax, e.g., in another language, one need to support attachment links. Attachment links are undoubtedly useful, but they are not core, at all. So, I feel uneasy about leaking that type of link in the Element library. Also, you sometimes seem to blur, on purpose, the difference between "attachment" and "file" links. If there should be no difference of treatment between them, as I already suggested, you may want to consider "attachment" as some functional link abbreviation. Then the "attachment" type doesn't really exist, much like the "bugzilla" link type from the manual. In any case, we need a proper definition, a proper category too, for "attachment" links. Meanwhile, modifying the parser is just grasping at straws. > I argue that the attachment folder is a part of the attachment link, > even though the information is found at a different location in the > document (i.e. as a property to nodes in the document hierarchy). > Parsing an attachment link would then be incomplete if that > information is discarded. I argue that the buffer position of the attachment link and the path as written in the link are enough to fully expand the attachment file name. If I'm wrong, which could be, I probably didn't invest enough time in the Attach changes, then having the expanded form in :path and the initial form in :raw-path is enough. > One option to adding an attribute could be to modify existing > properties by adding the attachment folder to, for example, the path > property. But that means to remove information about what was written > as path in the original link. There is :raw-path for that purpose. > So I argue to keep path as the original path. But that means extra > information is needed to also make it work in the filesystem. If we > would translate an attachment link to a file link in ox.el that means > we remove the option for exporters to decide for themselves what to do > with the link. And I think the exporter should have that option. :) Let's first think about what category of object an attachment link belongs to. Then we can discuss about how to export it. Again, if "attachment" == "file", the exporters shouldn't treat them differently. If "attachment" is a new link type, it should define its own rules in its own library, namely "org-attach.el". > Right now the ASCII exporter for example outputs attachment links as > attachment:expanded_path instead of file:expanded_path. Since the link > type actually is attachment. And for a solemnly textual export the > exported information should be kept as close to source as possible. So > either we explicitly and always say attachment-links *are* file-links > in disguise (i.e. even change type in the parser), or we don't say > that, and then don't say that all the way to the edge of the system. > And let the uses of the link type decide themselves what to do. Which > is what I propose. As I explained above, your proposal is not crystal clear. My gut feeling is that "attachment" links are just a regular link type, that can be opened, and exported, like "file" links. They should live in "org-attach.el", using the provided tools to define new link types, like almost every other link types do. If those tools are not enough to express all the subtleties of "attachment" links, then let's spot the needs and improve those tools. That will benefit to every developer that wants to implement a new link type, what creating another corner case in the parser cannot do. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-19 21:12 ` Nicolas Goaziou @ 2020-01-19 23:29 ` Gustav Wikström 2020-01-20 1:25 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-19 23:29 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi Nicolas, Thanks for your comments! > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 19 januari 2020 22:12 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > Functionally it's in a good (and maintainable) state right now, in my > > opinion. But I do understand that the contextual attribute added to > > the parser may require some discussion. > > This is not my main gripe here, although I'm not convinced that extra > attribute is warranted. My concern is that you hard-code "attachment" > type in the parser. I don't think this is the correct way to handle the > situation. Ok, noted. To my defense I was thinking more in the terms of subtyping then hardcoding. Because we have multiple link types which try to share an interface. But the interface isn't perfect for all different kinds of links. So it doesn't seem too farfetched that some of those link types would benefit from additional custom properties, specific for those types. =application= and =search-option= for example isn't universally applicable to all link types. And link abbreviations are completely hidden from the parser output, since even the raw-link is expanded. So maybe, in the quest for completion, link abbreviations should have custom properties as well? And allowing some kind of sub-typing might make the parsed output more easy to use, because the interpreter can infer based on type (which already exist as a link property) what extra properties to use. What I'm trying to argue for here is: Maybe it's not that crazy after all to allow links to have additional properties in the parser based on its type? (While certainly still trying to avoid it if possible!) > Some link types specifically handle files, e.g., "docview", yet do not > need a special treatment in the parser. Note that "file" links have a good > reason to be treated specially there, besides their obvious importance, as > their type can be omitted. E.g., [[~/file.org]]. OTOH, I see no strong > reason to handle "attachments" in here, since they behave like any other > link type. > > Worse, the parser is more or less the definition of the Org syntax. > Therefore, including "attachment" in the parser is a signal meaning that > in order to fully implement Org syntax, e.g., in another language, one > need to support attachment links. Attachment links are undoubtedly useful, > but they are not core, at all. So, I feel uneasy about leaking that type > of link in the Element library. > > Also, you sometimes seem to blur, on purpose, the difference between > "attachment" and "file" links. If there should be no difference of > treatment between them, as I already suggested, you may want to consider > "attachment" as some functional link abbreviation. Then the "attachment" > type doesn't really exist, much like the "bugzilla" link type from the > manual. (Off topic) I'm sorry to hear that you think I'm intentionally making things fuzzy. If it seems so, then please take it as a lack of clarity of thought or communication rather than intentional bad will. (/Off topic) > In any case, we need a proper definition, a proper category too, for > "attachment" links. Meanwhile, modifying the parser is just grasping at > straws. > > > I argue that the attachment folder is a part of the attachment link, > > even though the information is found at a different location in the > > document (i.e. as a property to nodes in the document hierarchy). > > Parsing an attachment link would then be incomplete if that > > information is discarded. > > I argue that the buffer position of the attachment link and the path as > written in the link are enough to fully expand the attachment file name. One can indeed use the buffer position to derive the part of the path that comes from the subtree. But leaving it at that puts more requirements on the user of the parsed link in order to use it. Which takes us back to my first implementation of how the exporters would deal with the parsed link information (d70db54dbc). > If I'm wrong, which could be, I probably didn't invest enough time in the > Attach changes, then having the expanded form in :path and the initial > form in :raw-path is enough. > > > One option to adding an attribute could be to modify existing > > properties by adding the attachment folder to, for example, the path > > property. But that means to remove information about what was written > > as path in the original link. > > There is :raw-path for that purpose. There is no :raw-path available in the properties for a parsed link. If there were we surely wouldn't have this conversation and I'd be using that already! :) I.e. I like this suggestion. I considered using the :raw-link property, but the way it's currently used by the parser (i.e. expanding abbreviations) stopped me. It felt rather like no matter how I tried to utilize the existing parameters I were making an overload with a slightly different meaning. Might have been a lack on my part. In that case, please someone enlighten me! > > So I argue to keep path as the original path. But that means extra > > information is needed to also make it work in the filesystem. If we > > would translate an attachment link to a file link in ox.el that means > > we remove the option for exporters to decide for themselves what to do > > with the link. And I think the exporter should have that option. :) > > Let's first think about what category of object an attachment link belongs > to. Then we can discuss about how to export it. So, we're discussing regarding attachment as either: an abbreviation or a proper separate link type? I'm not sure what other options we have? I personally can't categorize it as an abbreviation since that is handled by a separate piece of code with other specifications. I.e. attachment wouldn't fit well inside org-link-abbrev-alist. Attachments should function in the same way as file links, with search options and all. But be limited to the current set of attached files. Which it has completion functionality for when inserting links using C-c C-l. > Again, if "attachment" == "file", the exporters shouldn't treat them > differently. If "attachment" is a new link type, it should define its own > rules in its own library, namely "org-attach.el". > > > Right now the ASCII exporter for example outputs attachment links as > > attachment:expanded_path instead of file:expanded_path. Since the link > > type actually is attachment. And for a solemnly textual export the > > exported information should be kept as close to source as possible. So > > either we explicitly and always say attachment-links *are* file-links > > in disguise (i.e. even change type in the parser), or we don't say > > that, and then don't say that all the way to the edge of the system. > > And let the uses of the link type decide themselves what to do. Which > > is what I propose. > > As I explained above, your proposal is not crystal clear. Sorry for that... > My gut feeling is that "attachment" links are just a regular link type, > that can be opened, and exported, like "file" links. They should live in > "org-attach.el", using the provided tools to define new link types, like > almost every other link types do. If those tools are not enough to express > all the subtleties of "attachment" links, then let's spot the needs and > improve those tools. That will benefit to every developer that wants to > implement a new link type, what creating another corner case in the parser > cannot do. That's basically the way it was before the patches to fix stardiviners issues. Except not functioning well enough. It would require quite some code in org-attach to replicate existing file links functionality. Mostly code duplication I presume. The raw-path option sounds better to my ears. Sub-typing links by saying there are link types which have additional properties feels like a sound option too. I wouldn't regard that as hardcoding. One improvement I can think of (outside of the discussion above) is to make it possible to pass the argument to org-link-open along to each separate link type specialization. That one has bugged me for some time now, when I've wanted to force opening attachment links in emacs but couldn't. Not an issue for attachments any longer (for now I suppose), but all other link types still have that limitation. Respectfully, Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-19 23:29 ` Gustav Wikström @ 2020-01-20 1:25 ` Nicolas Goaziou 2020-01-25 11:34 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-01-20 1:25 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Ok, noted. To my defense I was thinking more in the terms of subtyping > then hardcoding. Because we have multiple link types which try to > share an interface. But the interface isn't perfect for all different > kinds of links. Then, I suggest to improve the interface. > So it doesn't seem too farfetched that some of those link types would > benefit from additional custom properties, specific for those types. > =application= and =search-option= for example isn't universally > applicable to all link types. As a side note, :application is on its way out, i.e., "file+emacs" stuff is in "org-compat.el". Also, IIRC, "docview" links have "go to page" option, and they don't touch the parser. > What I'm trying to argue for here is: Maybe it's not that crazy after > all to allow links to have additional properties in the parser based > on its type? (While certainly still trying to avoid it if possible!) If new link types may not function correctly without touching the parser, how do you create new link types out of Org's core? This is not modular at all. > (Off topic) I'm sorry to hear that you think I'm intentionally making > things fuzzy. Not at all! My wording is terrible. When I wrote Also, you sometimes seem to blur, on purpose, the difference between "attachment" and "file" links. I meant something like: It seems to me that your intent is to have "attachment" links transparently become "file" links to the user. Hence my suggestion to use link abbreviations. There's nothing negative in it. > One can indeed use the buffer position to derive the part of the path > that comes from the subtree. But leaving it at that puts more > requirements on the user of the parsed link in order to use it. And higher order functions in "org-attach" could take care of it. Note that expanding a link in the parser means all attachment links are always expanded, even if they are not used. There's a cost to consider. Besides, parser focus on the contents of the buffer. I think it is out of its scope to infer file names for abbreviation links. It's more the job of the parts consuming the parsed data. > There is no :raw-path available in the properties for a parsed link. > If there were we surely wouldn't have this conversation and I'd be > using that already! :) I meant :raw-link, sorry. > I.e. I like this suggestion. I considered using the :raw-link > property, but the way it's currently used by the parser (i.e. > expanding abbreviations) stopped me. Please take how link abbreviations are handled in the parser out of the equation. I already stated this is not a good way to handle them. We should probably expand them in a "temp-link" variable, and parse it, while keeping original link in :raw-link (barring white spaces fixes). That would not be perfect either, because we would still be inferring stuff. That's another topic, really. Let's just ignore it for now. > So, we're discussing regarding attachment as either: an abbreviation > or a proper separate link type? I'm not sure what other options we > have? I personally can't categorize it as an abbreviation since that > is handled by a separate piece of code with other specifications. I.e. > attachment wouldn't fit well inside org-link-abbrev-alist. What makes you think it wouldn't fit well? > Attachments should function in the same way as file links, with search > options and all. But be limited to the current set of attached files. This isn't incompatible with the above, AFAICT. > That's basically the way it was before the patches to fix stardiviners > issues. Except not functioning well enough. It would require quite > some code in org-attach to replicate existing file links > functionality. Mostly code duplication I presume. I didn't read stardiviner issues. Would you mind summarizing them? Or, at least could you explain what is not functioning well enough? Anyhow, you may have missed the "let's spot the needs and improve these tools" part. If current tools lead to code duplication, we can fix that. > The raw-path option sounds better to my ears. Except I was meaning :raw-link :) > One improvement I can think of (outside of the discussion above) is to > make it possible to pass the argument to org-link-open along to each > separate link type specialization. Isn't that the job of :follow when defining a new link type? > That one has bugged me for some time now, when I've wanted to force > opening attachment links in emacs but couldn't. IMO, forcing users to open stuff in a specific, non-configurable, way is a bad idea. Why would we know better than them? ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-01-20 1:25 ` Nicolas Goaziou @ 2020-01-25 11:34 ` Gustav Wikström 2020-02-05 16:54 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-25 11:34 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 10666 bytes --] Hi again, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 20 januari 2020 02:25 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > > Ok, noted. To my defense I was thinking more in the terms of subtyping > > then hardcoding. Because we have multiple link types which try to > > share an interface. But the interface isn't perfect for all different > > kinds of links. > > Then, I suggest to improve the interface. That was kind of what I was trying to do, by allowing subtyping, so that the parser would be more knowledgeable about particular types of links, by allowing extended attributes. Maybe not implemented in the most extensible way though I'll admit. My suggestion to the link parser would be to have the following properties as the catch-all properties for links: - type :: Which type of link protocol applies. E.g. file, http, ftp, attachment, duckduckgo (ex. for a custom link abbreviation to search ddg) - raw-path :: The path to use for the particular protocol. Would contain everything in the link following "protocol:" - format :: Which format the link has. Plain, bracket or angular bracket - description :: The description part of the link ([[protocol:path][description]]) - begin, end, post-blank :: The default properties used for all elements. Not sure if contents-begin and contents-end are a part here as well. In addition to that each protocol would be able to declare their own properties using a :parse function. All would probably implement a path property. Some would implement an options property, and some maybe would maybe declare their own properties. As you've stated previously, from a performance perspective maybe it will be best to not expand the specific properties and instead let the expansion of those be handled in code by the link type owner (e.g. org-attach.el for attachment links). But not letting specific protocol parsers expand their own properties into a link makes it more difficult to implement support outside of emacs for the org specification, which in my opinion includes also a certain set of link protocols which do have their own specifications. > > So it doesn't seem too farfetched that some of those link types would > > benefit from additional custom properties, specific for those types. > > =application= and =search-option= for example isn't universally > > applicable to all link types. > > As a side note, :application is on its way out, i.e., "file+emacs" stuff > is in "org-compat.el". > > Also, IIRC, "docview" links have "go to page" option, and they don't > touch the parser. Ah yes. Just briefly looking at the docview code. Docview doesn't seem to use the parser when extracting information about that "go to page" information from the link. Which means docview links doesn't really care how the link information is encoded in the parser anyways. Maybe if docview were allowed to encode custom docview information into the parsed link in the parser it and others could reused that encoded information later? Docview would be able to add a ":go-to-page" option, for example. Just a thought. > > What I'm trying to argue for here is: Maybe it's not that crazy after > > all to allow links to have additional properties in the parser based > > on its type? (While certainly still trying to avoid it if possible!) > > If new link types may not function correctly without touching the > parser, how do you create new link types out of Org's core? This is not > modular at all. Most link types probably won't need custom link properties anyways. But could maybe let the parser know stuff by use of higher order functions? Or push for being important enough to be included into Org and allowed to be known by the parser. > > (Off topic) I'm sorry to hear that you think I'm intentionally making > > things fuzzy. > > Not at all! My wording is terrible. When I wrote > > Also, you sometimes seem to blur, on purpose, the difference between > "attachment" and "file" links. > > I meant something like: > > It seems to me that your intent is to have "attachment" links > transparently become "file" links to the user. > > Hence my suggestion to use link abbreviations. There's nothing negative > in it. Ok, got it. Thanks for explaining. I'll admit it hasn't been totally clear to me what the best way forward is. After refreshing my understanding on links the conclusion I came to was that link abbreviations in its current form was not a fitting concept for attachment links. Attachments are pretty much similar to file links though, so even if my intention isn't to blur the meaning they will and should be treated very similar, since functionality is so similar. > > One can indeed use the buffer position to derive the part of the path > > that comes from the subtree. But leaving it at that puts more > > requirements on the user of the parsed link in order to use it. > > And higher order functions in "org-attach" could take care of it. Note > that expanding a link in the parser means all attachment links are > always expanded, even if they are not used. There's a cost to consider. Higher order functions were used for exporting attachments previously. But the intention to keep functionality as close to file links as possible made me move the code from there into the separate exporters, to let all functionality be inherited by the way file exports were done, with the minor tweak needed to make it work for attachment links as well. I've attached a patch that lets org-attach take care of expanding the link element into a path, instead of sub-typing inside org-element. While I'm still pro sub-typing links according to their type, this patch removes that. I.e. the performance cost of parsing is moved to the points where the information actually is used, with a sort of "informational cost" of not letting the org parser know about the peculiarities of certain link types. > Besides, parser focus on the contents of the buffer. I think it is out > of its scope to infer file names for abbreviation links. It's more the > job of the parts consuming the parsed data. > > > There is no :raw-path available in the properties for a parsed link. > > If there were we surely wouldn't have this conversation and I'd be > > using that already! :) > > I meant :raw-link, sorry. > > > I.e. I like this suggestion. I considered using the :raw-link > > property, but the way it's currently used by the parser (i.e. > > expanding abbreviations) stopped me. > > Please take how link abbreviations are handled in the parser out of the > equation. I already stated this is not a good way to handle them. We > should probably expand them in a "temp-link" variable, and parse it, > while keeping original link in :raw-link (barring white spaces fixes). > That would not be perfect either, because we would still be inferring > stuff. > > That's another topic, really. Let's just ignore it for now. > > > So, we're discussing regarding attachment as either: an abbreviation > > or a proper separate link type? I'm not sure what other options we > > have? I personally can't categorize it as an abbreviation since that > > is handled by a separate piece of code with other specifications. I.e. > > attachment wouldn't fit well inside org-link-abbrev-alist. > > What makes you think it wouldn't fit well? That list seems more like a feature to let end users expand links using find-replace with a tag in an existing path. Actually looking more into it now I see that it can also use expansion with functions. So maybe that could be used as a way of implementation. I'm not sure if there are other side effects of that though so it's nothing I'm pursuing now. > > Attachments should function in the same way as file links, with search > > options and all. But be limited to the current set of attached files. > > This isn't incompatible with the above, AFAICT. The path for attachment links needs to be complemented with the part from the attachment directory to make it work in the file system. That is the difference between the link types. > > That's basically the way it was before the patches to fix stardiviners > > issues. Except not functioning well enough. It would require quite > > some code in org-attach to replicate existing file links > > functionality. Mostly code duplication I presume. > > I didn't read stardiviner issues. Would you mind summarizing them? Or, > at least could you explain what is not functioning well enough? The expansions of image links didn't work correctly for attachment links. Simply because org-attach-export-link didn't support that. > Anyhow, you may have missed the "let's spot the needs and improve these > tools" part. If current tools lead to code duplication, we can fix that. Speaking from the perspective of attachment links, if there were a file link type exporter function available that could be used by attachment links without code duplication. Another thing might be to make the higher order functions in the interface for adding new link types be able to use the parsed link instead of just certain properties of the link. Not sure if performance would be an issue then though. > > The raw-path option sounds better to my ears. > > Except I was meaning :raw-link :) > > > One improvement I can think of (outside of the discussion above) is to > > make it possible to pass the argument to org-link-open along to each > > separate link type specialization. > > Isn't that the job of :follow when defining a new link type? Yes, and the function that implements that would also need the user argument as input. In addition to the link path. > > That one has bugged me for some time now, when I've wanted to force > > opening attachment links in emacs but couldn't. > > IMO, forcing users to open stuff in a specific, non-configurable, way is > a bad idea. Why would we know better than them? I was not clear enough with what I meant. I meant not to force the user in the code to a specific choice, but to let the user force emacs to open the link. By use of arg as is specified in org-link-open. Anyways, patch attached that makes org-element not know about attachments any longer, and moves most of the responsibility to org-attach.el. The exporters still needs to know to use the new function inside org-attach.el though. Regards Gustav [-- Attachment #2: attachment-links.patch --] [-- Type: application/octet-stream, Size: 10107 bytes --] diff --git a/lisp/ol.el b/lisp/ol.el index 31c34ec7b..10ce83f50 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -75,6 +75,7 @@ (declare-function org-src-source-type "org-src" ()) (declare-function org-time-stamp-format "org" (&optional long inactive)) (declare-function outline-next-heading "outline" ()) +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) \f ;;; Customization @@ -934,7 +935,7 @@ a \"file\" link." (cond ((member type '("file" "attachment")) (when (string= type "attachment") - (setq path (org-element-property :attachment-path link))) + (setq path (org-attach-link-expand link))) (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) ;; Look into `org-link-parameters' in order to find diff --git a/lisp/org-attach.el b/lisp/org-attach.el index f5c81e01f..8709c8b88 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -41,6 +41,7 @@ (require 'org-id) (declare-function dired-dwim-target-directory "dired-aux") +(declare-function org-element-property "org-element" (property element)) (defgroup org-attach nil "Options concerning attachments in Org mode." @@ -640,6 +641,21 @@ See `org-attach-open'." Basically, this adds the path to the attachment directory." (expand-file-name file (org-attach-dir))) +(defun org-attach-link-expand (link &optional buffer-or-name) + "Return the full path to the attachment in the LINK element. +Takes LINK which is a link element, as defined by +`org-element-link-parser'. If LINK `:type' is attachment the +full path to the attachment is expanded and returned. Otherwise, +return nil. If BUFFER-OR-NAME is specified, LINK is expanded in +that buffer, otherwise current buffer is assumed." + (let ((type (org-element-property :type link)) + (file (org-element-property :path link)) + (pos (org-element-property :begin link))) + (when (string= type "attachment") + (with-current-buffer (or buffer-or-name (current-buffer)) + (goto-char pos) + (org-attach-expand file))))) + (org-link-set-parameters "attachment" :complete #'org-attach-complete-link) diff --git a/lisp/org-element.el b/lisp/org-element.el index 9a62c5b94..85663ef57 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -3116,11 +3116,7 @@ When at a link, return a list whose car is `link' and cdr a plist with `:type', `:path', `:format', `:raw-link', `:application', `:search-option', `:begin', `:end', `:contents-begin', `:contents-end' and `:post-blank' as keywords. Otherwise, return -nil. Additionally, in the context of attachment links one -further property, `:attachment-path' is set. That property -contains the attachment link expanded into a full filesystem -path. - +nil. Assume point is at the beginning of the link." (catch 'no-object @@ -3229,27 +3225,18 @@ Assume point is at the beginning of the link." (when trans (setq type (car trans)) (setq path (cdr trans)))) - (let ((link - (list 'link - (list :type type - :path path - :format format - :raw-link (or raw-link path) - :application application - :search-option search-option - :begin begin - :end end - :contents-begin contents-begin - :contents-end contents-end - :post-blank post-blank)))) - ;; Add additional type specific properties for link types that - ;; need it - (when (string= type "attachment") - (org-element-put-property - link :attachment-path - (file-relative-name - (org-attach-expand path)))) - link)))) + (list 'link + (list :type type + :path path + :format format + :raw-link (or raw-link path) + :application application + :search-option search-option + :begin begin + :end end + :contents-begin contents-begin + :contents-end contents-end + :post-blank post-blank))))) (defun org-element-link-interpreter (link contents) "Interpret LINK object as Org syntax. diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 019c26c24..4ffb44a97 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -34,6 +34,7 @@ ;;; Function Declarations (declare-function aa2u "ext:ascii-art-to-unicode" ()) +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) ;;; Define Back-End ;; @@ -1573,7 +1574,7 @@ INFO is a plist holding contextual information." (raw-path (org-element-property :path link)) (path (cond ((string= type "attachment") - (setq raw-path (org-element-property :attachment-path link)) + (setq raw-path (org-attach-link-expand link)) (concat type ":" raw-path)) (t (concat type ":" raw-path))))) (cond diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 39ccae3ea..fa30bde95 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -42,6 +42,7 @@ (declare-function org-id-find-id-file "org-id" (id)) (declare-function htmlize-region "ext:htmlize" (beg end)) (declare-function mm-url-decode-entities "mm-url" ()) +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) (defvar htmlize-css-name-prefix) (defvar htmlize-output-type) @@ -3074,7 +3075,7 @@ INFO is a plist holding contextual information. See (url-encode-url (concat type ":" raw-path))) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) ;; During publishing, turn absolute file names belonging ;; to base directory into relative file names. Otherwise, ;; append "file" protocol to absolute file name. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index b307ff49a..1bc15a818 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -32,6 +32,8 @@ ;;; Function Declarations +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) + (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) @@ -2360,7 +2362,7 @@ LINK is the link pointing to the inline image. INFO is a plist used as a communication channel." (let* ((parent (org-export-get-parent-element link)) (path (let ((raw-path (if (string= (org-element-property :type link) "attachment") - (org-element-property :attachment-path link) + (org-attach-link-expand link) (org-element-property :path link)))) (if (not (file-name-absolute-p raw-path)) raw-path (expand-file-name raw-path)))) @@ -2528,7 +2530,7 @@ INFO is a plist holding contextual information. See (concat type ":" raw-path)) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) (org-export-file-uri raw-path)) (t raw-path))))) diff --git a/lisp/ox-man.el b/lisp/ox-man.el index 5de4c5ea5..b6925c696 100644 --- a/lisp/ox-man.el +++ b/lisp/ox-man.el @@ -42,6 +42,8 @@ ;;; Function Declarations +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) + (defvar org-export-man-default-packages-alist) (defvar org-export-man-packages-alist) (defvar orgtbl-exp-regexp) @@ -616,7 +618,7 @@ INFO is a plist holding contextual information. See (concat type ":" raw-path)) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) (org-export-file-uri raw-path)) (t raw-path)))) (cond diff --git a/lisp/ox-md.el b/lisp/ox-md.el index 61b31f987..7515df3a2 100644 --- a/lisp/ox-md.el +++ b/lisp/ox-md.el @@ -35,6 +35,8 @@ \f ;;; Function Declarations +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) + ;;; User-Configurable Variables (defgroup org-export-md nil @@ -405,7 +407,7 @@ INFO is a plist holding contextual information. See (concat type ":" raw-path)) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) (org-export-file-uri (funcall link-org-files-as-md raw-path))) (t raw-path)))) (cond diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el index 4f91e4a29..5d0ee7bfe 100644 --- a/lisp/ox-odt.el +++ b/lisp/ox-odt.el @@ -34,6 +34,8 @@ ;;; Function Declarations +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) + ;;; Define Back-End (org-export-define-backend 'odt @@ -2706,7 +2708,7 @@ INFO is a plist holding contextual information. See (concat type ":" raw-path)) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) (org-export-file-uri raw-path)) (t raw-path))) ;; Convert & to & for correct XML representation diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el index 22ea86e1c..89c6746d8 100644 --- a/lisp/ox-texinfo.el +++ b/lisp/ox-texinfo.el @@ -30,6 +30,8 @@ ;;; Function Declarations +(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) + (defvar orgtbl-exp-regexp) @@ -1058,7 +1060,7 @@ INFO is a plist holding contextual information. See (concat type ":" raw-path)) ((member type '("file" "attachment")) (when (string= type "attachment") - (setq raw-path (org-element-property :attachment-path link))) + (setq raw-path (org-attach-link-expand link))) (org-export-file-uri raw-path)) (t raw-path)))) (cond ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-01-25 11:34 ` Gustav Wikström @ 2020-02-05 16:54 ` Nicolas Goaziou 2020-02-06 20:55 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-05 16:54 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > That was kind of what I was trying to do, by allowing subtyping, so > that the parser would be more knowledgeable about particular types of > links, by allowing extended attributes. Maybe not implemented in the > most extensible way though I'll admit. Just to be clear, I firmly believe Element library should be as low-level as possible. Ideally (we're not there yet), it should not depend on any other part of Org. It should be the step (largely) above "re-search-forward". So, extending the parser to include knowledge to some other library in Org is not an option. Element is expected to dumbly stick to Org syntax, without knowing what it means. > My suggestion to the link parser would be to have the following properties as the catch-all properties for links: > - type :: Which type of link protocol applies. E.g. file, http, ftp, attachment, duckduckgo (ex. for a custom link abbreviation to search ddg) > - raw-path :: The path to use for the particular protocol. Would contain everything in the link following "protocol:" > - format :: Which format the link has. Plain, bracket or angular bracket Barring custom link abbreviations, this is already the case. > - description :: The description part of the link ([[protocol:path][description]]) Description is not meaningful here. This is parsed content. > - begin, end, post-blank :: The default properties used for all elements. Not sure if contents-begin and contents-end are a part here as well. They are when the link has contents, i.e., a description. > As you've stated previously, from a performance perspective maybe it > will be best to not expand the specific properties and instead let the > expansion of those be handled in code by the link type owner (e.g. > org-attach.el for attachment links). More than performance, this is a design issue. > Ah yes. Just briefly looking at the docview code. Docview doesn't seem > to use the parser when extracting information about that "go to page" > information from the link. Which means docview links doesn't really > care how the link information is encoded in the parser anyways. Indeed. However, higher level functions, e.g., org-open-link, do care about it and ensure that "ol-docview.el" really processes a link. > Maybe if docview were allowed to encode custom docview information > into the parsed link in the parser it and others could reused that > encoded information later? Docview would be able to add > a ":go-to-page" option, for example. Just a thought. I'm quite sure this is a wrong way to go. > Most link types probably won't need custom link properties anyways. > But could maybe let the parser know stuff by use of higher order > functions? Or push for being important enough to be included into Org > and allowed to be known by the parser. Only syntax changes can go into the parser. Attachment links are regular links, not something that requires extending Org's syntax. Note that this is not the case of file links, which have a special syntax, e.g., [[./cat.jpg]]. > Ok, got it. Thanks for explaining. I'll admit it hasn't been totally > clear to me what the best way forward is. After refreshing my > understanding on links the conclusion I came to was that link > abbreviations in its current form was not a fitting concept for > attachment links. Attachments are pretty much similar to file links > though, so even if my intention isn't to blur the meaning they will > and should be treated very similar, since functionality is so similar. Functionality may be familiar, but their syntax is not the same, therefore, the differences should be handled elsewhere. > Speaking from the perspective of attachment links, if there were > a file link type exporter function available that could be used by > attachment links without code duplication. Where would live that function? ox.el is not an option since every exporter treats file links differently. As suggested already (I think) we could add a phase in ox.el that would expand attachment links into their file link counterpart automatically. This would avoid adding specific code in every export back-end. However, export back-end would miss the opportunity to handle attachment links specifically. This is one way or the other. > Yes, and the function that implements that would also need the user > argument as input. In addition to the link path. Patch welcome. I see no objection to extending :follow link parameter in "ol.el". > Anyways, patch attached that makes org-element not know about > attachments any longer, and moves most of the responsibility to > org-attach.el. The exporters still needs to know to use the new > function inside org-attach.el though. Thank you. Please apply it. Now we can try improving the situation for exporters. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-05 16:54 ` Nicolas Goaziou @ 2020-02-06 20:55 ` Gustav Wikström 2020-02-07 14:28 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-02-06 20:55 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi again, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 5 februari 2020 17:54 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > > That was kind of what I was trying to do, by allowing subtyping, so > > that the parser would be more knowledgeable about particular types of > > links, by allowing extended attributes. Maybe not implemented in the > > most extensible way though I'll admit. > > Just to be clear, I firmly believe Element library should be as > low-level as possible. Ideally (we're not there yet), it should not > depend on any other part of Org. It should be the step (largely) above > "re-search-forward". Ok, fair enough. I guess where I was going was a bit further than only parsing the characters, into also interpreting them in meaningful ways. Especially true for attachment links that would need to look up other parts of the tree to fetch extended information. I'll leave that trail of thought. > > My suggestion to the link parser would be to have the following properties as the catch-all properties for links: > > - type :: Which type of link protocol applies. E.g. file, http, ftp, attachment, duckduckgo (ex. for a custom link abbreviation to search ddg) > > - raw-path :: The path to use for the particular protocol. Would contain everything in the link following "protocol:" > > - format :: Which format the link has. Plain, bracket or angular bracket > > Barring custom link abbreviations, this is already the case. Hmm, maybe that is so.. Except raw-path is called path (not really an issue though) and there is another property called raw-link. Not sure how to interpret the use of both path and raw-link. And there are things happening between parsing the actual buffer link and storing the raw-link and path parameters. In the end, what made me consider the sub-typing I've been writing about could very well just have been the ambiguities regarding what's what, and the lack of treatment for parts that arguably could be seen as additional parameters to the link-path. For example the "::extra_content" suffix in file links, that by the parser currently is just a part of the path itself. Maybe clearer documentation in the function of what each part is /supposed/ to be, and the design principle that is applied, i.e. that the path is the raw path with options included can help future me and others who might want to understand. Thoughts on that? > > - description :: The description part of the link ([[protocol:path][description]]) > > Description is not meaningful here. This is parsed content. > > > - begin, end, post-blank :: The default properties used for all elements. Not sure if contents-begin and contents-end are a part here as well. > > They are when the link has contents, i.e., a description. Hmm, don't really know if a link description should be regarded as content. I for one hadn't considered it until now when you mentioned it! But it preserves space in the parse tree I suppose. If the docstring of the link parser would make it clear what each property is supposed to contain, in this case :contents-begin & :contents-end, I'm sure I would have been less confused about this, and wouldn't have had any objections. > > As you've stated previously, from a performance perspective maybe it > > will be best to not expand the specific properties and instead let the > > expansion of those be handled in code by the link type owner (e.g. > > org-attach.el for attachment links). > > More than performance, this is a design issue. > > > Ah yes. Just briefly looking at the docview code. Docview doesn't seem > > to use the parser when extracting information about that "go to page" > > information from the link. Which means docview links doesn't really > > care how the link information is encoded in the parser anyways. > > Indeed. However, higher level functions, e.g., org-open-link, do care > about it and ensure that "ol-docview.el" really processes a link. > > > Maybe if docview were allowed to encode custom docview information > > into the parsed link in the parser it and others could reused that > > encoded information later? Docview would be able to add > > a ":go-to-page" option, for example. Just a thought. > > I'm quite sure this is a wrong way to go. Ok, got it. You're saying the link interpreter for docview (in this case) have to be able to parse the link one step further, to be able to extract this ":go-to-page" information, before being able to operate on it. Indeed a design decision. Maybe the best one, who am I to say otherwise. It will make the Org link parser leaner for sure. > > Most link types probably won't need custom link properties anyways. > > But could maybe let the parser know stuff by use of higher order > > functions? Or push for being important enough to be included into Org > > and allowed to be known by the parser. > > Only syntax changes can go into the parser. Attachment links are regular > links, not something that requires extending Org's syntax. Note that > this is not the case of file links, which have a special syntax, e.g., > [[./cat.jpg]]. Sure. > > Ok, got it. Thanks for explaining. I'll admit it hasn't been totally > > clear to me what the best way forward is. After refreshing my > > understanding on links the conclusion I came to was that link > > abbreviations in its current form was not a fitting concept for > > attachment links. Attachments are pretty much similar to file links > > though, so even if my intention isn't to blur the meaning they will > > and should be treated very similar, since functionality is so similar. > > Functionality may be familiar, but their syntax is not the same, > therefore, the differences should be handled elsewhere. > > > Speaking from the perspective of attachment links, if there were > > a file link type exporter function available that could be used by > > attachment links without code duplication. > > Where would live that function? ox.el is not an option since every > exporter treats file links differently. Not sure about location. Maybe ol.el? What I'm talking about is a higher order function for the :export property within org-link-parameters. File link exporting would then have to be declared using org-link-set-parameters, just as other link types are supposed to be declared for exporting. > As suggested already (I think) we could add a phase in ox.el that would > expand attachment links into their file link counterpart automatically. > This would avoid adding specific code in every export back-end. However, > export back-end would miss the opportunity to handle attachment links > specifically. This is one way or the other. Let's settle with option two for now. As it's defined in the patch. > > Yes, and the function that implements that would also need the user > > argument as input. In addition to the link path. > > Patch welcome. I see no objection to extending :follow link parameter in > "ol.el". Ok, got it. I'll see what I can come up with. > > Anyways, patch attached that makes org-element not know about > > attachments any longer, and moves most of the responsibility to > > org-attach.el. The exporters still needs to know to use the new > > function inside org-attach.el though. > > Thank you. Please apply it. Will do! > Now we can try improving the situation for exporters. > > Regards, > > -- > Nicolas Goaziou Thanks! Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-06 20:55 ` Gustav Wikström @ 2020-02-07 14:28 ` Nicolas Goaziou 2020-02-08 15:39 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-07 14:28 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Hmm, maybe that is so.. Except raw-path is called path (not really an > issue though) and there is another property called raw-link. Not sure > how to interpret the use of both path and raw-link. And there are > things happening between parsing the actual buffer link and storing > the raw-link and path parameters. There is some normalization involved, indeed. The intent of :raw-link is to provide the link almost as it was in the buffer, without any parsing. I agree there should not be any `org-link-unescape' and `org-link-expand-abbrev' involved there. Something to fix at some point. :path, on the contrary is parsed. It is the part of the link between the type and the search options, i.e., [[type:path::search]], [[type:path]], or [[path]]. > In the end, what made me consider the sub-typing I've been writing > about could very well just have been the ambiguities regarding what's > what, and the lack of treatment for parts that arguably could be seen > as additional parameters to the link-path. For example the > "::extra_content" suffix in file links, that by the parser currently > is just a part of the path itself. In [[file:name::extra_content]] :path is "name", and :search-option is "extra_content". As you noted, :search-option is not valid in non-file links, so it belongs to the path. It seems there is some friction about this search option part. IIUC, you want attachment links to support this link-specific syntax. This is indeed not possible. As I commented earlier, letting libraries decide what the parser should do is not an option. There are a few options, though: 1. Allow every link with an explicit type (i.e., not internal links) to have a search option, so you can write [[docview:filename::12]] or [[attachment:filename::*Section 2]]. IMO this is a waste, because most links do not need this, and it could become confusing [[https:www.orgmode.org::#sec2]]. 2. Provide a function in "ol.el" to do the parsing for you, so that every new link library doesn't have to re-invent the wheel. E.g., (org-link-extract-search-options "foo::bar") => (:path "foo" :search-options "bar"). 3. Keep that way, i.e., any link library requiring to read the search part can do a dumb `match-string` and, in two or three lines of code, extract it. IOW, since this is so trivial, why bother? WDYT? > Maybe clearer documentation in the function of what each part is > /supposed/ to be, and the design principle that is applied, i.e. that > the path is the raw path with options included can help future me and > others who might want to understand. Thoughts on that? There is some information in the manual, and the Org Syntax document. > Hmm, don't really know if a link description should be regarded as > content. I for one hadn't considered it until now when you mentioned > it! But it preserves space in the parse tree I suppose. This is unrelated to the size of the parse tree. A description may contain Org specific markup, e.g., bold, so it needs to be parsed further. Therefore, a link with a description is not a leaf: it has contents. > If the docstring of the link parser would make it clear what each > property is supposed to contain, in this case :contents-begin > & :contents-end, I'm sure I would have been less confused about this, > and wouldn't have had any objections. A docstring is not a manual. I explained this in the Org Element API documentation, IIRC. > Ok, got it. You're saying the link interpreter for docview (in this > case) have to be able to parse the link one step further, to be able > to extract this ":go-to-page" information, before being able to > operate on it. Indeed a design decision. Maybe the best one, who am > I to say otherwise. It will make the Org link parser leaner for sure. Sarcasm? My opinion is the library defining the Org syntax should be a fixed point. It is important that the output of the parser does not depend on what libraries are currently loaded. It guarantees that if we both open the same document, we'll get the same parse tree. Of course, this is not exactly true at the moment. For example, we may not have the same TODO keywords, or the same item list separator. Nevertheless, I see no reason to diverge further from this goal. > Not sure about location. Maybe ol.el? What I'm talking about is > a higher order function for the :export property within > org-link-parameters. File link exporting would then have to be > declared using org-link-set-parameters, just as other link types are > supposed to be declared for exporting. See above about my suggestion of a generic tool. >> As suggested already (I think) we could add a phase in ox.el that would >> expand attachment links into their file link counterpart automatically. >> This would avoid adding specific code in every export back-end. However, >> export back-end would miss the opportunity to handle attachment links >> specifically. This is one way or the other. > > Let's settle with option two for now. As it's defined in the patch. Too bad. I still think that first option is more seducing. Transparently turning attachment links into file links at export time would prevent some headache in exporters out there. It boils down to adding a function that transforms "attach" links into "file" links, e.g., `org-export--expand-attachments', and insert it in `org-export-as', right after (org-export--remove-uninterpreted-data tree info). Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-07 14:28 ` Nicolas Goaziou @ 2020-02-08 15:39 ` Gustav Wikström 2020-02-13 20:41 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-02-08 15:39 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 7 februari 2020 15:28 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > > Hmm, maybe that is so.. Except raw-path is called path (not really an > > issue though) and there is another property called raw-link. Not sure > > how to interpret the use of both path and raw-link. And there are > > things happening between parsing the actual buffer link and storing > > the raw-link and path parameters. > > There is some normalization involved, indeed. The intent of :raw-link is > to provide the link almost as it was in the buffer, without any parsing. > I agree there should not be any `org-link-unescape' and > `org-link-expand-abbrev' involved there. Something to fix at some point. > > :path, on the contrary is parsed. It is the part of the link between the > type and the search options, i.e., [[type:path::search]], [[type:path]], > or [[path]]. Unless search-option applies as a general construct for all link types I don't think it should be in the parser. Given the discussion we've had about design of the parser from before. I.e. if the parser isn't supposed to know anything about the specific types themselves, all properties of the parsed elements have to make sense for all types of links. So either search-option remains but is parsed in exactly the same way for all link types, or it's not there at all. And if it's not available in the parser, the file link interpreters (that still might need to be constructed) gets to parse the :search-option from the raw-link as it wishes itself. Given the above paragraph, the :path and :search-option property doesn't make sense in the parser. :raw-link is enough. Less ambiguous names for :path and :search-option would be :file-path and :file-search-option. But that's sub-typing. We've already concluded that that should not belong to the parser. > > In the end, what made me consider the sub-typing I've been writing > > about could very well just have been the ambiguities regarding what's > > what, and the lack of treatment for parts that arguably could be seen > > as additional parameters to the link-path. For example the > > "::extra_content" suffix in file links, that by the parser currently > > is just a part of the path itself. > > In [[file:name::extra_content]] :path is "name", and :search-option is > "extra_content". As you noted, :search-option is not valid in non-file > links, so it belongs to the path. > > It seems there is some friction about this search option part. IIUC, you > want attachment links to support this link-specific syntax. This is > indeed not possible. As I commented earlier, letting libraries decide > what the parser should do is not an option. There are a few options, > though: > > 1. Allow every link with an explicit type (i.e., not internal links) to > have a search option, so you can write [[docview:filename::12]] or > [[attachment:filename::*Section 2]]. IMO this is a waste, because > most links do not need this, and it could become confusing > [[https:www.orgmode.org::#sec2]]. > > 2. Provide a function in "ol.el" to do the parsing for you, so that > every new link library doesn't have to re-invent the wheel. E.g., > (org-link-extract-search-options "foo::bar") => (:path > "foo" :search-options "bar"). > > 3. Keep that way, i.e., any link library requiring to read the search > part can do a dumb `match-string` and, in two or three lines of code, > extract it. IOW, since this is so trivial, why bother? > > WDYT? I agree that option 1 is suboptimal. :search-option isn't obvious as a property for all link types. Since option 3 is fairly trivial, option 2 isn't necessary either. For attachment links to reuse the :search-option semantics, without the hard-coding we're currently doing, I see one option where attachment link higher order functions could reuse file link higher order functions. Those file link higher order functions don't exist yet as far as I know. > > Maybe clearer documentation in the function of what each part is > > /supposed/ to be, and the design principle that is applied, i.e. that > > the path is the raw path with options included can help future me and > > others who might want to understand. Thoughts on that? > > There is some information in the manual, and the Org Syntax document. > > > Hmm, don't really know if a link description should be regarded as > > content. I for one hadn't considered it until now when you mentioned > > it! But it preserves space in the parse tree I suppose. > > This is unrelated to the size of the parse tree. > > A description may contain Org specific markup, e.g., bold, so it needs > to be parsed further. Therefore, a link with a description is not > a leaf: it has contents. > > > If the docstring of the link parser would make it clear what each > > property is supposed to contain, in this case :contents-begin > > & :contents-end, I'm sure I would have been less confused about this, > > and wouldn't have had any objections. > > A docstring is not a manual. I explained this in the Org Element API > documentation, IIRC. True that. There is a balance to strike. Maybe it's time to pull in the org element document into the manual? I vote for that at least. > > Ok, got it. You're saying the link interpreter for docview (in this > > case) have to be able to parse the link one step further, to be able > > to extract this ":go-to-page" information, before being able to > > operate on it. Indeed a design decision. Maybe the best one, who am > > I to say otherwise. It will make the Org link parser leaner for sure. > > Sarcasm? No, not sarcasm. Sorry for not being more clear. I'm well aware that I'm delving in things quite advanced where my prior experience is thin. I can't cite articles about best way to work with parsers and interpreters. I can only reason to the best of my ability. > My opinion is the library defining the Org syntax should be a fixed > point. It is important that the output of the parser does not depend on > what libraries are currently loaded. It guarantees that if we both open > the same document, we'll get the same parse tree. > > Of course, this is not exactly true at the moment. For example, we may > not have the same TODO keywords, or the same item list separator. > Nevertheless, I see no reason to diverge further from this goal. Ok, sure. Let the syntax be as rigid as possible, and let extensibility to that be dealt with in auxiliary parsing/interpreting functions. I guess that would be the approach, put in different words. Still correct? > > Not sure about location. Maybe ol.el? What I'm talking about is > > a higher order function for the :export property within > > org-link-parameters. File link exporting would then have to be > > declared using org-link-set-parameters, just as other link types are > > supposed to be declared for exporting. > > See above about my suggestion of a generic tool. > > >> As suggested already (I think) we could add a phase in ox.el that would > >> expand attachment links into their file link counterpart automatically. > >> This would avoid adding specific code in every export back-end. However, > >> export back-end would miss the opportunity to handle attachment links > >> specifically. This is one way or the other. > > > > Let's settle with option two for now. As it's defined in the patch. > > Too bad. I still think that first option is more seducing. Transparently > turning attachment links into file links at export time would prevent > some headache in exporters out there. It boils down to adding a function > that transforms "attach" links into "file" links, e.g., > `org-export--expand-attachments', and insert it in `org-export-as', > right after (org-export--remove-uninterpreted-data tree info). It might be seducing but I'm not sold. I'd rather have an attachment-link exporter explicitly reuse functionality for exporting file links than automatic translation. For that to be possible, there first is a need for a file link exporter function. And the current implementation (since the patch) is good enough imo, for now, and until anyone of us does some file link refactoring. Kind regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-08 15:39 ` Gustav Wikström @ 2020-02-13 20:41 ` Nicolas Goaziou 2020-02-13 21:11 ` Gustav Wikström ` (2 more replies) 0 siblings, 3 replies; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-13 20:41 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Unless search-option applies as a general construct for all link types > I don't think it should be in the parser. Given the discussion we've > had about design of the parser from before. I.e. if the parser isn't > supposed to know anything about the specific types themselves, all > properties of the parsed elements have to make sense for all types of > links. So either search-option remains but is parsed in exactly the > same way for all link types, or it's not there at all. And if it's not > available in the parser, the file link interpreters (that still might > need to be constructed) gets to parse the :search-option from the > raw-link as it wishes itself. > > Given the above paragraph, the :path and :search-option property > doesn't make sense in the parser. :raw-link is enough. Less ambiguous > names for :path and :search-option would be :file-path > and :file-search-option. But that's sub-typing. We've already > concluded that that should not belong to the parser. I don't have much time, I apologize if I'm not clear. I disagree with you conclusion. Sub-typing is necessary in the parser. The `link' object is complex, so it needs categories or types. There are plain links, angle links, square links. In this last category, there are internal links, which include coderefs, fuzzy links, custom id, file links, and, "links with an explicit scheme part". For each of these categories, it is fine to have specific properties, like search-options. Note that this is sub-typing per syntax, not by meaning. This is what should not move, unless absolutely necessary. For example, attachment links belong to "square links with an explicit 'attachment' scheme part". That is all the parser needs to know. Now, it is true that [[file:...]] links are put in the same category as [[~/...]] links, for practical reasons, i.e., you wouldn't want them to differ in meaning. But this is a breach in the categories above. We might ignore the :search-option part in file links, but it's very easy to get, and, more importantly, we must extract the filename, so further parsing is necessary. > I agree that option 1 is suboptimal. :search-option isn't obvious as > a property for all link types. Since option 3 is fairly trivial, > option 2 isn't necessary either. For attachment links to reuse > the :search-option semantics, without the hard-coding we're currently > doing, I see one option where attachment link higher order functions > could reuse file link higher order functions. Those file link higher > order functions don't exist yet as far as I know. Higher order functions for what? `org-open-file' is such a higher order function for opening file links. There is no higher order function for exporting because each exporter handles file links differently. A higher order function for parsing doesn't mean much, since the consumer is not known yet. At this point, the best thing to do is to clarify what you need. I probably do not understand it. > True that. There is a balance to strike. Maybe it's time to pull in > the org element document into the manual? I vote for that at least. I have no strong opinion on that. It may fit into an appendix, indeed, or even as a section in first appendix: "Hacking", e.g. "Using the Parser API". > Ok, sure. Let the syntax be as rigid as possible, and let > extensibility to that be dealt with in auxiliary parsing/interpreting > functions. I guess that would be the approach, put in different words. > Still correct? It seems correct. > It might be seducing but I'm not sold. I'd rather have an > attachment-link exporter explicitly reuse functionality for exporting > file links than automatic translation. For that to be possible, there > first is a need for a file link exporter function. I don't see how that would be possible, since it would be different for each back-end. Again, do you have a more precise idea about what it would do? > And the current implementation (since the patch) is good enough imo, > for now, and until anyone of us does some file link refactoring. There is an "attachement" reference left in "org-element.el" at the moment. Can it be removed safely? I'm Cc'ing Bastien because that particular point should be solved before any release, IMO. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 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 21:57 ` Gustav Wikström 2020-02-14 10:02 ` Bastien 2 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-02-13 21:11 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Hi, Partial answer for now; > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 13 februari 2020 21:41 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org; Bastien Guerry <bzg@gnu.org> > Subject: Re: attachment: link type export to HTML invalid attach dir > > [...] > > There is an "attachement" reference left in "org-element.el" at the > moment. Can it be removed safely? Ah, you mean the reference on line 3216. No, I don't think it can be removed. And I honestly don't think it should be either. It's there to let attachment links mirror the peculiarities of file links. It's needed for feature compatibility. I don't see the issue with that. It's a core link type and it needs the information. That particular logic doesn't affect the parse tree. It's there only to give attachment links the same properties as file links. > I'm Cc'ing Bastien because that particular point should be solved > before any release, IMO. > > Regards, > > -- > Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-13 21:11 ` Gustav Wikström @ 2020-02-13 21:37 ` Nicolas Goaziou 2020-02-13 22:07 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-13 21:37 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Ah, you mean the reference on line 3216. No, I don't think it can be > removed. And I honestly don't think it should be either. It's there to > let attachment links mirror the peculiarities of file links. It's > needed for feature compatibility. I don't see the issue with that. > It's a core link type and it needs the information. That particular > logic doesn't affect the parse tree. It's there only to give > attachment links the same properties as file links. I disagree. This is not a core link type. The issue is that the parser should self-contained. Please use a different way to obtain the information; we already discussed it and suggested multiple solutions. ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-13 21:37 ` Nicolas Goaziou @ 2020-02-13 22:07 ` Gustav Wikström 2020-02-14 0:16 ` Nicolas Goaziou ` (2 more replies) 0 siblings, 3 replies; 113+ messages in thread From: Gustav Wikström @ 2020-02-13 22:07 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 13 februari 2020 22:38 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org; Bastien Guerry <bzg@gnu.org> > Subject: Re: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > > Ah, you mean the reference on line 3216. No, I don't think it can be > > removed. And I honestly don't think it should be either. It's there to > > let attachment links mirror the peculiarities of file links. It's > > needed for feature compatibility. I don't see the issue with that. > > It's a core link type and it needs the information. That particular > > logic doesn't affect the parse tree. It's there only to give > > attachment links the same properties as file links. > > I disagree. This is not a core link type. The issue is that the parser > should self-contained. Please use a different way to obtain the > information; we already discussed it and suggested multiple solutions. What makes attachment links not be a core link type? As I see it we have two categories here: Core = those inside Org mode. Not core = those in external libraries. No other distinction needs to be made. If a link type is inside Org mode, let it then use the special properties that Org mode provides. Attachment links need to be treated just as file links in most regards. Since file-links have special logic which attachment links also needs. Thus a reference to attachment in org-element.el. Nothing strange here, nothing breaking and the parser is still self-contained. Maybe time for Bastien to step in. Because I can't remove the reference to attachment in org-element.el without breaking it's functionality. Which, btw, was broken before adding the reference in org-element.el. The thing that started this discussion in the first place. We're in a better place now. Attachment links works as intended. It would be a pity to have to change that because of your argument that attachment links aren't "core" enough to be mentioned in org-element.el. Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 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 11:06 ` Bastien 2 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-14 0:16 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > What makes attachment links not be a core link type? 1. Org Attach is not loaded by default 2. Implementing Org syntax doesn't require to implement attachments Attachment links are in the same category as Docview links, for example. There is no "docview" occurrence in "org-element.el". We have been there already. > As I see it we have two categories here: Core = those inside Org mode. > Not core = those in external libraries. No other distinction needs to > be made. If a link type is inside Org mode, let it then use the > special properties that Org mode provides. Sure thing, but you use the wrong ones! > Attachment links need to be treated just as file links in most > regards. Since file-links have special logic which attachment links > also needs. Thus a reference to attachment in org-element.el. Nothing > strange here, nothing breaking and the parser is still self-contained. Attachement links should live only in "org-attach.el": like 99% of other links do live in their own library. They do not require a special treatment. Again, the parser is not self-contained if it references org-attach.el. > Maybe time for Bastien to step in. Because I can't remove the > reference to attachment in org-element.el without breaking it's > functionality. Which, btw, was broken before adding the reference in > org-element.el. The thing that started this discussion in the first > place. We're in a better place now. We're not. The way it is implemented is not correct. For opening link, attachment links should use the :follow link parameter. The "following" function can extract the search option, if any, and the file name, then call `org-open-file' appropriately. You're doing it backwards and modify `org-open-file' instead. Additional links are not supposed to modify "ol.el". For exporting link, it should use the :export link parameter. The "exporting" function can extract the search option, if any, and the file name. It can then re-create a file link object, and call `org-export-data' on it. You're also doing it backwards here and prefer to modify each export back-end instead. > Attachment links works as intended. It would be a pity to have to > change that because of your argument that attachment links aren't > "core" enough to be mentioned in org-element.el. I strongly insist that it should be removed. I gave you ways to solve the issue. If you need anything else, let me know, but please consider implementing them. ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-14 0:16 ` Nicolas Goaziou @ 2020-02-14 7:23 ` Gustav Wikström 0 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2020-02-14 7:23 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 14 februari 2020 01:16 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org; Bastien Guerry <bzg@gnu.org> > Subject: Re: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > > What makes attachment links not be a core link type? > > 1. Org Attach is not loaded by default > 2. Implementing Org syntax doesn't require to implement attachments > > Attachment links are in the same category as Docview links, for > example. > There is no "docview" occurrence in "org-element.el". We have been > there already. > > > As I see it we have two categories here: Core = those inside Org > mode. > > Not core = those in external libraries. No other distinction needs to > > be made. If a link type is inside Org mode, let it then use the > > special properties that Org mode provides. > > Sure thing, but you use the wrong ones! I meant that Core = inside the Org mode repository of source code files. Both Docview and Attachment is, both are mentioned in the manual as part of the system. Both should be able to use :search-option inside the Org element parser. > > Attachment links need to be treated just as file links in most > > regards. Since file-links have special logic which attachment links > > also needs. Thus a reference to attachment in org-element.el. Nothing > > strange here, nothing breaking and the parser is still self- > contained. > > Attachement links should live only in "org-attach.el": like 99% of > other links do live in their own library. They do not require a special > treatment. > > Again, the parser is not self-contained if it references org-attach.el. It doesn't referencen org-attach.el any longer. That reference is removed. What remains is a reference to the string "attachment". You may argue that even that is to much. And I can only agree with that vision if you also state that org-element shouldn't reference the string "file" either. Anything else is a subjective design that puts a sentiment on "more" or "less" importance of link types and how to regard if they're "important" enough to be mentioned. I don't think you want that in org-element any more than I do. > > Maybe time for Bastien to step in. Because I can't remove the > > reference to attachment in org-element.el without breaking it's > > functionality. Which, btw, was broken before adding the reference in > > org-element.el. The thing that started this discussion in the first > > place. We're in a better place now. > > We're not. The way it is implemented is not correct. Functionally we are - we have working attachment links that are treated in the same way as file links through out Org mode. Since there is special treatment for file links in Org, attachment links needs the same special treatment to get the same behavior. You might see it as a regression in the design of org-element.el. To which I've already given arguments about why it's not really - and different ways it can be solved - by removing special file-related properties from org-element.el. The added string-reference to attachment links is there because special string-references to file links are there. If special file link references are removed, then clearly attachment links will/should be removed as well. > For opening link, attachment links should use the :follow link > parameter. The "following" function can extract the search option, if > any, and the file name, then call `org-open-file' appropriately. You're > doing it backwards and modify `org-open-file' instead. Additional links > are not supposed to modify "ol.el". Sure, that's a principle I can agree to. And have already mentioned that I will try to refactor that part by giving the :follow function the same abilities as org-open-file currently has. But that won't be completed quite yet. > For exporting link, it should use the :export link parameter. The > "exporting" function can extract the search option, if any, and the > file name. It can then re-create a file link object, and call `org- > export-data' on it. You're also doing it backwards here and prefer to > modify each export back-end instead. Which I've argued about already, saying it will be difficult without having file already being treated the same way. I'm not opposed to doing it that way in the long run. But let it be done for file links first, then attachment links can follow. I don't have the capacity to dig into this on my own. > > Attachment links works as intended. It would be a pity to have to > > change that because of your argument that attachment links aren't > > "core" enough to be mentioned in org-element.el. > > I strongly insist that it should be removed. I gave you ways to solve > the issue. If you need anything else, let me know, but please consider > implementing them. In the end, I don't think I can roll back that change without breaking attachment links. For the reasons I've given below. I'm not trying to strong-arm anything here. /G ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-13 22:07 ` Gustav Wikström 2020-02-14 0:16 ` Nicolas Goaziou @ 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 2 siblings, 2 replies; 113+ messages in thread From: Kyle Meyer @ 2020-02-14 2:42 UTC (permalink / raw) To: Gustav Wikström, Nicolas Goaziou Cc: Bastien Guerry, emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: >> Gustav Wikström <gustav@whil.se> writes: >> >> > Ah, you mean the reference on line 3216. No, I don't think it can be >> > removed. And I honestly don't think it should be either. It's there to >> > let attachment links mirror the peculiarities of file links. It's >> > needed for feature compatibility. I don't see the issue with that. >> > It's a core link type and it needs the information. That particular >> > logic doesn't affect the parse tree. It's there only to give >> > attachment links the same properties as file links. >> >> I disagree. This is not a core link type. The issue is that the parser >> should self-contained. Please use a different way to obtain the >> information; we already discussed it and suggested multiple solutions. > > Maybe time for Bastien to step in. Because I can't remove the > reference to attachment in org-element.el without breaking it's > functionality. Which, btw, was broken before adding the reference in > org-element.el. The thing that started this discussion in the first > place. We're in a better place now. It seems unfair to say you can't remove it because it would break functionality. You committed 20d293b4a (Give link parser knowledge of attachment link expanded path, 2020-01-18) without posting it to the list [0] and giving Nicolas a chance to comment, which you've agreed was too hasty [1]. Misjudging the situation is of course okay, but please don't use that as a reason to keep a change that would not have landed if you had submitted it for discussion. [0]: https://lists.gnu.org/archive/html/emacs-orgmode/2020-01/msg00155.html [1]: https://lists.gnu.org/archive/html/emacs-orgmode/2020-01/msg00162.html ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-14 2:42 ` Kyle Meyer @ 2020-02-14 7:35 ` Gustav Wikström 2020-02-14 7:41 ` Gustav Wikström 1 sibling, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2020-02-14 7:35 UTC (permalink / raw) To: Kyle Meyer, Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Kyle Meyer <kyle@kyleam.com> > Sent: den 14 februari 2020 03:42 > To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou > <mail@nicolasgoaziou.fr> > Cc: Bastien Guerry <bzg@gnu.org>; emacs-orgmode@gnu.org > Subject: RE: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > >> Gustav Wikström <gustav@whil.se> writes: > >> > >> > Ah, you mean the reference on line 3216. No, I don't think it can > >> > be removed. And I honestly don't think it should be either. It's > >> > there to let attachment links mirror the peculiarities of file > >> > links. It's needed for feature compatibility. I don't see the > issue with that. > >> > It's a core link type and it needs the information. That > particular > >> > logic doesn't affect the parse tree. It's there only to give > >> > attachment links the same properties as file links. > >> > >> I disagree. This is not a core link type. The issue is that the > >> parser should self-contained. Please use a different way to obtain > >> the information; we already discussed it and suggested multiple > solutions. > > > > Maybe time for Bastien to step in. Because I can't remove the > > reference to attachment in org-element.el without breaking it's > > functionality. Which, btw, was broken before adding the reference in > > org-element.el. The thing that started this discussion in the first > > place. We're in a better place now. > > It seems unfair to say you can't remove it because it would break > functionality. You committed 20d293b4a (Give link parser knowledge of > attachment link expanded path, 2020-01-18) without posting it to the > list [0] and giving Nicolas a chance to comment, which you've agreed > was too hasty [1]. Misjudging the situation is of course okay, but > please don't use that as a reason to keep a change that would not have > landed if you had submitted it for discussion. > > [0]: https://lists.gnu.org/archive/html/emacs-orgmode/2020- > 01/msg00155.html > [1]: https://lists.gnu.org/archive/html/emacs-orgmode/2020- > 01/msg00162.html Just a short note before leaving for work. I'm not trying to strong-arm anything here. I'm just saying I don't think it's possible to remove the reference without breaking functionality. The changes discussed in [0] and [1] are in my opinion removed already. The reference to attachment we're talking about here is something else. This string reference is not a change in the design of org-element.el for links. The other was. And that's rolled back. I'm sorry if this is perceived as disingenuous and being done with a bad agenda. It's not. It's a discussion about design. Yes, we disagree about some things. Nothing strange there. Let's talk it out and try to find the middle ground. Which is what's going on. I'll respect the direction given by the better Org moders out there. But in this case I'm simply stating that the principles that needs to apply according to Nicolas will either break attachment link functionality (it was broken before my change in 20d293b4a) or require quite some thinking and/or code duplication in org-attach.el to get it right. And I don't have the capacity for that redesign. Rolling back the change to a broken state is ofc. still possible, but that is more of a regression in my mind than the string-reference to attachment link types in org-element.el. Which is why I think it's a decision for the maintainer of the project to step in and say if it's fine to have broken attachment links, or if it's fine to let attachment be used the way it is on line 3216 in org-element.el, while there is hard-coded logic for file links the way it is on that line today. Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-14 2:42 ` Kyle Meyer 2020-02-14 7:35 ` Gustav Wikström @ 2020-02-14 7:41 ` Gustav Wikström 1 sibling, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2020-02-14 7:41 UTC (permalink / raw) To: Kyle Meyer, Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Btw, the change 20d293b4a was done after a filed bug report. Maybe should be mentioned as well. The change was not something I just felt like doing just for the fun of it. Regards G > -----Original Message----- > From: Kyle Meyer <kyle@kyleam.com> > Sent: den 14 februari 2020 03:42 > To: Gustav Wikström <gustav@whil.se>; Nicolas Goaziou > <mail@nicolasgoaziou.fr> > Cc: Bastien Guerry <bzg@gnu.org>; emacs-orgmode@gnu.org > Subject: RE: attachment: link type export to HTML invalid attach dir > > Gustav Wikström <gustav@whil.se> writes: > > >> Gustav Wikström <gustav@whil.se> writes: > >> > >> > Ah, you mean the reference on line 3216. No, I don't think it can > >> > be removed. And I honestly don't think it should be either. It's > >> > there to let attachment links mirror the peculiarities of file > >> > links. It's needed for feature compatibility. I don't see the > issue with that. > >> > It's a core link type and it needs the information. That > particular > >> > logic doesn't affect the parse tree. It's there only to give > >> > attachment links the same properties as file links. > >> > >> I disagree. This is not a core link type. The issue is that the > >> parser should self-contained. Please use a different way to obtain > >> the information; we already discussed it and suggested multiple > solutions. > > > > Maybe time for Bastien to step in. Because I can't remove the > > reference to attachment in org-element.el without breaking it's > > functionality. Which, btw, was broken before adding the reference in > > org-element.el. The thing that started this discussion in the first > > place. We're in a better place now. > > It seems unfair to say you can't remove it because it would break > functionality. You committed 20d293b4a (Give link parser knowledge of > attachment link expanded path, 2020-01-18) without posting it to the > list [0] and giving Nicolas a chance to comment, which you've agreed > was too hasty [1]. Misjudging the situation is of course okay, but > please don't use that as a reason to keep a change that would not have > landed if you had submitted it for discussion. > > [0]: https://lists.gnu.org/archive/html/emacs-orgmode/2020- > 01/msg00155.html > [1]: https://lists.gnu.org/archive/html/emacs-orgmode/2020- > 01/msg00162.html ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-13 22:07 ` Gustav Wikström 2020-02-14 0:16 ` Nicolas Goaziou 2020-02-14 2:42 ` Kyle Meyer @ 2020-02-14 11:06 ` Bastien 2020-02-14 17:12 ` Nicolas Goaziou 2 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-14 11:06 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org, Nicolas Goaziou Okay, I've done my home work :) TL;DR: (1) The change is fresh, let's take the time to work together at making it right before 9.4*; (2) the current state with the line 3216 in org-element.el is not okay; (3) let's try implementing what Nicolas suggests wrt to attachment=>file link resolution. * Sorry that I rushed you into having this discussion by announcing the release with such a short notice, I should have seen this was not resolve. Now into more details. - The new feature for attachments is nice and useful. And I'm quite happy Gustav is now more acquainted with org-element.el -- we need more people with a good knowledge of that core file (thanks!) - My definition of Org core link types = the minimal set of types to which other types can be translated to. Given this definition, an attachment is not a core link type as it can resolve to file type. - org-element.el should only know about core link types. - Link type resolution should happen at exporting time: I think the design consistency is worth the potential parsing time cost. - One advantage of this approach (on top of design consistency) is that exporters won't each depend on org-attach.el to deal with file attachments, as they do right now. Now, I'm not sure who wants to try implementing Nicolas suggestion to let ox.el expand attachments into file links: since you both know the issue better than I do, I suggest one of you can try? We are not pressed by time, so whoever has the energy to finish this. Thanks! -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-14 11:06 ` Bastien @ 2020-02-14 17:12 ` Nicolas Goaziou 2020-02-14 20:33 ` Bastien 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-14 17:12 UTC (permalink / raw) To: Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hello, Bastien <bzg@gnu.org> writes: > Now, I'm not sure who wants to try implementing Nicolas suggestion to > let ox.el expand attachments into file links: since you both know the > issue better than I do, I suggest one of you can try? I will try to propose a patch by tomorrow evening. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-14 17:12 ` Nicolas Goaziou @ 2020-02-14 20:33 ` Bastien 2020-02-15 18:08 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-14 20:33 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: >> Now, I'm not sure who wants to try implementing Nicolas suggestion to >> let ox.el expand attachments into file links: since you both know the >> issue better than I do, I suggest one of you can try? > > I will try to propose a patch by tomorrow evening. Thanks! If things are okay, I'll then have some time on sunday to prepare for the release on monday. -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-14 20:33 ` Bastien @ 2020-02-15 18:08 ` Nicolas Goaziou 2020-02-15 23:04 ` Kyle Meyer ` (2 more replies) 0 siblings, 3 replies; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-15 18:08 UTC (permalink / raw) To: Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 1281 bytes --] Hello, Bastien <bzg@gnu.org> writes: >>> Now, I'm not sure who wants to try implementing Nicolas suggestion to >>> let ox.el expand attachments into file links: since you both know the >>> issue better than I do, I suggest one of you can try? >> >> I will try to propose a patch by tomorrow evening. > > Thanks! > > If things are okay, I'll then have some time on sunday to prepare for > the release on monday. This is the first part of the suggested changes. These do not touch attachment modifications, but rather improve the tooling in "ol.el". In a nutshell: `org-link-parameters' accepts a new property, :open, which is like :follow, but function installed there is called with a universal prefix argument. It could replace :follow altogether, but for compatibility reasons, they both live side by side for the moment. Also, :export function is called with a fourth argument, the export info channel. I updated the export back-ends to handle the new signature, and provided a compatibility layers for link libraries in the wild, which may still use three arguments. There are two new tools: `org-link-open-as-file' and `org-export-link-as-file'. They can be used as helper functions for, respectively, :open and :export functions. WDYT? Regards, -- Nicolas Goaziou [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Patch 1 --] [-- Type: text/x-diff, Size: 16544 bytes --] From 59172eb6c5edd5e74a6fd248e975065437bf5072 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou <mail@nicolasgoaziou.fr> Date: Fri, 14 Feb 2020 10:00:15 +0100 Subject: [PATCH 1/2] Extend export tooling in link parameters * lisp/ol.el (org-link-parameters): Allow a fourth "info" argument for `:export' property. Expound docstring. * lisp/ox.el (org-export-custom-protocol-maybe): Accept a fourth optional argument. * lisp/ox-ascii.el (org-ascii--describe-links): (org-ascii-link): * lisp/ox-beamer.el (org-beamer-link): * lisp/ox-html.el (org-html-link): * lisp/ox-latex.el (org-latex-link): * lisp/ox-man.el (org-man-link): * lisp/ox-md.el (org-md-link): * lisp/ox-odt.el (org-odt-link): * lisp/ox-org.el (org-org-link): * lisp/ox-texinfo.el (org-texinfo-link): * contrib/lisp/ox-groff.el (org-groff-link): Provide expected fourth argument. * lisp/ox.el (org-export-link-as-file): New function. * lisp/ol.el (org-link-parameters): Add reference to new function in docstring. * testing/lisp/test-ox.el (test-org-export/link-as-file): Add tests. (test-org-export/custom-protocol-maybe): Update tests. --- contrib/lisp/ox-groff.el | 2 +- lisp/ol.el | 99 ++++++++++++++++++++++++++++++---------- lisp/ox-ascii.el | 4 +- lisp/ox-beamer.el | 2 +- lisp/ox-html.el | 2 +- lisp/ox-latex.el | 2 +- lisp/ox-man.el | 4 +- lisp/ox-md.el | 2 +- lisp/ox-odt.el | 2 +- lisp/ox-org.el | 4 +- lisp/ox-texinfo.el | 2 +- lisp/ox.el | 37 +++++++++++---- testing/lisp/test-ox.el | 32 +++++++++++-- 13 files changed, 146 insertions(+), 48 deletions(-) diff --git a/contrib/lisp/ox-groff.el b/contrib/lisp/ox-groff.el index 9f7d3f11f..9f0a32432 100644 --- a/contrib/lisp/ox-groff.el +++ b/contrib/lisp/ox-groff.el @@ -1248,7 +1248,7 @@ INFO is a plist holding contextual information. See ((string= type "file") (org-export-file-uri raw-path)) (t raw-path)))) (cond - ((org-export-custom-protocol-maybe link desc 'groff)) + ((org-export-custom-protocol-maybe link desc 'groff info)) ;; Image file. (imagep (org-groff-link--inline-image link info)) ;; import groff files diff --git a/lisp/ol.el b/lisp/ol.el index ce53b3e69..f850a5313 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -86,42 +86,93 @@ :group 'org) (defcustom org-link-parameters nil - "An alist of properties that defines all the links in Org mode. + "Alist of properties that defines all the links in Org mode. + The key in each association is a string of the link type. -Subsequent optional elements make up a plist of link properties. +Subsequent optional elements make up a property list for that +type. + +All properties ar optional. However, the most important ones +are, in this order, `:follow', `:export', and `:store', described +below. + +`:follow' + + Function that takes the link path (a string) as an argument and + \"opens\" the link. + +`:export' + + Function that accepts three mandatory arguments : + - the path, as a string, + - the description as a string, or nil, + - the export back-end. + + Optionally, it may accept the export communication channel as + a fourth argument, in case you need using Org Export tooling, + e.g., `org-export-link-as-file'. + + When nil, export for that type of link is delegated to the + back-end. + +`:store' + + Function responsible for storing the link. See the function + `org-store-link-functions' for a description of the expected + arguments. + +Additional properties provide more specific control over the +link. + +`:activate-func' + + Function to run at the end of Font Lock activation. It must + accept four arguments: + - the buffer position at the start of the link, + - the buffer position at its end, + - the path, as a string, + - a boolean, non-nil when the link has brackets. + +`:complete' + + Function that inserts a link with completion. The function + takes one optional prefix argument. + +`:display' + + Value for `invisible' text property on the hidden parts of the + link. The most useful value is `full', which will not fold the + link in descriptive display. Default is `org-link'. + +`:face' -:follow - A function that takes the link path as an argument. + Face for the link, or a function returning a face. The + function takes one argument, which is the path. -:export - A function that takes the link path, description and -export-backend as arguments. + The default face is `org-link'. -:store - A function responsible for storing the link. See the -function `org-store-link-functions'. +`:help-echo' -:complete - A function that inserts a link with completion. The -function takes one optional prefix argument. + String or function used as a value for the `help-echo' text + property. The function is called with one argument, the help + string to display, and should return a string. -:face - A face for the link, or a function that returns a face. -The function takes one argument which is the link path. The -default face is `org-link'. +`:htmlize-link' -:mouse-face - The mouse-face. The default is `highlight'. + Function or plist for the `htmlize-link' text property. The + function takes no argument. -:display - `full' will not fold the link in descriptive -display. Default is `org-link'. + Default is (:uri \"type:path\") -:help-echo - A string or function that takes (window object position) -as arguments and returns a string. +`:keymap' -:keymap - A keymap that is active on the link. The default is -`org-mouse-map'. + Active keymap when point is on the link. Default is + `org-mouse-map'. -:htmlize-link - A function for the htmlize-link. Defaults -to (list :uri \"type:path\") +`:mouse-face' -:activate-func - A function to run at the end of font-lock -activation. The function must accept (link-start link-end path bracketp) -as arguments." + Face used when hovering over the link. Default is + `highlight'." :group 'org-link :package-version '(Org . "9.1") :type '(alist :tag "Link display parameters" diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 4ffb44a97..dc9846647 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -957,7 +957,7 @@ channel." ((not (org-element-contents link)) nil) ;; Do not add a link already handled by custom export ;; functions. - ((org-export-custom-protocol-maybe link anchor 'ascii) nil) + ((org-export-custom-protocol-maybe link anchor 'ascii info) nil) (t (concat (org-ascii--fill-string @@ -1578,7 +1578,7 @@ INFO is a plist holding contextual information." (concat type ":" raw-path)) (t (concat type ":" raw-path))))) (cond - ((org-export-custom-protocol-maybe link desc 'ascii)) + ((org-export-custom-protocol-maybe link desc 'ascii info)) ((string= type "coderef") (format (org-export-get-coderef-format path desc) (org-export-resolve-coderef path info))) diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 23656db44..66589fac5 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -731,7 +731,7 @@ channel." "Transcode a LINK object into Beamer code. CONTENTS is the description part of the link. INFO is a plist used as a communication channel." - (or (org-export-custom-protocol-maybe link contents 'beamer) + (or (org-export-custom-protocol-maybe link contents 'beamer info) ;; Fall-back to LaTeX export. However, prefer "\hyperlink" over ;; "\hyperref" since the former handles overlay specifications. (let ((latex-link (org-export-with-backend 'latex link contents info))) diff --git a/lisp/ox-html.el b/lisp/ox-html.el index ea6aa63c3..1ce41ee1a 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -3054,7 +3054,7 @@ INFO is a plist holding contextual information. See (if (org-string-nw-p attr) (concat " " attr) "")))) (cond ;; Link type is handled by a special function. - ((org-export-custom-protocol-maybe link desc 'html)) + ((org-export-custom-protocol-maybe link desc 'html info)) ;; Image file. ((and (plist-get info :html-inline-images) (org-export-inline-image-p diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 1361f336c..bf242db08 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -2537,7 +2537,7 @@ INFO is a plist holding contextual information. See raw-path))))) (cond ;; Link type is handled by a special function. - ((org-export-custom-protocol-maybe link desc 'latex)) + ((org-export-custom-protocol-maybe link desc 'latex info)) ;; Image file. (imagep (org-latex--inline-image link info)) ;; Radio link: Transcode target's contents and use them as link's diff --git a/lisp/ox-man.el b/lisp/ox-man.el index b6925c696..dce11f450 100644 --- a/lisp/ox-man.el +++ b/lisp/ox-man.el @@ -603,7 +603,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;;; Link -(defun org-man-link (link desc _info) +(defun org-man-link (link desc info) "Transcode a LINK object from Org to Man. DESC is the description part of the link, or the empty string. @@ -623,7 +623,7 @@ INFO is a plist holding contextual information. See (t raw-path)))) (cond ;; Link type is handled by a special function. - ((org-export-custom-protocol-maybe link desc 'man)) + ((org-export-custom-protocol-maybe link desc 'man info)) ;; External link with a description part. ((and path desc) (format "%s \\fBat\\fP \\fI%s\\fP" path desc)) ;; External link without a description part. diff --git a/lisp/ox-md.el b/lisp/ox-md.el index 7515df3a2..0e2559afe 100644 --- a/lisp/ox-md.el +++ b/lisp/ox-md.el @@ -412,7 +412,7 @@ INFO is a plist holding contextual information. See (t raw-path)))) (cond ;; Link type is handled by a special function. - ((org-export-custom-protocol-maybe link desc 'md)) + ((org-export-custom-protocol-maybe link desc 'md info)) ((member type '("custom-id" "id" "fuzzy")) (let ((destination (if (string= type "fuzzy") (org-export-resolve-fuzzy-link link info) diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el index 49e37cc1d..64bb97811 100644 --- a/lisp/ox-odt.el +++ b/lisp/ox-odt.el @@ -2715,7 +2715,7 @@ INFO is a plist holding contextual information. See (path (replace-regexp-in-string "&" "&" path))) (cond ;; Link type is handled by a special function. - ((org-export-custom-protocol-maybe link desc 'odt)) + ((org-export-custom-protocol-maybe link desc 'odt info)) ;; Image file. ((and (not desc) imagep) (org-odt-link--inline-image link info)) ;; Formula file. diff --git a/lisp/ox-org.el b/lisp/ox-org.el index 97d8d0e92..740419e0e 100644 --- a/lisp/ox-org.el +++ b/lisp/ox-org.el @@ -165,11 +165,11 @@ CONTENTS is nil. INFO is ignored." '("AUTHOR" "CREATOR" "DATE" "EMAIL" "OPTIONS" "TITLE")) (org-element-keyword-interpreter keyword nil)))) -(defun org-org-link (link contents _info) +(defun org-org-link (link contents info) "Transcode LINK object back into Org syntax. CONTENTS is the description of the link, as a string, or nil. INFO is a plist containing current export state." - (or (org-export-custom-protocol-maybe link contents 'org) + (or (org-export-custom-protocol-maybe link contents 'org info) (org-element-link-interpreter link contents))) (defun org-org-template (contents info) diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el index 89c6746d8..50d131fed 100644 --- a/lisp/ox-texinfo.el +++ b/lisp/ox-texinfo.el @@ -1064,7 +1064,7 @@ INFO is a plist holding contextual information. See (org-export-file-uri raw-path)) (t raw-path)))) (cond - ((org-export-custom-protocol-maybe link desc 'texinfo)) + ((org-export-custom-protocol-maybe link desc 'texinfo info)) ((org-export-inline-image-p link org-texinfo-inline-image-rules) (org-texinfo--inline-image link info)) ((equal type "radio") diff --git a/lisp/ox.el b/lisp/ox.el index b5cf9cc73..260efecba 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4185,8 +4185,23 @@ meant to be translated with `org-export-data' or alike." (org-define-error 'org-link-broken "Unable to resolve link; aborting") -(defun org-export-custom-protocol-maybe (link desc backend) - "Try exporting LINK with a dedicated function. +(defun org-export-link-as-file (path description backend info) + "Pretend PATH is a file name, and export it. + +DESCRIPTION, when non-nil, is the description of the link, as +a string. BACKEND is the symbol representing the back-end used +for export. INFO is the communication channel, as a plist. + +This function is meant to be used as a possible tool for +`:export' property in `org-link-parameters'." + (org-export-data-with-backend + (org-element-parse-secondary-string + (org-link-make-string (concat "file:" path) description) '(link)) + backend + info)) + +(defun org-export-custom-protocol-maybe (link desc backend &optional info) + "Try exporting LINK object with a dedicated function. DESC is its description, as a string, or nil. BACKEND is the back-end used for export, as a symbol. @@ -4197,14 +4212,20 @@ A custom protocol has precedence over regular back-end export. The function ignores links with an implicit type (e.g., \"custom-id\")." (let ((type (org-element-property :type link))) - (unless (or (member type '("coderef" "custom-id" "fuzzy" "radio")) + (unless (or (member type '("coderef" "custom-id" "fuzzy" "radio" nil)) (not backend)) - (let ((protocol (org-link-get-parameter type :export))) + (let ((protocol (org-link-get-parameter type :export)) + (path (org-element-property :path link))) (and (functionp protocol) - (funcall protocol - (org-element-property :path link) - desc - backend)))))) + (condition-case nil + (funcall protocol path desc backend info) + ;; XXX: The function used (< Org 9.4) to accept only + ;; three mandatory arguments. Type-specific `:export' + ;; functions in the wild may not handle current + ;; signature. Provide backward compatibility support + ;; for them. + (wrong-number-of-arguments + (funcall protocol path desc backend)))))))) (defun org-export-get-coderef-format (path desc) "Return format string for code reference link. diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index 29916b4f6..551d9b717 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -2965,6 +2965,32 @@ Para2" \f ;;; Links +(ert-deftest test-org-export/link-as-file () + "Test `org-export-link-as-file' specifications." + ;; Export path as a "file"-type link. + (should + (equal "success" + (let ((backend + (org-export-create-backend + :name 'test + :transcoders + '((link . (lambda (l _c _i) + (if (equal "file" (org-element-property :type l)) + "success" + "failure"))))))) + (org-export-link-as-file "foo.org" nil backend nil)))) + ;; Exported path handles "file"-type specific properties, + ;; e.g., :search-option. + (should + (equal "bar" + (let ((backend + (org-export-create-backend + :name 'test + :transcoders + '((link . (lambda (l _c _i) + (org-element-property :search-option l))))))) + (org-export-link-as-file "foo.org::bar" nil backend nil))))) + (ert-deftest test-org-export/custom-protocol-maybe () "Test `org-export-custom-protocol-maybe' specifications." (should @@ -2980,7 +3006,7 @@ Para2" '((section . (lambda (s c i) c)) (paragraph . (lambda (p c i) c)) (link . (lambda (l c i) - (or (org-export-custom-protocol-maybe l c 'test) + (or (org-export-custom-protocol-maybe l c 'test i) "failure"))))))))) (should-not (string-match @@ -2996,7 +3022,7 @@ Para2" '((section . (lambda (s c i) c)) (paragraph . (lambda (p c i) c)) (link . (lambda (l c i) - (or (org-export-custom-protocol-maybe l c 'no-test) + (or (org-export-custom-protocol-maybe l c 'no-test i) "failure"))))))))) ;; Ignore anonymous back-ends. (should-not @@ -3012,7 +3038,7 @@ Para2" '((section . (lambda (s c i) c)) (paragraph . (lambda (p c i) c)) (link . (lambda (l c i) - (or (org-export-custom-protocol-maybe l c nil) + (or (org-export-custom-protocol-maybe l c nil i) "failure")))))))))) (ert-deftest test-org-export/get-coderef-format () -- 2.25.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: Patch 2 --] [-- Type: text/x-diff, Size: 5056 bytes --] From 371a3294887cdb714aff14494c5286a19524c807 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou <mail@nicolasgoaziou.fr> Date: Sat, 15 Feb 2020 17:31:34 +0100 Subject: [PATCH 2/2] ol: Extend open tooling in link parameters * lisp/ol.el (org-link-parameters): Add :open parameter. (org-link-open): Call custom-link functions after internal ones. (org-link-open-as-file): New function. (org-link-parameters): Reference new function. (org-link-open): Use new function. --- lisp/ol.el | 75 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/lisp/ol.el b/lisp/ol.el index f850a5313..710947c92 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -93,13 +93,21 @@ Subsequent optional elements make up a property list for that type. All properties ar optional. However, the most important ones -are, in this order, `:follow', `:export', and `:store', described -below. +are, in this order, `:open' (or `:follow'), `:export', and +`:store', described below. +`:open' `:follow' - Function that takes the link path (a string) as an argument and - \"opens\" the link. + Function used to follow the link, when `org-open-at-point' is + command runs on it. + + The function stored in `:open' is called with two arguments: + the path, as a string, and a universal prefix argument, whereas + the one stored in `:follow' is called with the path only. + + You may use `org-link-open-as-file' helper function for types + similar to \"file\". `:export' @@ -990,37 +998,14 @@ for internal and \"file\" links, or stored as a parameter in (let ((type (org-element-property :type link)) (path (org-element-property :path link))) (cond + ;; Opening a "file" link requires special treatment since we + ;; first need to integrate search option, if any. ((member type '("file" "attachment")) (when (string= type "attachment") (setq path (org-attach-link-expand link))) - (if (string-match "[*?{]" (file-name-nondirectory path)) - (dired path) - ;; Look into `org-link-parameters' in order to find - ;; a DEDICATED-FUNCTION to open file. The function will be - ;; applied on raw link instead of parsed link due to the - ;; limitation in `org-add-link-type' ("open" function called - ;; with a single argument). If no such function is found, - ;; fallback to `org-open-file'. - (let* ((option (org-element-property :search-option link)) - (app (org-element-property :application link)) - (dedicated-function - (org-link-get-parameter (if app (concat type "+" app) type) - :follow))) - (if dedicated-function - (funcall dedicated-function - (concat path - (and option (concat "::" option)))) - (apply #'org-open-file - path - (cond (arg) - ((equal app "emacs") 'emacs) - ((equal app "sys") 'system)) - (cond ((not option) nil) - ((string-match-p "\\`[0-9]+\\'" option) - (list (string-to-number option))) - (t (list nil option)))))))) - ((functionp (org-link-get-parameter type :follow)) - (funcall (org-link-get-parameter type :follow) path)) + (let* ((option (org-element-property :search-option link)) + (path (if option (concat path "::" option) path))) + (org-link-open-as-file path arg))) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (unless (run-hook-with-args-until-success 'org-open-link-functions path) (if (not arg) (org-mark-ring-push) @@ -1042,6 +1027,10 @@ for internal and \"file\" links, or stored as a parameter in (>= (point-max) destination)) (widen)) (goto-char destination)))) + ((functionp (org-link-get-parameter type :open)) + (funcall (org-link-get-parameter type :open) path arg)) + ((functionp (org-link-get-parameter type :follow)) + (funcall (org-link-get-parameter type :follow) path)) (t (browse-url-at-point))))) (defun org-link-open-from-string (s &optional arg) @@ -1240,6 +1229,28 @@ of matched result, which is either `dedicated' or `fuzzy'." (reverse slines))) "\n"))))) (mapconcat #'identity (split-string s) " "))) +(defun org-link-open-as-file (path arg) + "Pretend PATH is a file name and open it. + +According to \"file\"-link syntax, PATH may include addition +search options, separated from the file name with \"::\". + +This function is meant to be used as a possible tool for `:open' +property in `org-link-parameters.'" + (if (string-match "[*?{]" (file-name-nondirectory path)) + (dired path) + (let* ((option (and (string-match "::\\(.*\\)\\'" path) + (match-string 1 path))) + (path (if (not option) path + (substring path 0 (match-beginning 0))))) + (apply #'org-open-file + path + arg + (cond ((not option) nil) + ((string-match-p "\\`[0-9]+\\'" option) + (list (string-to-number option))) + (t (list nil option))))))) + (defun org-link-display-format (s) "Replace links in string S with their description. If there is no description, use the link target." -- 2.25.0 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 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:58 ` Bastien 2020-02-20 9:20 ` Nicolas Goaziou 2 siblings, 1 reply; 113+ messages in thread From: Kyle Meyer @ 2020-02-15 23:04 UTC (permalink / raw) To: Nicolas Goaziou, Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > In a nutshell: > > `org-link-parameters' accepts a new property, :open, which is > like :follow, but function installed there is called with a universal > prefix argument. It could replace :follow altogether, but for > compatibility reasons, they both live side by side for the moment. > > Also, :export function is called with a fourth argument, the export info > channel. I updated the export back-ends to handle the new signature, and > provided a compatibility layers for link libraries in the wild, which > may still use three arguments. > > There are two new tools: `org-link-open-as-file' and > `org-export-link-as-file'. They can be used as helper functions for, > respectively, :open and :export functions. > > WDYT? It looks like a good direction to go. > Subject: [PATCH 1/2] Extend export tooling in link parameters [...] > (defcustom org-link-parameters nil > - "An alist of properties that defines all the links in Org mode. > + "Alist of properties that defines all the links in Org mode. > + [...] > +`:export' > + > + Function that accepts three mandatory arguments : nit: extra space before colon > + Optionally, it may accept the export communication channel as > + a fourth argument, in case you need using Org Export tooling, s/need using/need to use/ ? > Subject: [PATCH 2/2] ol: Extend open tooling in link parameters [...] > - Function that takes the link path (a string) as an argument and > - \"opens\" the link. > + Function used to follow the link, when `org-open-at-point' is > + command runs on it. Delete "is"? (Also, assuming the "is" is dropped, to my ears it'd read better with a "the" in front of org-open-at-point.) > [ @@ -990,37 +998,14 @@ (defun org-link-open (link &optional arg) ] > - (if (string-match "[*?{]" (file-name-nondirectory path)) > - (dired path) > - ;; Look into `org-link-parameters' in order to find > - ;; a DEDICATED-FUNCTION to open file. The function will be > - ;; applied on raw link instead of parsed link due to the > - ;; limitation in `org-add-link-type' ("open" function called > - ;; with a single argument). If no such function is found, > - ;; fallback to `org-open-file'. > - (let* ((option (org-element-property :search-option link)) > - (app (org-element-property :application link)) > - (dedicated-function > - (org-link-get-parameter (if app (concat type "+" app) type) > - :follow))) As far as I can see (by looking at the diff and quickly testing), the file+{sys,emacs} functionality is being removed. That's probably okay/intended, given that it was marked as deprecated in 9.0. But perhaps it's worth mentioning in ORG-NEWS that this functionality has now been removed entirely. > +(defun org-link-open-as-file (path arg) > + "Pretend PATH is a file name and open it. > + > +According to \"file\"-link syntax, PATH may include addition s/addition/additional/ > +search options, separated from the file name with \"::\". > + > +This function is meant to be used as a possible tool for `:open' > +property in `org-link-parameters.'" nit: I think the period should go after the quote (regardless of the strange preference in American English to put commas and periods within quotes). ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-15 23:04 ` Kyle Meyer @ 2020-02-16 8:51 ` Nicolas Goaziou 2020-02-16 23:59 ` Bastien 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-16 8:51 UTC (permalink / raw) To: Kyle Meyer; +Cc: Bastien, Gustav Wikström, emacs-orgmode@gnu.org Hello, Kyle Meyer <kyle@kyleam.com> writes: > It looks like a good direction to go. Thank you for the feedback! I fixed the various typos you mentioned. > As far as I can see (by looking at the diff and quickly testing), the > file+{sys,emacs} functionality is being removed. That's probably > okay/intended, given that it was marked as deprecated in 9.0. But > perhaps it's worth mentioning in ORG-NEWS that this functionality has > now been removed entirely. Good catch! That is subconscious, actually. I considered removing them, then hesitated, and it all ended up in an intermediate state. Removing it properly would require to remove :application property in the parser, too. At some point, this functionality needs to go, but it is not necessarily now. I can add it back if needed. Otherwise, I will remove it completely in a subsequent patch. Removing this feature may not break existing documents, however. Indeed, with the suggested tooling, we may simply make "file+sys" and "file+emacs" aliases for "file" in "org-compat.el". IOW, they would do nothing more than regular file links, except maybe send an obnoxious message to the user (linter already does this). I didn't write the required ORG-NEWS entry because we are not settled on the final design. I agree all the changes discussed here have to be mentioned in that file. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-16 8:51 ` Nicolas Goaziou @ 2020-02-16 23:59 ` Bastien 2020-02-17 9:37 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-16 23:59 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org, Gustav Wikström Hi Nicolas, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > That is subconscious, actually. I considered removing them, > then hesitated, and it all ended up in an intermediate state. Removing > it properly would require to remove :application property in the parser, > too. At some point, this functionality needs to go, but it is not > necessarily now. FWIW, I'm for delaying the removal for 9.5, not 9.4. -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-16 23:59 ` Bastien @ 2020-02-17 9:37 ` Nicolas Goaziou 2020-02-17 10:25 ` Bastien 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-17 9:37 UTC (permalink / raw) To: Bastien; +Cc: emacs-orgmode@gnu.org, Gustav Wikström Hello, Bastien <bzg@gnu.org> writes: > FWIW, I'm for delaying the removal for 9.5, not 9.4. Sure, I added it back. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-17 9:37 ` Nicolas Goaziou @ 2020-02-17 10:25 ` Bastien 0 siblings, 0 replies; 113+ messages in thread From: Bastien @ 2020-02-17 10:25 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: >> FWIW, I'm for delaying the removal for 9.5, not 9.4. > > Sure, I added it back. Thanks! -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-15 18:08 ` Nicolas Goaziou 2020-02-15 23:04 ` Kyle Meyer @ 2020-02-16 23:58 ` Bastien 2020-02-17 10:32 ` Nicolas Goaziou 2020-02-20 9:20 ` Nicolas Goaziou 2 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-16 23:58 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hi Nicolas, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > This is the first part of the suggested changes. These do not touch > attachment modifications, but rather improve the tooling in "ol.el". Thanks for working on this--and Kyle for the careful review. > `org-link-parameters' accepts a new property, :open, which is > like :follow, but function installed there is called with a universal > prefix argument. I'm not sure why the distinction between :open and :follow is needed in the context of the discussion for exporting attachments: is it because attachment need to be "open", not just followed? > Also, :export function is called with a fourth argument, the export info > channel. I updated the export back-ends to handle the new signature, and > provided a compatibility layers for link libraries in the wild, which > may still use three arguments. > > There are two new tools: `org-link-open-as-file' and > `org-export-link-as-file'. They can be used as helper functions for, > respectively, :open and :export functions. > WDYT? LGTM, feel free to go ahead when you want. Thanks, -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-16 23:58 ` Bastien @ 2020-02-17 10:32 ` Nicolas Goaziou 2020-02-17 10:53 ` Bastien 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-17 10:32 UTC (permalink / raw) To: Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hello, Bastien <bzg@gnu.org> writes: > I'm not sure why the distinction between :open and :follow is needed > in the context of the discussion for exporting attachments: is it > because attachment need to be "open", not just followed? The motivation is that the new behaviour for `:follow' is not compatible with the previous one, since the signature changed. So, we have two options: either we write a workaround, as is done for :export (i.e., `condition-case' with `wrong-number-of-arguments'), or we add new keywords so old code still works during transition. Thinking about it, we can stick to a single solution, e.g., the `condition-case' workaround. Therefore we do not need to introduce a new keyword. However, all "ol-" libraries need to be updated. I'll do that instead. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-17 10:32 ` Nicolas Goaziou @ 2020-02-17 10:53 ` Bastien 0 siblings, 0 replies; 113+ messages in thread From: Bastien @ 2020-02-17 10:53 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hi Nicolas, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > Thinking about it, we can stick to a single solution, e.g., the > `condition-case' workaround. Therefore we do not need to introduce a new > keyword. However, all "ol-" libraries need to be updated. I think the release of 9.4 is an important one, so it's probably a good time to advertize changes that may break existing ol-* libraries that we are not aware of -- provided we clearly explain what needs to be changed, of course. > I'll do that instead. Thanks, -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-15 18:08 ` Nicolas Goaziou 2020-02-15 23:04 ` Kyle Meyer 2020-02-16 23:58 ` Bastien @ 2020-02-20 9:20 ` Nicolas Goaziou 2020-02-20 10:20 ` Bastien 2 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-20 9:20 UTC (permalink / raw) To: Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 1014 bytes --] Following up, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > This is the first part of the suggested changes. These do not touch > attachment modifications, but rather improve the tooling in "ol.el". This second patch removes most of the "attachment" leakage in the code base (mainly "org-element.el" and "ox-*.el"). The features should be the same as before. Let me know if there's anything wrong. The only thing left is to refactor the ability to display "attachment" links as inline images. For now, this is hard-coded in "org.el", but this should not be the case. As a third phase, I suggest to add a new parameter in `org-link-parameters', for example :inlineable. This parameter would be either a boolean, or a function transforming the path. For example, "file" links should set it to t and "attachment" links to `org-attach-expand'. Then `org-display-inline-images' should collect link types with this flag, apply the transformation, and display images accordingly. Regards, -- Nicolas Goaziou [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: Clear "attachment" leakage --] [-- Type: text/x-diff, Size: 16903 bytes --] From e5ccffcf617f3d04d97840873c0b16913eb65369 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou <mail@nicolasgoaziou.fr> Date: Thu, 20 Feb 2020 09:29:21 +0100 Subject: [PATCH] Do not leak "attachment" links * lisp/ol.el (org-link-open): Remove "attachment" for special cases. * lisp/org-attach.el (org-attach-expand-links): (org-attach-follow): New functions. (org-attach-link-expand): Remove function. * lisp/org-element.el (org-element-link-parser): * lisp/ox-ascii.el (org-ascii-link): * lisp/ox-html.el (org-html-link): * lisp/ox-latex.el (org-latex--inline-image): (org-latex-link): * lisp/ox-man.el (org-man-link): * lisp/ox-md.el (org-md-link): * lisp/ox-odt.el (org-odt-inline-image-rules): (org-odt-link): * lisp/ox-texinfo.el (org-texinfo-inline-image-rules): (org-texinfo-link): Remove "attachment" from special cases. --- lisp/ol.el | 5 +---- lisp/org-attach.el | 45 +++++++++++++++++++++++++++++++-------------- lisp/org-element.el | 10 +++++----- lisp/ox-ascii.el | 23 +++++++++-------------- lisp/ox-html.el | 6 +----- lisp/ox-latex.el | 23 ++++++++--------------- lisp/ox-man.el | 17 ++++++----------- lisp/ox-md.el | 10 ++-------- lisp/ox-odt.el | 11 ++--------- lisp/ox-texinfo.el | 10 +--------- 10 files changed, 66 insertions(+), 94 deletions(-) diff --git a/lisp/ol.el b/lisp/ol.el index 76454d2db..e9bed3972 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -75,7 +75,6 @@ (declare-function org-src-source-type "org-src" ()) (declare-function org-time-stamp-format "org" (&optional long inactive)) (declare-function outline-next-heading "outline" ()) -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) \f ;;; Customization @@ -1027,9 +1026,7 @@ for internal and \"file\" links, or stored as a parameter in (pcase type ;; Opening a "file" link requires special treatment since we ;; first need to integrate search option, if any. - ((or "file" "attachment") - (when (string= type "attachment") - (setq path (org-attach-link-expand link))) + ("file" (let* ((option (org-element-property :search-option link)) (path (if option (concat path "::" option) path))) (org-link-open-as-file path diff --git a/lisp/org-attach.el b/lisp/org-attach.el index d073291a2..97a7236e4 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -41,6 +41,8 @@ (declare-function dired-dwim-target-directory "dired-aux") (declare-function org-element-property "org-element" (property element)) +(declare-function org-element-type "org-element" (element)) +(declare-function org-export-link-as-file "org-export" (path description backend info)) (defgroup org-attach nil "Options concerning attachments in Org mode." @@ -646,22 +648,36 @@ See `org-attach-open'." Basically, this adds the path to the attachment directory." (expand-file-name file (org-attach-dir))) -(defun org-attach-link-expand (link &optional buffer-or-name) - "Return the full path to the attachment in the LINK element. -Takes LINK which is a link element, as defined by -`org-element-link-parser'. If LINK `:type' is attachment the -full path to the attachment is expanded and returned. Otherwise, -return nil. If BUFFER-OR-NAME is specified, LINK is expanded in -that buffer, otherwise current buffer is assumed." - (let ((type (org-element-property :type link)) - (file (org-element-property :path link)) - (pos (org-element-property :begin link))) - (when (string= type "attachment") - (with-current-buffer (or buffer-or-name (current-buffer)) - (goto-char pos) - (org-attach-expand file))))) +(defun org-attach-expand-links (_) + "Expand links in current buffer. +It is meant to be added to `org-export-before-parsing-hook'." + (save-excursion + (while (re-search-forward "attachment:" nil t) + (let ((link (org-element-context))) + (when (and (eq 'link (org-element-type link)) + (string-equal "attachment" + (org-element-property :type link))) + (let* ((description (and (org-element-property :contents-begin link) + (buffer-substring-no-properties + (org-element-property :contents-begin link) + (org-element-property :contents-end link)))) + (file (org-element-property :path link)) + (new-link (org-link-make-string + (concat "attachment:" (org-attach-expand file)) + description))) + (goto-char (org-element-property :end link)) + (skip-chars-backward " \t") + (delete-region (org-element-property :begin link) (point)) + (insert new-link))))))) + +(defun org-attach-follow (file arg) + "Open FILE attachment. +See `org-open-file' for details about ARG." + (org-link-open-as-file (org-attach-expand file) arg)) (org-link-set-parameters "attachment" + :follow #'org-attach-follow + :export #'org-export-link-as-file :complete #'org-attach-complete-link) (defun org-attach-complete-link () @@ -729,6 +745,7 @@ Idea taken from `gnus-dired-attach'." \f (add-hook 'org-archive-hook 'org-attach-archive-delete-maybe) +(add-hook 'org-export-before-parsing-hook 'org-attach-expand-links) (provide 'org-attach) diff --git a/lisp/org-element.el b/lisp/org-element.el index 575a568a2..798c540e9 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -3210,11 +3210,11 @@ Assume point is at the beginning of the link." (setq post-blank (progn (goto-char link-end) (skip-chars-forward " \t"))) (setq end (point))) - ;; Special "file" or "attachment" type link processing. Extract - ;; opening application and search option, if any. Also - ;; normalize URI. - (when (string-match "\\`\\(file\\|attachment\\)\\(?:\\+\\(.+\\)\\)?\\'" type) - (setq application (match-string 2 type) type (match-string 1 type)) + ;; Special "file"-type link processing. Extract opening + ;; application and search option, if any. Also normalize URI. + (when (string-match "\\`file\\(?:\\+\\(.+\\)\\)?\\'" type) + (setq application (match-string 1 type)) + (setq type "file") (when (string-match "::\\(.*\\)\\'" path) (setq search-option (match-string 1 path)) (setq path (replace-match "" nil nil path))) diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 981a7660e..e5240f5c8 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -34,7 +34,6 @@ ;;; Function Declarations (declare-function aa2u "ext:ascii-art-to-unicode" ()) -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) ;;; Define Back-End ;; @@ -1571,18 +1570,13 @@ CONTENTS is nil. INFO is a plist holding contextual DESC is the description part of the link, or the empty string. INFO is a plist holding contextual information." - (let* ((type (org-element-property :type link)) - (raw-path (org-element-property :path link)) - (path (cond - ((string= type "attachment") - (setq raw-path (org-attach-link-expand link)) - (concat type ":" raw-path)) - (t (concat type ":" raw-path))))) + (let ((type (org-element-property :type link))) (cond ((org-export-custom-protocol-maybe link desc 'ascii info)) ((string= type "coderef") - (format (org-export-get-coderef-format path desc) - (org-export-resolve-coderef path info))) + (let ((ref (org-element-property :path link))) + (format (org-export-get-coderef-format ref desc) + (org-export-resolve-coderef ref info)))) ;; Do not apply a special syntax on radio links. Though, use ;; transcoded target's contents as output. ((string= type "radio") desc) @@ -1614,10 +1608,11 @@ INFO is a plist holding contextual information." ;; Don't know what to do. Signal it. (_ "???")))) (t - (if (not (org-string-nw-p desc)) (format "<%s>" path) - (concat (format "[%s]" desc) - (and (not (plist-get info :ascii-links-to-notes)) - (format " (<%s>)" path)))))))) + (let ((path (org-element-property :raw-link link))) + (if (not (org-string-nw-p desc)) (format "<%s>" path) + (concat (format "[%s]" desc) + (and (not (plist-get info :ascii-links-to-notes)) + (format " (<%s>)" path))))))))) ;;;; Node Properties diff --git a/lisp/ox-html.el b/lisp/ox-html.el index e77cd3b12..602c5390c 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -42,7 +42,6 @@ (declare-function org-id-find-id-file "org-id" (id)) (declare-function htmlize-region "ext:htmlize" (beg end)) (declare-function mm-url-decode-entities "mm-url" ()) -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) (defvar htmlize-css-name-prefix) (defvar htmlize-output-type) @@ -814,7 +813,6 @@ link to the image." (defcustom org-html-inline-image-rules `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg"))) - ("attachment" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg"))) ("http" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg"))) ("https" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg")))) "Rules characterizing image files that can be inlined into HTML. @@ -2996,9 +2994,7 @@ INFO is a plist holding contextual information. See (cond ((member type '("http" "https" "ftp" "mailto" "news")) (url-encode-url (concat type ":" raw-path))) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) + ((string= "file" type) ;; During publishing, turn absolute file names belonging ;; to base directory into relative file names. Otherwise, ;; append "file" protocol to absolute file name. diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 6540d1e70..c0af8157d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -32,8 +32,6 @@ ;;; Function Declarations -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) - (defvar org-latex-default-packages-alist) (defvar org-latex-packages-alist) (defvar orgtbl-exp-regexp) @@ -741,8 +739,6 @@ environment." (defcustom org-latex-inline-image-rules `(("file" . ,(regexp-opt - '("pdf" "jpeg" "jpg" "png" "ps" "eps" "tikz" "pgf" "svg"))) - ("attachment" . ,(regexp-opt '("pdf" "jpeg" "jpg" "png" "ps" "eps" "tikz" "pgf" "svg")))) "Rules characterizing image files that can be inlined into LaTeX. @@ -2366,9 +2362,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." LINK is the link pointing to the inline image. INFO is a plist used as a communication channel." (let* ((parent (org-export-get-parent-element link)) - (path (let ((raw-path (if (string= (org-element-property :type link) "attachment") - (org-attach-link-expand link) - (org-element-property :path link)))) + (path (let ((raw-path (org-element-property :path link))) (if (not (file-name-absolute-p raw-path)) raw-path (expand-file-name raw-path)))) (filetype (file-name-extension path)) @@ -2531,14 +2525,13 @@ INFO is a plist holding contextual information. See (imagep (org-export-inline-image-p link (plist-get info :latex-inline-image-rules))) (path (org-latex--protect-text - (cond ((member type '("http" "https" "ftp" "mailto" "doi")) - (concat type ":" raw-path)) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) - (org-export-file-uri raw-path)) - (t - raw-path))))) + (pcase type + ((or "http" "https" "ftp" "mailto" "doi") + (concat type ":" raw-path)) + ("file" + (org-export-file-uri raw-path)) + (_ + raw-path))))) (cond ;; Link type is handled by a special function. ((org-export-custom-protocol-maybe link desc 'latex info)) diff --git a/lisp/ox-man.el b/lisp/ox-man.el index 1de8d522c..0e487d896 100644 --- a/lisp/ox-man.el +++ b/lisp/ox-man.el @@ -42,8 +42,6 @@ ;;; Function Declarations -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) - (defvar org-export-man-default-packages-alist) (defvar org-export-man-packages-alist) (defvar orgtbl-exp-regexp) @@ -610,17 +608,14 @@ DESC is the description part of the link, or the empty string. INFO is a plist holding contextual information. See `org-export-data'." (let* ((type (org-element-property :type link)) - (raw-path (org-element-property :path link)) + (raw-path (org-element-property :path link)) ;; Ensure DESC really exists, or set it to nil. (desc (and (not (string= desc "")) desc)) - (path (cond - ((member type '("http" "https" "ftp" "mailto")) - (concat type ":" raw-path)) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) - (org-export-file-uri raw-path)) - (t raw-path)))) + (path (pcase type + ((or "http" "https" "ftp" "mailto") + (concat type ":" raw-path)) + ("file" (org-export-file-uri raw-path)) + (_ raw-path)))) (cond ;; Link type is handled by a special function. ((org-export-custom-protocol-maybe link desc 'man info)) diff --git a/lisp/ox-md.el b/lisp/ox-md.el index 1933d9e9f..f27645976 100644 --- a/lisp/ox-md.el +++ b/lisp/ox-md.el @@ -33,10 +33,6 @@ (require 'ox-publish) \f -;;; Function Declarations - -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) - ;;; User-Configurable Variables (defgroup org-export-md nil @@ -405,9 +401,7 @@ INFO is a plist holding contextual information. See (path (cond ((member type '("http" "https" "ftp" "mailto")) (concat type ":" raw-path)) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) + ((string-equal type "file") (org-export-file-uri (funcall link-org-files-as-md raw-path))) (t raw-path)))) (cond @@ -449,7 +443,7 @@ INFO is a plist holding contextual information. See description (org-export-get-reference destination info)))))))) ((org-export-inline-image-p link org-html-inline-image-rules) - (let ((path (cond ((not (member type '("file" "attachment"))) + (let ((path (cond ((not (string-equal type "file")) (concat type ":" raw-path)) ((not (file-name-absolute-p raw-path)) raw-path) (t (expand-file-name raw-path)))) diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el index 64bb97811..2723c60c9 100644 --- a/lisp/ox-odt.el +++ b/lisp/ox-odt.el @@ -32,10 +32,6 @@ (require 'ox) (require 'table nil 'noerror) -;;; Function Declarations - -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) - ;;; Define Back-End (org-export-define-backend 'odt @@ -745,8 +741,7 @@ link's path." :value-type (regexp :tag "Path"))) (defcustom org-odt-inline-image-rules - `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg"))) - ("attachment" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg")))) + `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg")))) "Rules characterizing image files that can be inlined into ODT. A rule consists in an association whose key is the type of link @@ -2706,9 +2701,7 @@ INFO is a plist holding contextual information. See (path (cond ((member type '("http" "https" "ftp" "mailto")) (concat type ":" raw-path)) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) + ((string= type "file") (org-export-file-uri raw-path)) (t raw-path))) ;; Convert & to & for correct XML representation diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el index 4e7b575a7..6019eb79b 100644 --- a/lisp/ox-texinfo.el +++ b/lisp/ox-texinfo.el @@ -28,10 +28,6 @@ (require 'cl-lib) (require 'ox) -;;; Function Declarations - -(declare-function org-attach-link-expand "org-attach" (link &optional buffer-or-name)) - (defvar orgtbl-exp-regexp) @@ -407,8 +403,6 @@ If two strings share the same prefix (e.g. \"ISO-8859-1\" and (defconst org-texinfo-inline-image-rules (list (cons "file" - (regexp-opt '("eps" "pdf" "png" "jpg" "jpeg" "gif" "svg"))) - (cons "attachment" (regexp-opt '("eps" "pdf" "png" "jpg" "jpeg" "gif" "svg")))) "Rules characterizing image files that can be inlined.") @@ -1059,9 +1053,7 @@ INFO is a plist holding contextual information. See (path (cond ((member type '("http" "https" "ftp")) (concat type ":" raw-path)) - ((member type '("file" "attachment")) - (when (string= type "attachment") - (setq raw-path (org-attach-link-expand link))) + ((string-equal type "file") (org-export-file-uri raw-path)) (t raw-path)))) (cond -- 2.25.0 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-20 9:20 ` Nicolas Goaziou @ 2020-02-20 10:20 ` Bastien 2020-02-22 12:58 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-20 10:20 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hi Nicolas, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > This second patch removes most of the "attachment" leakage in the code > base (mainly "org-element.el" and "ox-*.el"). The features should be the > same as before. Let me know if there's anything wrong. Thanks a lot -- feel free to apply it when you think it's okay. Also, perhaps can you or Gustav suggest a way to test the new feature so that we can test this new code? > The only thing left is to refactor the ability to display "attachment" > links as inline images. For now, this is hard-coded in "org.el", but > this should not be the case. > > As a third phase, I suggest to add a new parameter in > `org-link-parameters', for example :inlineable. This parameter would be > either a boolean, or a function transforming the path. For example, > "file" links should set it to t and "attachment" links to > `org-attach-expand'. Then `org-display-inline-images' should collect > link types with this flag, apply the transformation, and display images > accordingly. Do you want to do this for 9.4 or can it be done later on? Thanks, -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-20 10:20 ` Bastien @ 2020-02-22 12:58 ` Nicolas Goaziou 2020-02-22 13:32 ` Bastien 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-22 12:58 UTC (permalink / raw) To: Bastien; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hello, Bastien <bzg@gnu.org> writes: > Thanks a lot -- feel free to apply it when you think it's okay. I'd like to hear from Gustav, too, since this affects the changes he introduced. If you are in a hurry, we can also apply it. Up to you. > Also, perhaps can you or Gustav suggest a way to test the new feature > so that we can test this new code? I don't use the feature. I just tried to avoid introducing regressions. It is related to how attachments are opened, and exported. I guess testing should focus on this, in particular export of attached images, i.e., attachements with an image extension. > Do you want to do this for 9.4 or can it be done later on? This can be done later on. I don't have time to work on this. Of course, if someone wants to do it, that would be great, too. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-22 12:58 ` Nicolas Goaziou @ 2020-02-22 13:32 ` Bastien 2020-02-25 23:36 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Bastien @ 2020-02-22 13:32 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hi, Thanks for your answer. Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > I'd like to hear from Gustav, too, since this affects the changes he > introduced. If you are in a hurry, we can also apply it. Up to you. I just applied it - Gustav let us know if it fits your needs and if it does not introduce regressions. >> Do you want to do this for 9.4 or can it be done later on? > > This can be done later on. I don't have time to work on this. Of course, > if someone wants to do it, that would be great, too. Okay, thanks. Noted for Org > 9.4. Best, -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-22 13:32 ` Bastien @ 2020-02-25 23:36 ` Gustav Wikström 2020-02-26 15:22 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-02-25 23:36 UTC (permalink / raw) To: Bastien, Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 2594 bytes --] Hi Bastien and Nicolas, > -----Original Message----- > From: Bastien <bzg@gnu.org> > Sent: den 22 februari 2020 14:32 > To: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Cc: Gustav Wikström <gustav@whil.se>; emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > [...] > > Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > > > I'd like to hear from Gustav, too, since this affects the changes he > > introduced. If you are in a hurry, we can also apply it. Up to you. > > I just applied it - Gustav let us know if it fits your needs and if it > does not introduce regressions. It does work. Thanks. One issue though, with org-attach-expand-links: +(defun org-attach-expand-links (_) + "Expand links in current buffer. +It is meant to be added to `org-export-before-parsing-hook'." + (save-excursion + (while (re-search-forward "attachment:" nil t) + (let ((link (org-element-context))) + (when (and (eq 'link (org-element-type link)) + (string-equal "attachment" + (org-element-property :type link))) + (let* ((description (and (org-element-property :contents-begin link) + (buffer-substring-no-properties + (org-element-property :contents-begin link) + (org-element-property :contents-end link)))) + (file (org-element-property :path link)) + (new-link (org-link-make-string + (concat "attachment:" (org-attach-expand file)) + description))) + (goto-char (org-element-property :end link)) + (skip-chars-backward " \t") + (delete-region (org-element-property :begin link) (point)) Expanding attachment-links in the buffer makes the link type no longer be attachment. I would prefer if we explicitly set the link type to files here instead. Storing intermediate state in an attachment link types makes less sense imo. One issue with the current way it's done is that images are treated differently between attachment links and file links. For HTML exports, file links are wrapped in a div with class figure where expanded attachment links are not. Letting org-attach-expand-links do the full transform to file links would solve that issue. That also means :export is not needed for org-link-set-parameters. Patch attached if you agree to this. > >> Do you want to do this for 9.4 or can it be done later on? > > > > This can be done later on. I don't have time to work on this. Of > > course, if someone wants to do it, that would be great, too. > > Okay, thanks. Noted for Org > 9.4. > > Best, > > -- > Bastien [-- Attachment #2: org-attach.patch --] [-- Type: application/octet-stream, Size: 847 bytes --] diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 97a7236e4..443485ab4 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -663,7 +663,7 @@ It is meant to be added to `org-export-before-parsing-hook'." (org-element-property :contents-end link)))) (file (org-element-property :path link)) (new-link (org-link-make-string - (concat "attachment:" (org-attach-expand file)) + (concat "file:" (org-attach-expand file)) description))) (goto-char (org-element-property :end link)) (skip-chars-backward " \t") @@ -677,7 +677,6 @@ See `org-open-file' for details about ARG." (org-link-set-parameters "attachment" :follow #'org-attach-follow - :export #'org-export-link-as-file :complete #'org-attach-complete-link) (defun org-attach-complete-link () ^ permalink raw reply related [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-25 23:36 ` Gustav Wikström @ 2020-02-26 15:22 ` Nicolas Goaziou 2020-02-27 19:02 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-26 15:22 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien, emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Expanding attachment-links in the buffer makes the link type no longer > be attachment. What makes you think that? The link type is preserved during the substitution, according to the (concat "attachment" ...). > I would prefer if we explicitly set the link type to > files here instead. Storing intermediate state in an attachment link > types makes less sense imo. > > One issue with the current way it's done is that images are treated > differently between attachment links and file links. For HTML exports, > file links are wrapped in a div with class figure where expanded > attachment links are not. It would be nice to investigate why this happens. > Letting org-attach-expand-links do the full > transform to file links would solve that issue. That also > means :export is not needed for org-link-set-parameters. > > Patch attached if you agree to this. Of course! This is what I suggested, like, 6 weeks ago (although, at this time, I was thinking about having the substitution in "ox.el"). Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-26 15:22 ` Nicolas Goaziou @ 2020-02-27 19:02 ` Gustav Wikström 2020-02-28 0:37 ` Nicolas Goaziou 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-02-27 19:02 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Bastien, emacs-orgmode@gnu.org Hello, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 26 februari 2020 16:23 > To: Gustav Wikström <gustav@whil.se> > Cc: Bastien <bzg@gnu.org>; emacs-orgmode@gnu.org > Subject: Re: attachment: link type export to HTML invalid attach dir > > Hello, > > Gustav Wikström <gustav@whil.se> writes: > > > Expanding attachment-links in the buffer makes the link type no longer > > be attachment. > > What makes you think that? The link type is preserved during the > substitution, according to the (concat "attachment" ...). What I meant is that the content of the link, even though mentioned to be "attachment" cannot be reasoned about and worked with in the same way as an unexpanded attachment link. Thus, it's not the same type of link any longer. It's effectively a "file" link when expanded. But this discussion doesn't carry much meaning any longer I suppose, given the agreement to apply the patch. > > I would prefer if we explicitly set the link type to > > files here instead. Storing intermediate state in an attachment link > > types makes less sense imo. > > > > One issue with the current way it's done is that images are treated > > differently between attachment links and file links. For HTML exports, > > file links are wrapped in a div with class figure where expanded > > attachment links are not. > > It would be nice to investigate why this happens. Surely custom code for file links. Haven't dug much deeper since the issue is solved by the attached patch. > > Letting org-attach-expand-links do the full > > transform to file links would solve that issue. That also > > means :export is not needed for org-link-set-parameters. > > > > Patch attached if you agree to this. > > Of course! This is what I suggested, like, 6 weeks ago (although, at > this time, I was thinking about having the substitution in "ox.el"). Well yes... I had other ideas at that point and would rather see attachment links as something of its own. But we're not in that place now, and the decision was to treat link types that can be expanded into file links just like that. You've kindly fixed the code so Org mode can do that now, something I'm sure I couldn't have done myself anyhow. So let's do it as you suggested from the beginning. I'll apply the patch then, unless already taken care of by you or Bastien! :) Kindly Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-27 19:02 ` Gustav Wikström @ 2020-02-28 0:37 ` Nicolas Goaziou 0 siblings, 0 replies; 113+ messages in thread From: Nicolas Goaziou @ 2020-02-28 0:37 UTC (permalink / raw) To: Gustav Wikström; +Cc: Bastien, emacs-orgmode@gnu.org Hello, Gustav Wikström <gustav@whil.se> writes: > Surely custom code for file links. Haven't dug much deeper since the > issue is solved by the attached patch. Certainly, but that means `org-export-link-as-file' is not working at some level. Since adding a hook is better, and the function was not used anymore, I removed it: it is not necessary. > I'll apply the patch then, unless already taken care of by you or > Bastien! :) Applied. Thank you. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: attachment: link type export to HTML invalid attach dir 2020-02-13 20:41 ` Nicolas Goaziou 2020-02-13 21:11 ` Gustav Wikström @ 2020-02-13 21:57 ` Gustav Wikström 2020-02-14 10:02 ` Bastien 2 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2020-02-13 21:57 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Bastien Guerry, emacs-orgmode@gnu.org Continuation from previous answer, > -----Original Message----- > From: Nicolas Goaziou <mail@nicolasgoaziou.fr> > Sent: den 13 februari 2020 21:41 > To: Gustav Wikström <gustav@whil.se> > Cc: emacs-orgmode@gnu.org; Bastien Guerry <bzg@gnu.org> > Subject: Re: attachment: link type export to HTML invalid attach dir > > [...] > > > Given the above paragraph, the :path and :search-option property > > doesn't make sense in the parser. :raw-link is enough. Less ambiguous > > names for :path and :search-option would be :file-path > > and :file-search-option. But that's sub-typing. We've already > > concluded that that should not belong to the parser. > > I don't have much time, I apologize if I'm not clear. > > I disagree with you conclusion. Sub-typing is necessary in the parser. > The `link' object is complex, so it needs categories or types. There are > plain links, angle links, square links. In this last category, there are > internal links, which include coderefs, fuzzy links, custom id, file > links, and, "links with an explicit scheme part". For each of these > categories, it is fine to have specific properties, like search-options. Sure, that's not too far away from what I suggested in one of my first mails on the subject (except I took it a few steps too far maybe). Saying there are properties for categories of sub-types is fine but then this needs to be made much more explicit than today. > Note that this is sub-typing per syntax, not by meaning. This is what > should not move, unless absolutely necessary. For example, attachment > links belong to "square links with an explicit 'attachment' scheme > part". That is all the parser needs to know. That, and the way to extract the :search-options and :application from the link, as is done for file-links. Since attachment links would fit into your category of links that needs specific properties, like search-options. > Now, it is true that [[file:...]] links are put in the same category as > [[~/...]] links, for practical reasons, i.e., you wouldn't want them to > differ in meaning. But this is a breach in the categories above. Perfectly valid in my opinion. [[~/...]] is shorthand for [[file:~/...]] and, as long as documented as such, I see no breach. Only one such shorthand is possible anyways so not much ambiguity there. > We might ignore the :search-option part in file links, but it's very > easy to get, and, more importantly, we must extract the filename, so > further parsing is necessary. As you might have figured, I don't hold a very strong opinion on which design decision to take. I just want the choice to be based on principles and to be without ambiguities. If you say there are sub-types of links that require the :search-option, then fine, let it be so. But then we have to make it perfectly clear which particular types this applies to. And also make it clear that those special properties are only available for built-in types. I.e. to use them one have to get the new link-type into Org mode and into org-element.el. > > I agree that option 1 is suboptimal. :search-option isn't obvious as > > a property for all link types. Since option 3 is fairly trivial, > > option 2 isn't necessary either. For attachment links to reuse > > the :search-option semantics, without the hard-coding we're currently > > doing, I see one option where attachment link higher order functions > > could reuse file link higher order functions. Those file link higher > > order functions don't exist yet as far as I know. > > Higher order functions for what? `org-open-file' is such a higher order > function for opening file links. There is no higher order function for > exporting because each exporter handles file links differently. A higher > order function for parsing doesn't mean much, since the consumer is not > known yet. Yes, each exporter handles file links differently. And I'm saying each exporter shouldn't handle file links at all. They should delegate that to the file exporter higher order function. In the same way that other link types are supposed to be dealt with. Principles. > At this point, the best thing to do is to clarify what you need. > I probably do not understand it. I'm trying :) But it's not that /I need/ anything. It's rather the issue of how to solve the conundrum we're in. Where you say "attachment" links should work differently and not be hardcoded next to file links. And I'm saying it won't work unless we refactor how file-links are handled. And how we should have a principled approach to these kinds of things. > > It might be seducing but I'm not sold. I'd rather have an > > attachment-link exporter explicitly reuse functionality for exporting > > file links than automatic translation. For that to be possible, there > > first is a need for a file link exporter function. > > I don't see how that would be possible, since it would be different for > each back-end. Again, do you have a more precise idea about what it > would do? It would do exactly the same thing that other link type exporters are supposed to do. I.e. implement the translation for each back-end. Kind regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: attachment: link type export to HTML invalid attach dir 2020-02-13 20:41 ` Nicolas Goaziou 2020-02-13 21:11 ` Gustav Wikström 2020-02-13 21:57 ` Gustav Wikström @ 2020-02-14 10:02 ` Bastien 2 siblings, 0 replies; 113+ messages in thread From: Bastien @ 2020-02-14 10:02 UTC (permalink / raw) To: Nicolas Goaziou; +Cc: Gustav Wikström, emacs-orgmode@gnu.org Hi Nicolas and Gustav, Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > I'm Cc'ing Bastien because that particular point should be solved before > any release, IMO. Thanks for adding me to the loop. I'll take the time today or tomorrow to understand what is at stake here and of course, I won't release Org 9.4 before it is sorted out. Everyone can take a break from this thread :) -- Bastien ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (6 preceding siblings ...) 2020-01-13 12:24 ` attachment: link type export to HTML invalid attach dir stardiviner @ 2020-01-13 13:41 ` stardiviner 2020-01-14 21:17 ` Gustav Wikström 2020-01-17 7:39 ` Missing `org-attach-set-inherit' function stardiviner 8 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-13 13:41 UTC (permalink / raw) To: emacs-orgmode I found when I set option ~(setq org-attach-store-link-p t)~. Then attach a file, store file link with =[C-c C-l]=. The stored link. I open this link got error "No such file: ....". I tested this with minimal Emacs config. confirmed this problem. -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner @ 2020-01-14 21:17 ` Gustav Wikström 2020-01-15 6:20 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-14 21:17 UTC (permalink / raw) To: numbchild@gmail.com, emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On > Behalf Of stardiviner > Sent: den 13 januari 2020 14:42 > To: emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > > I found when I set option ~(setq org-attach-store-link-p t)~. Then attach > a file, store file link with =[C-c C-l]=. The stored link. I open this > link got error "No such file: ....". I tested this with minimal Emacs > config. confirmed this problem. > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and with only that single customization it works for me. I'm testing it in linux. A wild guess.. Could it be that you used the move operation instead of the copy operation when attaching the file? Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2020-01-14 21:17 ` Gustav Wikström @ 2020-01-15 6:20 ` stardiviner 2020-01-15 22:42 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-15 6:20 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On >> Behalf Of stardiviner >> Sent: den 13 januari 2020 14:42 >> To: emacs-orgmode@gnu.org >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then attach >> a file, store file link with =[C-c C-l]=. The stored link. I open this >> link got error "No such file: ....". I tested this with minimal Emacs >> config. confirmed this problem. >> > > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and with only that single customization it works for me. I'm testing it in linux. A wild guess.. Could it be that you used the move operation instead of the copy operation when attaching the file? > > Regards > Gustav Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode version which does not contains the latest version =org-attach.el=. Here is my minimal Emacs config: #+begin_src emacs-lisp :tangle "~/.config/emacs/minimal-init.el" (package-initialize) ;;; add my init files directory (add-to-list 'load-path "/usr/share/emacs/site-lisp/") (add-to-list 'load-path (expand-file-name "init" user-emacs-directory)) ;; recursively load init files. (let ((default-directory (expand-file-name "init" user-emacs-directory))) (setq load-path (append (let ((load-path (copy-sequence load-path))) ; shadow (append (copy-sequence (normal-top-level-add-to-load-path '("."))) (normal-top-level-add-subdirs-to-load-path))) load-path))) (setq load-prefer-newer t) ;;; [ package.el ] -- Emacs Lisp Package Archive (ELPA) (require 'package) (setq package-enable-at-startup nil) (setq package-menu-async t) (setq package-user-dir (expand-file-name "elpa" user-emacs-directory)) ;;; ELPA Mirrors ;; (setq-default package-archives ;; '(("gnu" . "https://elpa.gnu.org/packages/") ;; ("melpa" . "http://melpa.org/packages/") ;; ("melpa-stable" . "http://stable.melpa.org/packages/") ;; ("marmalade" . "http://marmalade-repo.org/packages/") ;; ("org" . "http://orgmode.org/elpa/"))) (setq-default package-archives '(("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/") ("org" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/org/") ("gnu" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/"))) (let* ((elpa-archives-dir (expand-file-name "elpa/archives/" user-emacs-directory)) (elpa-gnu-archives-dir (concat elpa-archives-dir "gnu")) (elpa-melpa-archives-dir (concat elpa-archives-dir "melpa")) (elpa-org-archives-dir (concat elpa-archives-dir "org"))) (unless (and (file-exists-p elpa-gnu-archives-dir) (file-exists-p elpa-melpa-archives-dir) (file-exists-p elpa-org-archives-dir)) (package-refresh-contents))) (package-initialize) (add-to-list 'display-buffer-alist '("^\\*package-build-result\\*" (display-buffer-reuse-window display-buffer-below-selected))) ;;; Load `use-package' ahead before `package-initialize' for (use-package org :pin manual ...). ;;; [ use-package ] (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (require 'use-package)) (require 'bind-key) ; if you use any `:bind' variant (use-package delight ; if you use `:delight' :ensure t) ;; (use-package deminish ; if you use `:diminish' ;; :ensure t) (setq use-package-verbose t ; 'debug: any evaluation errors report to `*use-package*` buffer. use-package-always-ensure nil) ;;; use latest source code version Org Mode. (if (not (file-exists-p "~/Code/Emacs/org-mode/lisp/")) (progn (use-package org :pin org :ensure t :preface (setq org-modules nil) :mode (("\\.org\\'" . org-mode))) (use-package org-plus-contrib :pin org :ensure t)) ;; disable Emacs built-in Org Mode (delete (format "/usr/local/share/emacs/%s/lisp/org" emacs-version) load-path) (delete "/usr/share/emacs/site-lisp/org/" load-path) (use-package org :pin manual :load-path "~/Code/Emacs/org-mode/lisp/" :defer t :preface ;; Org Mode modules -- modules that should always be loaded together with org.el. ;; t: greedy load all modules. ;; nil: disable all extra org-mode modules to speed-up Org-mode file opening. (setq org-modules nil) :mode (("\\.org\\'" . org-mode)) :init ;; add source code version Org-mode Info into Emacs. (with-eval-after-load 'info (add-to-list 'Info-directory-list "~/Code/Emacs/org-mode/doc/") (info-initialize)) ;; load org before using some Org settings. (require 'org) (use-package org-plus-contrib :pin manual :load-path "~/Code/Emacs/org-mode/contrib/lisp/" :defer t :no-require t))) ;;============================================================================== ;;; Here is org-attach.el customization (require 'org-attach) ;; store link auto with `org-store-link' using `file:' link type or `attachment:' link type. (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t) (setq org-attach-preferred-new-method 'ask) #+end_src #+begin_src sh :eval no emacs -q -l '~/.config/emacs/minimal-init.el' #+end_src -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2020-01-15 6:20 ` stardiviner @ 2020-01-15 22:42 ` Gustav Wikström 2020-01-16 11:15 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-15 22:42 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 15 januari 2020 07:21 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > [...] > > >> I found when I set option ~(setq org-attach-store-link-p t)~. Then > >> attach a file, store file link with =[C-c C-l]=. The stored link. I > >> open this link got error "No such file: ....". I tested this with > >> minimal Emacs config. confirmed this problem. > >> > > > > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and > with only that single customization it works for me. I'm testing it in > linux. A wild guess.. Could it be that you used the move operation instead > of the copy operation when attaching the file? > > > > Regards > > Gustav > > Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode > version which does not contains the latest version =org-attach.el=. > > Here is my minimal Emacs config: > > [...] > > ;;======================================================================== > ====== > ;;; Here is org-attach.el customization > > (require 'org-attach) > > ;; store link auto with `org-store-link' using `file:' link type or > `attachment:' link type. > (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t) > (setq org-attach-preferred-new-method 'ask) #+end_src > > #+begin_src sh :eval no > emacs -q -l '~/.config/emacs/minimal-init.el' > #+end_src Hmm, in the first mail you said that you set org-attach-store-link-p to t, but in your config it says 'attached. I've tried with a minimal config as well (using emacs -q because I build the newest org mode version into the emacs folder) and can only reproduce your issue when using the attached option for org-attach-store-link-p and then inserting that link with C-c C-l /in another heading/. Pasting the link in another heading is expected to break since the attachment link is context dependent (i.e. requires an attachment folder). Makes sense? If I'm still misunderstanding your use-case, would you care to describe the steps to reproduce it more in detail? Regards Gustav ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2020-01-15 22:42 ` Gustav Wikström @ 2020-01-16 11:15 ` stardiviner 2020-01-18 14:56 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-16 11:15 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: stardiviner <numbchild@gmail.com> >> Sent: den 15 januari 2020 07:21 >> To: Gustav Wikström <gustav@whil.se> >> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> [...] >> >> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then >> >> attach a file, store file link with =[C-c C-l]=. The stored link. I >> >> open this link got error "No such file: ....". I tested this with >> >> minimal Emacs config. confirmed this problem. >> >> >> > >> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and >> with only that single customization it works for me. I'm testing it in >> linux. A wild guess.. Could it be that you used the move operation instead >> of the copy operation when attaching the file? >> > >> > Regards >> > Gustav >> >> Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode >> version which does not contains the latest version =org-attach.el=. >> >> Here is my minimal Emacs config: >> >> [...] >> >> ;;======================================================================== >> ====== >> ;;; Here is org-attach.el customization >> >> (require 'org-attach) >> >> ;; store link auto with `org-store-link' using `file:' link type or >> `attachment:' link type. >> (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t) >> (setq org-attach-preferred-new-method 'ask) #+end_src >> >> #+begin_src sh :eval no >> emacs -q -l '~/.config/emacs/minimal-init.el' >> #+end_src > > Hmm, in the first mail you said that you set org-attach-store-link-p to t, but > in your config it says 'attached. Sorry about this. > I've tried with a minimal config as well > (using emacs -q because I build the newest org mode version into the emacs > folder) and can only reproduce your issue when using the attached option for > org-attach-store-link-p and then inserting that link with C-c C-l /in another > heading/. Pasting the link in another heading is expected to break since the > attachment link is context dependent (i.e. requires an attachment folder). > Makes sense? If I'm still misunderstanding your use-case, would you care to > describe the steps to reproduce it more in detail? After updated commit, don't know why, but all links worked again. I'm not good at expressing thanks, but you got all my thanks on this. :) > Regards > Gustav > -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2020-01-16 11:15 ` stardiviner @ 2020-01-18 14:56 ` stardiviner 2020-01-18 15:30 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-18 14:56 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org [-- Attachment #1: Type: text/plain, Size: 3089 bytes --] stardiviner <numbchild@gmail.com> writes: I finally figured out why the link always failed. Because it use wrong variable which is old filename path. I attached a patch. > Gustav Wikström <gustav@whil.se> writes: > >> Hi, >> >>> -----Original Message----- >>> From: stardiviner <numbchild@gmail.com> >>> Sent: den 15 januari 2020 07:21 >>> To: Gustav Wikström <gustav@whil.se> >>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >>> >>> [...] >>> >>> >> I found when I set option ~(setq org-attach-store-link-p t)~. Then >>> >> attach a file, store file link with =[C-c C-l]=. The stored link. I >>> >> open this link got error "No such file: ....". I tested this with >>> >> minimal Emacs config. confirmed this problem. >>> >> >>> > >>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) and >>> with only that single customization it works for me. I'm testing it in >>> linux. A wild guess.. Could it be that you used the move operation instead >>> of the copy operation when attaching the file? >>> > >>> > Regards >>> > Gustav >>> >>> Did you reproduce this issue with =emacs -q= ? That is a built-in Org Mode >>> version which does not contains the latest version =org-attach.el=. >>> >>> Here is my minimal Emacs config: >>> >>> [...] >>> >>> ;;======================================================================== >>> ====== >>> ;;; Here is org-attach.el customization >>> >>> (require 'org-attach) >>> >>> ;; store link auto with `org-store-link' using `file:' link type or >>> `attachment:' link type. >>> (setq org-attach-store-link-p 'attached) (setq org-attach-dir-relative t) >>> (setq org-attach-preferred-new-method 'ask) #+end_src >>> >>> #+begin_src sh :eval no >>> emacs -q -l '~/.config/emacs/minimal-init.el' >>> #+end_src >> > >> Hmm, in the first mail you said that you set org-attach-store-link-p to t, but >> in your config it says 'attached. > > Sorry about this. > >> I've tried with a minimal config as well >> (using emacs -q because I build the newest org mode version into the emacs >> folder) and can only reproduce your issue when using the attached option for >> org-attach-store-link-p and then inserting that link with C-c C-l /in another >> heading/. Pasting the link in another heading is expected to break since the >> attachment link is context dependent (i.e. requires an attachment folder). >> Makes sense? If I'm still misunderstanding your use-case, would you care to >> describe the steps to reproduce it more in detail? > > After updated commit, don't know why, but all links worked again. I'm not good > at expressing thanks, but you got all my thanks on this. :) > >> Regards >> Gustav >> -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Fix-org-attach-store-link-use-old-filename.patch --] [-- Type: text/x-patch, Size: 882 bytes --] From 006583a83bc3b05b28ed1ad3610081066c0b1f95 Mon Sep 17 00:00:00 2001 From: stardiviner <numbchild@gmail.com> Date: Sat, 18 Jan 2020 22:51:53 +0800 Subject: [PATCH] Fix org-attach store link use old filename --- lisp/org-attach.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 6bb438c72..c3d3ecda9 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -504,8 +504,8 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from (file-name-nondirectory fname)) org-stored-links)) ((eq org-attach-store-link-p t) - (push (list (concat "file:" file) - (file-name-nondirectory file)) + (push (list (concat "file:" fname) + (file-name-nondirectory fname)) org-stored-links))) (if visit-dir (dired attach-dir) -- 2.25.0 ^ permalink raw reply related [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2020-01-18 14:56 ` stardiviner @ 2020-01-18 15:30 ` Gustav Wikström 2020-01-19 4:28 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-18 15:30 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi! org-attach-store-link-p with option t is supposed to store a link to the original location (i.e. the location the file was/is in before it was attached to the node. That was the default before I started working with attachments I believe. Haven't ever used that feature myself but the patch you provide would change the functionality which I don't think is correct. It would also not match the documentation any longer. See the documentation for the customization parameter: #+begin_src emacs-lisp (defcustom org-attach-store-link-p nil "Non-nil means store a link to a file when attaching it." :group 'org-attach :version "24.1" :type '(choice (const :tag "Don't store link" nil) (const :tag "Link to origin location" t) (const :tag "Link to the attach-dir location" attached))) #+end_src Regards Gustav > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 18 januari 2020 15:56 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > > stardiviner <numbchild@gmail.com> writes: > > I finally figured out why the link always failed. Because it use wrong > variable which is old filename path. I attached a patch. > > > Gustav Wikström <gustav@whil.se> writes: > > > >> Hi, > >> > >>> -----Original Message----- > >>> From: stardiviner <numbchild@gmail.com> > >>> Sent: den 15 januari 2020 07:21 > >>> To: Gustav Wikström <gustav@whil.se> > >>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > >>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach > >>> options > >>> > >>> [...] > >>> > >>> >> I found when I set option ~(setq org-attach-store-link-p t)~. > >>> >> Then attach a file, store file link with =[C-c C-l]=. The stored > >>> >> link. I open this link got error "No such file: ....". I tested > >>> >> this with minimal Emacs config. confirmed this problem. > >>> >> > >>> > > >>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) > >>> > and > >>> with only that single customization it works for me. I'm testing it > >>> in linux. A wild guess.. Could it be that you used the move > >>> operation instead of the copy operation when attaching the file? > >>> > > >>> > Regards > >>> > Gustav > >>> > >>> Did you reproduce this issue with =emacs -q= ? That is a built-in > >>> Org Mode version which does not contains the latest version =org- > attach.el=. > >>> > >>> Here is my minimal Emacs config: > >>> > >>> [...] > >>> > >>> ;;================================================================== > >>> ====== > >>> ====== > >>> ;;; Here is org-attach.el customization > >>> > >>> (require 'org-attach) > >>> > >>> ;; store link auto with `org-store-link' using `file:' link type or > >>> `attachment:' link type. > >>> (setq org-attach-store-link-p 'attached) (setq > >>> org-attach-dir-relative t) (setq org-attach-preferred-new-method > >>> 'ask) #+end_src > >>> > >>> #+begin_src sh :eval no > >>> emacs -q -l '~/.config/emacs/minimal-init.el' > >>> #+end_src > >> > > > >> Hmm, in the first mail you said that you set org-attach-store-link-p > >> to t, but in your config it says 'attached. > > > > Sorry about this. > > > >> I've tried with a minimal config as well (using emacs -q because I > >> build the newest org mode version into the emacs > >> folder) and can only reproduce your issue when using the attached > >> option for org-attach-store-link-p and then inserting that link with > >> C-c C-l /in another heading/. Pasting the link in another heading is > >> expected to break since the attachment link is context dependent (i.e. > requires an attachment folder). > >> Makes sense? If I'm still misunderstanding your use-case, would you > >> care to describe the steps to reproduce it more in detail? > > > > After updated commit, don't know why, but all links worked again. I'm > > not good at expressing thanks, but you got all my thanks on this. :) > > > >> Regards > >> Gustav > >> > > -- > [ stardiviner ] > I try to make every word tell the meaning what I want to express. > > Blog: https://stardiviner.github.io/ > IRC(freenode): stardiviner, Matrix: stardiviner > GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 > ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: FW: [RFC] Link-type for attachments, more attach options 2020-01-18 15:30 ` Gustav Wikström @ 2020-01-19 4:28 ` stardiviner 2020-01-19 9:53 ` Gustav Wikström 0 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-19 4:28 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi! > > org-attach-store-link-p with option t is supposed to store a link to the original location (i.e. the location the file was/is in before it was attached to the node. That was the default before I started working with attachments I believe. Haven't ever used that feature myself but the patch you provide would change the functionality which I don't think is correct. It would also not match the documentation any longer. > > See the documentation for the customization parameter: > > #+begin_src emacs-lisp > (defcustom org-attach-store-link-p nil > "Non-nil means store a link to a file when attaching it." > :group 'org-attach > :version "24.1" > :type '(choice > (const :tag "Don't store link" nil) > (const :tag "Link to origin location" t) > (const :tag "Link to the attach-dir location" attached))) > #+end_src > > Regards > Gustav I've been used this functionality for a long time, I always store the link after attached file. Because the old path is gone. For example, I have a file in =~/Downloads/kk.png=, then I attached it under a node, then the file moved to =data/images/kk.png=. The original file =~/Downloads/kk.png= is gone, does not exist, because I use =mv= method. If still link to original location, so the link file does not exist. That's why I found it inconsistent. Here is the commit which might affected this behavior if I guess right. #+begin_src diff 26ace9004 origin/master Make org-attach store links using attachment-links modified lisp/org-attach.el @@ -487,33 +479,37 @@ (defun org-attach-attach (file &optional visit-dir method) "Move/copy/link FILE into the attachment directory of the current outline node. If VISIT-DIR is non-nil, visit the directory with dired. METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from `org-attach-method'." (interactive (list (read-file-name "File to keep as an attachment:" (or (progn (require 'dired-aux) (dired-dwim-target-directory)) default-directory)) current-prefix-arg nil)) (setq method (or method org-attach-method)) (let ((basename (file-name-nondirectory file))) (let* ((attach-dir (org-attach-dir 'get-create)) (fname (expand-file-name basename attach-dir))) (cond ((eq method 'mv) (rename-file file fname)) ((eq method 'cp) (copy-file file fname)) ((eq method 'ln) (add-name-to-file file fname)) ((eq method 'lns) (make-symbolic-link file fname)) ((eq method 'url) (url-copy-file file fname))) (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (cond ((eq org-attach-store-link-p 'attached) - (org-attach-store-link fname)) + (push (list (concat "attachment:" (file-name-nondirectory fname)) + (file-name-nondirectory fname)) + org-stored-links)) ((eq org-attach-store-link-p t) - (org-attach-store-link file))) + (push (list (concat "file:" file) + (file-name-nondirectory file)) + org-stored-links))) (if visit-dir (dired attach-dir) (message "File %S is now an attachment." basename))))) #+end_src And in the commit "26ace9004260a056acef58a7c1c80222bc9587c9": #+begin_src diff modified lisp/org-attach.el @@ -457,14 +457,6 @@ DIR-property exists (that is different than the unset one)." "Turn the autotag off." (org-attach-tag 'off)) -(defun org-attach-store-link (file) - "Add a link to `org-stored-link' when attaching a file. -Only do this when `org-attach-store-link-p' is non-nil." - (setq org-stored-links - (cons (list (org-attach-expand-link file) - (file-name-nondirectory file)) - org-stored-links))) - (defun org-attach-url (url) (interactive "MURL of the file to attach: \n") (let ((org-attach-method 'url)) @@ -511,9 +503,13 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from (run-hook-with-args 'org-attach-after-change-hook attach-dir) (org-attach-tag) (cond ((eq org-attach-store-link-p 'attached) - (org-attach-store-link fname)) + (push (list (concat "attachment:" (file-name-nondirectory fname)) + (file-name-nondirectory fname)) + org-stored-links)) ((eq org-attach-store-link-p t) - (org-attach-store-link file))) + (push (list (concat "file:" file) + (file-name-nondirectory file)) + org-stored-links))) (if visit-dir (dired attach-dir) (message "File %S is now an attachment." basename))))) @@ -642,12 +638,6 @@ See `org-attach-open'." Basically, this adds the path to the attachment directory." (expand-file-name file (org-attach-dir))) -(defun org-attach-expand-link (file) - "Return a file link pointing to the current entry's attachment file FILE. -Basically, this adds the path to the attachment directory, and a \"file:\" -prefix." - (concat "file:" (org-attach-expand file))) - (org-link-set-parameters "attachment" :follow #'org-attach-open-link :export #'org-attach-export-link #+end_src From the source code, it seems indeed still original code logic. Then I checked out my Emacs init git log, confirmed it is ~'attached~ option value at first time. So this is my mistake. Because this new ~attachment:~ link type has potential issues like on exporting. So I decided to still use old ~file:~ link type. So I thought should set ~org-attach-store-link-p~ to ~t~. It indeed use ~file:~ link type instead of ~attachment:~ now. But the store link behavior affected. So the problem is how can I use both ~file:~ link type for attachments and use this new attached store link? > >> -----Original Message----- >> From: stardiviner <numbchild@gmail.com> >> Sent: den 18 januari 2020 15:56 >> To: Gustav Wikström <gustav@whil.se> >> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options >> >> >> stardiviner <numbchild@gmail.com> writes: >> >> I finally figured out why the link always failed. Because it use wrong >> variable which is old filename path. I attached a patch. >> >> > Gustav Wikström <gustav@whil.se> writes: >> > >> >> Hi, >> >> >> >>> -----Original Message----- >> >>> From: stardiviner <numbchild@gmail.com> >> >>> Sent: den 15 januari 2020 07:21 >> >>> To: Gustav Wikström <gustav@whil.se> >> >>> Cc: numbchild@gmail.com; emacs-orgmode@gnu.org >> >>> Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach >> >>> options >> >>> >> >>> [...] >> >>> >> >>> >> I found when I set option ~(setq org-attach-store-link-p t)~. >> >>> >> Then attach a file, store file link with =[C-c C-l]=. The stored >> >>> >> link. I open this link got error "No such file: ....". I tested >> >>> >> this with minimal Emacs config. confirmed this problem. >> >>> >> >> >>> > >> >>> > I cannot reproduce this. In my try with a minimal Emacs (emacs -q) >> >>> > and >> >>> with only that single customization it works for me. I'm testing it >> >>> in linux. A wild guess.. Could it be that you used the move >> >>> operation instead of the copy operation when attaching the file? >> >>> > >> >>> > Regards >> >>> > Gustav >> >>> >> >>> Did you reproduce this issue with =emacs -q= ? That is a built-in >> >>> Org Mode version which does not contains the latest version =org- >> attach.el=. >> >>> >> >>> Here is my minimal Emacs config: >> >>> >> >>> [...] >> >>> >> >>> ;;================================================================== >> >>> ====== >> >>> ====== >> >>> ;;; Here is org-attach.el customization >> >>> >> >>> (require 'org-attach) >> >>> >> >>> ;; store link auto with `org-store-link' using `file:' link type or >> >>> `attachment:' link type. >> >>> (setq org-attach-store-link-p 'attached) (setq >> >>> org-attach-dir-relative t) (setq org-attach-preferred-new-method >> >>> 'ask) #+end_src >> >>> >> >>> #+begin_src sh :eval no >> >>> emacs -q -l '~/.config/emacs/minimal-init.el' >> >>> #+end_src >> >> >> > >> >> Hmm, in the first mail you said that you set org-attach-store-link-p >> >> to t, but in your config it says 'attached. >> > >> > Sorry about this. >> > >> >> I've tried with a minimal config as well (using emacs -q because I >> >> build the newest org mode version into the emacs >> >> folder) and can only reproduce your issue when using the attached >> >> option for org-attach-store-link-p and then inserting that link with >> >> C-c C-l /in another heading/. Pasting the link in another heading is >> >> expected to break since the attachment link is context dependent (i.e. >> requires an attachment folder). >> >> Makes sense? If I'm still misunderstanding your use-case, would you >> >> care to describe the steps to reproduce it more in detail? >> > >> > After updated commit, don't know why, but all links worked again. I'm >> > not good at expressing thanks, but you got all my thanks on this. :) >> > >> >> Regards >> >> Gustav >> >> >> >> -- >> [ stardiviner ] >> I try to make every word tell the meaning what I want to express. >> >> Blog: https://stardiviner.github.io/ >> IRC(freenode): stardiviner, Matrix: stardiviner >> GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 >> -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: FW: [RFC] Link-type for attachments, more attach options 2020-01-19 4:28 ` stardiviner @ 2020-01-19 9:53 ` Gustav Wikström 0 siblings, 0 replies; 113+ messages in thread From: Gustav Wikström @ 2020-01-19 9:53 UTC (permalink / raw) To: numbchild@gmail.com; +Cc: emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: stardiviner <numbchild@gmail.com> > Sent: den 19 januari 2020 05:28 > To: Gustav Wikström <gustav@whil.se> > Cc: numbchild@gmail.com; emacs-orgmode@gnu.org > Subject: Re: [O] FW: [RFC] Link-type for attachments, more attach options > > [...] > > From the source code, it seems indeed still original code logic. > > Then I checked out my Emacs init git log, confirmed it is ~'attached~ > option value at first time. So this is my mistake. > > Because this new ~attachment:~ link type has potential issues like on > exporting. The issue with attachment links in the exporters should be fixed since the report of the export issues you sent a short while back. Any external exporter you use may ofc still need to be updated for attachment links. > So I decided to still use old ~file:~ link type. So I thought should set > ~org-attach-store-link-p~ to ~t~. It indeed use ~file:~ link type instead > of ~attachment:~ now. But the store link behavior affected. > > So the problem is how can I use both ~file:~ link type for attachments and > use this new attached store link? Understood, and I see no issue with complementing org-attach-store-link-p with another option. One that stores a file link to the attached files location. Pushed a change for that just now. ^ permalink raw reply [flat|nested] 113+ messages in thread
* Missing `org-attach-set-inherit' function 2018-10-21 7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström ` (7 preceding siblings ...) 2020-01-13 13:41 ` FW: [RFC] Link-type for attachments, more attach options stardiviner @ 2020-01-17 7:39 ` stardiviner 2020-01-17 16:31 ` Gustav Wikström 8 siblings, 1 reply; 113+ messages in thread From: stardiviner @ 2020-01-17 7:39 UTC (permalink / raw) To: emacs-orgmode I found the function ~org-attach-set-inherit~ is missing. I noticed it in the Info document. #+begin_quote ‘i’ (‘org-attach-set-inherit’) Set the ‘ATTACH_DIR_INHERIT’ property, so that children use the same directory for attachments as the parent does. #+end_quote -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
* RE: Missing `org-attach-set-inherit' function 2020-01-17 7:39 ` Missing `org-attach-set-inherit' function stardiviner @ 2020-01-17 16:31 ` Gustav Wikström 2020-01-18 14:54 ` stardiviner 0 siblings, 1 reply; 113+ messages in thread From: Gustav Wikström @ 2020-01-17 16:31 UTC (permalink / raw) To: numbchild@gmail.com, emacs-orgmode@gnu.org Hi, > -----Original Message----- > From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On > Behalf Of stardiviner > Sent: den 17 januari 2020 08:39 > To: emacs-orgmode@gnu.org > Subject: Missing `org-attach-set-inherit' function > > > I found the function ~org-attach-set-inherit~ is missing. I noticed it in > the Info document. > > #+begin_quote > ‘i’ (‘org-attach-set-inherit’) > Set the ‘ATTACH_DIR_INHERIT’ property, so that children use > the same directory for attachments as the parent does. > #+end_quote I can't find that reference in the newest version of the documentation. Should be removed since commit ae9cd437. Are you sure the documentation and your Org mode version is the same? > > -- > [ stardiviner ] > I try to make every word tell the meaning what I want to express. > > Blog: https://stardiviner.github.io/ > IRC(freenode): stardiviner, Matrix: stardiviner > GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 > ^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: Missing `org-attach-set-inherit' function 2020-01-17 16:31 ` Gustav Wikström @ 2020-01-18 14:54 ` stardiviner 0 siblings, 0 replies; 113+ messages in thread From: stardiviner @ 2020-01-18 14:54 UTC (permalink / raw) To: Gustav Wikström; +Cc: emacs-orgmode@gnu.org Gustav Wikström <gustav@whil.se> writes: > Hi, > >> -----Original Message----- >> From: Emacs-orgmode <emacs-orgmode-bounces+gustav=whil.se@gnu.org> On >> Behalf Of stardiviner >> Sent: den 17 januari 2020 08:39 >> To: emacs-orgmode@gnu.org >> Subject: Missing `org-attach-set-inherit' function >> >> >> I found the function ~org-attach-set-inherit~ is missing. I noticed it in >> the Info document. >> >> #+begin_quote >> ‘i’ (‘org-attach-set-inherit’) >> Set the ‘ATTACH_DIR_INHERIT’ property, so that children use >> the same directory for attachments as the parent does. >> #+end_quote > > I can't find that reference in the newest version of the documentation. Should be removed since commit ae9cd437. > > Are you sure the documentation and your Org mode version is the same? You're right, seems my org.info file is old. I recompiled it with command =make info=, That "i" is gone now. Thanks for hint. :) > >> >> -- >> [ stardiviner ] >> I try to make every word tell the meaning what I want to express. >> >> Blog: https://stardiviner.github.io/ >> IRC(freenode): stardiviner, Matrix: stardiviner >> GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 >> -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 ^ permalink raw reply [flat|nested] 113+ messages in thread
end of thread, other threads:[~2020-02-28 0:37 UTC | newest] Thread overview: 113+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 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 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
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.