emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* How to keep correct filepaths when using the #+INCLUDE derivative?
@ 2018-02-28 13:29 Daniel P Gomez
  2018-02-28 17:51 ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-02-28 13:29 UTC (permalink / raw)
  To: emacs-orgmode

Dear org users,

If I include a file child.org in parent.org using the #+INCLUDE
derivative, and the following two conditions are true:

1. child.org and parent.org are not in the same directory nor share
directory structure,
2. child.org contains file links with relative file paths,

then exporting parent.org will produce a file with broken links.

Is there a way to have org sort this out? Or even make this optional,
say by using:

#+INCLUDE: child.org :fix-paths t

I guess the quickest (but perhaps not cleanest) way to have this
feature would be to convert relative paths in file links into absolute
paths within `org-export-expand-include-keyword`. I'm not that well
versed in Elisp yet to do this yet, though.

Are there any known solutions to this, or suggestions on how to get it working?

Thanks in advance,

Daniel

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-02-28 13:29 How to keep correct filepaths when using the #+INCLUDE derivative? Daniel P Gomez
@ 2018-02-28 17:51 ` Nicolas Goaziou
  2018-02-28 20:11   ` Daniel P Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Goaziou @ 2018-02-28 17:51 UTC (permalink / raw)
  To: Daniel P Gomez; +Cc: emacs-orgmode

Hello,

Daniel P Gomez <gomez.danp@gmail.com> writes:

> If I include a file child.org in parent.org using the #+INCLUDE
> derivative, and the following two conditions are true:
>
> 1. child.org and parent.org are not in the same directory nor share
> directory structure,
> 2. child.org contains file links with relative file paths,
>
> then exporting parent.org will produce a file with broken links.
>
> Is there a way to have org sort this out?
>
> Or even make this optional,
> say by using:
>
> #+INCLUDE: child.org :fix-paths t
>
> I guess the quickest (but perhaps not cleanest) way to have this
> feature would be to convert relative paths in file links into absolute
> paths within `org-export-expand-include-keyword`. I'm not that well
> versed in Elisp yet to do this yet, though.
>
> Are there any known solutions to this, or suggestions on how to get it
> working?

As you suggest, I would use a parse tree filter that turns every
relative file link into an absolute one.

Regards,

