1 ;;; muse-blosxom.el --- Publish a document tree for serving by (py)Blosxom
3 ;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
5 ;; Date: Wed, 13 June 2005
6 ;; Author: Michael Olson (mwolson AT gnu DOT org)
7 ;; Maintainer: Michael Olson (mwolson AT gnu DOT org)
9 ;; This file is not part of GNU Emacs.
11 ;; This is free software; you can redistribute it and/or modify it under
12 ;; the terms of the GNU General Public License as published by the Free
13 ;; Software Foundation; either version 2, or (at your option) any later
16 ;; This is distributed in the hope that it will be useful, but WITHOUT
17 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; This file is in experimental status.
30 ;; It was a collection of routines that were removed from Muse because
31 ;; they didn't fit neatly into its paradigm. Eventually it is hoped
32 ;; that this will provide bare WikiName and interwiki support.
34 ;; Yann Hodique's implementation of WikiName highlighting will
35 ;; probably be merged into this file, or something to that effect.
41 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43 ;; Muse Wiki Publishing and Highlighting
45 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 ;; This was a removed rule from `muse-publish-markup-regexps'.
51 (defcustom muse-interwiki-names
52 '(("GnuEmacs" .
"http://www.gnu.org/software/emacs/emacs.html")
55 (concat "http://www.emacswiki.org/cgi-bin/wiki.pl?"
59 (concat "http://www.usemod.com/cgi-bin/mb.pl?"
60 (or tag
"MeatballWiki")))))
61 "A table of WikiNames that refer to external entities.
62 The format of this table is an alist, or series of cons cells.
63 Each cons cell must be of the form:
65 (WIKINAME . STRING-OR-FUNCTION)
67 The second part of the cons cell may either be a STRING, which in most
68 cases should be a URL, or a FUNCTION. If a function, it will be
69 called with one argument: the tag applied to the Interwiki name, or
70 nil if no tag was used. If the cdr was a STRING and a tag is used,
71 the tag is simply appended.
73 Here are some examples:
75 (\"JohnWiki\" . \"http://alice.dynodns.net/wiki?\")
77 Referring to [[JohnWiki#EmacsModules]] then really means:
79 http://alice.dynodns.net/wiki?EmacsModules
81 If a function is used for the replacement text, you can get creative
82 depending on what the tag is. Tags may contain any alphabetic
83 character, any number, % or _. If you need other special characters,
84 use % to specify the hex code, as in %2E. All browsers should support
86 :type
'(repeat (cons (string :tag
"WikiName")
87 (choice (string :tag
"URL") function
)))
90 (defcustom muse-publish-small-title-words
91 '("the" "and" "at" "on" "of" "for" "in" "an" "a")
92 "Strings that should be downcased in a page title."
93 :type
'(repeat string
)
96 (defun muse-publish-pretty-title (title)
97 "Return a pretty version of the given TITLE."
99 (let ((case-fold-search nil
))
100 (while (string-match "\\([A-Za-z]\\)\\([A-Z0-9]\\)" title
)
101 (setq title
(replace-match "\\1 \\2" t nil title
)))
102 (let* ((words (split-string title
))
105 (if (member (downcase (car w
))
106 muse-publish-small-title-words
)
107 (setcar w
(downcase (car w
))))
109 (mapconcat 'identity words
" ")))))
111 (defun muse-publish-nop-tag (beg end
)
112 (when (looking-at "\\<[A-Z][a-z]+\\([A-Z][a-z]+\\)+")
113 (goto-char (match-end 0))
114 (muse-publish-mark-read-only beg
(point))))
116 ;; regenerate the index if any pages were published
117 (with-current-buffer (muse-generate-index t t
)
118 (muse-replace-markup muse-publish-index-page
)
119 (let ((backup-inhibited t
))
120 (write-file (muse-published-file muse-publish-index-page
)))
121 (kill-buffer (current-buffer))
122 (message "All pages in %s have been published." (car project
)))
125 (defun muse-count-chars (string char
)
130 (if (eq char
(aref string i
))
131 (setq count
(1+ count
)))
135 (defun muse-set-sym-and-url-regexp (sym value
)
136 (setq muse-url-or-name-regexp
138 (if (eq sym
'muse-name-regexp
)
140 muse-name-regexp
) "\\|"
141 (if (eq sym
'muse-name-regexp
)
142 (if (boundp 'muse-url-regexp
)
146 muse-url-or-name-regexp-group-count
148 muse-url-or-name-regexp ?\
() 2))
151 (defcustom muse-name-regexp
152 (concat "\\(" muse-extended-link-regexp
"\\|"
153 "\\<[A-Z][a-z]+\\([A-Z][a-z]+\\)+\\(#\\S-+[A-Za-z0-9]\\)?" "\\)")
154 "Regexp used to match WikiNames."
156 :set
'muse-set-sym-and-url-regexp
159 (defvar muse-url-or-name-regexp nil
160 "Matches either a Wiki link or a URL. This variable is auto-generated.")
162 (defvar muse-url-or-name-regexp-group-count nil
163 "Matches either a Wiki link or a URL. This variable is auto-generated.")
165 ;; Utility functions to extract parts of a Wiki name
167 (defvar muse-serving-p nil
168 "Non-nil when Muse is serving a page directly.")
170 (defsubst muse-transform-name
(name)
171 "Transform NAME as per `muse-publishing-transforms', returning NAME"
175 (let ((reg (car elt
))
177 (when (string-match reg name
)
178 (setq name
(replace-match rep t nil name
))))))
179 muse-publishing-transforms
)
182 (defsubst muse-published-name
(name &optional current
)
183 "Return the externally visible NAME for a wiki page, possibly transformed
184 via `muse-publishing-transforms'. If CURRENT is provided, convert any
185 path to be relative to it"
189 (setq name
(file-relative-name name
191 (muse-transform-name current
)))))
192 (concat (if muse-serving-p
193 (unless (string-match "\\?" name
) "wiki?")
194 muse-publishing-file-prefix
)
196 (unless muse-serving-p
197 muse-publishing-file-suffix
)))))
199 (defsubst muse-published-file
(&optional file
)
200 "Return the filename of the published file. Since this is based on the
201 published-name, it will be filtered through
202 `muse-publishing-transforms'"
203 (expand-file-name (muse-published-name (muse-page-name
205 muse-publishing-directory
))
207 (defcustom muse-publishing-transforms nil
208 "A list of cons cells mapping regexps to replacements, which is
209 applied when generating the published name from the wiki file
210 name. The replacements run in order so you can chain them
213 An example is how I publish the Muse documentation. The Muse
214 homepage is in a file called EmacsWiki. With the following
215 settings I can publish directly to my webserver via tramp (the
216 first rule catches 'WikiMarkup' for instance):
218 (setq muse-publishing-directory \"/webserver:/var/www/\")
219 (setq muse-publishing-transforms
220 '((\".*Wiki.*\" . \"emacs/wiki/\\&\")
221 (\"EmacsWiki\\|WelcomePage\" . \"index\")))
223 Then when trying to publish a page EmacsWiki:
225 (muse-published-file \"EmacsWiki\")
229 \"/webserver:/var/www/emacs/wiki/index.html\""
232 (regexp :tag
"String to match")
233 (string :tag
"Replacement string")))
234 :group
'muse-publish
)
236 (defsubst muse-wiki-url-p
(name)
237 "Return non-nil if NAME is a URL."
240 (string-match muse-url-regexp name
))))
242 (defun muse-wiki-visible-name (wiki-name)
243 "Return the visible part of a Wiki link.
244 This only really means something if [[extended][links]] are involved."
246 (let ((name wiki-name
))
247 (if (string-match muse-extended-link-regexp name
)
248 (if (match-string 2 name
)
249 (setq name
(match-string 3 name
))
250 (setq name
(match-string 1 name
))))
251 (if (and (not (muse-wiki-url-p name
))
252 (string-match "#" name
))
253 (if (= 0 (match-beginning 0))
254 (setq name
(muse-page-name))
255 (let ((base (substring name
0 (match-beginning 0))))
256 (if (assoc base muse-interwiki-names
)
257 (setq name
(concat (substring name
0 (match-beginning 0))
258 ":" (substring name
(match-end 0))))
262 (defun muse-wiki-tag (wiki-name)
264 (if (string-match "#" wiki-name
)
265 (substring wiki-name
(match-end 0)))))
267 (defun muse-wiki-link-target (wiki-name)
268 "Return the target of a Wiki link. This might include anchor tags."
270 (let ((name wiki-name
) lookup
)
271 (if (string-match "^\\[\\[\\([^]]+\\)\\]" name
)
272 (setq name
(match-string 1 name
)))
273 (if (and muse-interwiki-names
274 (string-match "\\`\\([^#]+\\)\\(#\\(.+\\)\\)?\\'" name
)
275 (setq lookup
(assoc (match-string 1 name
)
276 muse-interwiki-names
)))
277 (let ((tag (match-string 3 name
))
278 (target (cdr lookup
)))
280 (setq name
(concat target tag
))
281 (setq name
(funcall target tag
))))
282 (if (and (> (length name
) 0)
283 (eq (aref name
0) ?
#))
284 (setq name
(concat (muse-page-name) name
))))
287 (defun muse-wiki-base (wiki-name)
288 "Find the WikiName or URL mentioned by a Wiki link.
289 This means without tags, in the case of a WikiName."
291 (let ((file (muse-wiki-link-target wiki-name
)))
292 (if (muse-wiki-url-p file
)
294 (if (string-match "#" file
)
295 (substring file
0 (match-beginning 0))