emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: "Gustav Wikström" <gustav@whil.se>
To: Nicolas Goaziou <mail@nicolasgoaziou.fr>
Cc: emacs-orgmode <emacs-orgmode@gnu.org>
Subject: Re: [RFC] Link-type for attachments, more attach options
Date: Sun, 25 Nov 2018 21:13:00 +0000	[thread overview]
Message-ID: <PR1PR02MB4732B95D15A405B39B6D039DDAD60@PR1PR02MB4732.eurprd02.prod.outlook.com> (raw)
In-Reply-To: <877eh8vd52.fsf_-_@nicolasgoaziou.fr>

[-- 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


  reply	other threads:[~2018-11-25 21:13 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-21  7:53 FW: [RFC] Link-type for attachments, more attach options Gustav Wikström
2018-11-01  1:45 ` tumashu
2018-11-02 22:40   ` Gustav Wikström
2018-11-01 16:00 ` Marco Wahl
2018-11-02 23:07   ` Gustav Wikström
2018-11-03  3:37     ` Ihor Radchenko
2018-11-17 12:13       ` Gustav Wikström
2018-11-18  0:42         ` Ihor Radchenko
2018-11-18  8:57           ` Gustav Wikström
2018-11-20 14:00             ` Ihor Radchenko
2018-11-24 13:56               ` Gustav Wikström
2018-12-14  2:16                 ` Ihor Radchenko
2019-05-26 22:24                   ` Gustav Wikström
2018-11-04 22:37 ` Nicolas Goaziou
2018-11-17 11:58   ` Gustav Wikström
     [not found]     ` <PR1PR02MB47322711B7F7B7142D156F54DADE0@PR1PR02MB4732.eurprd02.prod.outlook.com>
2018-11-19 23:52       ` Nicolas Goaziou
2018-11-25 21:13         ` Gustav Wikström [this message]
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

Reply instructions:

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

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

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

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

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

  git send-email \
    --in-reply-to=PR1PR02MB4732B95D15A405B39B6D039DDAD60@PR1PR02MB4732.eurprd02.prod.outlook.com \
    --to=gustav@whil.se \
    --cc=emacs-orgmode@gnu.org \
    --cc=mail@nicolasgoaziou.fr \
    /path/to/YOUR_REPLY

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

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

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

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