1 ;;; browse-url.el --- ask a WWW browser to load a URL
3 ;; Copyright 1995 Free Software Foundation, Inc.
5 ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
6 ;; Maintainer: Denis Howe <dbh@doc.ic.ac.uk>
7 ;; Created: 03 Apr 1995
8 ;; Version: 0.16 17 May 1995
10 ;; X-Home page: http://wombat.doc.ic.ac.uk/
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published
16 ;; by the Free Software Foundation; either version 1, or (at your
17 ;; option) any later version.
19 ;; GNU Emacs is distributed in the hope that it will be useful, but
20 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ;; General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;; The latest version of this package should be available from
32 ;; <URL:http://wombat.doc.ic.ac.uk/emacs/browse-url.el>.
34 ;; This package provides functions which read a URL (Uniform Resource
35 ;; Locator) from the minibuffer, defaulting to the URL around point,
36 ;; and ask a World-Wide Web browser to load it. It can also load the
37 ;; URL associated with the current buffer. Different browsers use
38 ;; different methods of remote control so there is one function for
39 ;; each supported browser. If the chosen browser is not running, it
40 ;; is started. Currently there is support for:
42 ;; Function Browser Earliest version
43 ;; browse-url-netscape Netscape 1.1b1
44 ;; browse-url-mosaic XMosaic <= 2.4
46 ;; browse-url-iximosaic IXI Mosaic ?
48 ;; Note that earlier versions of Netscape did not have remote control.
49 ;; <URL:http://home.netscape.com/newsref/std/x-remote.html> and
50 ;; <URL:http://home.netscape.com/info/APIs/>.
52 ;; If using Mosaic, check the definition of browse-url-usr1-signal
54 ;; <URL:http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/remote-control.html>
56 ;; William M. Perry's excellent "w3" WWW browser for
57 ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
58 ;; has a function w3-follow-url-at-point, but that
59 ;; doesn't let you edit the URL like browse-url.
61 ;; I recommend Nelson Minar <nelson@santafe.edu>'s excellent
62 ;; html-helper-mode.el for editing HTML and thank Nelson for
63 ;; his many useful comments on this code.
64 ;; <URL:http://www.santafe.edu/~nelson/hhm-beta/>
66 ;; This package generalises function html-previewer-process in Marc
67 ;; Andreessen <marca@ncsa.uiuc.edu>'s html-mode (LCD
68 ;; modes/html-mode.el.Z) and provides better versions of the URL
69 ;; functions in Michelangelo Grigni <mic@cs.ucsd.edu>'s ffap.el
70 ;; (find-file-at-point) <URL:ftp://cs.ucsd.edu:/pub/mic/>. The huge
71 ;; hyperbole package also contains similar functions.
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
76 ;; Can you write and test some code for the Macintrash and Windoze
77 ;; Netscape remote control APIs? (See the URL above).
79 ;; Did earlier versions of Mosaic have remote control?
81 ;; Do any other browsers have remote control?
83 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 ;; In your ~/.emacs, put:
88 ;; (setq browse-url-browser-function
89 ;; (if (eq window-system 'x)
90 ;; 'browse-url-netscape ; or browse-url-mosaic
92 ;; (autoload browse-url-browser-function "browse-url.el"
93 ;; "Ask a WWW browser to show a URL." t)
94 ;; Bind this to control-X w (normally undefined):
95 ;; (global-set-key "\C-xw" browse-url-browser-function)
96 ;; ;; Note: no quote ^
98 ;; For viewing current buffer:
100 ;; (autoload 'browse-url-of-file "browse-url.el"
101 ;; "Ask a WWW browser to display the current file." t)
102 ;; (setq browse-url-save-file t) ; Always save
104 ;; To get round the Netscape caching problem, you could try either of
105 ;; the following (but not both). EITHER write-file in
106 ;; html-helper-mode makes Netscape reload document:
108 ;; (autoload 'browse-url-netscape-reload "browse-url.el"
109 ;; "Ask a WWW browser to redisplay the current file." t)
110 ;; (add-hook 'html-helper-mode-hook
111 ;; (function (lambda ()
112 ;; (add-hook 'local-write-file-hooks
113 ;; (function (lambda ()
114 ;; (let ((local-write-file-hooks))
116 ;; (browse-url-netscape-reload)
117 ;; t)) ; => file written by hook
118 ;; t)))) ; append to l-w-f-hooks
120 ;; [Does this work for html-mode too?]
122 ;; OR browse-url-of-file ask Netscape to load and then reload the
125 ;; (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
127 ;; You may also want to customise browse-url-netscape-arguments, eg.
129 ;; (setq browse-url-netscape-arguments '("-install"))
131 ;; or similarly for the other browsers.
133 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
136 ;; 0.00 03 Apr 1995 Denis Howe <dbh@doc.ic.ac.uk>
140 ;; All names start with "browse-url-". Added provide.
143 ;; Save file at start of browse-url-of-file.
144 ;; Use start-process instead of start-process-shell-command.
147 ;; Add browse-url-netscape-reload, browse-url-netscape-command.
148 ;; browse-url-of-file save file option.
151 ;; b-u-file-url separate function. Change b-u-filename-alist
155 ;; Added b-u-of-file-hook.
158 ;; Improved .emacs suggestions and documentation.
161 ;; Added browse-url-interactive-arg optional prompt.
164 ;; Exclude final "." from browse-url-regexp.
167 ;; Added mouse-set-point to browse-url-interactive-arg.
170 ;; Added Mosaic signal sending variations.
171 ;; Thanks Brian K Servis <servis@ecn.purdue.edu>.
172 ;; Don't use xprop for Netscape.
175 ;; Fix reading of ~/.mosaicpid. Thanks Dag.H.Wanvik@kvatro.no.
178 ;; Interactive prefix arg => URL *after* point.
179 ;; Thanks Michelangelo Grigni <mic@cs.ucsd.edu>.
180 ;; Added IXI Mosaic support.
181 ;; Thanks David Karr <dkarr@nmo.gtegsc.com>.
184 ;; Exclude final [,;] from browse-url-regexp.
187 ;; Provide browser argument variables.
190 ;; More Netscape options. Thanks Peter Arius
191 ;; <arius@immd2.informatik.uni-erlangen.de>.
194 ;; Added browse-url-at-mouse.
195 ;; Thanks Wayne Mesard <wmesard@sgi.com>
198 ;; Renamed browse-url-at-point to browse-url-url-at-point.
199 ;; Added browse-url-at-point.
200 ;; Thanks Jonathan Cano <cano@patch.tandem.com>.
202 ;; Netscape can cache Web pages so it may be necessary to tell it to
203 ;; reload the current page if it has changed (eg. if you have edited
204 ;; it). There is currently no perfect automatic solution to this.
206 ;; Netscape allows you to specify the id of the window you want to
207 ;; control but which window DO you want to control and how do you
210 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
213 (defvar browse-url-regexp
214 "\\(https?://\\|ftp://\\|gopher://\\|telnet://\\|wais://\\|file:/\\|s?news:\\|mailto:\\)[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+"
215 "A regular expression probably matching a URL.")
217 (defvar browse-url-browser-function
219 "*Function to display the current buffer in a WWW browser.
220 Used by function `browse-url-of-file'.")
222 (defvar browse-url-netscape-arguments nil
223 "*A list of strings to pass to Netscape as arguments.")
225 (defvar browse-url-netscape-new-window-p nil
226 "*If non-nil, Netscape always opens a new window.
227 Passing an interactive argument to \\[browse-url-netscape] reverses
228 the effect of this variable. Requires Netscape version 1.1N or
231 (defvar browse-url-mosaic-arguments nil
232 "*A list of strings to pass to Mosaic as arguments.")
234 (defvar browse-url-filename-alist
235 '(("^/+" . "file:/"))
236 "An alist of (REGEXP . STRING) pairs.
237 Any substring of a filename matching one of the REGEXPs is replaced by
238 the corresponding STRING. All pairs are applied in the order given.
239 Used by function `browse-url-of-file'.")
241 (defvar browse-url-save-file nil
242 "If non-nil, save the buffer before displaying its file.
243 Used by function `browse-url-of-file'.")
245 (defvar browse-url-of-file-hook nil
246 "A hook to be run with run-hook after `browse-url-of-file' has asked
247 a browser to load a file.
249 Set this to `browse-url-netscape-reload' to force Netscape to load the
250 file rather than displaying a cached copy.")
252 (defvar browse-url-usr1-signal
253 (if (and (boundp 'emacs-major-version)
254 (or (> emacs-major-version 19) (>= emacs-minor-version 29)))
256 30) ; Check /usr/include/signal.h.
257 "The argument to `signal-process' for sending SIGUSR1 to XMosaic.
258 Emacs 19.29 accepts 'sigusr1, earlier versions require an integer
259 which is 30 on SunOS and 16 on HP-UX and Solaris.")
261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
264 ;; thingatpt.el doesn't work for complex regexps.
266 (defun browse-url-url-at-point ()
267 "Return the URL around or before point.
268 Then search backwards for the start of a URL. If no URL found, return
270 (if (or (looking-at browse-url-regexp) ; Already at start
271 (let ((eol (save-excursion (end-of-line) (point))))
272 ;; Search forwards for the next URL or end of line in case
273 ;; we're in the middle of one.
274 (and (re-search-forward browse-url-regexp eol 'lim)
275 (goto-char (match-beginning 0)))
276 ;; Now back to where we started or earlier.
277 (re-search-backward browse-url-regexp nil t)))
278 (buffer-substring (match-beginning 0) (match-end 0))
281 ;; Todo: restrict to around or immediately before point. Expand bare
284 (defun browse-url-interactive-arg (&optional prompt)
285 "Read a URL from the minibuffer, optionally prompting with PROMPT.
286 Default to the URL at or before point. If bound to a mouse button,
287 set point to the position clicked. Return the result as a list for
288 use in `interactive'."
289 (let ((event (elt (this-command-keys) 0)))
290 (and (listp event) (mouse-set-point event)))
291 (list (read-string (or prompt "URL: ") (browse-url-url-at-point))))
293 (defun browse-url-at-point ()
294 "Pass the URL at or before point to a WWW browser."
296 (funcall browse-url-browser-function (browse-url-at-point)))
298 (defun browse-url-at-mouse (event)
299 "Ask a browser to load a URL clicked with the mouse.
300 The URL is the one around or before the position of the mouse click
301 but point is not changed. The URL is loaded using variable
302 `browse-url-browser-function'."
305 (let ((posn (event-start event)))
306 (set-buffer (window-buffer (posn-window posn)))
307 (goto-char (posn-point posn))
308 (let ((url (browse-url-url-at-point)))
309 (if (string-equal url "")
310 (error "No URL found"))
311 (funcall browse-url-browser-function url)))))
313 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314 ;; Browse current buffer
316 (defun browse-url-of-file (&optional file)
317 "Ask a WWW browser to display FILE.
318 Display the current buffer's file if FILE is nil or if called
319 interactively. Turn the filename into a URL by performing
320 replacements given in variable `browse-url-filename-alist'. Pass the
321 URL to a browser using variable `browse-url-browser-function' then run
322 `browse-url-of-file-hook'."
326 (and (boundp 'dired-directory) dired-directory)))
327 (let ((buf (get-file-buffer file)))
328 (if buf (save-excursion
331 ((not (buffer-modified-p)))
332 (browse-url-save-file (save-buffer))
333 (t (message "%s modified since last save" file))))))
334 (funcall browse-url-browser-function
335 (browse-url-file-url file))
336 (run-hooks 'browse-url-of-file-hook))
338 (defun browse-url-file-url (file)
339 "Return the URL corresponding to FILE.
340 Uses variable `browse-url-filename-alist' to map filenames to URLs."
341 (let ((maps browse-url-filename-alist))
343 (let* ((map (car maps))
345 (to-string (cdr map)))
346 (setq maps (cdr maps))
347 (if (string-match from-re file)
348 (setq file (concat (substring file 0 (match-beginning 0))
350 (substring file (match-end 0))))))))
353 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
354 ;; Browser-specific functions
356 (defun browse-url-netscape (url &optional new-window)
357 "Ask the Netscape WWW browser to load URL.
359 Default to the URL around or before point. The strings in variable
360 `browse-url-netscape-arguments' are also passed to Netscape.
362 If variable `browse-url-netscape-new-window-p' is non-nil, load the
363 document in a new Netscape window, otherwise use a random existing
364 one. If optional argument NEW-WINDOW (prefix argument if interactive)
365 is non-nil, the effect of browse-url-netscape-new-window-p is
367 (interactive (append (browse-url-interactive-arg "Netscape URL: ")
368 (list (not (eq (null browse-url-netscape-new-window-p)
369 (null current-prefix-arg))))))
371 (apply 'call-process "netscape" nil nil nil
372 (append browse-url-netscape-arguments
373 (if new-window '("-noraise"))
375 (concat "openURL(" url
376 (if new-window ",new-window")
378 (progn ; Netscape not running - start it
379 (message "Starting Netscape...")
380 (apply 'start-process "netscape" nil "netscape"
381 (append browse-url-netscape-arguments (list url))))))
383 (defun browse-url-netscape-reload ()
384 "Ask Netscape to reload its current document."
386 (browse-url-netscape-command "reload"))
388 (defun browse-url-netscape-command (command)
389 "Send a remote control command to Netscape."
390 (apply 'start-process "netscape" nil "netscape"
391 (append browse-url-netscape-arguments
392 (list "-remote" command))))
394 (defun browse-url-mosaic (url)
395 "Ask the XMosaic WWW browser to load URL.
396 Default to the URL around or before point."
397 (interactive (browse-url-interactive-arg "Mosaic URL: "))
398 (let ((pidfile (expand-file-name "~/.mosaicpid"))
400 (if (file-readable-p pidfile)
403 (goto-char (point-min))
404 (setq pid (read (current-buffer)))
406 (if (and pid (zerop (signal-process pid 0))) ; Mosaic running
408 (find-file (format "/tmp/Mosaic.%d" pid))
410 (insert "goto\n" url "\n")
413 ;; Send signal SIGUSR to Mosaic
414 (message "Signalling Mosaic...")
415 (signal-process pid browse-url-usr1-signal)
417 ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
419 ;; Mosaic not running - start it
420 (message "Starting Mosaic...")
421 (apply 'start-process "xmosaic" nil "xmosaic"
422 (append browse-url-mosaic-arguments (list url))))))
424 (defun browse-url-iximosaic (url)
425 "Ask the IXIMosaic WWW browser to load URL.
426 Default to the URL around or before point."
427 (interactive (browse-url-interactive-arg "IXI Mosaic URL: "))
428 (start-process "tellw3b" nil "tellw3b"
429 "-service WWW_BROWSER ixi_showurl " url))
431 (defun browse-url-w3 (url)
432 "Ask the w3 WWW browser to load URL.
433 Default to the URL around or before point."
434 (interactive (browse-url-interactive-arg "W3 URL: "))
437 (provide 'browse-url)
439 ;;; browse-url.el ends here