This patch hacks Emacs 20's browse-url.el to add and document BROWSER support.
See the BROWSER page at http://www.tuxedo.org/~esr/BROWSER/ for discussion.
--- browse-url.el 2001年01月24日 12:24:40 1.1
+++ browse-url.el 2001年01月24日 17:25:43
@@ -46,6 +46,19 @@
;; browse-url-mmm MMM ?
;; browse-url-generic arbitrary
+;; The user may set an explicit handler association list of URL-matching
+;; regexps that dispatches to browser functions. If the environment
+;; of Emacs includes a BROWSER variable, and the user has not set an
+;; explicit list of URL handlers, the value of BROWSER is interpreted
+;; a colon-separated series of browser command parts. These should be
+;; tried in order until one succeeds. Each command part may
+;; optionally contain the string "%s"; if it does, the URL to be
+;; viewed is substituted there. If a command part does not contain
+;; %s, the browser will be launched as if the URL had been supplied as
+;; its first argument. If the user has neither set an explicit handler
+;; list nor supplied BROWSER, Emacs falls back to a default browser
+;; function (which the user may also configure).
+
;; [A version of the Netscape browser is now free software
;; , albeit not GPLed, so it is
;; reasonable to have that as the default.]
@@ -613,6 +626,53 @@
(browse-url-of-buffer))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Interpretation of the BROWSER variable.
+;; See http://www.tuxedo.org/~esr/BROWSER/ for discussion.
+
+(defun browse-url-parse-colon-path (value)
+ "Explode a colon-separated search path into a list of parts."
+ (and value
+ (let (prefix part-list (start 0) colon)
+ (setq value (concat value ":"))
+ (while (setq colon (string-match ":" value start))
+ (setq part-list
+ (nconc part-list
+ (list (if (= start colon)
+ nil
+ (substring value start colon)))))
+ (setq start (+ colon 1)))
+ part-list)))
+
+(defun browse-url-default-from-environment ()
+ "Initialize browsers to be tried from the environment variable BROWSER.
+The value of BROWSER may consist of a colon-separated series of
+browser command parts. These should be tried in order until one succeeds.
+Each command part may optionally contain the string \"%s\"; if it does, the
+URL to be viewed is substituted there. If a command part does not
+contain %s, the browser will be launched as if the URL had been
+supplied as its first argument."
+ (mapcar
+ (lambda (part)
+ (cons "."
+ ;; First, look for the names of browsers we know about.
+ (cond ((string= part "netscape") 'browse-url-netscape)
+ ((string= part "mosaic") 'browse-url-mosaic)
+ ((string= part "grail") 'browse-url-grail)
+ ((string= part "iximosaic") 'browse-url-iximosaic)
+ ((string= part "w3") 'browse-url-w3)
+ ((string= part "lynx") 'browse-url-lynx-emacs)
+ ((string= part "mmm") 'browse-url-mmm)
+ ;; Not one we know about? OK, construct a lambda to call it.
+ (t
+ (let ((command
+ (cond ((string-match "%s" part) part)
+ (t (concat part " %s")))))
+ `(lambda (url &optional new-window)
+ (start-process-shell-command
+ url nil (format ,command url))))))))
+ (browse-url-parse-colon-path (getenv "BROWSER"))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Browser-independent commands
;; A generic command to call the current browse-url-browser-function
@@ -623,19 +683,43 @@
Prompts for a URL, defaulting to the URL at or before point. Variable
`browse-url-browser-function' says which browser to use."
(interactive (browse-url-interactive-arg "URL: "))
- (if (functionp browse-url-browser-function)
- (apply browse-url-browser-function url args)
- ;; The `function' can be an alist; look down it for first match
- ;; and apply the function (which might be a lambda).
- (catch 'done
- (mapcar
- (lambda (bf)
- (when (string-match (car bf) url)
- (apply (cdr bf) url args)
- (throw 'done t)))
- browse-url-browser-function)
- (error "No browser in browse-url-browser-function matching URL %s"
- url))))
+ ;; Weirdness here comes from trying to be backward compatible. The
+ ;; old behavior was to use `browse-url-browser-function' if it's a
+ ;; function, otherwise interpret it as a handler list. New
+ ;; behavior: if `browse-url-browser-function' is an explicit handler
+ ;; list, use it. Otherwise check to see if we can generate a handler
+ ;; list by parsing the BROWSER environment variable; if so, use that.
+ ;; Finally, if we neither have an explicit handler list nor can get one
+ ;; from BROWSER, just execute `browse-url-browser-function'.
+ (let ((handler-list
+ (cond ((and
+ browse-url-browser-function
+ (not (functionp browse-url-browser-function)))
+ browse-url-browser-function)
+ ((getenv "BROWSER")
+ (browse-url-default-from-environment))
+ (t
+ nil))))
+ (if (not handler-list)
+ (apply browse-url-browser-function url args)
+ ;; The `function' can be an alist; look down it for first match
+ ;; and apply the function (which might be a lambda). If the
+ ;; function throws an error, we take this as a signal that the attempt
+ ;; to launch the browser failed and continue down the list. Thus
+ ;; multiple handlers can match the same URL regexp; the first one
+ ;; to successfully launch terminates the search.
+ (catch 'done
+ (mapcar
+ (lambda (bf)
+ (when (string-match (car bf) url)
+ (condition-case nil
+ (progn
+ (apply (cdr bf) url args)
+ (throw 'done t))
+ (error nil))))
+ handler-list)
+ (error "No browser in browse-url-browser-function matching URL %s"
+ url)))))
;;;###autoload
(defun browse-url-at-point ()