Browse Source

Merge branch 'master' of orgmode.org:org-mode

Carsten Dominik 7 năm trước cách đây
mục cha
commit
feed16e1ed
8 tập tin đã thay đổi với 248 bổ sung121 xóa
  1. 21 17
      doc/org.texi
  2. 11 1
      etc/ORG-NEWS
  3. 10 68
      lisp/org-element.el
  4. 14 8
      lisp/org-macro.el
  5. 62 12
      lisp/org.el
  6. 23 15
      lisp/ox.el
  7. 75 0
      testing/lisp/test-org.el
  8. 32 0
      testing/lisp/test-ox.el

+ 21 - 17
doc/org.texi

@@ -10411,14 +10411,14 @@ override options set at a more general level.
 
 
 @cindex #+SETUPFILE
 @cindex #+SETUPFILE
 In-buffer settings may appear anywhere in the file, either directly or
 In-buffer settings may appear anywhere in the file, either directly or
-indirectly through a file included using @samp{#+SETUPFILE: filename} syntax.
-Option keyword sets tailored to a particular back-end can be inserted from
-the export dispatcher (@pxref{The export dispatcher}) using the @code{Insert
-template} command by pressing @key{#}.  To insert keywords individually,
-a good way to make sure the keyword is correct is to type @code{#+} and then
-to use @kbd{M-@key{TAB}}@footnote{Many desktops intercept @kbd{M-TAB} to
-switch windows.  Use @kbd{C-M-i} or @kbd{@key{ESC} @key{TAB}} instead.} for
-completion.
+indirectly through a file included using @samp{#+SETUPFILE: filename or URL}
+syntax.  Option keyword sets tailored to a particular back-end can be
+inserted from the export dispatcher (@pxref{The export dispatcher}) using the
+@code{Insert template} command by pressing @key{#}.  To insert keywords
+individually, a good way to make sure the keyword is correct is to type
+@code{#+} and then to use @kbd{M-@key{TAB}}@footnote{Many desktops intercept
+@kbd{M-TAB} to switch windows.  Use @kbd{C-M-i} or @kbd{@key{ESC} @key{TAB}}
+instead.} for completion.
 
 
 The export keywords available for every back-end, and their equivalent global
 The export keywords available for every back-end, and their equivalent global
 variables, include:
 variables, include:
@@ -17179,14 +17179,16 @@ have a lower ASCII number than the lowest priority.
 This line sets a default inheritance value for entries in the current
 This line sets a default inheritance value for entries in the current
 buffer, most useful for specifying the allowed values of a property.
 buffer, most useful for specifying the allowed values of a property.
 @cindex #+SETUPFILE
 @cindex #+SETUPFILE
-@item #+SETUPFILE: file
-The setup file is for additional in-buffer settings.  Org loads this file and
-parses it for any settings in it only when Org opens the main file.  @kbd{C-c
-C-c} on the settings line will also parse and load.  Org also parses and
-loads the file during normal exporting process.  Org parses the contents of
-this file as if it was included in the buffer.  It can be another Org file.
-To visit the file, @kbd{C-c '} while the cursor is on the line with the file
-name.
+@item #+SETUPFILE: file or URL
+The setup file or a URL pointing to such file is for additional in-buffer
+settings.  Org loads this file and parses it for any settings in it only when
+Org opens the main file.  If URL is specified, the contents are downloaded
+and stored in a temporary file cache.  @kbd{C-c C-c} on the settings line
+will parse and load the file, and also reset the temporary file cache.  Org
+also parses and loads the document during normal exporting process.  Org
+parses the contents of this document as if it was included in the buffer.  It
+can be another Org file.  To visit the file (not a URL), @kbd{C-c '} while
+the cursor is on the line with the file name.
 @item #+STARTUP:
 @item #+STARTUP:
 @cindex #+STARTUP
 @cindex #+STARTUP
 Startup options Org uses when first visiting a file.
 Startup options Org uses when first visiting a file.
@@ -17427,7 +17429,9 @@ If any highlights shown in the buffer from the creation of a sparse tree, or
 from clock display, remove such highlights.
 from clock display, remove such highlights.
 @item
 @item
 If the cursor is in one of the special @code{#+KEYWORD} lines, scan the
 If the cursor is in one of the special @code{#+KEYWORD} lines, scan the
-buffer for these lines and update the information.
+buffer for these lines and update the information.  Also reset the Org file
+cache used to temporary store the contents of URLs used as values for
+keywords like @code{#+SETUPFILE}.
 @item
 @item
 If the cursor is inside a table, realign the table.  The table realigns even
 If the cursor is inside a table, realign the table.  The table realigns even
 if automatic table editor is turned off.
 if automatic table editor is turned off.

+ 11 - 1
etc/ORG-NEWS

@@ -203,7 +203,7 @@ manual for details.
 **** Add global macros through ~org-export-global-macros~
 **** Add global macros through ~org-export-global-macros~
 With this variable, one can define macros available for all documents.
 With this variable, one can define macros available for all documents.
 **** New keyword ~#+EXPORT_FILE_NAME~
 **** New keyword ~#+EXPORT_FILE_NAME~
-Simiralry to ~:EXPORT_FILE_NAME:~ property, this keyword allows the
+Similarly to ~:EXPORT_FILE_NAME:~ property, this keyword allows the
 user to specify the name of the output file upon exporting the
 user to specify the name of the output file upon exporting the
 document.  This also has an effect on publishing.
 document.  This also has an effect on publishing.
 **** Horizontal rules are no longer ignored in LaTeX table math mode
 **** Horizontal rules are no longer ignored in LaTeX table math mode
@@ -240,6 +240,16 @@ which causes refile targets to be prefixed with the buffer’s
 name. This is particularly useful when used in conjunction with
 name. This is particularly useful when used in conjunction with
 ~uniquify.el~.
 ~uniquify.el~.
 
 
+*** ~org-file-contents~ now allows the FILE argument to be a URL.
+This allows ~#+SETUPFILE:~ to accept a URL instead of a local file
+path.  The URL contents are auto-downloaded and saved to a temporary
+cache ~org--file-cache~.  A new optional argument ~NOCACHE~ is added
+to ~org-file-contents~.
+
+*** ~org-mode-restart~ now resets the newly added ~org--file-cache~.
+Using ~C-c C-c~ on any keyword (like ~#+SETUPFILE~) will reset the
+that file cache.
+
 ** Removed functions
 ** Removed functions
 
 
 *** Org Timeline
 *** Org Timeline

+ 10 - 68
lisp/org-element.el

@@ -22,79 +22,21 @@
 
 
 ;;; Commentary:
 ;;; Commentary:
 ;;
 ;;
-;; Org syntax can be divided into three categories: "Greater
-;; elements", "Elements" and "Objects".
+;; See <http://orgmode.org/worg/dev/org-syntax.html> for details about
+;; Org syntax.
 ;;
 ;;
-;; Elements are related to the structure of the document.  Indeed, all
-;; elements are a cover for the document: each position within belongs
-;; to at least one element.
-;;
-;; An element always starts and ends at the beginning of a line.  With
-;; a few exceptions (`clock', `headline', `inlinetask', `item',
-;; `planning', `property-drawer', `node-property', `section' and
-;; `table-row' types), it can also accept a fixed set of keywords as
-;; attributes.  Those are called "affiliated keywords" to distinguish
-;; them from other keywords, which are full-fledged elements.  Almost
-;; all affiliated keywords are referenced in
-;; `org-element-affiliated-keywords'; the others are export attributes
-;; and start with "ATTR_" prefix.
-;;
-;; Element containing other elements (and only elements) are called
-;; greater elements.  Concerned types are: `center-block', `drawer',
-;; `dynamic-block', `footnote-definition', `headline', `inlinetask',
-;; `item', `plain-list', `property-drawer', `quote-block', `section'
-;; and `special-block'.
-;;
-;; Other element types are: `babel-call', `clock', `comment',
-;; `comment-block', `diary-sexp', `example-block', `export-block',
-;; `fixed-width', `horizontal-rule', `keyword', `latex-environment',
-;; `node-property', `paragraph', `planning', `src-block', `table',
-;; `table-row' and `verse-block'.  Among them, `paragraph' and
-;; `verse-block' types can contain Org objects and plain text.
-;;
-;; Objects are related to document's contents.  Some of them are
-;; recursive.  Associated types are of the following: `bold', `code',
-;; `entity', `export-snippet', `footnote-reference',
-;; `inline-babel-call', `inline-src-block', `italic',
-;; `latex-fragment', `line-break', `link', `macro', `radio-target',
-;; `statistics-cookie', `strike-through', `subscript', `superscript',
-;; `table-cell', `target', `timestamp', `underline' and `verbatim'.
-;;
-;; Some elements also have special properties whose value can hold
-;; objects themselves (e.g. an item tag or a headline name).  Such
-;; values are called "secondary strings".  Any object belongs to
-;; either an element or a secondary string.
-;;
-;; Notwithstanding affiliated keywords, each greater element, element
-;; and object has a fixed set of properties attached to it.  Among
-;; them, four are shared by all types: `:begin' and `:end', which
-;; refer to the beginning and ending buffer positions of the
-;; considered element or object, `:post-blank', which holds the number
-;; of blank lines, or white spaces, at its end and `:parent' which
-;; refers to the element or object containing it.  Greater elements,
-;; elements and objects containing objects will also have
-;; `:contents-begin' and `:contents-end' properties to delimit
-;; contents.  Eventually, All elements have a `:post-affiliated'
-;; property referring to the buffer position after all affiliated
-;; keywords, if any, or to their beginning position otherwise.
-;;
-;; At the lowest level, a `:parent' property is also attached to any
-;; string, as a text property.
-;;
-;; Lisp-wise, an element or an object can be represented as a list.
+;; Lisp-wise, a syntax object can be represented as a list.
 ;; It follows the pattern (TYPE PROPERTIES CONTENTS), where:
 ;; It follows the pattern (TYPE PROPERTIES CONTENTS), where:
-;;   TYPE is a symbol describing the Org element or object.
+;;   TYPE is a symbol describing the object.
 ;;   PROPERTIES is the property list attached to it.  See docstring of
 ;;   PROPERTIES is the property list attached to it.  See docstring of
-;;              appropriate parsing function to get an exhaustive
-;;              list.
-;;   CONTENTS is a list of elements, objects or raw strings contained
-;;            in the current element or object, when applicable.
+;;              appropriate parsing function to get an exhaustive list.
+;;   CONTENTS is a list of syntax objects or raw strings contained
+;;            in the current object, when applicable.
 ;;
 ;;
-;; An Org buffer is a nested list of such elements and objects, whose
-;; type is `org-data' and properties is nil.
+;; For the whole document, TYPE is `org-data' and PROPERTIES is nil.
 ;;
 ;;
-;; The first part of this file defines Org syntax, while the second
-;; one provide accessors and setters functions.
+;; The first part of this file defines constants for the Org syntax,
+;; while the second one provide accessors and setters functions.
 ;;
 ;;
 ;; The next part implements a parser and an interpreter for each
 ;; The next part implements a parser and an interpreter for each
 ;; element and object type in Org syntax.
 ;; element and object type in Org syntax.

+ 14 - 8
lisp/org-macro.el

@@ -55,7 +55,8 @@
 (declare-function org-element-macro-parser "org-element" ())
 (declare-function org-element-macro-parser "org-element" ())
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-type "org-element" (element))
 (declare-function org-element-type "org-element" (element))
-(declare-function org-file-contents "org" (file &optional noerror))
+(declare-function org-file-contents "org" (file &optional noerror nocache))
+(declare-function org-file-url-p "org" (file))
 (declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
 (declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
 (declare-function org-mode "org" ())
 (declare-function org-mode "org" ())
 (declare-function vc-backend "vc-hooks" (f))
 (declare-function vc-backend "vc-hooks" (f))
@@ -102,16 +103,21 @@ Return an alist containing all macro templates found."
 				 (if old-cell (setcdr old-cell template)
 				 (if old-cell (setcdr old-cell template)
 				   (push (cons name template) templates))))
 				   (push (cons name template) templates))))
 			   ;; Enter setup file.
 			   ;; Enter setup file.
-			   (let ((file (expand-file-name
-					(org-unbracket-string "\"" "\"" val))))
-			     (unless (member file files)
+			   (let* ((uri (org-unbracket-string "\"" "\"" (org-trim val)))
+				  (uri-is-url (org-file-url-p uri))
+				  (uri (if uri-is-url
+					   uri
+					 (expand-file-name uri))))
+			     ;; Avoid circular dependencies.
+			     (unless (member uri files)
 			       (with-temp-buffer
 			       (with-temp-buffer
-				 (setq default-directory
-				       (file-name-directory file))
+				 (unless uri-is-url
+				   (setq default-directory
+					 (file-name-directory uri)))
 				 (org-mode)
 				 (org-mode)
-				 (insert (org-file-contents file 'noerror))
+				 (insert (org-file-contents uri 'noerror))
 				 (setq templates
 				 (setq templates
-				       (funcall collect-macros (cons file files)
+				       (funcall collect-macros (cons uri files)
 						templates)))))))))))
 						templates)))))))))))
 		templates))))
 		templates))))
     (funcall collect-macros nil nil)))
     (funcall collect-macros nil nil)))

