[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] Allow #+SETUPFILE to point to an URL for the org file

From: Kaushal Modi
Subject: Re: [O] Allow #+SETUPFILE to point to an URL for the org file
Date: Mon, 13 Mar 2017 17:37:03 +0000

On Thu, Dec 8, 2016 at 5:40 PM Nicolas Goaziou <address@hidden> wrote:
Kaushal Modi <address@hidden> writes:

You can use something like `url-insert' and `url-retrieve' or

Thanks. I am using url-retrieve-synchronously. 

Sure, but SETUPFILE still accepts local file names. So I was pointing
out that you need to check if the URL is a local file name before
proceeding. In particular, this check needs to happen when using "C-c '"
(which may display URL contents in a read-only buffer, BTW).

Understood. I might need some help when baking this into org.el, org-macros.el, etc.

Is it necessary? File contents could be stored in, e.g., a hash table,
url being the key. The file is downloaded only if the entry doesn't
exist in the table and the user didn't force download.-

Correct. Thanks for the idea. I am now using hash table for this. 

Here is my implementation.. it is still not baked into org.el, etc and provided as a complete patch; I have some questions..

(defvar org-setupfile-ht (make-hash-table :test 'equal)
  "Hash table to store the org SETUPFILE.
This acts as a cache of setup files read using `org-insert-setupfile-contents'.")

(defun org-setupfile-clear-cache ()
  "Clear the SETUPFILE cache stored in `org-setupfile-ht'."
  (clrhash org-setupfile-ht))

(defun org-insert-setupfile-contents (setupfile &optional nocache noerror)
  "Insert the contents of SETUPFILE.
SETUPFILE can be a file path or URL.

If SETUPFILE is a file path, use `org-file-contents' to get the file contents.
If it is a URL instead, download the contents. If the URL contents are already
cached in the `org-setupfile-ht' hash table, the download step is skipped.

If NOCACHE is non-nil, do a fresh fetch of SETUPFILE even if cached version is
available. This option applies only if SETUPFILE is a URL.

If NOERROR is non-nil, ignore the error when unable to read the SETUPFILE from
file or URL."
  (require 'ffap)                       ;for `ffap-url-regexp'
  (let* ((is-url (string-match-p ffap-url-regexp setupfile))
         (cache (when (and is-url (not nocache))
                  (gethash setupfile org-setupfile-ht)))
         (contents (when (and is-url cache) cache)))
    (if is-url
        (unless cache
          (let (url-retrieve-header)
            (with-current-buffer (url-retrieve-synchronously setupfile)
              (goto-char (point-min))
              ;; Take point to after the url-retrieve header
              (re-search-forward "\n\n") ; 2 consecutive new-line chars
              (setq url-retrieve-header (buffer-substring-no-properties
                                         (point-min) (point)))
              (message url-retrieve-header) ;Dump the URL retrieve header to *Messages*
              (if (string-match-p "HTTP.*\\s-+200\\s-OK" url-retrieve-header) ;URL retrieved correctly
                    (setq contents (buffer-substring-no-properties (point) (point-max)))
                    ;; Update the cache `org-setupfile-ht'
                    (puthash setupfile contents org-setupfile-ht))
                (funcall (if noerror 'message 'error)
                         "Unable to fetch SETUPFILE from `%s'" setupfile)))))
      (setq contents (org-file-contents setupfile noerror)))
    (when contents
        (insert contents)))))


- All the places where the content of SETUPFILE is inserted in a temp buffer, it is assumed that the file is retrieved from disk and not from URL.

Example in ox.el:

 ((equal key "SETUPFILE")
  (let ((file
  (org-unbracket-string "\"" "\"" (org-trim val)))))
    ;; Avoid circular dependencies.
    (unless (member file files)
(setq default-directory
  (file-name-directory file))
(insert (org-file-contents file 'noerror))
(let ((org-inhibit-startup t)) (org-mode))
(funcall get-options (cons file files))))))

Note the use of expand-file-name, (member file files), default-directory, (funcall get-options (cons file files)).

How do we deal with those parts of the code when the 'file' is a URL.

Using my implementation above, 

    (org-insert-setupfile-contents "/file/path/or/url" nil :noerror)

works the same way as 

    (insert (org-file-contents "/file/path" 'noerror))

So org-insert-setupfile-contents can replace (insert (org-file-contents ..)) easily. The unknown is how to deal with the surrounding code that deals with

> expand-file-name, (member file files), default-directory, (funcall get-options (cons file files)).

Here's a similar code snippet around setupfile insertion in ox.el again, in org-export--list-bound-variables:

    ;; Enter setup file.
    (let ((file (expand-file-name
 (org-unbracket-string "\"" "\"" val))))
      (unless (member file files)
  (setq default-directory
(file-name-directory file))
  (let ((org-inhibit-startup t)) (org-mode))
  (insert (org-file-contents file 'noerror))
  (setq alist
(funcall collect-bind
 (cons file files)


Kaushal Modi

reply via email to

[Prev in Thread] Current Thread [Next in Thread]