-- 
Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-02-28 17:51 ` Nicolas Goaziou
@ 2018-02-28 20:11   ` Daniel P Gomez
  2018-03-01  1:01     ` Daniel P Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-02-28 20:11 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Sorry for the ignorance, but where could I look up how to use a parse
tree filter? And where would these modifications make sense?
Any pointers towards documentation, functions, or any help of any kind
would be appreciated. I must say I am a bit lost.

Thank you in advance,

Daniel

On Wed, Feb 28, 2018 at 6:51 PM, Nicolas Goaziou <mail@nicolasgoaziou.fr> wrote:
> Hello,
>
> Daniel P Gomez <gomez.danp@gmail.com> writes:
>
>> If I include a file child.org in parent.org using the #+INCLUDE
>> derivative, and the following two conditions are true:
>>
>> 1. child.org and parent.org are not in the same directory nor share
>> directory structure,
>> 2. child.org contains file links with relative file paths,
>>
>> then exporting parent.org will produce a file with broken links.
>>
>> Is there a way to have org sort this out?
>>
>> Or even make this optional,
>> say by using:
>>
>> #+INCLUDE: child.org :fix-paths t
>>
>> I guess the quickest (but perhaps not cleanest) way to have this
>> feature would be to convert relative paths in file links into absolute
>> paths within `org-export-expand-include-keyword`. I'm not that well
>> versed in Elisp yet to do this yet, though.
>>
>> Are there any known solutions to this, or suggestions on how to get it
>> working?
>
> As you suggest, I would use a parse tree filter that turns every
> relative file link into an absolute one.
>
> Regards,
>
> --
> Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-02-28 20:11   ` Daniel P Gomez
@ 2018-03-01  1:01     ` Daniel P Gomez
  2018-03-01 18:32       ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-03-01  1:01 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

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

If there is any interest, I've created a patch adding support for a
:absolute-paths functionality.
As I said, I don't have much experience writing Elisp, so any
suggestions on how to improve the code would be appreciated. If there
is any interest in adding this feature to Org I could try to clean it
up.

Patch attached.


On Wed, Feb 28, 2018 at 9:11 PM, Daniel P Gomez <gomez.danp@gmail.com> wrote:
> Sorry for the ignorance, but where could I look up how to use a parse
> tree filter? And where would these modifications make sense?
> Any pointers towards documentation, functions, or any help of any kind
> would be appreciated. I must say I am a bit lost.
>
> Thank you in advance,
>
> Daniel
>
> On Wed, Feb 28, 2018 at 6:51 PM, Nicolas Goaziou <mail@nicolasgoaziou.fr> wrote:
>> Hello,
>>
>> Daniel P Gomez <gomez.danp@gmail.com> writes:
>>
>>> If I include a file child.org in parent.org using the #+INCLUDE
>>> derivative, and the following two conditions are true:
>>>
>>> 1. child.org and parent.org are not in the same directory nor share
>>> directory structure,
>>> 2. child.org contains file links with relative file paths,
>>>
>>> then exporting parent.org will produce a file with broken links.
>>>
>>> Is there a way to have org sort this out?
>>>
>>> Or even make this optional,
>>> say by using:
>>>
>>> #+INCLUDE: child.org :fix-paths t
>>>
>>> I guess the quickest (but perhaps not cleanest) way to have this
>>> feature would be to convert relative paths in file links into absolute
>>> paths within `org-export-expand-include-keyword`. I'm not that well
>>> versed in Elisp yet to do this yet, though.
>>>
>>> Are there any known solutions to this, or suggestions on how to get it
>>> working?
>>
>> As you suggest, I would use a parse tree filter that turns every
>> relative file link into an absolute one.
>>
>> Regards,
>>
>> --
>> Nicolas Goaziou

[-- Attachment #2: 0001-Add-support-for-absolute-paths-in-INCLUDE-derivative.patch --]
[-- Type: application/octet-stream, Size: 3601 bytes --]

From c52a993f91567d87eb87ded907dcccd83a0f2ed3 Mon Sep 17 00:00:00 2001
From: Daniel Gomez <d.gomez@posteo.org>
Date: Thu, 1 Mar 2018 01:49:54 +0100
Subject: [PATCH 1/1] Add support for :absolute-paths in #+INCLUDE derivatives.

---
 lisp/ox.el | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/lisp/ox.el b/lisp/ox.el
index bd49a8a26..b6f6e576e 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3302,6 +3302,11 @@ storing and resolving footnotes.  It is created automatically."
 				       value)
 			 (prog1 (org-not-nil (match-string 1 value))
 			   (setq value (replace-match "" nil nil value)))))
+		   (absolute-paths
+                    (and (string-match ":absolute-paths *\\([^: \r\t\n]\\S-*\\)?"
+                                       value)
+                         (prog1 (org-not-nil (match-string 1 value))
+                           (setq value (replace-match "" nil nil value)))))
 		   (lines
 		    (and (string-match
 			  ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\""
@@ -3373,7 +3378,8 @@ storing and resolving footnotes.  It is created automatically."
 			 (or
 			  (gethash file file-prefix)
 			  (puthash file (cl-incf current-prefix) file-prefix))
-			 footnotes)))
+			 footnotes
+			 absolute-paths)))
 		     (org-export-expand-include-keyword
 		      (cons (list file lines) included)
 		      (file-name-directory file)
@@ -3451,7 +3457,7 @@ Return a string of lines to be included in the format expected by
 		       counter))))))))
 
 (defun org-export--prepare-file-contents
-    (file &optional lines ind minlevel id footnotes)
+    (file &optional lines ind minlevel id footnotes absolute-paths)
   "Prepare contents of FILE for inclusion and return it as a string.
 
 When optional argument LINES is a string specifying a range of
@@ -3473,7 +3479,10 @@ This is useful to avoid conflicts when more than one Org file
 with footnotes is included in a document.
 
 Optional argument FOOTNOTES is a hash-table to store footnotes in
-the included document."
+the included document.
+
+Optional argument ABSOLUTE-PATHS, when non-nil, toggles the convertion
+of all relative paths in the included document into absolute paths."
   (with-temp-buffer
     (insert-file-contents file)
     (when lines
@@ -3533,6 +3542,23 @@ the included document."
 		(lambda ()
 		  (if (< offset 0) (delete-char (abs offset))
 		    (insert (make-string offset ?*)))))))))))
+    ;;; When ABSOLUTE-PATHS is specified, all paths from links of type
+    ;;; "file" that are present in the file being included are
+    ;;; converted to absolute and canonicalized.
+    (when absolute-paths
+      (goto-char (point-min))
+      (while (re-search-forward org-any-link-re nil t)
+        (let ((link (save-excursion
+                      (backward-char)
+                      (org-element-context))))
+          (when (string= (org-element-property :type link) "file")
+            (let* ((old-path (org-element-property :path link))
+                   (new-path (expand-file-name old-path
+                                               (file-name-directory file)))
+                   (remove (list (org-element-property :begin link)
+                                 (org-element-property :end link))))
+              (apply #'delete-region remove)
+              (insert "[[file:" new-path "]]"))))))
     ;; Append ID to all footnote references and definitions, so they
     ;; become file specific and cannot collide with footnotes in other
     ;; included files.  Further, collect relevant footnote definitions
-- 
2.16.2


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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-01  1:01     ` Daniel P Gomez
@ 2018-03-01 18:32       ` Nicolas Goaziou
  2018-03-01 18:56         ` Daniel P Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Goaziou @ 2018-03-01 18:32 UTC (permalink / raw)
  To: Daniel P Gomez; +Cc: emacs-orgmode