+ 62 - 12
lisp/org.el

@@ -181,6 +181,8 @@ Stars are put in group 1 and the trimmed body in group 2.")
 (declare-function org-export-get-environment "ox" (&optional backend subtreep ext-plist))
 (declare-function org-export-get-environment "ox" (&optional backend subtreep ext-plist))
 (declare-function org-latex-make-preamble "ox-latex" (info &optional template snippet?))
 (declare-function org-latex-make-preamble "ox-latex" (info &optional template snippet?))
 
 
+(defvar ffap-url-regexp)		;Silence byte-compiler
+
 (defsubst org-uniquify (list)
 (defsubst org-uniquify (list)
   "Non-destructively remove duplicate elements from LIST."
   "Non-destructively remove duplicate elements from LIST."
   (let ((res (copy-sequence list))) (delete-dups res)))
   (let ((res (copy-sequence list))) (delete-dups res)))
@@ -5280,17 +5282,62 @@ a string, summarizing TAGS, as a list of strings."
 	   (setq current-group (list tag))))
 	   (setq current-group (list tag))))
 	(_ nil)))))
 	(_ nil)))))
 
 
-(defun org-file-contents (file &optional noerror)
-  "Return the contents of FILE, as a string."
-  (if (and file (file-readable-p file))
+(defvar org--file-cache (make-hash-table :test #'equal)
+  "Hash table to store contents of files referenced via a URL.
+This is the cache of file URLs read using `org-file-contents'.")
+
+(defun org-reset-file-cache ()
+  "Reset the cache of files downloaded by `org-file-contents'."
+  (clrhash org--file-cache))
+
+(defun org-file-url-p (file)
+  "Non-nil if FILE is a URL."
+  (require 'ffap)
+  (string-match-p ffap-url-regexp file))
+
+(defun org-file-contents (file &optional noerror nocache)
+  "Return the contents of FILE, as a string.
+
+FILE can be a file name or URL.
+
+If FILE is a URL, download the contents.  If the URL contents are
+already cached in the `org--file-cache' hash table, the download step
+is skipped.
+
+If NOERROR is non-nil, ignore the error when unable to read the FILE
+from file or URL.
+
+If NOCACHE is non-nil, do a fresh fetch of FILE even if cached version
+is available.  This option applies only if FILE is a URL."
+  (let* ((is-url (org-file-url-p file))
+         (cache (and is-url
+                     (not nocache)
+                     (gethash file org--file-cache))))
+    (cond
+     (cache)
+     (is-url
+      (with-current-buffer (url-retrieve-synchronously file)
+	(goto-char (point-min))
+	;; Move point to after the url-retrieve header.
+	(search-forward "\n\n" nil :move)
+	;; Search for the success code only in the url-retrieve header.
+	(if (save-excursion (re-search-backward "HTTP.*\\s-+200\\s-OK" nil :noerror))
+	    ;; Update the cache `org--file-cache' and return contents.
+	    (puthash file
+		     (buffer-substring-no-properties (point) (point-max))
+		     org--file-cache)
+	  (funcall (if noerror #'message #'user-error)
+		   "Unable to fetch file from %S"
+		   file))))
+     (t
       (with-temp-buffer
       (with-temp-buffer
-	(insert-file-contents file)
-	(buffer-string))
-    (funcall (if noerror 'message 'error)
-	     "Cannot read file \"%s\"%s"
-	     file
-	     (let ((from (buffer-file-name (buffer-base-buffer))))
-	       (if from (concat " (referenced in file \"" from "\")") "")))))
+        (condition-case err
+	    (progn
+	      (insert-file-contents file)
+	      (buffer-string))
+	  (file-error
+           (funcall (if noerror #'message #'user-error)
+		    (error-message-string err)))))))))
 
 
 (defun org-extract-log-state-settings (x)
 (defun org-extract-log-state-settings (x)
   "Extract the log state setting from a TODO keyword string.
   "Extract the log state setting from a TODO keyword string.
@@ -20687,7 +20734,9 @@ Otherwise, return a user error."
 	    (format "[[%s]]"
 	    (format "[[%s]]"
 		    (expand-file-name
 		    (expand-file-name
 		     (let ((value (org-element-property :value element)))
 		     (let ((value (org-element-property :value element)))
-		       (cond ((not (org-string-nw-p value))
+		       (cond ((org-file-url-p value)
+			      (user-error "The file is specified as a URL, cannot be edited"))
+			     ((not (org-string-nw-p value))
 			      (user-error "No file to edit"))
 			      (user-error "No file to edit"))
 			     ((string-match "\\`\"\\(.*?\\)\"" value)
 			     ((string-match "\\`\"\\(.*?\\)\"" value)
 			      (match-string 1 value))
 			      (match-string 1 value))
@@ -20951,7 +21000,8 @@ Use `\\[org-edit-special]' to edit table.el tables"))
     (funcall major-mode)
     (funcall major-mode)
     (hack-local-variables)
     (hack-local-variables)
     (when (and indent-status (not (bound-and-true-p org-indent-mode)))
     (when (and indent-status (not (bound-and-true-p org-indent-mode)))
-      (org-indent-mode -1)))
+      (org-indent-mode -1))
+    (org-reset-file-cache))
   (message "%s restarted" major-mode))
   (message "%s restarted" major-mode))
 
 
 (defun org-kill-note-or-show-branches ()
 (defun org-kill-note-or-show-branches ()

+ 23 - 15
lisp/ox.el

@@ -1499,17 +1499,20 @@ Assume buffer is in Org mode.  Narrowing, if any, is ignored."
 			 (cond
 			 (cond
 			  ;; Options in `org-export-special-keywords'.
 			  ;; Options in `org-export-special-keywords'.
 			  ((equal key "SETUPFILE")
 			  ((equal key "SETUPFILE")
-			   (let ((file
-				  (expand-file-name
-				   (org-unbracket-string "\"" "\"" (org-trim val)))))
+			   (let* ((uri (org-unbracket-string "\"" "\"" (org-trim val)))
+				  (uri-is-url (org-file-url-p uri))
+				  (uri (if uri-is-url
+					   uri
+					 (expand-file-name uri))))
 			     ;; Avoid circular dependencies.
 			     ;; Avoid circular dependencies.
-			     (unless (member file files)
+			     (unless (member uri files)
 			       (with-temp-buffer
 			       (with-temp-buffer
-				 (setq default-directory
-				   (file-name-directory file))
-				 (insert (org-file-contents file 'noerror))
+				 (unless uri-is-url
+				   (setq default-directory
+					 (file-name-directory uri)))
+				 (insert (org-file-contents uri 'noerror))
 				 (let ((org-inhibit-startup t)) (org-mode))
 				 (let ((org-inhibit-startup t)) (org-mode))
-				 (funcall get-options (cons file files))))))
+				 (funcall get-options (cons uri files))))))
 			  ((equal key "OPTIONS")
 			  ((equal key "OPTIONS")
 			   (setq plist
 			   (setq plist
 				 (org-combine-plists
 				 (org-combine-plists
@@ -1647,17 +1650,22 @@ an alist where associations are (VARIABLE-NAME VALUE)."
 				      "BIND")
 				      "BIND")
 			       (push (read (format "(%s)" val)) alist)
 			       (push (read (format "(%s)" val)) alist)
 			     ;; Enter setup file.
 			     ;; Enter setup file.
-			     (let ((file (expand-file-name
-					  (org-unbracket-string "\"" "\"" val))))
-			       (unless (member file files)
+			     (let* ((uri (org-unbracket-string "\"" "\"" val))
+				    (uri-is-url (org-file-url-p uri))
+				    (uri (if uri-is-url
+					     uri
+					   (expand-file-name uri))))
+			       ;; Avoid circular dependencies.
+			       (unless (member uri files)
 				 (with-temp-buffer
 				 (with-temp-buffer
-				   (setq default-directory
-					 (file-name-directory file))
+				   (unless uri-is-url
+				     (setq default-directory
+					   (file-name-directory uri)))
 				   (let ((org-inhibit-startup t)) (org-mode))
 				   (let ((org-inhibit-startup t)) (org-mode))
-				   (insert (org-file-contents file 'noerror))
+				   (insert (org-file-contents uri 'noerror))
 				   (setq alist
 				   (setq alist
 					 (funcall collect-bind
 					 (funcall collect-bind
-						  (cons file files)
+						  (cons uri files)
 						  alist))))))))))
 						  alist))))))))))
 		   alist)))))
 		   alist)))))
       ;; Return value in appropriate order of appearance.
       ;; Return value in appropriate order of appearance.

+ 75 - 0
testing/lisp/test-org.el

@@ -6498,6 +6498,81 @@ Paragraph<point>"
      (org-show-set-visibility 'minimal)
      (org-show-set-visibility 'minimal)
      (org-invisible-p2))))
      (org-invisible-p2))))
 
 
+(ert-deftest test-org/org-file-contents-file ()
+  "Test `org-file-contents' with a file as input."
+  (should
+   (string= "#+BIND: variable value
+#+DESCRIPTION: l2
+#+LANGUAGE: en
+#+SELECT_TAGS: b
+#+TITLE: b
+#+PROPERTY: a 1
+" (org-file-contents (expand-file-name "setupfile3.org"
+				       (concat org-test-dir "examples/")))))
+  
+  (let ((invalid-file "this-file-must-not-exist"))
+    ;; Throw error when trying to access an invalid file.
+    (should-error
+     (org-file-contents invalid-file))
+    ;; Try to access an invalid file, but do not throw an error.
+    (should
+     (string-match-p "\\`Opening input file: No such file or directory"
+		     (org-file-contents invalid-file :noerror)))))
+
+(ert-deftest test-org/org-file-contents-url ()
+  "Test `org-file-contents' with a URL as input."
+  (should
+   (string= "foo"
+	    (let ((buffer (generate-new-buffer "url-retrieve-output")))
+	      (unwind-protect
+		  ;; Simulate successful retrieval of a URL.
+		  (cl-letf (((symbol-function 'url-retrieve-synchronously)
+			     (lambda (&rest_)
+			       (with-current-buffer buffer
+				 (insert "HTTP/1.1 200 OK\n\nfoo"))
+			       buffer)))
+		    (org-file-contents "http://some-valid-url"))
+		(kill-buffer buffer)))))
+
+  (let ((invalid-url "http://this-url-must-not-exist"))
+    ;; Throw error when trying to access an invalid URL.
+    (should-error
+     (let ((buffer (generate-new-buffer "url-retrieve-output")))
+       (unwind-protect
+	   ;; Simulate unsuccessful retrieval of a URL.
+	   (cl-letf (((symbol-function 'url-retrieve-synchronously)
+		      (lambda (&rest_)
+			(with-current-buffer buffer
+			  (insert "HTTP/1.1 404 Not found\n\ndoes not matter"))
+			buffer)))
+	     (org-file-contents invalid-url))
+	 (kill-buffer buffer))))
+    ;; Try to access an invalid URL, but do not throw an error.
+    (should-error
+     (let ((buffer (generate-new-buffer "url-retrieve-output")))
+       (unwind-protect
+	   ;; Simulate unsuccessful retrieval of a URL.
+	   (cl-letf (((symbol-function 'url-retrieve-synchronously)
+		      (lambda (&rest_)
+			(with-current-buffer buffer
+			  (insert "HTTP/1.1 404 Not found\n\ndoes not matter"))
+			buffer)))
+	     (org-file-contents invalid-url))
+	 (kill-buffer buffer))))
+    (should
+     (string=
+      (format "Unable to fetch file from \"%s\"" invalid-url)
+      (let ((buffer (generate-new-buffer "url-retrieve-output")))
+	(unwind-protect
+	    ;; Simulate unsuccessful retrieval of a URL.
+	    (cl-letf (((symbol-function 'url-retrieve-synchronously)
+		       (lambda (&rest_)
+			 (with-current-buffer buffer
+			   (insert "HTTP/1.1 404 Not found\n\ndoes not matter"))
+			 buffer)))
+	      (org-file-contents invalid-url :noerror))
+	  (kill-buffer buffer)))))))
+
 
 
 (provide 'test-org)
 (provide 'test-org)
 
 

+ 32 - 0
testing/lisp/test-ox.el

@@ -232,6 +232,38 @@ num:2 <:active")))
 		org-test-dir)
 		org-test-dir)
       (org-export--get-inbuffer-options))
       (org-export--get-inbuffer-options))
     '(:language "fr" :select-tags ("a" "b" "c") :title ("a b c"))))
     '(:language "fr" :select-tags ("a" "b" "c") :title ("a b c"))))
+  ;; Options set through SETUPFILE specified using a URL.
+  (let ((buffer (generate-new-buffer "url-retrieve-output")))
+    (unwind-protect
+	;; Simulate successful retrieval of a setupfile from URL.
+	(cl-letf (((symbol-function 'url-retrieve-synchronously)
+		   (lambda (&rest_)
+		     (with-current-buffer buffer
+		       (insert "HTTP/1.1 200 OK
+
+# Contents of http://link-to-my-setupfile.org
+#+BIND: variable value
+#+DESCRIPTION: l2
+#+LANGUAGE: en
+#+SELECT_TAGS: b
+#+TITLE: b
+#+PROPERTY: a 1
+"))
+		     buffer)))
+	  (should
+	   (equal
+	    (org-test-with-temp-text
+		"#+DESCRIPTION: l1
+#+LANGUAGE: es
+#+SELECT_TAGS: a
+#+TITLE: a
+#+SETUPFILE: \"http://link-to-my-setupfile.org\"
+#+LANGUAGE: fr
+#+SELECT_TAGS: c
+#+TITLE: c"
+	      (org-export--get-inbuffer-options))
+	    '(:language "fr" :select-tags ("a" "b" "c") :title ("a b c")))))
+      (kill-buffer buffer)))
   ;; More than one property can refer to the same buffer keyword.
   ;; More than one property can refer to the same buffer keyword.
   (should
   (should
    (equal '(:k2 "value" :k1 "value")
    (equal '(:k2 "value" :k1 "value")