1 ;;; muse-protocols.el --- URL protocols that Muse recognizes
3 ;; Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 ;; Author: Brad Collins (brad AT chenla DOT org)
7 ;; This file is part of Emacs Muse. It is not part of GNU Emacs.
9 ;; Emacs Muse is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published
11 ;; by the Free Software Foundation; either version 3, or (at your
12 ;; option) any later version.
14 ;; Emacs Muse is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with Emacs Muse; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
26 ;; Here's an example for adding a protocol for the site yubnub, a Web
27 ;; Command line service.
29 ;; (add-to-list 'muse-url-protocols '("yubnub://" muse-browse-url-yubnub
30 ;; muse-resolve-url-yubnub))
32 ;; (defun muse-resolve-url-yubnub (url)
33 ;; "Resolve a yubnub URL."
34 ;; ;; Remove the yubnub://
35 ;; (when (string-match "\\`yubnub://\\(.+\\)" url)
38 ;; (defun muse-browse-url-yubnub (url)
39 ;; "If this is a yubnub URL-command, jump to it."
40 ;; (setq url (muse-resolve-url-yubnub url))
41 ;; (browse-url (concat "http://yubnub.org/parser/parse?command="
46 ;; Phillip Lord (Phillip.Lord AT newcastle DOT ac DOT uk) provided a
47 ;; handler for DOI URLs.
49 ;; Stefan Schlee fixed a bug with handling of colons at the end of
52 ;; Valery V. Vorotyntsev contribued the woman:// protocol handler and
53 ;; simplified `muse-browse-url-man'.
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
61 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
64 (require 'muse-regexps
)
66 (defvar muse-url-regexp nil
67 "A regexp used to match URLs within a Muse page.
68 This is autogenerated from `muse-url-protocols'.")
70 (defun muse-update-url-regexp (sym value
)
72 (concat "\\<\\(" (mapconcat 'car value
"\\|") "\\)"
73 "[^][" muse-regexp-blank
"\"'()<>^`{}\n]*"
74 "[^][" muse-regexp-blank
"\"'()<>^`{}.,;:\n]+"))
77 (defcustom muse-url-protocols
78 '(("[uU][rR][lL]:" muse-browse-url-url identity
)
79 ("info://" muse-browse-url-info nil
)
80 ("man://" muse-browse-url-man nil
)
81 ("woman://" muse-browse-url-woman nil
)
82 ("google://" muse-browse-url-google muse-resolve-url-google
)
83 ("http:/?/?" browse-url identity
)
84 ("https:/?/?" browse-url identity
)
85 ("ftp:/?/?" browse-url identity
)
86 ("gopher://" browse-url identity
)
87 ("telnet://" browse-url identity
)
88 ("wais://" browse-url identity
)
89 ("file://?" browse-url identity
)
90 ("dict:" muse-browse-url-dict muse-resolve-url-dict
)
91 ("doi:" muse-browse-url-doi muse-resolve-url-doi
)
92 ("news:" browse-url identity
)
93 ("snews:" browse-url identity
)
94 ("mailto:" browse-url identity
))
95 "A list of (PROTOCOL BROWSE-FUN RESOLVE-FUN) used to match URL protocols.
96 PROTOCOL describes the first part of the URL, including the
97 \"://\" part. This may be a regexp.
99 BROWSE-FUN should accept URL as an argument and open the URL in
102 RESOLVE-FUN should accept URL as an argument and return the final
103 URL, or nil if no URL should be included."
104 :type
'(repeat (list :tag
"Protocol"
105 (string :tag
"Regexp")
106 (function :tag
"Browse")
107 (choice (function :tag
"Resolve")
108 (const :tag
"Don't resolve" nil
))))
109 :set
'muse-update-url-regexp
112 (add-hook 'muse-update-values-hook
114 (muse-update-url-regexp 'muse-url-protocols muse-url-protocols
)))
116 (defcustom muse-wikipedia-country
"en"
117 "Indicate the 2-digit country code that we use for Wikipedia
120 :options
'("de" "en" "es" "fr" "it" "pl" "pt" "ja" "nl" "sv")
123 (defun muse-protocol-find (proto list
)
124 "Return the first element of LIST whose car matches the regexp PROTO."
127 (when (string-match (concat "\\`" (car item
)) proto
)
128 (throw 'found item
)))))
131 (defun muse-browse-url (url &optional other-window
)
132 "Handle URL with the function specified in `muse-url-protocols'.
133 If OTHER-WINDOW is non-nil, open in a different window."
134 (interactive (list (read-string "URL: ")
136 ;; Strip text properties
137 (when (fboundp 'set-text-properties
)
138 (set-text-properties 0 (length url
) nil url
))
140 (switch-to-buffer-other-window (current-buffer)))
141 (when (string-match muse-url-regexp url
)
142 (let* ((proto (match-string 1 url
))
143 (entry (muse-protocol-find proto muse-url-protocols
)))
145 (funcall (cadr entry
) url
)))))
147 (defun muse-resolve-url (url &rest ignored
)
148 "Resolve URL with the function specified in `muse-url-protocols'."
149 (when (string-match muse-url-regexp url
)
150 (let* ((proto (match-string 1 url
))
151 (entry (muse-protocol-find proto muse-url-protocols
)))
153 (let ((func (car (cddr entry
))))
155 (setq url
(funcall func url
))
159 (defun muse-protocol-add (protocol browse-function resolve-function
)
160 "Add PROTOCOL to `muse-url-protocols'. PROTOCOL may be a regexp.
162 BROWSE-FUNCTION should be a function that visits a URL in the
165 RESOLVE-FUNCTION should be a function that transforms a URL for
166 publishing or returns nil if not linked."
167 (add-to-list 'muse-url-protocols
168 (list protocol browse-function resolve-function
))
169 (muse-update-url-regexp 'muse-url-protocols
172 (defun muse-browse-url-url (url)
173 "Call `muse-protocol-browse-url' to browse URL.
174 This is used when we are given something like
175 \"URL:http://example.org/\".
177 If you're looking for a good example for how to make a custom URL
178 handler, look at `muse-browse-url-dict' instead."
179 (when (string-match "\\`[uU][rR][lL]:\\(.+\\)" url
)
180 (muse-browse-url (match-string 1 url
))))
182 (defun muse-resolve-url-dict (url)
183 "Return the Wikipedia link corresponding with the given URL."
184 (when (string-match "\\`dict:\\(.+\\)" url
)
185 (concat "http://" muse-wikipedia-country
".wikipedia.org/"
186 "wiki/Special:Search?search=" (match-string 1 url
))))
188 (defun muse-browse-url-dict (url)
189 "If this is a Wikipedia URL, browse it."
190 (let ((dict-url (muse-resolve-url-dict url
)))
192 (browse-url dict-url
))))
194 (defun muse-resolve-url-doi (url)
195 "Return the URL through DOI proxy server."
196 (when (string-match "\\`doi:\\(.+\\)" url
)
197 (concat "http://dx.doi.org/"
198 (match-string 1 url
))))
200 (defun muse-browse-url-doi (url)
201 "If this is a DOI URL, browse it.
203 DOI's (digitial object identifiers) are a standard identifier
204 used in the publishing industry."
205 (let ((doi-url (muse-resolve-url-doi url
)))
207 (browse-url doi-url
))))
209 (defun muse-resolve-url-google (url)
210 "Return the correct Google search string."
211 (when (string-match "\\`google:/?/?\\(.+\\)" url
)
212 (concat "http://www.google.com/search?q="
213 (match-string 1 url
))))
215 (defun muse-browse-url-google (url)
216 "If this is a Google URL, jump to it."
217 (let ((google-url (muse-resolve-url-google url
)))
219 (browse-url google-url
))))
221 (defun muse-browse-url-info (url)
222 "If this in an Info URL, jump to it."
225 ((string-match "\\`info://\\([^#\n]+\\)#\\(.+\\)" url
)
226 (Info-find-node (match-string 1 url
)
227 (match-string 2 url
)))
228 ((string-match "\\`info://\\([^#\n]+\\)" url
)
229 (Info-find-node (match-string 1 url
)
231 ((string-match "\\`info://(\\([^)\n]+\\))\\(.+\\)" url
)
232 (Info-find-node (match-string 1 url
) (match-string 2 url
)))
233 ((string-match "\\`info://\\(.+\\)" url
)
234 (Info-find-node (match-string 1 url
) "Top"))))
236 (defun muse-browse-url-man (url)
237 "If this in a manpage URL, jump to it."
239 (when (string-match "\\`man://\\([^(]+\\(([^)]+)\\)?\\)" url
)
240 (man (match-string 1 url
))))
242 (defun muse-browse-url-woman (url)
243 "If this is a WoMan URL, jump to it."
245 (when (string-match "\\`woman://\\(.+\\)" url
)
246 (woman (match-string 1 url
))))
248 (provide 'muse-protocols
)
250 ;;; muse-protocols.el ends here