Hello,

Daniel P Gomez <gomez.danp@gmail.com> writes:

> If there is any interest, I've created a patch adding support for a
> :absolute-paths functionality.
> As I said, I don't have much experience writing Elisp, so any
> suggestions on how to improve the code would be appreciated. If there
> is any interest in adding this feature to Org I could try to clean it
> up.

Thank you.

Would it make sense to automatically deduce this directory from included
file and apply this automatically?

Regards,

-- 
Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-01 18:32       ` Nicolas Goaziou
@ 2018-03-01 18:56         ` Daniel P Gomez
  2018-03-01 22:42           ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-03-01 18:56 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Currently when passing the :absolute-paths toggle to an include
derivative, as in :

#+INCLUDE: file.org :absolute-paths t

The function `org-export--prepare-file-contents` will automatically
deduce the directory from file.org and adapt links by calling:
`(new-path (expand-file-name old-path (file-name-directory file)))`.
I could either make this a default option, such that links get
corrected but users can overwrite this by calling `:absolute-paths
nil`, or I could completely remove this toggle and always correct
links no matter what.

One question regarding the implementation, currently I'm deleting the
link with a call to `delete-region` and using `(insert "[[file:"
new-path "]]")` to insert the corrected one. This does not take into
consideration whether links are bracketed or not ( is there a
functional difference if links are not bracketed?). Also, my approach
completely disregards link descriptions, which may be relevant if the
linked file would be, for example, an html document.  Would there be a
cleaner org approach to replace the path keeping the description?

Thank you.

Regards,
Daniel

