Fix bug with recognizing wiki project names too loosely
[muse-el.git] / lisp / muse-protocols.el
blob9c30351ff585762d0ce76733a561b7c8dc43c3eb
1 ;;; muse-protocols.el --- URL protocols that Muse recognizes
3 ;; Copyright (C) 2005, 2006 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 2, 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.
24 ;;; Commentary:
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)
36 ;; (match-string 1)))
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="
42 ;; url)))
44 ;;; Contributors:
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
50 ;; URLs.
52 ;;; Code:
54 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56 ;; Muse URL Protocols
58 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
60 (require 'info)
61 (require 'muse-regexps)
63 (defvar muse-url-regexp nil
64 "A regexp used to match URLs within a Muse page.
65 This is autogenerated from `muse-url-protocols'.")
67 (defun muse-update-url-regexp (sym value)
68 (setq muse-url-regexp
69 (concat "\\<\\(" (mapconcat 'car value "\\|") "\\)"
70 "[^][" muse-regexp-blank "\"'()<>^`{}\n]*"
71 "[^][" muse-regexp-blank "\"'()<>^`{}.,;:\n]+"))
72 (set sym value))
74 (defcustom muse-url-protocols
75 '(("info://" muse-browse-url-info nil)
76 ("man://" muse-browse-url-man nil)
77 ("google://" muse-browse-url-google muse-resolve-url-google)
78 ("http:/?/?" browse-url identity)
79 ("https:/?/?" browse-url identity)
80 ("ftp:/?/?" browse-url identity)
81 ("gopher://" browse-url identity)
82 ("telnet://" browse-url identity)
83 ("wais://" browse-url identity)
84 ("file://?" browse-url identity)
85 ("dict:" muse-browse-url-dict muse-resolve-url-dict)
86 ("doi:" muse-browse-url-doi muse-resolve-url-doi)
87 ("news:" browse-url identity)
88 ("snews:" browse-url identity)
89 ("mailto:" browse-url identity))
90 "A list of (PROTOCOL BROWSE-FUN RESOLVE-FUN) used to match URL protocols.
91 PROTOCOL describes the first part of the URL, including the
92 \"://\" part. This may be a regexp.
94 BROWSE-FUN should accept URL as an argument and open the URL in
95 the current window.
97 RESOLVE-FUN should accept URL as an argument and return the final
98 URL, or nil if no URL should be included."
99 :type '(repeat (list :tag "Protocol"
100 (string :tag "Regexp")
101 (function :tag "Browse")
102 (choice (function :tag "Resolve")
103 (const :tag "Don't resolve" nil))))
104 :set 'muse-update-url-regexp
105 :group 'muse)
107 (add-hook 'muse-update-values-hook
108 (lambda ()
109 (muse-update-url-regexp 'muse-url-protocols muse-url-protocols)))
111 (defcustom muse-wikipedia-country "en"
112 "Indicate the 2-digit country code that we use for Wikipedia
113 queries."
114 :type 'string
115 :options '("de" "en" "es" "fr" "it" "pl" "pt" "ja" "nl" "sv")
116 :group 'muse)
118 (defun muse-protocol-find (proto list)
119 "Return the first element of LIST whose car matches the regexp PROTO."
120 (setq list (copy-alist list))
121 (let (entry)
122 (while list
123 (when (string-match (caar list) proto)
124 (setq entry (car list)
125 list nil))
126 (setq list (cdr list)))
127 entry))
129 ;;;###autoload
130 (defun muse-browse-url (url &optional other-window)
131 "Handle URL with the function specified in `muse-url-protocols'.
132 If OTHER-WINDOW is non-nil, open in a different window."
133 (interactive (list (read-string "URL: ")
134 current-prefix-arg))
135 ;; Strip text properties
136 (when (fboundp 'set-text-properties)
137 (set-text-properties 0 (length url) nil url))
138 (when other-window
139 (switch-to-buffer-other-window (current-buffer)))
140 (when (string-match muse-url-regexp url)
141 (let* ((proto (concat "\\`" (match-string 1 url)))
142 (entry (muse-protocol-find proto muse-url-protocols)))
143 (when entry
144 (funcall (cadr entry) url)))))
146 (defun muse-resolve-url (url &rest ignored)
147 "Resolve URL with the function specified in `muse-url-protocols'."
148 (when (string-match muse-url-regexp url)
149 (let* ((proto (concat "\\`" (match-string 1 url)))
150 (entry (muse-protocol-find proto muse-url-protocols)))
151 (when entry
152 (let ((func (car (cddr entry))))
153 (if func
154 (setq url (funcall func url))
155 (setq url nil))))))
156 url)
158 (defun muse-protocol-add (protocol browse-function resolve-function)
159 "Add PROTOCOL to `muse-url-protocols'. PROTOCOL may be a regexp.
161 BROWSE-FUNCTION should be a function that visits a URL in the
162 current buffer.
164 RESOLVE-FUNCTION should be a function that transforms a URL for
165 publishing or returns nil if not linked."
166 (add-to-list 'muse-url-protocols
167 (list protocol browse-function resolve-function))
168 (muse-update-url-regexp 'muse-url-protocols
169 muse-url-protocols))
171 (defun muse-resolve-url-dict (url)
172 "Return the Wikipedia link corresponding with the given URL."
173 (when (string-match "\\`dict:\\(.+\\)" url)
174 (concat "http://" muse-wikipedia-country ".wikipedia.org/"
175 "wiki/Special:Search?search=" (match-string 1 url))))
177 (defun muse-browse-url-dict (url)
178 "If this is a Wikipedia URL, browse it."
179 (let ((dict-url (muse-resolve-url-dict url)))
180 (when dict-url
181 (browse-url dict-url))))
183 (defun muse-resolve-url-doi (url)
184 "Return the URL through DOI proxy server."
185 (when (string-match "\\`doi:\\(.+\\)" url)
186 (concat "http://dx.doi.org/"
187 (match-string 1 url))))
189 (defun muse-browse-url-doi (url)
190 "If this is a DOI URL, browse it.
192 DOI's (digitial object identifiers) are a standard identifier
193 used in the publishing industry."
194 (let ((doi-url (muse-resolve-url-doi url)))
195 (when doi-url
196 (browse-url doi-url))))
198 (defun muse-resolve-url-google (url)
199 "Return the correct Google search string."
200 (when (string-match "\\`google:/?/?\\(.+\\)" url)
201 (concat "http://www.google.com/search?q="
202 (match-string 1 url))))
204 (defun muse-browse-url-google (url)
205 "If this is a Google URL, jump to it."
206 (let ((google-url (muse-resolve-url-google url)))
207 (when google-url
208 (browse-url google-url))))
210 (defun muse-browse-url-info (url)
211 "If this in an Info URL, jump to it."
212 (require 'info)
213 (cond
214 ((string-match "\\`info://\\([^#\n]+\\)#\\(.+\\)" url)
215 (Info-find-node (match-string 1 url)
216 (match-string 2 url)))
217 ((string-match "\\`info://\\([^#\n]+\\)" url)
218 (Info-find-node (match-string 1 url)
219 "Top"))
220 ((string-match "\\`info://(\\([^)\n]+\\))\\(.+\\)" url)
221 (Info-find-node (match-string 1 url) (match-string 2 url)))
222 ((string-match "\\`info://\\(.+\\)" url)
223 (Info-find-node (match-string 1 url) "Top"))))
225 (defun muse-browse-url-man (url)
226 "If this in a manpage URL, jump to it."
227 (cond ((string-match "\\`man://\\(.+\\):\\(.+\\)" url)
228 (manual-entry (concat (match-string 1 url)
229 "(" (match-string 2 url) ")")))
230 ((string-match "\\`man://\\(.+\\)" url)
231 (manual-entry (concat (match-string 1 url))))))
233 (provide 'muse-protocols)
235 ;;; muse-protocols.el ends here