On Thu, Mar 1, 2018 at 7:32 PM, Nicolas Goaziou <mail@nicolasgoaziou.fr> wrote:
> Hello,
>
> Daniel P Gomez <gomez.danp@gmail.com> writes:
>
>> If there is any interest, I've created a patch adding support for a
>> :absolute-paths functionality.
>> As I said, I don't have much experience writing Elisp, so any
>> suggestions on how to improve the code would be appreciated. If there
>> is any interest in adding this feature to Org I could try to clean it
>> up.
>
> Thank you.
>
> Would it make sense to automatically deduce this directory from included
> file and apply this automatically?
>
> Regards,
>
> --
> Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-01 18:56         ` Daniel P Gomez
@ 2018-03-01 22:42           ` Nicolas Goaziou
  2018-03-02 14:16             ` Daniel P Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Goaziou @ 2018-03-01 22:42 UTC (permalink / raw)
  To: Daniel P Gomez; +Cc: emacs-orgmode

Hello,

Daniel P Gomez <gomez.danp@gmail.com> writes:

> Currently when passing the :absolute-paths toggle to an include
> derivative, as in :
>
> #+INCLUDE: file.org :absolute-paths t
>
> The function `org-export--prepare-file-contents` will automatically
> deduce the directory from file.org and adapt links by calling:
> `(new-path (expand-file-name old-path (file-name-directory file)))`.
> I could either make this a default option, such that links get
> corrected but users can overwrite this by calling `:absolute-paths
> nil`, or I could completely remove this toggle and always correct
> links no matter what.

I am wondering about the latter. If there is no reason to keep broken
file names, it makes sense to automatically apply it.

Also, rewriting needs not be always absolute path, if both directories
share a common root.

> One question regarding the implementation, currently I'm deleting the
> link with a call to `delete-region` and using `(insert "[[file:"
> new-path "]]")` to insert the corrected one. This does not take into
> consideration whether links are bracketed or not ( is there a
> functional difference if links are not bracketed?).

Yes. White spaces are handled differently in each link type.

> Also, my approach completely disregards link descriptions, which may
> be relevant if the linked file would be, for example, an html
> document. Would there be a cleaner org approach to replace the path
> keeping the description?

You could check :contents-begin and :contents-end for the link. If they
are not nil, extract this region, and insert it again in the new link.

Regards,

-- 
Nicolas Goaziou                                                0x80A93738

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-01 22:42           ` Nicolas Goaziou
@ 2018-03-02 14:16             ` Daniel P Gomez
  2018-03-03  1:24               ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-03-02 14:16 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

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

I've adapted the code such that it handles both bracketed and
unbracketed links, and links with descriptions.
As it is now, the changes are always automatically applied.

> Also, rewriting needs not be always absolute path, if both directories
> share a common root.

I couldn't find a simple way of rewriting links without making them
absolute, as `org-export--prepare-file-contents` does not have access
to the path of the including file, only of the included file.



On Thu, Mar 1, 2018 at 11:42 PM, Nicolas Goaziou <mail@nicolasgoaziou.fr> wrote:
> Hello,
>
> Daniel P Gomez <gomez.danp@gmail.com> writes:
>
>> Currently when passing the :absolute-paths toggle to an include
>> derivative, as in :
>>
>> #+INCLUDE: file.org :absolute-paths t
>>
>> The function `org-export--prepare-file-contents` will automatically
>> deduce the directory from file.org and adapt links by calling:
>> `(new-path (expand-file-name old-path (file-name-directory file)))`.
>> I could either make this a default option, such that links get
>> corrected but users can overwrite this by calling `:absolute-paths
>> nil`, or I could completely remove this toggle and always correct
>> links no matter what.
>
> I am wondering about the latter. If there is no reason to keep broken
> file names, it makes sense to automatically apply it.
>
> Also, rewriting needs not be always absolute path, if both directories
> share a common root.
>
>> One question regarding the implementation, currently I'm deleting the
>> link with a call to `delete-region` and using `(insert "[[file:"
>> new-path "]]")` to insert the corrected one. This does not take into
>> consideration whether links are bracketed or not ( is there a
>> functional difference if links are not bracketed?).
>
> Yes. White spaces are handled differently in each link type.
>
>> Also, my approach completely disregards link descriptions, which may
>> be relevant if the linked file would be, for example, an html
>> document. Would there be a cleaner org approach to replace the path
>> keeping the description?
>
> You could check :contents-begin and :contents-end for the link. If they
> are not nil, extract this region, and insert it again in the new link.
>
> Regards,
>
> --
> Nicolas Goaziou                                                0x80A93738

[-- Attachment #2: 0001-Fix-file-links-when-using-INCLUDE.patch --]
[-- Type: application/octet-stream, Size: 1778 bytes --]

From feccfe829ea9fa4f44c47d8c845ed602d2945dcd Mon Sep 17 00:00:00 2001
From: Daniel Gomez <d.gomez@posteo.org>
Date: Fri, 2 Mar 2018 14:46:41 +0100
Subject: [PATCH 1/1] Fix file links when using #+INCLUDE

---
 lisp/ox.el | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/lisp/ox.el b/lisp/ox.el
index bd49a8a26..8f0aca989 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3476,6 +3476,34 @@ Optional argument FOOTNOTES is a hash-table to store footnotes in
 the included document."
   (with-temp-buffer
     (insert-file-contents file)
+    (goto-char (point-min))
+    (while (re-search-forward org-any-link-re nil t)
+      (let ((link (save-excursion
+		    (backward-char)
+		    (org-element-context))))
+	(when (string= (org-element-property :type link) "file")
+	  (let* ((has-bracket (string=
+			       (org-element-property :format link) "bracket"))
+		 (has-content (org-element-property :contents-begin link))
+		 (old-path (org-element-property :path link))
+		 (new-path (expand-file-name old-path
+					     (file-name-directory file)))
+		 (raw-new-link
+		  (concat "file:" new-path))
+		 (new-link
+		  (cond
+		   ((and has-bracket (not has-content))
+		    (concat "[[" raw-new-link "]]"))
+		   ((and has-bracket has-content)
+		    (let ((description
+			   (buffer-substring
+			    (org-element-property :contents-begin link)
+			    (org-element-property :contents-end link))))
+		      (concat "[[" raw-new-link "][" description "]]")))
+		   (t raw-new-link))))
+	    (apply #'delete-region (list (org-element-property :begin link)
+					 (org-element-property :end link)))
+	    (insert new-link)))))
     (when lines
       (let* ((lines (split-string lines "-"))
 	     (lbeg (string-to-number (car lines)))
-- 
2.16.2


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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-02 14:16             ` Daniel P Gomez
@ 2018-03-03  1:24               ` Nicolas Goaziou
  2018-03-03 13:06                 ` Daniel P Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Goaziou @ 2018-03-03  1:24 UTC (permalink / raw)
  To: Daniel P Gomez; +Cc: emacs-orgmode

Hello,

Daniel P Gomez <gomez.danp@gmail.com> writes:

> I've adapted the code such that it handles both bracketed and
> unbracketed links, and links with descriptions.
> As it is now, the changes are always automatically applied.

Thank you.

> I couldn't find a simple way of rewriting links without making them
> absolute, as `org-export--prepare-file-contents` does not have access
> to the path of the including file, only of the included file.

`org-export--prepare-file-contents' is called from the including
document, so you can get its path with (buffer-file-name
(buffer-base-buffer)).

However, we need to handle the case where the including buffer is not
associated to a file, i.e., the Sexp above returns nil.

> +    (goto-char (point-min))
> +    (while (re-search-forward org-any-link-re nil t)
> +      (let ((link (save-excursion
> +		    (backward-char)
> +		    (org-element-context))))

It would be nice to add a comment explaining what we are going to do.

> +	(when (string= (org-element-property :type link) "file")
> +	  (let* ((has-bracket (string=
> +			       (org-element-property :format link) "bracket"))
> +		 (has-content (org-element-property :contents-begin link))
> +		 (old-path (org-element-property :path link))
> +		 (new-path (expand-file-name old-path
> +					     (file-name-directory file)))
> +		 (raw-new-link
> +		  (concat "file:" new-path))
> +		 (new-link
> +		  (cond
> +		   ((and has-bracket (not has-content))
> +		    (concat "[[" raw-new-link "]]"))
> +		   ((and has-bracket has-content)
> +		    (let ((description
> +			   (buffer-substring
> +			    (org-element-property :contents-begin link)
> +			    (org-element-property :contents-end link))))
> +		      (concat "[[" raw-new-link "][" description "]]")))
> +		   (t raw-new-link))))
> +	    (apply #'delete-region (list (org-element-property :begin link)
> +					 (org-element-property :end link)))
> +	    (insert new-link)))))

I suggest the following inner part:

    (when (string= "file" (org-element-property :type link))
      (let* ((old-path (org-element-property :path link))
             (new-path (expand-file-name old-path (file-name-directory file))))
        (delete-region (org-element-property :begin link)
                       (org-element-property :end link))
        (insert (let ((new (org-element-copy link)))
                  (org-element-put-property new :path new-path)
                  (when (org-element-property :contents-begin link)
                    (org-element-adopt-elements new
                      (buffer-substring (org-element-property :contents-begin link)
                                        (org-element-property :contents-end link))))
                  (org-element-interpret-data new)))))
              
Also, would you mind adding a test in "text-ox.el", within
`test-org-export/expand-include'?

Regards,

-- 
Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-03  1:24               ` Nicolas Goaziou
@ 2018-03-03 13:06                 ` Daniel P Gomez
  2018-03-06  8:51                   ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P Gomez @ 2018-03-03 13:06 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Hi,


> `org-export--prepare-file-contents' is called from the including
> document, so you can get its path with (buffer-file-name
> (buffer-base-buffer)).
>
> However, we need to handle the case where the including buffer is not
> associated to a file, i.e., the Sexp above returns nil.
>

I noticed that (buffer-file-name (buffer-base-buffer)) will always
return nil because `org-export--prepare-file-contents` is called in
`org-export-include-keyword` after a call to `with-temp-buffer`. Two
possible solutions to this issue would be either 1. passing the
includer-file as an extra parameter to
`org-export--prepare-file-contents` and then using
`file-relative-name` to generate a relative path, or alternatively 2 .
passing the matched string that points to the file to be included.
Example:

#+INCLUDE: "directory/file.org"

Here, if file.org contains a link [[other/image.png]], then all one
has to do is append the (file-name-directory matched) to the old-path.
In this example this would result in directory/other/image.png.

This second solution does not require a call to (buffer-file-name
(buffer-base-buffer)), but seems hackish in the sense that we would
pass 2 redundant arguments to `org-export-prepare-file-contents`: both
the expanded and the non-expanded include-file filename.
Perhaps I'm missing a simpler 3rd solution?


> It would be nice to add a comment explaining what we are going to do.
>
Of course.

    ;; Adapt all file links within the included document that
    ;; contain relative paths in order to make these paths
    ;; relative to the base document, or absolute

> I suggest the following inner part:
>
>     (when (string= "file" (org-element-property :type link))
>       (let* ((old-path (org-element-property :path link))
>              (new-path (expand-file-name old-path (file-name-directory file))))

I noticed that the call to delete here will break
`org-element-adopt-elements` later on since the real buffer positions
will be changed and we are still querying for old, invalid positions
stored in link.
>         ;; (delete-region (org-element-property :begin link)
>         ;;               (org-element-property :end link))
>         (insert (let ((new (org-element-copy link)))

If we opt for solution 1 then new-path could be made relative here
>                  ;; (org-element-put-property new :path new-path)

(org-element-put-property
               new :path
               (if includer-file
               (file-relative-name
                new-path (file-name-directory includer-file))
             new-path))

>                   (when (org-element-property :contents-begin link)
>                     (org-element-adopt-elements new
>                       (buffer-substring (org-element-property :contents-begin link)
>                                         (org-element-property :contents-end link))))

Deleting immediately before the insertion works.
    (delete-region (org-element-property :begin link)
                           (org-element-property :end link))

>                   (org-element-interpret-data new)))))
>
> Also, would you mind adding a test in "text-ox.el", within
> `test-org-export/expand-include'?

I will attempt to write them once the implementation is completed.

Thanks for the support.

Regards,

Daniel

> Regards,
>
> --
> Nicolas Goaziou

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-03 13:06                 ` Daniel P Gomez
@ 2018-03-06  8:51                   ` Nicolas Goaziou
  2018-03-10 11:28                     ` Daniel P. Gomez
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Goaziou @ 2018-03-06  8:51 UTC (permalink / raw)
  To: Daniel P Gomez; +Cc: emacs-orgmode

Hello,

Daniel P Gomez <gomez.danp@gmail.com> writes:

> I noticed that (buffer-file-name (buffer-base-buffer)) will always
> return nil because `org-export--prepare-file-contents` is called in
> `org-export-include-keyword` after a call to `with-temp-buffer`. Two
> possible solutions to this issue would be either 1. passing the
> includer-file as an extra parameter to
> `org-export--prepare-file-contents` and then using
> `file-relative-name` to generate a relative path, or alternatively 2 .
> passing the matched string that points to the file to be included.
> Example:
>
> #+INCLUDE: "directory/file.org"
>
> Here, if file.org contains a link [[other/image.png]], then all one
> has to do is append the (file-name-directory matched) to the old-path.
> In this example this would result in directory/other/image.png.
>
> This second solution does not require a call to (buffer-file-name
> (buffer-base-buffer)), but seems hackish in the sense that we would
> pass 2 redundant arguments to `org-export-prepare-file-contents`: both
> the expanded and the non-expanded include-file filename.
> Perhaps I'm missing a simpler 3rd solution?

I think solution 1 is fine.

> If we opt for solution 1 then new-path could be made relative here
>>                  ;; (org-element-put-property new :path new-path)
>
> (org-element-put-property
>                new :path
>                (if includer-file
>                (file-relative-name
>                 new-path (file-name-directory includer-file))
>              new-path))

Indeed. However, the (if includer-file ...) should be integrated in
new-path binding, IMO.

> I will attempt to write them once the implementation is completed.

Great. Thank you!

Regards,

-- 
Nicolas Goaziou                                                0x80A93738

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-06  8:51                   ` Nicolas Goaziou
@ 2018-03-10 11:28                     ` Daniel P. Gomez
  2018-03-18 15:15                       ` Nicolas Goaziou
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel P. Gomez @ 2018-03-10 11:28 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

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


I've fixed the implementation of 
`org-export--prepare-file-contents` so
that links are relative to the included file. A patch is attached.

I've also created two org files in the test examples directory:
"includer-with-links.org" and "subdir/includee-with-links.org". My 
goal
was to add a test in "test-ox.el" `test-org-export/expand-include` 
that
checks whether, after exporting the "includer-with-links.org" file 
to
Org, the headings *Source and *Target are the same.

I did not figure out how to do this cleanly, so any help 
implementing
the test itself would be greatly appreciated.

Regards,

Daniel


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-file-links-when-using-INCLUDE.patch --]
[-- Type: text/x-patch, Size: 4560 bytes --]

From b47dcf43067cd57e2ee3c1f8e4dfea94bca7d14b Mon Sep 17 00:00:00 2001
From: Daniel Gomez <d.gomez@posteo.org>
Date: Fri, 2 Mar 2018 14:46:41 +0100
Subject: [PATCH 1/1] Fix file links when using #+INCLUDE

---
 lisp/ox.el                                      | 36 ++++++++++++++++++++++---
 testing/examples/includer-with-links.org        | 19 +++++++++++++
 testing/examples/subdir/includee-with-links.org | 12 +++++++++
 3 files changed, 64 insertions(+), 3 deletions(-)
 create mode 100644 testing/examples/includer-with-links.org
 create mode 100644 testing/examples/subdir/includee-with-links.org

diff --git a/lisp/ox.el b/lisp/ox.el
index bd49a8a26..f9b2d8095 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3257,7 +3257,8 @@ avoid infinite recursion.  Optional argument DIR is the current
 working directory.  It is used to properly resolve relative
 paths.  Optional argument FOOTNOTES is a hash-table used for
 storing and resolving footnotes.  It is created automatically."
-  (let ((case-fold-search t)
+  (let ((includer-file (buffer-file-name (buffer-base-buffer)))
+	(case-fold-search t)
 	(file-prefix (make-hash-table :test #'equal))
 	(current-prefix 0)
 	(footnotes (or footnotes (make-hash-table :test #'equal)))
@@ -3373,7 +3374,8 @@ storing and resolving footnotes.  It is created automatically."
 			 (or
 			  (gethash file file-prefix)
 			  (puthash file (cl-incf current-prefix) file-prefix))
-			 footnotes)))
+			 footnotes
+			 includer-file)))
 		     (org-export-expand-include-keyword
 		      (cons (list file lines) included)
 		      (file-name-directory file)
@@ -3451,7 +3453,7 @@ Return a string of lines to be included in the format expected by
 		       counter))))))))
 
 (defun org-export--prepare-file-contents
-    (file &optional lines ind minlevel id footnotes)
+    (file &optional lines ind minlevel id footnotes includer-file)
   "Prepare contents of FILE for inclusion and return it as a string.
 
 When optional argument LINES is a string specifying a range of
@@ -3476,6 +3478,34 @@ Optional argument FOOTNOTES is a hash-table to store footnotes in
 the included document."
   (with-temp-buffer
     (insert-file-contents file)
+    ;; Adapt all file links within the included document that
+    ;; contain relative paths in order to make these paths
+    ;; relative to the base document, or absolute
+    (goto-char (point-min))
+    (while (re-search-forward org-any-link-re nil t)
+      (let ((link (save-excursion
+		    (backward-char)
+		    (org-element-context))))
+	(when (string= "file" (org-element-property :type link))
+	  (let* ((old-path (org-element-property :path link))
+		 (new-path (let ((abspath (expand-file-name
+				     old-path
+				     (file-name-directory file))))
+			     (if includer-file
+				 (file-relative-name
+				  abspath (file-name-directory includer-file))
+			       abspath))))
+	    (insert (let ((new (org-element-copy link)))
+		      (org-element-put-property new :path new-path)
+		      (when (org-element-property :contents-begin link)
+			(org-element-adopt-elements
+			 new
+			 (buffer-substring
+			  (org-element-property :contents-begin link)
+			  (org-element-property :contents-end link))))
+		      (delete-region (org-element-property :begin link)
+				     (org-element-property :end link))
+		      (org-element-interpret-data new)))))))
     (when lines
       (let* ((lines (split-string lines "-"))
 	     (lbeg (string-to-number (car lines)))
diff --git a/testing/examples/includer-with-links.org b/testing/examples/includer-with-links.org
new file mode 100644
index 000000000..f97b76375
--- /dev/null
+++ b/testing/examples/includer-with-links.org
@@ -0,0 +1,19 @@
+* Source
+
+#+INCLUDE: "./subdir/includee-with-links.org::*Links" :only-contents t
+
+
+* Target
+
+File link with description
+[[file:subdir/setupfile2.org][A setupfile]]
+
+File link pointing to a specific header
+[[file:normal.org::top]]
+
+Bracketed file link without description
+[[file:subdir/setupfile.org]]
+
+Plain file link
+file:subdir/setupfile.org
+
diff --git a/testing/examples/subdir/includee-with-links.org b/testing/examples/subdir/includee-with-links.org
new file mode 100644
index 000000000..1f734ab86
--- /dev/null
+++ b/testing/examples/subdir/includee-with-links.org
@@ -0,0 +1,12 @@
+* Links
+File link with description
+[[file:setupfile2.org][A setupfile]]
+
+File link pointing to a specific header
+[[file:../normal.org::top]]
+
+Bracketed file link without description
+[[file:setupfile.org]]
+
+Plain file link
+file:setupfile.org
-- 
2.16.2


[-- Attachment #3: Type: text/plain, Size: 1896 bytes --]




Nicolas Goaziou writes:

> Hello,
>
> Daniel P Gomez <gomez.danp@gmail.com> writes:
>
>> I noticed that (buffer-file-name (buffer-base-buffer)) will 
>> always
>> return nil because `org-export--prepare-file-contents` is 
>> called in
>> `org-export-include-keyword` after a call to 
>> `with-temp-buffer`. Two
>> possible solutions to this issue would be either 1. passing the
>> includer-file as an extra parameter to
>> `org-export--prepare-file-contents` and then using
>> `file-relative-name` to generate a relative path, or 
>> alternatively 2 .
>> passing the matched string that points to the file to be 
>> included.
>> Example:
>>
>> #+INCLUDE: "directory/file.org"
>>
>> Here, if file.org contains a link [[other/image.png]], then all 
>> one
>> has to do is append the (file-name-directory matched) to the 
>> old-path.
>> In this example this would result in directory/other/image.png.
>>
>> This second solution does not require a call to 
>> (buffer-file-name
>> (buffer-base-buffer)), but seems hackish in the sense that we 
>> would
>> pass 2 redundant arguments to 
>> `org-export-prepare-file-contents`: both
>> the expanded and the non-expanded include-file filename.
>> Perhaps I'm missing a simpler 3rd solution?
>
> I think solution 1 is fine.
>
>> If we opt for solution 1 then new-path could be made relative 
>> here
>>>                  ;; (org-element-put-property new :path 
>>>                  new-path)
>>
>> (org-element-put-property
>>                new :path
>>                (if includer-file
>>                (file-relative-name
>>                 new-path (file-name-directory includer-file))
>>              new-path))
>
> Indeed. However, the (if includer-file ...) should be integrated 
> in
> new-path binding, IMO.
>
>> I will attempt to write them once the implementation is 
>> completed.
>
> Great. Thank you!
>
> Regards,


--
Daniel P. Gomez

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

* Re: How to keep correct filepaths when using the #+INCLUDE derivative?
  2018-03-10 11:28                     ` Daniel P. Gomez
@ 2018-03-18 15:15                       ` Nicolas Goaziou
  0 siblings, 0 replies; 13+ messages in thread
From: Nicolas Goaziou @ 2018-03-18 15:15 UTC (permalink / raw)
  To: Daniel P. Gomez; +Cc: emacs-orgmode

Hello,

"Daniel P. Gomez" <gomez.danp@gmail.com> writes:

> I've fixed the implementation of `org-export--prepare-file-contents`
> so
> that links are relative to the included file. A patch is attached.
>
> I've also created two org files in the test examples directory:
> "includer-with-links.org" and "subdir/includee-with-links.org". My
> goal
> was to add a test in "test-ox.el" `test-org-export/expand-include`
> that
> checks whether, after exporting the "includer-with-links.org" file to
> Org, the headings *Source and *Target are the same.
>
> I did not figure out how to do this cleanly, so any help implementing
> the test itself would be greatly appreciated.

I applied your patch and wrote a few tests. Let me know if it works for
you.

BTW, what's your status wrt FSF papers? I don't remember if you have
signed them already.

Thank you!

Regards,

-- 
Nicolas Goaziou                                                0x80A93738

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

end of thread, other threads:[~2018-03-18 15:16 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-28 13:29 How to keep correct filepaths when using the #+INCLUDE derivative? Daniel P Gomez
2018-02-28 17:51 ` Nicolas Goaziou
2018-02-28 20:11   ` Daniel P Gomez
2018-03-01  1:01     ` Daniel P Gomez
2018-03-01 18:32       ` Nicolas Goaziou
2018-03-01 18:56         ` Daniel P Gomez
2018-03-01 22:42           ` Nicolas Goaziou
2018-03-02 14:16             ` Daniel P Gomez
2018-03-03  1:24               ` Nicolas Goaziou
2018-03-03 13:06                 ` Daniel P Gomez
2018-03-06  8:51                   ` Nicolas Goaziou
2018-03-10 11:28                     ` Daniel P. Gomez
2018-03-18 15:15                       ` Nicolas Goaziou

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