Emacs config utilizing prelude as a base
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2146 lines
80 KiB

14 years ago
  1. ;;; mediawiki.el --- mediawiki frontend
  2. ;; Copyright (C) 2008, 2009, 2010, 2011 Mark A. Hershberger
  3. ;; Original Authors: Jerry <unidevel@yahoo.com.cn>,
  4. ;; Chong Yidong <cyd at stupidchicken com> for wikipedia.el,
  5. ;; Uwe Brauer <oub at mat.ucm.es> for wikimedia.el
  6. ;; Author: Mark A. Hershberger <mah@everybody.org>
  7. ;; Version: 2.2.3
  8. ;; Created: Sep 17 2004
  9. ;; Keywords: mediawiki wikipedia network wiki
  10. ;; URL: http://launchpad.net/mediawiki-el
  11. ;; Last Modified: <2011-11-28 22:55:57 mah>
  12. (defconst mediawiki-version "2.2.3"
  13. "Current version of mediawiki.el")
  14. ;; This file is NOT (yet) part of GNU Emacs.
  15. ;; This program is free software: you can redistribute it and/or modify
  16. ;; it under the terms of the GNU General Public License as published by
  17. ;; the Free Software Foundation, either version 3 of the License, or
  18. ;; (at your option) any later version.
  19. ;; This program is distributed in the hope that it will be useful,
  20. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. ;; GNU General Public License for more details.
  23. ;; You should have received a copy of the GNU General Public License
  24. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. ;;; Commentary:
  26. ;; This version of mediawiki.el represents a merging of
  27. ;; wikipedia-mode.el (maintained by Uwe Brauer <oub at mat.ucm.es>)
  28. ;; from http://www.emacswiki.org/emacs/wikipedia-mode.el for its
  29. ;; font-lock code, menu, draft mode, replying and convenience
  30. ;; functions to produce mediawiki.el 2.0.
  31. ;;; Installation
  32. ;; If you use ELPA (http://tromey.com/elpa), you can install via the
  33. ;; M-x package-list-packages interface. This is preferrable as you
  34. ;; will have access to updates automatically.
  35. ;; Otherwise, just make sure this file is in your load-path (usually
  36. ;; ~/.emacs.d is included) and put (require 'mediawiki.el) in your
  37. ;; ~/.emacs or ~/.emacs.d/init.el file.
  38. ;;; Howto:
  39. ;; M-x customize-group RET mediawiki RET
  40. ;; *dink* *dink*
  41. ;; M-x mediawiki-site RET Wikipedia RET
  42. ;;
  43. ;; Open a wiki file: M-x mediawiki-open
  44. ;; Save a wiki buffer: C-x C-s
  45. ;; Save a wiki buffer with a different name: C-x C-w
  46. ;;; TODO:
  47. ;; * Optionally use org-mode formatting for editing and translate
  48. ;; that to mw
  49. ;; * Move url-* methods to url-http
  50. ;; * Use the MW API to support searching, etc.
  51. ;; * Clean up and thoroughly test imported wikimedia.el code
  52. ;; * Improve language support. Currently there is a toggle for
  53. ;; English or German. This should probably just be replaced with
  54. ;; customizable words given MediaWiki's wide language support.
  55. ;;; History
  56. ;; From the News section of wikipedia.el comes this bit, kept here for
  57. ;; reference later.
  58. ;; (4) "Draft", "send" and "reply" (for discussion pages)
  59. ;; abilities `based' on ideas of John Wigleys remember.el: see
  60. ;; the functions wikipedia-draft-*
  61. ;; RATIONALE: This comes handy in 2 situations
  62. ;; 1. You are editing articles which various authors (this I
  63. ;; think is the usual case), you then want not to submit
  64. ;; your edit immediately but want to copy it somewhere and
  65. ;; to continue later. You can use the following functions
  66. ;; for doing that:
  67. ;; wikipedia-draft-buffer \C-c\C-b
  68. ;; wikipedia-draft-region \C-c\C-r
  69. ;; then the buffer/region will be appended to the
  70. ;; wikipedia-draft-data-file (default is
  71. ;; "~/Wiki/discussions/draft.wiki", which you can visit via
  72. ;; wikipedia-draft-view-draft) and it will be
  73. ;; surrounded by the ^L marks in order to set a page.
  74. ;; moreover on top on that a section header == will be
  75. ;; inserted, which consists of the Word Draft, a subject
  76. ;; you are asked for and a date stamp.
  77. ;;
  78. ;; Another possibility consists in using the function
  79. ;; wikipedia-draft, bound to \C-c \C-m then a new buffer
  80. ;; will opened already in wikipedia mode. You edit and then
  81. ;; either can send the content of the buffer to the
  82. ;; wikipedia-draft-data-file in the same manner as
  83. ;; described above using the function
  84. ;; wikipedia-draft-buffer (bound to \C-c\C-k)
  85. ;;
  86. ;; BACK: In order to copy/send the content of temporary
  87. ;; buffer or of a page in the wikipedia-draft-data-file
  88. ;; back in to your wikipedia file, use the function
  89. ;; wikipedia-send-draft-to-mozex bound to "\C-c\C-c". You
  90. ;; will be asked to which buffer to copy your text!
  91. ;;
  92. ;;
  93. ;; 2. You want to reply in a discussion page to a specific
  94. ;; contribution, you can use either the function
  95. ;;
  96. ;; \\[wikipedia-reply-at-point-simple] bound to [(meta shift r)]
  97. ;; which inserts a newline, a hline, and the signature of
  98. ;; the author. Or can use
  99. ;; \\[wikipedia-draft-reply] bound [(meta r)]
  100. ;; which does the same as wikipedia-reply-at-point-simple
  101. ;; but in a temporary draft buffer.
  102. ;;
  103. ;; BACK: In order to copy/send the content of that buffer
  104. ;; back in to your wikipedia file, use the function
  105. ;; \\[wikipedia-send-draft-to-mozex] bound to "\C-c\C-c". You
  106. ;; will be asked to which buffer to copy your text! If
  107. ;; you want a copy to be send to your draft file, use
  108. ;; the variable wikipedia-draft-send-archive
  109. ;;
  110. ;;; Code:
  111. (require 'url-http)
  112. (require 'mml)
  113. (require 'mm-url)
  114. (require 'ring)
  115. (eval-when-compile (progn
  116. (require 'cl)
  117. ;; Below copied from url-http to avoid compilation warnings
  118. (defvar url-http-extra-headers)
  119. (defvar url-http-target-url)
  120. (defvar url-http-proxy)
  121. (defvar url-http-connection-opened)
  122. ;; This should only be used in xemacs, anyway
  123. (setq byte-compile-not-obsolete-funcs (list 'assoc-ignore-case))))
  124. ;; As of 2010-06-22, these functions are in Emacs
  125. (unless (fboundp 'url-bit-for-url)
  126. (defun url-bit-for-url (method lookfor url)
  127. (when (fboundp 'auth-source-user-or-password)
  128. (let* ((urlobj (url-generic-parse-url url))
  129. (bit (funcall method urlobj))
  130. (methods (list 'url-recreate-url
  131. 'url-host)))
  132. (if (and (not bit) (> (length methods) 0))
  133. (auth-source-user-or-password
  134. lookfor (funcall (pop methods) urlobj) (url-type urlobj))
  135. bit)))))
  136. (unless (fboundp 'url-url-for-url)
  137. (defun url-user-for-url (url)
  138. "Attempt to use .authinfo to find a user for this URL."
  139. (url-bit-for-url 'url-user "login" url)))
  140. (unless (fboundp 'url-password-for-url)
  141. (defun url-password-for-url (url)
  142. "Attempt to use .authinfo to find a password for this URL."
  143. (url-bit-for-url 'url-password "password" url)))
  144. (when (fboundp 'url-http-create-request)
  145. (if (string= "GET / HTTP/1.0 \nMIME-Version: 1.0 \nConnection: close \nHost: example.com \nAccept: */* \nUser-Agent: URL/Emacs \nContent-length: 4 \n \ntest"
  146. (let ((url-http-target-url (url-generic-parse-url "http://example.com/"))
  147. (url-http-data "test") (url-http-version "1.0")
  148. url-http-method url-http-attempt-keepalives url-extensions-header
  149. url-http-extra-headers url-http-proxy url-mime-charset-string)
  150. (url-http-create-request)))
  151. (defun url-http-create-request (&optional ref-url)
  152. "Create an HTTP request for `url-http-target-url', referred to by REF-URL."
  153. (declare (special proxy-info
  154. url-http-method url-http-data
  155. url-http-extra-headers))
  156. (let* ((extra-headers)
  157. (request nil)
  158. (no-cache (cdr-safe (assoc "Pragma" url-http-extra-headers)))
  159. (using-proxy url-http-proxy)
  160. (proxy-auth (if (or (cdr-safe (assoc "Proxy-Authorization"
  161. url-http-extra-headers))
  162. (not using-proxy))
  163. nil
  164. (let ((url-basic-auth-storage
  165. 'url-http-proxy-basic-auth-storage))
  166. (url-get-authentication url-http-target-url nil 'any nil))))
  167. (real-fname (concat (url-filename url-http-target-url)
  168. (url-recreate-url-attributes url-http-target-url)))
  169. (host (url-host url-http-target-url))
  170. (auth (if (cdr-safe (assoc "Authorization" url-http-extra-headers))
  171. nil
  172. (url-get-authentication (or
  173. (and (boundp 'proxy-info)
  174. proxy-info)
  175. url-http-target-url) nil 'any nil))))
  176. (if (equal "" real-fname)
  177. (setq real-fname "/"))
  178. (setq no-cache (and no-cache (string-match "no-cache" no-cache)))
  179. (if auth
  180. (setq auth (concat "Authorization: " auth "\r\n")))
  181. (if proxy-auth
  182. (setq proxy-auth (concat "Proxy-Authorization: " proxy-auth "\r\n")))
  183. ;; Protection against stupid values in the referer
  184. (if (and ref-url (stringp ref-url) (or (string= ref-url "file:nil")
  185. (string= ref-url "")))
  186. (setq ref-url nil))
  187. ;; We do not want to expose the referer if the user is paranoid.
  188. (if (or (memq url-privacy-level '(low high paranoid))
  189. (and (listp url-privacy-level)
  190. (memq 'lastloc url-privacy-level)))
  191. (setq ref-url nil))
  192. ;; url-http-extra-headers contains an assoc-list of
  193. ;; header/value pairs that we need to put into the request.
  194. (setq extra-headers (mapconcat
  195. (lambda (x)
  196. (concat (car x) ": " (cdr x)))
  197. url-http-extra-headers "\r\n"))
  198. (if (not (equal extra-headers ""))
  199. (setq extra-headers (concat extra-headers "\r\n")))
  200. ;; This was done with a call to `format'. Concatting parts has
  201. ;; the advantage of keeping the parts of each header together and
  202. ;; allows us to elide null lines directly, at the cost of making
  203. ;; the layout less clear.
  204. (setq request
  205. ;; We used to concat directly, but if one of the strings happens
  206. ;; to being multibyte (even if it only contains pure ASCII) then
  207. ;; every string gets converted with `string-MAKE-multibyte' which
  208. ;; turns the 127-255 codes into things like latin-1 accented chars
  209. ;; (it would work right if it used `string-TO-multibyte' instead).
  210. ;; So to avoid the problem we force every string to be unibyte.
  211. (mapconcat
  212. ;; FIXME: Instead of `string-AS-unibyte' we'd want
  213. ;; `string-to-unibyte', so as to properly signal an error if one
  214. ;; of the strings contains a multibyte char.
  215. 'string-as-unibyte
  216. (delq nil
  217. (list
  218. ;; The request
  219. (or url-http-method "GET") " "
  220. (if using-proxy (url-recreate-url url-http-target-url) real-fname)
  221. " HTTP/" url-http-version "\r\n"
  222. ;; Version of MIME we speak
  223. "MIME-Version: 1.0\r\n"
  224. ;; (maybe) Try to keep the connection open
  225. "Connection: " (if (or using-proxy
  226. (not url-http-attempt-keepalives))
  227. "close" "keep-alive") "\r\n"
  228. ;; HTTP extensions we support
  229. (if url-extensions-header
  230. (format
  231. "Extension: %s\r\n" url-extensions-header))
  232. ;; Who we want to talk to
  233. (if (/= (url-port url-http-target-url)
  234. (url-scheme-get-property
  235. (url-type url-http-target-url) 'default-port))
  236. (format
  237. "Host: %s:%d\r\n" host (url-port url-http-target-url))
  238. (format "Host: %s\r\n" host))
  239. ;; Who its from
  240. (if url-personal-mail-address
  241. (concat
  242. "From: " url-personal-mail-address "\r\n"))
  243. ;; Encodings we understand
  244. (if url-mime-encoding-string
  245. (concat
  246. "Accept-encoding: " url-mime-encoding-string "\r\n"))
  247. (if url-mime-charset-string
  248. (concat
  249. "Accept-charset: " url-mime-charset-string "\r\n"))
  250. ;; Languages we understand
  251. (if url-mime-language-string
  252. (concat
  253. "Accept-language: " url-mime-language-string "\r\n"))
  254. ;; Types we understand
  255. "Accept: " (or url-mime-accept-string "*/*") "\r\n"
  256. ;; User agent
  257. (url-http-user-agent-string)
  258. ;; Proxy Authorization
  259. proxy-auth
  260. ;; Authorization
  261. auth
  262. ;; Cookies
  263. (url-cookie-generate-header-lines host real-fname
  264. (equal "https" (url-type url-http-target-url)))
  265. ;; If-modified-since
  266. (if (and (not no-cache)
  267. (member url-http-method '("GET" nil)))
  268. (let ((tm (url-is-cached url-http-target-url)))
  269. (if tm
  270. (concat "If-modified-since: "
  271. (url-get-normalized-date tm) "\r\n"))))
  272. ;; Whence we came
  273. (if ref-url (concat
  274. "Referer: " ref-url "\r\n"))
  275. extra-headers
  276. ;; Length of data
  277. (if url-http-data
  278. (concat
  279. "Content-length: " (number-to-string
  280. (length url-http-data))
  281. "\r\n"))
  282. ;; End request
  283. "\r\n"
  284. ;; Any data
  285. url-http-data "\r\n"))
  286. ""))
  287. (url-http-debug "Request is: \n%s" request)
  288. request))))
  289. (unless (fboundp 'mm-url-encode-multipart-form-data)
  290. (defun mm-url-encode-multipart-form-data (pairs &optional boundary)
  291. "Return PAIRS encoded in multipart/form-data."
  292. ;; RFC1867
  293. ;; Get a good boundary
  294. (unless boundary
  295. (setq boundary (mml-compute-boundary '())))
  296. (concat
  297. ;; Start with the boundary
  298. "--" boundary "\r\n"
  299. ;; Create name value pairs
  300. (mapconcat
  301. 'identity
  302. ;; Delete any returned items that are empty
  303. (delq nil
  304. (mapcar (lambda (data)
  305. (cond
  306. ((consp (car data))
  307. (let ((fieldname (cadar data))
  308. (filename (caadar data))
  309. (mimetype (car (caadar data)))
  310. (content (caar (caadar data))))
  311. (concat
  312. ;; Encode the name
  313. "Content-Disposition: form-data; name=\"" fieldname "\"\r\n"
  314. "Content-Type: " mimetype "\r\n"
  315. "Content-Transfer-Encoding: binary\r\n\r\n"
  316. content
  317. "\r\n")))
  318. ((stringp (car data))
  319. ;; For each pair
  320. (concat
  321. ;; Encode the name
  322. "Content-Disposition: form-data; name=\""
  323. (car data) "\"\r\n"
  324. "Content-Type: text/plain; charset=utf-8\r\n"
  325. "Content-Transfer-Encoding: binary\r\n\r\n"
  326. (cond ((stringp (cdr data))
  327. (cdr data))
  328. ((integerp (cdr data))
  329. (int-to-string (cdr data))))
  330. "\r\n"))
  331. (t (error "I don't handle this."))))
  332. pairs))
  333. ;; use the boundary as a separator
  334. (concat "--" boundary "\r\n"))
  335. ;; put a boundary at the end.
  336. "--" boundary "--\r\n")))
  337. ;; Not defined in my Xemacs
  338. (unless (fboundp 'assoc-string)
  339. (defun assoc-string (key list &optional case-fold)
  340. (if case-fold
  341. (assoc-ignore-case key list)
  342. (assoc key list))))
  343. (defun url-compat-retrieve (url post-process bufname callback cbargs)
  344. (cond ((boundp 'url-be-asynchronous) ; Sniff w3 lib capability
  345. (if callback
  346. (setq url-be-asynchronous t)
  347. (setq url-be-asynchronous nil))
  348. (url-retrieve url t)
  349. (when (not url-be-asynchronous)
  350. (let ((result (funcall post-process bufname)))
  351. result)))
  352. (t (if callback
  353. (url-retrieve url post-process
  354. (list bufname callback cbargs))
  355. (with-current-buffer (url-retrieve-synchronously url)
  356. (funcall post-process bufname))))))
  357. (defvar url-http-get-post-process 'url-http-response-post-process)
  358. (defun url-http-get (url &optional headers bufname callback cbargs)
  359. "Convenience method to use method 'GET' to retrieve URL"
  360. (let* ((url-request-extra-headers (if headers headers
  361. (if url-request-extra-headers
  362. url-request-extra-headers
  363. (cons nil nil))))
  364. (url-request-method "GET"))
  365. (when (url-basic-auth url)
  366. (add-to-list 'url-request-extra-headers
  367. (cons "Authorization" (url-basic-auth url))))
  368. (url-compat-retrieve url url-http-get-post-process
  369. bufname callback cbargs)))
  370. (defvar url-http-post-post-process 'url-http-response-post-process)
  371. (defun url-http-post (url parameters &optional multipart headers bufname
  372. callback cbargs)
  373. "Convenience method to use method 'POST' to retrieve URL"
  374. (let* ((url-request-extra-headers
  375. (if headers headers
  376. (when url-request-extra-headers url-request-extra-headers)))
  377. (boundary (int-to-string (random)))
  378. (cs 'utf-8)
  379. (content-type
  380. (if multipart
  381. (concat "multipart/form-data, boundary=" boundary)
  382. (format "application/x-www-form-urlencoded; charset=%s" cs)))
  383. (url-request-method "POST")
  384. (url-request-coding-system cs)
  385. (url-request-data
  386. (if multipart
  387. (mm-url-encode-multipart-form-data
  388. parameters boundary)
  389. (mm-url-encode-www-form-urlencoded (delq nil parameters)))))
  390. (mapc
  391. (lambda (pair)
  392. (let ((key (car pair))
  393. (val (cdr pair)))
  394. (if (assoc key url-request-extra-headers)
  395. (setcdr (assoc key url-request-extra-headers) val)
  396. (add-to-list 'url-request-extra-headers
  397. (cons key val)))))
  398. (list
  399. (cons "Connection" "close")
  400. (cons "Content-Type" content-type)))
  401. (message "Posting to: %s" url)
  402. (url-compat-retrieve url url-http-post-post-process
  403. bufname callback cbargs)))
  404. (defun url-http-response-post-process (status &optional bufname
  405. callback cbargs)
  406. "Post process on HTTP response."
  407. (declare (special url-http-end-of-headers))
  408. (let ((kill-this-buffer (current-buffer)))
  409. (when (and (integerp status) (not (< status 300)))
  410. (kill-buffer kill-this-buffer)
  411. (error "Oops! Invalid status: %d" status))
  412. (when (or (not (boundp 'url-http-end-of-headers))
  413. (not url-http-end-of-headers))
  414. (kill-buffer kill-this-buffer)
  415. (error "Oops! Don't see end of headers!"))
  416. ;; FIXME: need to limit redirects
  417. (if (and (listp status)
  418. (eq (car status) :redirect))
  419. (progn
  420. (message (concat "Redirecting to " (cadr status)))
  421. (url-http-get (cadr status) nil bufname callback cbargs))
  422. (goto-char url-http-end-of-headers)
  423. (forward-line)
  424. (let ((str (decode-coding-string
  425. (buffer-substring-no-properties (point) (point-max))
  426. 'utf-8)))
  427. (kill-buffer (current-buffer))
  428. (when bufname
  429. (set-buffer bufname)
  430. (insert str)
  431. (goto-char (point-min))
  432. (set-buffer-modified-p nil))
  433. (when callback
  434. (apply callback (list str cbargs)))
  435. (when (not (or callback bufname))
  436. str)))))
  437. (defgroup mediawiki nil
  438. "A mode for editting pages on MediaWiki sites."
  439. :tag "MediaWiki"
  440. :group 'applications)
  441. (defcustom mediawiki-site-default "Wikipedia"
  442. "The default mediawiki site to point to. Set here for the
  443. default and use `mediawiki-site' to set it per-session
  444. later."
  445. :type 'string
  446. :tag "MediaWiki Site Default"
  447. :group 'mediawiki)
  448. (defcustom mediawiki-site-alist '(("Wikipedia"
  449. "http://en.wikipedia.org/w/"
  450. "username"
  451. "password"
  452. "Main Page"))
  453. "A list of MediaWiki websites."
  454. :group 'mediawiki
  455. :type '(alist :tag "Site Name"
  456. :key-type (string :tag "Site Name")
  457. :value-type (list :tag "Parameters"
  458. (string :tag "URL")
  459. (string :tag "Username")
  460. (string :tag "Password")
  461. (string :tag "First Page"
  462. :description "First page to open when `mediawiki-site' is called for this site"))))
  463. (defcustom mediawiki-pop-buffer-hook '()
  464. "List of functions to execute after popping to a buffer. Can
  465. be used to to open the whole buffer."
  466. :options '(delete-other-windows)
  467. :type 'hook
  468. :group 'mediawiki)
  469. (defvar mediawiki-page-history '()
  470. "Assoc list of visited pages on this MW site.")
  471. (defvar mediawiki-enumerate-with-terminate-paragraph nil
  472. "*Before insert enumerate/itemize do \\[mediawiki-terminate-paragraph].")
  473. (defvar mediawiki-english-or-german t
  474. "*Variable in order to set the english (t) or german (nil) environment.")
  475. (defvar mediawiki-user-simplify-signature t
  476. "*Simple varible in order to threat complicated signatures of users, which uses
  477. fonts and other makeup.")
  478. (defgroup mediawiki-draft nil
  479. "A mode to mediawiki-draft information."
  480. :group 'mediawiki)
  481. ;;; User Variables:
  482. (defcustom mediawiki-draft-mode-hook nil
  483. "*Functions run upon entering mediawiki-draft-mode."
  484. :type 'hook
  485. :group 'mediawiki-draft)
  486. (defcustom mediawiki-draft-register ?R
  487. "The register in which the window configuration is stored."
  488. :type 'character
  489. :group 'mediawiki-draft)
  490. (defcustom mediawiki-draft-filter-functions nil
  491. "*Functions run to filter mediawiki-draft data.
  492. All functions are run in the mediawiki-draft buffer."
  493. :type 'hook
  494. :group 'mediawiki-draft)
  495. (defcustom mediawiki-draft-handler-functions '(mediawiki-draft-append-to-file)
  496. "*Functions run to process mediawiki-draft data.
  497. Each function is called with the current buffer narrowed to what the
  498. user wants mediawiki-drafted.
  499. If any function returns non-nil, the data is assumed to have been
  500. recorded somewhere by that function. "
  501. :type 'hook
  502. :group 'mediawiki-draft)
  503. (defcustom mediawiki-draft-data-file "~/Wiki/discussions/draft.wiki"
  504. "*The file in which to store the wikipedia drafts."
  505. :type 'file
  506. :group 'mediawiki-draft)
  507. (defcustom mediawiki-draft-reply-register ?M
  508. "The register in which the window configuration is stored."
  509. :type 'character
  510. :group 'mediawiki-draft)
  511. (defcustom mediawiki-draft-page ?S ;Version:1.37
  512. "The register in which the a page of the wiki draft file is stored."
  513. :type 'character
  514. :group 'mediawiki-draft)
  515. (defcustom mediawiki-draft-leader-text "== "
  516. "*The text used to begin each mediawiki-draft item."
  517. :type 'string
  518. :group 'mediawiki-draft)
  519. (defvar mediawiki-reply-with-hline nil
  520. "*Whether to use a hline as a header seperator in the reply.")
  521. (defvar mediawiki-reply-with-quote nil
  522. "*Whether to use a quotation tempalate or not.")
  523. (defvar mediawiki-imenu-generic-expression
  524. (list '(nil "^==+ *\\(.*[^\n=]\\)==+" 1))
  525. "Imenu expression for `mediawiki-mode'. See `imenu-generic-expression'.")
  526. (defvar mediawiki-login-success "pt-logout"
  527. "A string that should be present on login success on all
  528. mediawiki sites.")
  529. (defvar mediawiki-permission-denied
  530. "[^;]The action you have requested is limited"
  531. "A string that will indicate permission has been denied, Note
  532. that it should not match the mediawiki.el file itself since it
  533. is sometimes put on MediaWiki sites.")
  534. (defvar mediawiki-view-source
  535. "ca-viewsource"
  536. "A string that will indicate you can only view source on this
  537. page.")
  538. (defvar mediawiki-site nil
  539. "The current mediawiki site from `mediawiki-site-alist'. If
  540. not set, defaults to `mediawiki-site-default'.")
  541. (defvar mediawiki-argument-pattern "?title=%s&action=%s"
  542. "Format of the string to append to URLs. Two string arguments
  543. are expected: first is a title and then an action.")
  544. (defvar mediawiki-URI-pattern
  545. "http://\\([^/:]+\\)\\(:\\([0-9]+\\)\\)?/"
  546. "Pattern matching a URI like this:
  547. http://mediawiki.sf.net/index.php
  548. Password not support yet")
  549. (defvar mediawiki-page-uri nil
  550. "The URI of the page corresponding to the current buffer, thus defining
  551. the base URI of the wiki engine as well as group and page name.")
  552. (defvar mediawiki-page-title nil
  553. "The title of the page corresponding to the current buffer")
  554. (defvar mediawiki-edittoken nil
  555. "The edit token for this page.")
  556. (defvar mediawiki-starttimestamp nil
  557. "The starttimestamp for this page.")
  558. (defvar mediawiki-basetimestamp nil
  559. "The base timestamp for this page.")
  560. (defvar mediawiki-page-ring nil
  561. "Ring that holds names of buffers we navigate through.")
  562. (defvar mediawiki-page-ring-index 0)
  563. (defvar font-mediawiki-sedate-face 'font-mediawiki-sedate-face
  564. "Face to use for mediawiki minor keywords.")
  565. (defvar font-mediawiki-italic-face 'font-mediawiki-italic-face
  566. "Face to use for mediawiki italics.")
  567. (defvar font-mediawiki-bold-face 'font-mediawiki-bold-face
  568. "Face to use for mediawiki bolds.")
  569. (defvar font-mediawiki-math-face 'font-mediawiki-math-face
  570. "Face to use for mediawiki math environments.")
  571. (defvar font-mediawiki-string-face 'font-mediawiki-string-face
  572. "Face to use for strings.")
  573. (defvar font-mediawiki-verbatim-face 'font-mediawiki-verbatim-face
  574. "Face to use for text in verbatim macros or environments.")
  575. (defface font-mediawiki-bold-face
  576. (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
  577. ((assq :weight custom-face-attributes) '(:weight bold))
  578. (t '(:bold t)))))
  579. `((((class grayscale) (background light))
  580. (:foreground "DimGray" ,@font))
  581. (((class grayscale) (background dark))
  582. (:foreground "LightGray" ,@font))
  583. (((class color) (background light))
  584. (:foreground "DarkOliveGreen" ,@font))
  585. (((class color) (background dark))
  586. (:foreground "OliveDrab" ,@font))
  587. (t (,@font))))
  588. "Face used to highlight text to be typeset in bold."
  589. :group 'font-mediawiki-highlighting-faces)
  590. (defface font-mediawiki-italic-face
  591. (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
  592. ((assq :slant custom-face-attributes) '(:slant italic))
  593. (t '(:italic t)))))
  594. `((((class grayscale) (background light))
  595. (:foreground "DimGray" ,@font))
  596. (((class grayscale) (background dark))
  597. (:foreground "LightGray" ,@font))
  598. (((class color) (background light))
  599. (:foreground "DarkOliveGreen" ,@font))
  600. (((class color) (background dark))
  601. (:foreground "OliveDrab" ,@font))
  602. (t (,@font))))
  603. "Face used to highlight text to be typeset in italic."
  604. :group 'font-mediawiki-highlighting-faces)
  605. (defface font-mediawiki-math-face
  606. (let ((font (cond ((assq :inherit custom-face-attributes)
  607. '(:inherit underline))
  608. (t '(:underline t)))))
  609. `((((class grayscale) (background light))
  610. (:foreground "DimGray" ,@font))
  611. (((class grayscale) (background dark))
  612. (:foreground "LightGray" ,@font))
  613. (((class color) (background light))
  614. (:foreground "SaddleBrown"))
  615. (((class color) (background dark))
  616. (:foreground "burlywood"))
  617. (t (,@font))))
  618. "Face used to highlight math."
  619. :group 'font-mediawiki-highlighting-faces)
  620. (defface font-mediawiki-sedate-face
  621. '((((class grayscale) (background light)) (:foreground "DimGray"))
  622. (((class grayscale) (background dark)) (:foreground "LightGray"))
  623. (((class color) (background light)) (:foreground "DimGray"))
  624. (((class color) (background dark)) (:foreground "LightGray"))
  625. ;;;(t (:underline t))
  626. )
  627. "Face used to highlight sedate stuff."
  628. :group 'font-mediawiki-highlighting-faces)
  629. (defface font-mediawiki-string-face
  630. (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
  631. ((assq :slant custom-face-attributes) '(:slant italic))
  632. (t '(:italic t)))))
  633. `((((type tty) (class color))
  634. (:foreground "green"))
  635. (((class grayscale) (background light))
  636. (:foreground "DimGray" ,@font))
  637. (((class grayscale) (background dark))
  638. (:foreground "LightGray" ,@font))
  639. (((class color) (background light))
  640. (:foreground "RosyBrown"))
  641. (((class color) (background dark))
  642. (:foreground "LightSalmon"))
  643. (t (,@font))))
  644. "Face used to highlight strings."
  645. :group 'font-mediawiki-highlighting-faces)
  646. (defface font-mediawiki-warning-face
  647. (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
  648. ((assq :weight custom-face-attributes) '(:weight bold))
  649. (t '(:bold t)))))
  650. `((((class grayscale)(background light))
  651. (:foreground "DimGray" ,@font))
  652. (((class grayscale)(background dark))
  653. (:foreground "LightGray" ,@font))
  654. (((class color)(background light))
  655. (:foreground "red" ,@font))
  656. (((class color)(background dark))
  657. (:foreground "red" ,@font))
  658. (t (,@font))))
  659. "Face for important keywords."
  660. :group 'font-mediawiki-highlighting-faces)
  661. (defface font-mediawiki-verbatim-face
  662. (let ((font (if (and (assq :inherit custom-face-attributes)
  663. (if (fboundp 'find-face)
  664. (find-face 'fixed-pitch)
  665. (facep 'fixed-pitch)))
  666. '(:inherit fixed-pitch)
  667. '(:family "courier"))))
  668. `((((class grayscale) (background light))
  669. (:foreground "DimGray" ,@font))
  670. (((class grayscale) (background dark))
  671. (:foreground "LightGray" ,@font))
  672. (((class color) (background light))
  673. (:foreground "SaddleBrown" ,@font))
  674. (((class color) (background dark))
  675. (:foreground "burlywood" ,@font))
  676. (t (,@font))))
  677. "Face used to highlight TeX verbatim environments."
  678. :group 'font-mediawiki-highlighting-faces)
  679. (defvar mediawiki-simple-tags
  680. '("b" "big" "blockquote" "br" "caption" "code" "center" "cite" "del"
  681. "dfn" "dl" "em" "i" "ins" "kbd" "math" "nowiki" "ol" "pre" "samp"
  682. "small" "strike" "strong" "sub" "sup" "tt" "u" "ul" "var")
  683. "Tags that do not accept arguments.")
  684. (defvar mediawiki-complex-tags
  685. '("a" "div" "font" "table" "td" "th" "tr")
  686. "Tags that accept arguments.")
  687. (defvar mediawiki-url-protocols
  688. '("ftp" "gopher" "http" "https" "mailto" "news")
  689. "Valid protocols for URLs in Wikipedia articles.")
  690. (defvar mediawiki-draft-buffer "*MW-Draft*"
  691. "The name of the wikipedia-draft (temporary) data entry buffer.")
  692. (defvar mediawiki-edit-form-vars nil)
  693. (defvar mediawiki-font-lock-keywords
  694. (list
  695. ;; Apostrophe-style text markup
  696. (cons "''''\\([^']\\|[^']'\\)*?\\(''''\\|\n\n\\)"
  697. 'font-lock-builtin-face)
  698. (cons "'''\\([^']\\|[^']'\\)*?\\('''\\|\n\n\\)"
  699. ;'font-lock-builtin-face)
  700. 'font-mediawiki-bold-face)
  701. (cons "''\\([^']\\|[^']'\\)*?\\(''\\|\n\n\\)"
  702. 'font-mediawiki-italic-face)
  703. ;; Headers and dividers
  704. (list "^\\(==+\\)\\(.*\\)\\(\\1\\)"
  705. '(1 font-lock-builtin-face)
  706. ;'(2 mediawiki-header-face)
  707. '(2 font-mediawiki-sedate-face)
  708. '(3 font-lock-builtin-face))
  709. (cons "^-----*" 'font-lock-builtin-face)
  710. ;; Bare URLs and ISBNs
  711. (cons (concat "\\(^\\| \\)" (regexp-opt mediawiki-url-protocols t)
  712. "://[-A-Za-z0-9._\/~%+&#?!=()@]+")
  713. 'font-lock-variable-name-face)
  714. (cons "\\(^\\| \\)ISBN [-0-9A-Z]+" 'font-lock-variable-name-face)
  715. ;; Colon indentation, lists, definitions, and tables
  716. (cons "^\\(:+\\|[*#]+\\||[}-]?\\|{|\\)" 'font-lock-builtin-face)
  717. (list "^\\(;\\)\\([^:\n]*\\)\\(:?\\)"
  718. '(1 font-lock-builtin-face)
  719. '(2 font-lock-keyword-face)
  720. '(3 font-lock-builtin-face))
  721. ;; Tags and comments
  722. (list (concat "\\(</?\\)"
  723. (regexp-opt mediawiki-simple-tags t) "\\(>\\)")
  724. '(1 font-lock-builtin-face t t)
  725. '(2 font-lock-function-name-face t t)
  726. '(3 font-lock-builtin-face t t))
  727. (list (concat "\\(</?\\)"
  728. (regexp-opt mediawiki-complex-tags t)
  729. "\\(\\(?: \\(?:[^\"'/><]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?\\)\\(>\\)")
  730. '(1 font-lock-builtin-face t t)
  731. '(2 font-lock-function-name-face t t)
  732. '(3 font-lock-keyword-face t t)
  733. '(4 font-lock-builtin-face t t))
  734. (cons (concat "<!-- \\([^->]\\|>\\|-\\([^-]\\|-[^>]\\)\\)*-->")
  735. '(0 font-lock-comment-face t t))
  736. ;; External Links
  737. (list (concat "\\(\\[\\)\\(\\(?:"
  738. (regexp-opt mediawiki-url-protocols)
  739. "\\)://[-A-Za-z0-9._\/~%-+&#?!=()@]+\\)\\(\\(?: [^]\n]*\\)?\\)\\(\\]\\)")
  740. '(1 font-lock-builtin-face t t)
  741. '(2 font-lock-variable-name-face t t)
  742. '(3 font-lock-keyword-face t t)
  743. '(4 font-lock-builtin-face t t))
  744. ;; Wiki links
  745. '("\\(\\[\\[\\)\\([^]\n|]*\\)\\(|?\\)\\([^]\n]*\\)\\(\\]\\]\\)"
  746. (1 font-lock-builtin-face t t)
  747. (2 font-lock-variable-name-face t t)
  748. (3 font-lock-builtin-face t t)
  749. (4 font-lock-keyword-face t t)
  750. (5 font-lock-builtin-face t t))
  751. ;; Semantic relations
  752. '("\\(\\[\\[\\)\\([^]\n|]*\\)\\(::\\)\\([^]\n|]*\\)\\(|?\\)\\([^]\n]*\\)\\(\\]\\]\\)"
  753. (1 font-lock-builtin-face t t)
  754. (2 font-lock-variable-name-face t t)
  755. (3 font-lock-builtin-face t t)
  756. (4 font-lock-constant-face t t)
  757. (5 font-lock-builtin-face t t)
  758. (6 font-lock-keyword-face t t)
  759. (7 font-lock-builtin-face t t))
  760. ;; Wiki variables
  761. '("\\({{\\)\\(.+?\\)\\(}}\\)"
  762. (1 font-lock-builtin-face t t)
  763. (2 font-lock-variable-name-face t t)
  764. (3 font-lock-builtin-face t t))
  765. ;; Semantic variables
  766. '("\\({{{\\)\\(.+?\\)\\(}}}\\)"
  767. (1 font-lock-builtin-face t t)
  768. (2 font-lock-variable-name-face t t)
  769. (3 font-lock-builtin-face t t))
  770. ;; Character entity references
  771. (cons "&#?[a-zA-Z0-9]+;" '(0 font-lock-type-face t t))
  772. ;; Preformatted text
  773. (cons "^ .*$" '(0 font-lock-constant-face t t))
  774. ;; Math environment (uniform highlight only, no TeX markup)
  775. (list "<math>\\(\\(\n?.\\)*\\)</math>"
  776. '(1 font-lock-keyword-face t t))))
  777. (defvar mediawiki-draft-send-archive t
  778. "*Archive the reply.")
  779. (defvar mediawiki-draft-mode-map ())
  780. (defun mediawiki-translate-pagename (name)
  781. "Given NAME, returns the typical name that MediaWiki would use.
  782. Right now, this only means replacing \"_\" with \" \"."
  783. (if (not name)
  784. "Main Page"
  785. (mapconcat 'identity (split-string name "_" t) " ")))
  786. (defun mediawiki-make-api-url (&optional sitename)
  787. (format (concat (mediawiki-site-url (or sitename mediawiki-site))
  788. "api.php")))
  789. (defun mediawiki-api-call (sitename action args)
  790. (let* ((raw (url-http-post (mediawiki-make-api-url sitename)
  791. (delq nil
  792. (append args (list (cons "format" "xml")
  793. (cons "action" action))))
  794. (string= action "upload")))
  795. (result (assoc 'api
  796. (with-temp-buffer
  797. (insert raw)
  798. (xml-parse-region (point-min) (point-max))))))
  799. (unless result
  800. (error "There was an error parsing the result of the API call"))
  801. (when (assq 'error (cddr result))
  802. (let* ((err (cadr (assq 'error (cddr result))))
  803. (err-code (cdr (assq 'code err)))
  804. (err-info (cdr (assq 'info err))))
  805. (error "The server encountered an error: (%s) %s" err-code err-info)))
  806. (if (cddr result)
  807. (let ((action-res (assq (intern action) (cddr result))))
  808. (unless action-res
  809. (error "Didn't see action name in the result list"))
  810. action-res)
  811. t)))
  812. (defun mediawiki-make-url (title action &optional sitename)
  813. (format (concat (mediawiki-site-url (or sitename mediawiki-site))
  814. (if action
  815. mediawiki-argument-pattern
  816. "?title=%s"))
  817. (mm-url-form-encode-xwfu
  818. (mediawiki-translate-pagename title))
  819. action))
  820. (defun mediawiki-open (name)
  821. "Open a wiki page specified by NAME from the mediawiki engine"
  822. (interactive
  823. (let ((hist (cdr (assoc-string mediawiki-site mediawiki-page-history))))
  824. (list (read-string "Wiki Page: " nil 'hist))))
  825. (when (or (not (stringp name))
  826. (string-equal "" name))
  827. (error "Need to specify a name"))
  828. (mediawiki-edit mediawiki-site name))
  829. (defun mediawiki-reload ()
  830. (interactive)
  831. (let ((title mediawiki-page-title))
  832. (if title
  833. (mediawiki-open title)
  834. (error "Error: %s is not a mediawiki document" (buffer-name)))))
  835. (defun mediawiki-add-page-history (site title)
  836. (let ((hist (cdr (assoc-string site mediawiki-page-history))))
  837. (unless hist
  838. (add-to-list 'mediawiki-page-history (cons site "")))
  839. (setcdr (assoc-string site mediawiki-page-history) (append (list title) hist))))
  840. (defun mediawiki-edit (site title)
  841. "Edit wiki file with the name of title"
  842. (when (not (ring-p mediawiki-page-ring))
  843. (setq mediawiki-page-ring (make-ring 30)))
  844. (let ((pagetitle (mediawiki-translate-pagename title)))
  845. (mediawiki-add-page-history site title)
  846. (with-current-buffer (get-buffer-create
  847. (concat site ": " pagetitle))
  848. (unless (mediawiki-logged-in-p site)
  849. (mediawiki-do-login site)
  850. (setq mediawiki-site site))
  851. (ring-insert mediawiki-page-ring (current-buffer))
  852. (delete-region (point-min) (point-max))
  853. (mediawiki-mode)
  854. (set-buffer-file-coding-system 'utf-8)
  855. (insert (or (mediawiki-get site pagetitle) ""))
  856. (set-buffer-modified-p nil)
  857. (setq buffer-undo-list t)
  858. (buffer-enable-undo)
  859. (mediawiki-pop-to-buffer (current-buffer))
  860. (setq mediawiki-page-title pagetitle)
  861. (goto-char (point-min))
  862. (current-buffer))))
  863. (defun mediawiki-get-edit-form-vars (str bufname)
  864. "Extract the form variables from a page. This should only be
  865. called from a buffer in mediawiki-mode as the variables it sets
  866. there will be local to that buffer."
  867. (let ((args (mediawiki-get-form-vars str "id" "editform")))
  868. (if args
  869. (with-current-buffer bufname
  870. (setq mediawiki-edit-form-vars args))
  871. (cond
  872. ((string-match mediawiki-permission-denied str)
  873. (message "Permission Denied"))
  874. ((string-match mediawiki-view-source str)
  875. (message "Editing of this page is disabled, here is the source"))))))
  876. (defun mediawiki-get-form-vars (str attr val)
  877. ;; Find the form
  878. (when (string-match
  879. (concat "<form [^>]*" attr "=[\"']" val "['\"][^>]*>")
  880. str)
  881. (let* ((start-form (match-end 0))
  882. (end-form (when (string-match "</form>" str start-form)
  883. (match-beginning 0)))
  884. (form (substring str start-form end-form))
  885. (start (string-match
  886. "<input \\([^>]*name=[\"']\\([^\"']+\\)['\"][^>]*\\)>"
  887. form))
  888. (vars '(nil)))
  889. ;; Continue until we can't find any more input elements
  890. (while start
  891. ;; First, capture the place where we'll start next. Have
  892. ;; to do this here since match-end doesn't seem to let you
  893. ;; specify the string you were matching against, unlike
  894. ;; match-string
  895. (setq start (match-end 0))
  896. ;; Capture the string that defines this element
  897. (let ((el (match-string 1 form))
  898. ;; get the element name
  899. (el-name (match-string 2 form)))
  900. ;; figure out if this is a submit button and skip it if it is.
  901. (when (not (string-match "type=[\"']submit['\"]" el))
  902. (add-to-list 'vars
  903. (if (string-match "value=[\"']\\([^\"']*\\)['\"]" el)
  904. (cons el-name (match-string 1 el))
  905. (cons el-name nil)))))
  906. (setq start
  907. (string-match
  908. "<input \\([^>]*name=[\"']\\([^\"']+\\)['\"][^>]*\\)>"
  909. form start)))
  910. vars)))
  911. (defun mediawiki-logged-in-p (&optional site)
  912. "Returns t if we are we have cookies for the site."
  913. (let ((urlobj (url-generic-parse-url
  914. (mediawiki-site-url (or site mediawiki-site)))))
  915. (url-cookie-retrieve
  916. (url-host urlobj)
  917. (url-filename urlobj)
  918. (equal "https" (url-type urlobj)))))
  919. (defun mediawiki-pop-to-buffer (bufname)
  920. "Pop to buffer and then execute a hook."
  921. (pop-to-buffer bufname)
  922. (run-hooks 'mediawiki-pop-buffer-hook))
  923. (defun mediawiki-api-param (v)
  924. "Concat a list into a bar-separated string, turn an integer
  925. into a string, or just return the string"
  926. (cond
  927. ((integerp v) (int-to-string v))
  928. ((stringp v) v)
  929. ((listp v) (mapconcat 'identity v "|"))
  930. (t (error "Don't know what to do with %s" v))))
  931. (defun mediawiki-api-query-revisions (site titles props &optional limit)
  932. "Get a list of revisions and properties for a given page."
  933. (cddr (mediawiki-api-call site "query"
  934. (list (cons "prop" (mediawiki-api-param (list "info" "revisions")))
  935. (cons "intoken" (mediawiki-api-param "edit"))
  936. (cons "titles" (mediawiki-api-param titles))
  937. (when limit
  938. (cons "rvlimit" (mediawiki-api-param limit)))
  939. (cons "rvprop" (mediawiki-api-param props))))))
  940. (defun mediawiki-page-get-title (page)
  941. "Given a page from a pagelist structure, extract the title."
  942. (cdr (assq 'title (cadr page))))
  943. (defun mediawiki-page-get-revision (page rev &optional bit)
  944. "Extract a revision from the pagelist structure."
  945. (let ((rev (cdr (nth rev (cddr (assq 'revisions (cddr page)))))))
  946. (cond
  947. ((eq bit 'content)
  948. (cadr rev))
  949. ((assoc bit (car rev))
  950. (cdr (assoc bit (car rev))))
  951. (t rev))))
  952. (defun mediawiki-pagelist-find-page (pagelist title)
  953. "Extract a page TITLE from a PAGELIST returned by mediawiki"
  954. (let ((pl (cddr (assq 'pages pagelist)))
  955. page current)
  956. (while (and (not page)
  957. (setq current (pop pl)))
  958. ;; This fails when underbars are here instead of spaces,
  959. ;; so we make sure that it has the mediawiki pagename
  960. (when (string= (mediawiki-page-get-title current)
  961. (mediawiki-translate-pagename title))
  962. (setq page current)))
  963. page))
  964. (defun mediawiki-api-query-title (site title)
  965. "Retrieve the current content of the page."
  966. (let* ((pagelist (mediawiki-api-query-revisions
  967. site title
  968. (list "ids" "timestamp" "flags" "comment" "user" "content"))))
  969. (mediawiki-pagelist-find-page pagelist title)))
  970. (defun mediawiki-get (site title)
  971. (let ((page (mediawiki-api-query-title site title)))
  972. (mediawiki-save-metadata site page)
  973. (mediawiki-page-get-revision page 0 'content)))
  974. (defun mediawiki-page-get-metadata (page item)
  975. (cdr (assoc item (cadr page))))
  976. (defun mediawiki-save-metadata (site page)
  977. (setq mediawiki-site site)
  978. (setq mediawiki-page-title
  979. (mediawiki-page-get-metadata page 'title))
  980. (setq mediawiki-edittoken
  981. (mediawiki-page-get-metadata page 'edittoken))
  982. (setq mediawiki-basetimestamp
  983. (mediawiki-page-get-revision page 0 'timestamp))
  984. (setq mediawiki-starttimestamp
  985. (mediawiki-page-get-metadata page 'starttimestamp)))
  986. (defun mediawiki-save (&optional summary)
  987. (interactive "sSummary: ")
  988. (if mediawiki-page-title
  989. (mediawiki-save-page
  990. mediawiki-site
  991. mediawiki-page-title
  992. summary
  993. (buffer-substring-no-properties (point-min) (point-max)))
  994. (error "Error: %s is not a mediawiki document" (buffer-name))))
  995. (defun mediawiki-prompt-for-page ()
  996. (let* ((prompt (concat "Page"
  997. (when mediawiki-page-title
  998. (format " (default %s)" mediawiki-page-title))
  999. ": "))
  1000. (answer (completing-read prompt '())))
  1001. (if (string= "" answer)
  1002. mediawiki-page-title
  1003. answer)))
  1004. (defun mediawiki-prompt-for-summary ()
  1005. (completing-read "Summary: " '()))
  1006. (defun mediawiki-save-on (&optional site name summary)
  1007. (interactive)
  1008. (when (not site)
  1009. (setq site (mediawiki-prompt-for-site)))
  1010. (when (not name)
  1011. (setq name (mediawiki-translate-pagename (mediawiki-prompt-for-page))))
  1012. (when (not summary)
  1013. (setq summary (mediawiki-prompt-for-summary)))
  1014. (setq mediawiki-site (mediawiki-do-login site))
  1015. (mediawiki-get mediawiki-site name)
  1016. (mediawiki-save-as name summary))
  1017. (defun mediawiki-save-as (&optional name summary)
  1018. (interactive "sSave As: \nsSummary: ")
  1019. (if name
  1020. (mediawiki-save-page
  1021. mediawiki-site
  1022. name
  1023. summary
  1024. (buffer-substring-no-properties (point-min) (point-max)))
  1025. (error "Error: %s is not a mediawiki document" (buffer-name))))
  1026. (defun mediawiki-save-and-bury (&optional summary)
  1027. (interactive "sSummary: ")
  1028. (mediawiki-save summary)
  1029. (bury-buffer))
  1030. (defun mediawiki-site-extract (sitename index)
  1031. (let ((bit (nth index (assoc sitename mediawiki-site-alist))))
  1032. (cond
  1033. ((eq nil sitename)
  1034. (error "Sitename isn't set"))
  1035. ((eq nil bit)
  1036. (error "Couldn't find a site named: %s" sitename))
  1037. ((string-match "[^ \t\n]" bit) bit)
  1038. (nil))))
  1039. (defun mediawiki-site-url (sitename)
  1040. "Get the url for a given site."
  1041. (mediawiki-site-extract sitename 1))
  1042. (defun mediawiki-site-username (sitename)
  1043. "Get the username for a given site."
  1044. (or (mediawiki-site-extract sitename 2)
  1045. (url-user-for-url (mediawiki-site-url sitename))))
  1046. (defun mediawiki-site-password (sitename)
  1047. "Get the password for a given site."
  1048. (or (mediawiki-site-extract sitename 3)
  1049. (url-password-for-url (mediawiki-site-url sitename))))
  1050. (defun mediawiki-site-first-page (sitename)
  1051. "Get the password for a given site."
  1052. (mediawiki-site-extract sitename 4))
  1053. (defun mediawiki-do-login (&optional sitename username password)
  1054. "Use USERNAME and PASSWORD to log into the MediaWiki site and
  1055. get a cookie."
  1056. (interactive)
  1057. (when (not sitename)
  1058. (setq sitename (mediawiki-prompt-for-site)))
  1059. (setq mediawiki-site nil) ; This wil be set once we are
  1060. ; logged in
  1061. ;; Possibly save info once we have it, eh?
  1062. (lexical-let* ((user (or (mediawiki-site-username sitename)
  1063. username
  1064. (read-string "Username: ")))
  1065. (pass (or (mediawiki-site-password sitename)
  1066. password
  1067. (read-passwd "Password: ")))
  1068. (sitename sitename)
  1069. (args (list (cons "lgname" user)
  1070. (cons "lgpassword" pass)))
  1071. (result (cadr (mediawiki-api-call sitename "login" args))))
  1072. (when (string= (cdr (assq 'result result)) "NeedToken")
  1073. (setq result
  1074. (cadr (mediawiki-api-call
  1075. sitename "login"
  1076. (append
  1077. args (list (cons "lgtoken"
  1078. (cdr (assq 'token result)))))))))
  1079. (when (string= "Success" (cdr (assoc 'result result)))
  1080. sitename)))
  1081. (defun mediawiki-do-logout (&optional sitename)
  1082. (interactive)
  1083. (when (not sitename)
  1084. (setq sitename (mediawiki-prompt-for-site)))
  1085. (mediawiki-api-call sitename "logout" nil)
  1086. (setq mediawiki-site nil))
  1087. (defun mediawiki-save-page (site title summary content)
  1088. "Save the current page to a MediaWiki wiki."
  1089. ;; FIXME error checking, conflicts!
  1090. (mediawiki-api-call site "edit" (list (cons "title"
  1091. (mediawiki-translate-pagename title))
  1092. (cons "text" content)
  1093. (cons "summary" summary)
  1094. (cons "token" mediawiki-edittoken)
  1095. (cons "basetimestamp"
  1096. (or mediawiki-basetimestamp ""))
  1097. (cons "starttimestamp"
  1098. (or mediawiki-starttimestamp ""))))
  1099. (set-buffer-modified-p nil))
  1100. ;; (cdr (assoc 'edittoken (cadr (caddr (caddr (mediawiki-api-call "mw-svn" "query"
  1101. ;; (list '("prop" . "info")
  1102. ;; '("intoken" . "edit")
  1103. ;; '("titles" . (concat "File:" filename)))))))))
  1104. ;
  1105. ;(mediawiki-api-call "mw-svn" "upload" (list '("filename" . "info.exe") '("file" . "edit") '("token" . token)))
  1106. (defun mediawiki-browse (&optional buf)
  1107. "Open the buffer BUF in a browser. If BUF is not given,
  1108. the current buffer is used."
  1109. (interactive)
  1110. (if mediawiki-page-title
  1111. (browse-url (mediawiki-make-url mediawiki-page-title "view"))))
  1112. (defun mediawiki-prompt-for-site ()
  1113. (let* ((prompt (concat "Sitename"
  1114. (when mediawiki-site
  1115. (format " (default %s)" mediawiki-site))
  1116. ": "))
  1117. (answer (completing-read prompt mediawiki-site-alist nil t)))
  1118. (if (string= "" answer)
  1119. mediawiki-site
  1120. answer)))
  1121. (defun mediawiki-site (&optional site)
  1122. "Set up mediawiki.el for a site. Without an argument, use
  1123. `mediawiki-site-default'. Interactively, prompt for a site."
  1124. (interactive)
  1125. (when (not site)
  1126. (setq site (mediawiki-prompt-for-site)))
  1127. (when (or (eq nil mediawiki-site)
  1128. (not (string-equal site mediawiki-site)))
  1129. (setq mediawiki-site (mediawiki-do-login site)))
  1130. (mediawiki-edit site (mediawiki-site-first-page site)))
  1131. (defun mediawiki-open-page-at-point ()
  1132. "Open a new buffer with the page at point."
  1133. (interactive)
  1134. (mediawiki-open (mediawiki-page-at-point)))
  1135. (defun mediawiki-page-at-point ()
  1136. "Return the page name under point. Typically, this means
  1137. anything enclosed in [[PAGE]]."
  1138. (let ((pos (point))
  1139. (eol (point-at-eol))
  1140. (bol (point-at-bol)))
  1141. (save-excursion
  1142. (let* ((start (when (search-backward "[[" bol t)
  1143. (+ (point) 2)))
  1144. (end (when (search-forward "]]" eol t)
  1145. (- (point) 2)))
  1146. (middle (progn
  1147. (goto-char start)
  1148. (when (search-forward "|" end t)
  1149. (1- (point)))))
  1150. (pagename (when (and
  1151. (not (eq nil start))
  1152. (not (eq nil end))
  1153. (<= pos end)
  1154. (>= pos start))
  1155. (buffer-substring-no-properties
  1156. start (or middle end)))))
  1157. (if (string= "/"
  1158. (substring pagename 0 1))
  1159. (concat mediawiki-page-title pagename)
  1160. pagename)))))
  1161. (defun mediawiki-next-header ()
  1162. "Move point to the end of the next section header."
  1163. (interactive)
  1164. (let ((oldpoint (point)))
  1165. (end-of-line)
  1166. (if (re-search-forward "\\(^==+\\).*\\1" (point-max) t)
  1167. (beginning-of-line)
  1168. (goto-char oldpoint)
  1169. (message "No section headers after point."))))
  1170. (defun mediawiki-prev-header ()
  1171. "Move point to the start of the previous section header."
  1172. (interactive)
  1173. (unless (re-search-backward "\\(^==+\\).*\\1" (point-min) t)
  1174. (message "No section headers before point.")))
  1175. (defun mediawiki-terminate-paragraph () ;Version:1.58
  1176. "In a list, start a new list item. In a paragraph, start a new
  1177. paragraph; if the current paragraph is colon indented, the new
  1178. paragraph will be indented in the same way."
  1179. (interactive)
  1180. (let (indent-chars)
  1181. (save-excursion
  1182. (beginning-of-line)
  1183. (while (cond ((looking-at "^$") nil)
  1184. ((looking-at "^\\(\\(?: \\|:+\\|[#*]+\\) *\\)")
  1185. (setq indent-chars (match-string 1)) nil)
  1186. ((eq (point) (point-min)) nil)
  1187. ((progn (forward-line -1) t)))
  1188. t))
  1189. (newline) (if (not indent-chars) (newline)
  1190. (insert indent-chars))))
  1191. (defun mediawiki-terminate-paragraph-and-indent ()
  1192. "In a list, start a new list item. In a paragraph, start a new
  1193. paragraph but *,# will be ignored; if the current paragraph is colon
  1194. ; indented, the new paragraph will be indented in the same way."
  1195. (interactive)
  1196. (let (indent-chars)
  1197. (save-excursion
  1198. (beginning-of-line)
  1199. (while (cond ((looking-at "^$") nil)
  1200. ((looking-at "^\\(\\(?: \\|:+\\) *\\)")
  1201. (setq indent-chars (match-string 1)) nil)
  1202. ((eq (point) (point-min)) nil)
  1203. ((progn (forward-line -1) t)))
  1204. t))
  1205. (newline)
  1206. (if (not indent-chars) (newline)
  1207. (insert indent-chars))))
  1208. (defun mediawiki-link-fill-nobreak-p ()
  1209. "When filling, don't break the line for preformatted (fixed-width)
  1210. text or inside a Wiki link. See `fill-nobreak-predicate'."
  1211. (save-excursion
  1212. (let ((pos (point)))
  1213. (or (eq (char-after (line-beginning-position)) ? )
  1214. (if (re-search-backward "\\[\\[" (line-beginning-position) t)
  1215. ;; Break if the link is really really long.
  1216. ;; You often get this with captioned images.
  1217. (null (or (> (- pos (point)) fill-column)
  1218. (re-search-forward "\\]\\]" pos t))))))))
  1219. (defun mediawiki-fill-article ()
  1220. "Fill the entire article."
  1221. (interactive)
  1222. (save-excursion
  1223. (fill-region (point-min) (point-max))))
  1224. (defun mediawiki-unfill-article ()
  1225. "Undo filling, deleting stand-alone newlines (newlines that do not
  1226. end paragraphs, list entries, etc.)"
  1227. (interactive)
  1228. (save-excursion
  1229. (goto-char (point-min))
  1230. (while (re-search-forward ".\\(\n\\)\\([^# *;:|!\n]\\|----\\)" nil t)
  1231. (replace-match " " nil nil nil 1)))
  1232. (message "Stand-alone newlines deleted"))
  1233. (defun mediawiki-draft-reply ()
  1234. "Open a temporary buffer in mediawiki mode for editing an
  1235. mediawiki draft, with an arbitrary piece of data. After finishing
  1236. the editing |]]:either use \"C-c C-k\" \\[mediawiki-draft-buffer]
  1237. to send the data into the mediawiki-draft-data-file, or send the
  1238. buffer \"C-c\C-c\", to the current article. Check the variable
  1239. mediawiki-draft-send-archive."
  1240. (interactive)
  1241. (mediawiki-reply-at-point-simple)
  1242. (beginning-of-line 1)
  1243. (kill-line nil)
  1244. (save-excursion
  1245. (window-configuration-to-register mediawiki-draft-register)
  1246. (let ((buf (get-buffer-create mediawiki-draft-buffer)))
  1247. (switch-to-buffer-other-window buf)
  1248. (mediawiki-mode)
  1249. (if mediawiki-reply-with-quote
  1250. (progn
  1251. (insert "{{Quotation|")
  1252. (yank)
  1253. (insert "'''Re: ")
  1254. (insert-register mediawiki-draft-reply-register 1)
  1255. (insert "''' |~~~~}}")
  1256. (backward-char 7))
  1257. (when mediawiki-reply-with-hline
  1258. (insert "----")
  1259. (newline 1))
  1260. (yank)
  1261. (end-of-line 1))
  1262. (message " C-c C-k sends to draft, C-c C-c sends to org buffer."))))
  1263. (defun mediawiki-reply-at-point-simple ()
  1264. "Very simple function to reply to posts in the discussion forum. You have to set
  1265. the point around the signature, then the functions inserts the following
  1266. :'''Re: [[User:foo]]'''."
  1267. (interactive)
  1268. (beginning-of-line 1)
  1269. (if mediawiki-english-or-german
  1270. (progn
  1271. (search-forward "(UTC)")
  1272. (search-backward "[[User:"))
  1273. (search-forward "(CET)")
  1274. (search-backward "[[Benutzer:"))
  1275. (if mediawiki-user-simplify-signature
  1276. (mark-word 2)
  1277. (mark-word 3))
  1278. (copy-to-register mediawiki-draft-reply-register (region-beginning) (region-end) nil)
  1279. (end-of-line 1)
  1280. (mediawiki-terminate-paragraph-and-indent)
  1281. (insert ":'''Re: ")
  1282. (insert-register mediawiki-draft-reply-register 1)
  1283. (if mediawiki-user-simplify-signature
  1284. (insert "|]]''' ")
  1285. (insert "]]''' ")))
  1286. (defmacro mediawiki-goto-relative-page (direction)
  1287. `(let ((buff (ring-ref mediawiki-page-ring
  1288. (setq mediawiki-page-ring-index
  1289. (,direction mediawiki-page-ring-index 1)))))
  1290. (while (not (buffer-live-p buff))
  1291. (setq buff
  1292. (ring-ref mediawiki-page-ring
  1293. (setq mediawiki-page-ring-index
  1294. (,direction mediawiki-page-ring-index 1)))))
  1295. (mediawiki-pop-to-buffer buff)))
  1296. (defun mediawiki-goto-previous-page ()
  1297. "Pop up the previous page being editted."
  1298. (interactive)
  1299. (mediawiki-goto-relative-page -))
  1300. (defun mediawiki-goto-next-page ()
  1301. "Pop up the previous page being editted."
  1302. (interactive)
  1303. (mediawiki-goto-relative-page +))
  1304. (defun mediawiki-goto-relative-link (&optional backward)
  1305. "Move point to a link. If backward is t, will search backwards."
  1306. (let* ((search (if backward 're-search-backward
  1307. 're-search-forward))
  1308. (limitfunc (if backward 'point-min
  1309. 'point-max))
  1310. (point (funcall search "\\[\\[.+\\]\\]" (funcall limitfunc) t)))
  1311. (when point
  1312. (let ((point (match-beginning 0)))
  1313. (goto-char (+ point 2))))))
  1314. (defun mediawiki-goto-next-link ()
  1315. (interactive)
  1316. (mediawiki-goto-relative-link))
  1317. (defun mediawiki-goto-prev-link ()
  1318. (interactive)
  1319. (mediawiki-goto-relative-link t))
  1320. (defvar wikipedia-enumerate-with-terminate-paragraph nil
  1321. "*Before insert enumerate/itemize do \\[wikipedia-terminate-paragraph].")
  1322. (defun mediawiki-insert-enumerate ()
  1323. "Primitive Function for inserting enumerated items, check the
  1324. variable wikipedia-enumerate-with-terminate-paragraph. Note however
  1325. that the function \\[wikipedia-terminate-paragraph] does not work very
  1326. well will longlines-mode."
  1327. (interactive)
  1328. (if mediawiki-enumerate-with-terminate-paragraph
  1329. (progn
  1330. (mediawiki-terminate-paragraph)
  1331. (insert "#"))
  1332. (newline nil)
  1333. (insert ":#")))
  1334. (defun mediawiki-insert-itemize ()
  1335. "Primitive Function for inserting no enumerated items, check
  1336. the variable mediawiki-enumerate-with-terminate-paragraph. Note
  1337. however that the function \\[mediawiki-terminate-paragraph] does
  1338. not work very well will longlines-mode."
  1339. (interactive)
  1340. (if mediawiki-enumerate-with-terminate-paragraph
  1341. (progn
  1342. (mediawiki-terminate-paragraph)
  1343. (insert "*"))
  1344. (newline nil)
  1345. (insert ":*")))
  1346. (defun mediawiki-insert (pre post)
  1347. (if (or (and (boundp 'zmacs-region-active-p) zmacs-region-active-p)
  1348. (and (boundp 'transient-mark-mode) transient-mark-mode mark-active))
  1349. (let ((beg (region-beginning))
  1350. (end (region-end)))
  1351. (save-excursion
  1352. (goto-char beg)
  1353. (insert pre)
  1354. (goto-char (+ end (string-width pre)))
  1355. (insert post)))
  1356. (insert (concat pre " " post))
  1357. (backward-char (+ 1 (string-width post)))))
  1358. (defun mediawiki-insert-strong-emphasis ()
  1359. "Insert strong emphasis italics via four
  1360. apostrophes (e.g. ''''FOO''''.) When mark is active, surrounds
  1361. region."
  1362. (interactive)
  1363. (mediawiki-insert "''''" "''''"))
  1364. (defun mediawiki-insert-bold ()
  1365. "Insert bold via three apostrophes (e.g. '''FOO'''.)
  1366. When mark is active, surrounds region."
  1367. (interactive)
  1368. (mediawiki-insert "'''" "'''"))
  1369. (defun mediawiki-insert-italics ()
  1370. "Insert bold via TWO apostrophes (e.g. ''FOO''.) When mark is active,
  1371. surrounds region."
  1372. (interactive)
  1373. (mediawiki-insert "''" "''"))
  1374. (defun mediawiki-insert-quotation-with-signature ()
  1375. "Insert bold via TWO apostrophes (e.g. ''FOO''.) When mark is active,
  1376. surrounds region."
  1377. (interactive)
  1378. (mediawiki-insert "{{Quotation|}}" "{{~~~~}}"))
  1379. (defun mediawiki-insert-quotation ()
  1380. "Quotation box of the form {{Quotation}}{{}}. When mark is active,
  1381. surrounds region."
  1382. (interactive)
  1383. (mediawiki-insert "{{Quotation|}}{{" "}}"))
  1384. (defun mediawiki-insert-bible-verse-template ()
  1385. "Insert a template for the quotation of bible verses."
  1386. (interactive)
  1387. (insert "({{niv|")
  1388. (let ((name (read-string "Name: ")))
  1389. (insert (concat name "|"))
  1390. (let ((verse (read-string "Verse: ")))
  1391. (insert (concat verse "|" name " " verse "}})")))))
  1392. (defun mediawiki-insert-user ()
  1393. "Inserts, interactively a user name [[User:foo]]"
  1394. (interactive)
  1395. (if mediawiki-english-or-german
  1396. (let ((user (read-string "Name of user: " )))
  1397. (insert (concat "[[User:" user "|" user "]]"))))
  1398. (let ((user (read-string "Name des Benutzers: " )))
  1399. (insert (concat "[[Benutzer:" user "|" user "]]"))))
  1400. (defun mediawiki-insert-reply-prefix ()
  1401. "Quotation box of the form {{Quotation}}{{}}. When mark is active,
  1402. surrounds region."
  1403. (interactive)
  1404. (beginning-of-line 1)
  1405. (search-forward "[[")
  1406. (backward-char 2)
  1407. (mark-sexp 1)
  1408. (copy-to-register mediawiki-draft-reply-register (region-beginning) (region-end) nil)
  1409. (end-of-line 1)
  1410. (mediawiki-terminate-paragraph)
  1411. (beginning-of-line 1)
  1412. (kill-line nil)
  1413. (insert "----")
  1414. (newline 1)
  1415. (yank)
  1416. (insert ":'''Re: ")
  1417. (insert-register mediawiki-draft-reply-register 1)
  1418. (insert "''' ")
  1419. (end-of-line 1))
  1420. (defun mediawiki-insert-header ()
  1421. "Insert subheader via == (e.g. == FOO ==.)"
  1422. (interactive)
  1423. (mediawiki-insert "==" "=="))
  1424. (defun mediawiki-insert-link ()
  1425. "Insert link via [[ (e.g. [[FOO]].) When mark is active, surround region."
  1426. (interactive)
  1427. (mediawiki-insert "[[" "]]"))
  1428. (defun mediawiki-insert-link-www ()
  1429. "Insert link via [[ (e.g. [http://FOO].) When mark is active, surround region."
  1430. (interactive)
  1431. (mediawiki-insert "[http://" "]"))
  1432. (defun mediawiki-insert-image ()
  1433. "Insert link image [[ (e.g. [[Image:FOO]].) Check the variable
  1434. mediawiki-english-or-german. When mark is active, surround region."
  1435. (interactive)
  1436. (mediawiki-insert (if mediawiki-english-or-german
  1437. "[[Image:"
  1438. "[[Bild:") "]]"))
  1439. (defun mediawiki-insert-audio ()
  1440. "Insert link image [[ (e.g. [[Image:FOO]].) Check the variable
  1441. mediawiki-english-or-german. When mark is active, surround region."
  1442. (interactive)
  1443. (mediawiki-insert (if mediawiki-english-or-german
  1444. "[[Media:"
  1445. "[[Bild:") "]]"))
  1446. (defun mediawiki-insert-signature ()
  1447. "Insert \"~~~~:\" "
  1448. (interactive)
  1449. (insert "~~~~: "))
  1450. (defun mediawiki-insert-hline ()
  1451. "Insert \"----\" "
  1452. (interactive)
  1453. (insert "\n----\n"))
  1454. (defun mediawiki-unfill-paragraph-or-region ()
  1455. "Unfill region, this function does NOT explicitly search for \"soft newlines\"
  1456. as does mediawiki-unfill-region."
  1457. (interactive)
  1458. (set (make-local-variable 'paragraph-start) "[ \t\n\f]")
  1459. (set (make-local-variable 'paragraph-start)
  1460. "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")
  1461. (set-fill-prefix)
  1462. (beginning-of-line 1)
  1463. (if use-hard-newlines
  1464. (progn
  1465. (set (make-local-variable 'use-hard-newlines) nil)
  1466. (set (make-local-variable 'sentence-end-double-space) t))
  1467. (set (make-local-variable 'sentence-end-double-space) nil)
  1468. (set (make-local-variable 'use-hard-newlines) t))
  1469. (let ((fill-column (point-max)))
  1470. (if (fboundp 'fill-paragraph-or-region)
  1471. (fill-paragraph-or-region nil)
  1472. (fill-paragraph nil))))
  1473. (defun mediawiki-start-paragraph ()
  1474. (interactive)
  1475. (set (make-local-variable 'paragraph-start)
  1476. "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$"))
  1477. (defun mediawiki-hardlines ()
  1478. "Set use-hard-newlines to NIL."
  1479. (interactive)
  1480. (setq use-hard-newlines nil))
  1481. (defun mediawiki-next-long-line ()
  1482. "Move forward to the next long line with column-width greater
  1483. than `fill-column'.
  1484. TODO: When function reaches end of buffer, save-excursion to
  1485. starting point. Generalise to make `previous-long-line'."
  1486. (interactive)
  1487. ;; global-variable: fill-column
  1488. (if (= (forward-line) 0)
  1489. (let ((line-length
  1490. (save-excursion
  1491. (end-of-line)
  1492. (current-column))))
  1493. (if (<= line-length fill-column)
  1494. (mediawiki-next-long-line)
  1495. (message "Long line found")))
  1496. ;; Stop, end of buffer reached.
  1497. (error "Long line not found")))
  1498. (defun mediawiki-unfill-paragraph-simple ()
  1499. "A very simple function for unfilling a paragraph."
  1500. (interactive)
  1501. (let ((fill-column (point-max)))
  1502. (fill-paragraph nil)))
  1503. ;; See http://staff.science.uva.nl/~dominik/Tools/outline-magic.el
  1504. (defun mediawiki-outline-magic-keys ()
  1505. (interactive)
  1506. (unless (featurep 'xemacs)
  1507. (local-set-key [(shift iso-lefttab)] 'outline-cycle)
  1508. (local-set-key [iso-left-tab] 'outline-cycle))
  1509. (local-set-key [(meta left)] 'outline-promote)
  1510. (local-set-key [(meta right)] 'outline-demote)
  1511. (local-set-key [(shift return)] 'newline-and-indent)
  1512. (local-set-key [(control left)] 'mediawiki-simple-outline-promote)
  1513. (local-set-key [(control right)] 'mediawiki-simple-outline-demote)
  1514. (local-set-key [(control up)] 'outline-move-subtree-up)
  1515. (local-set-key [(control down)] 'outline-move-subtree-down))
  1516. (add-hook 'mediawiki-mode-hook (lambda () (outline-minor-mode nil)))
  1517. (add-hook 'outline-minor-mode-hook 'mediawiki-outline-magic-keys)
  1518. (defun mediawiki-enhance-indent ()
  1519. (interactive)
  1520. (string-rectangle (region-beginning) (region-end) ":"))
  1521. (defun mediawiki-yank-prefix ()
  1522. (interactive)
  1523. (string-rectangle (region-beginning) (region-end) ":"))
  1524. (defun mediawiki-simple-outline-promote ()
  1525. "Function simple deletes \"=\" and the end and the beginning of line,
  1526. does not promote the whole tree!"
  1527. (interactive)
  1528. (save-excursion
  1529. (beginning-of-line 1)
  1530. (search-forward "=")
  1531. (delete-char 1 nil)
  1532. (end-of-line 1)
  1533. (search-backward "=")
  1534. (delete-char 1 nil)))
  1535. (defun mediawiki-simple-outline-demote ()
  1536. "Function simple adds \"=\" and the end and the beginning of line,
  1537. does not promote the whole tree!"
  1538. (interactive)
  1539. (save-excursion
  1540. (beginning-of-line 1)
  1541. (search-forward "=")
  1542. (insert "=")
  1543. (end-of-line 1)
  1544. (search-backward "=")
  1545. (insert "=")))
  1546. (defun mediawiki-rename-buffer ()
  1547. "Make sure that the option UNIQUE is used."
  1548. (interactive)
  1549. (rename-buffer (read-string "Name of new buffer (unique): " ) 1))
  1550. (defsubst mediawiki-draft-time-to-seconds (time)
  1551. "Convert TIME to a floating point number."
  1552. (+ (* (car time) 65536.0)
  1553. (cadr time)
  1554. (/ (or (car (cdr (cdr time))) 0) 1000000.0)))
  1555. (defsubst mediawiki-draft-mail-date (&optional rfc822-p)
  1556. "Return a simple date. Nothing fancy."
  1557. (if rfc822-p
  1558. (format-time-string "%a, %e %b %Y %T %z" (current-time))
  1559. (format-time-string "%c" (current-time))))
  1560. (defun mediawiki-draft-buffer-desc ()
  1561. "Using the first line of the current buffer, create a short description."
  1562. (buffer-substring (point-min)
  1563. (save-excursion
  1564. (goto-char (point-min))
  1565. (end-of-line)
  1566. (if (> (- (point) (point-min)) 60)
  1567. (goto-char (+ (point-min) 60)))
  1568. (point))))
  1569. (defun mediawiki-draft-append-to-file ()
  1570. "Add a header together with a subject to the text and add it to the
  1571. draft file. It might be better if longlines-mode is off."
  1572. (let ((text (buffer-string)))
  1573. (with-temp-buffer
  1574. (insert (concat "\n\n" mediawiki-draft-leader-text "Draft: "
  1575. (read-string "Enter Subject: ") " "
  1576. (current-time-string) " "
  1577. mediawiki-draft-leader-text
  1578. "\n\n\f\n\n" text "\n\f\n"))
  1579. (if (not (bolp))
  1580. (insert "\n\n"))
  1581. (if (find-buffer-visiting mediawiki-draft-data-file)
  1582. (let ((mediawiki-draft-text (buffer-string)))
  1583. (set-buffer (get-file-buffer mediawiki-draft-data-file))
  1584. (save-excursion
  1585. (goto-char (point-max))
  1586. (insert (concat "\n" mediawiki-draft-text "\n"))
  1587. (save-buffer)))
  1588. (append-to-file (point-min) (point-max) mediawiki-draft-data-file)))))
  1589. ;;;###autoload
  1590. (defun mediawiki-draft ()
  1591. "Open a temporary buffer in wikipedia mode for editing an wikipedia
  1592. draft, which an arbitrary piece of data. After finishing the editing
  1593. either use C-c C-k \\[mediawiki-draft-buffer] to send the data into
  1594. the mediawiki-draft-data-file, or send the buffer using C-x C-s
  1595. \\[mediawiki-save] and insert it later into a wikipedia article."
  1596. (interactive)
  1597. (window-configuration-to-register mediawiki-draft-register)
  1598. (let ((buf (get-buffer-create mediawiki-draft-buffer)))
  1599. (switch-to-buffer-other-window buf)
  1600. (mediawiki-mode)
  1601. (message " C-c C-k sends to draft file, C-c C-c sends to org buffer.")))
  1602. ;;;###autoload
  1603. (defun mediawiki-draft-page ()
  1604. (interactive)
  1605. (mark-page)
  1606. (copy-region-as-kill (region-beginning) (region-end))
  1607. (mediawiki-draft)
  1608. (yank nil))
  1609. (defun mediawiki-draft-region (&optional beg end)
  1610. "Mediawiki-Draft the data from BEG to END.
  1611. If called from within the mediawiki-draft buffer, BEG and END are ignored,
  1612. and the entire buffer will be mediawiki-drafted. If called from any other
  1613. buffer, that region, plus any context information specific to that
  1614. region, will be mediawiki-drafted."
  1615. (interactive)
  1616. (let ((b (or beg (min (point) (or (mark) (point-min)))))
  1617. (e (or end (max (point) (or (mark) (point-max))))))
  1618. (save-restriction
  1619. (narrow-to-region b e)
  1620. (run-hook-with-args-until-success 'mediawiki-draft-handler-functions)
  1621. (when (equal mediawiki-draft-buffer (buffer-name))
  1622. (kill-buffer (current-buffer))
  1623. (jump-to-register mediawiki-draft-register)))))
  1624. ;;;###autoload
  1625. (defun mediawiki-draft-buffer ()
  1626. "Mediawiki-draft-buffer sends the contents of the current (temporary)
  1627. buffer to the mediawiki-draft-buffer, see the variable
  1628. mediawiki-draft-data-file."
  1629. (interactive)
  1630. (mediawiki-draft-region (point-min) (point-max)))
  1631. (defun mediawiki-draft-clipboard ()
  1632. "Mediawiki-Draft the contents of the current clipboard.
  1633. Most useful for mediawiki-drafting things from Netscape or other X Windows
  1634. application."
  1635. (interactive)
  1636. (with-temp-buffer
  1637. (insert (x-get-clipboard))
  1638. (run-hook-with-args-until-success 'mediawiki-draft-handler-functions)))
  1639. (defun mediawiki-draft-view-draft ()
  1640. "Simple shortcut to visit the file, which contains the wikipedia drafts."
  1641. (interactive)
  1642. (find-file mediawiki-draft-data-file))
  1643. (defun mediawiki-mark-section ()
  1644. "Set mark at end of current logical section, and point at top."
  1645. (interactive)
  1646. (re-search-forward (concat "== " "[a-z,A-z \t]*" " =="))
  1647. (re-search-backward "^")
  1648. (set-mark (point))
  1649. (re-search-backward (concat "== " "[a-z,A-z \t]*" " "))
  1650. (when (fboundp 'zmacs-activate-region)
  1651. (zmacs-activate-region)))
  1652. (defun mediawiki-mark-signature ()
  1653. "Set mark at end of current logical section, and point at top."
  1654. (interactive)
  1655. (re-search-forward "]]") ;;[[ ]]
  1656. (re-search-backward "^")
  1657. (set-mark (point))
  1658. (re-search-backward "[[")
  1659. (when (fboundp 'zmacs-activate-region)
  1660. (zmacs-activate-region)))
  1661. (defun mediawiki-draft-copy-page-to-register ()
  1662. "Copy a page via the mediawiki-draft-register."
  1663. (interactive)
  1664. (save-excursion
  1665. (narrow-to-page nil)
  1666. (copy-to-register mediawiki-draft-page (point-min) (point-max) nil)
  1667. (message "draft page copied to wikipedia register mediawiki-draft-page.")
  1668. (widen)))
  1669. (defun mediawiki-draft-yank-page-to-register ()
  1670. "Insert a page via the mediawiki-draft-register."
  1671. (interactive)
  1672. (insert-register mediawiki-draft-page nil))
  1673. (defun mediawiki-draft-send (target-buffer)
  1674. "Copy the current page from the mediawiki draft file to
  1675. TARGET-BUFFER. Check the variable mediawiki-draft-send-archive.
  1676. If it is t, then additionally the text will be archived in the
  1677. draft.wiki file. Check longlines-mode, it might be better if it
  1678. is set off."
  1679. (interactive "bTarget buffer: ")
  1680. (mediawiki-draft-copy-page-to-register)
  1681. (switch-to-buffer target-buffer)
  1682. (end-of-line 1)
  1683. (newline 1)
  1684. (mediawiki-draft-yank-page-to-register)
  1685. (message "The page has been sent (copied) to the mozex file!")
  1686. (switch-to-buffer "*MW-Draft*")
  1687. (when mediawiki-draft-send-archive
  1688. (let ((text (buffer-string)))
  1689. (with-temp-buffer
  1690. (insert (concat "\n\n" mediawiki-draft-leader-text)
  1691. (insert-register mediawiki-draft-reply-register 1)
  1692. (insert (concat " " (current-time-string) " "
  1693. mediawiki-draft-leader-text "\n\n\f\n\n"
  1694. text "\n\f\n"))
  1695. (if (not (bolp))
  1696. (insert "\n\n"))
  1697. (if (find-buffer-visiting mediawiki-draft-data-file)
  1698. (let ((mediawiki-draft-text (buffer-string)))
  1699. (set-buffer (get-file-buffer mediawiki-draft-data-file))
  1700. (save-excursion
  1701. (goto-char (point-max))
  1702. (insert (concat "\n" mediawiki-draft-text "\n"))
  1703. (save-buffer)))
  1704. (append-to-file (point-min) (point-max)
  1705. mediawiki-draft-data-file)))))
  1706. (when (equal mediawiki-draft-buffer (buffer-name))
  1707. (kill-buffer (current-buffer)))
  1708. (switch-to-buffer target-buffer)))
  1709. (define-derived-mode mediawiki-draft-mode text-mode "MW-Draft"
  1710. "Major mode for output from \\[mediawiki-draft].
  1711. \\<mediawiki-draft-mode-map> This buffer is used to collect data that
  1712. you want mediawiki-draft. Just hit \\[mediawiki-draft-region] when
  1713. you're done entering, and it will go ahead and file the data for
  1714. latter retrieval, and possible indexing.
  1715. \\{mediawiki-draft-mode-map}"
  1716. (kill-all-local-variables)
  1717. (indented-text-mode)
  1718. (define-key mediawiki-draft-mode-map "\C-c\C-k" 'mediawiki-draft-buffer)
  1719. (define-key mediawiki-draft-mode-map "\C-c\C-d" 'mediawiki-draft-buffer))
  1720. (define-derived-mode mediawiki-mode text-mode "MW"
  1721. "Major mode for editing articles written in the markup language
  1722. used by Mediawiki.
  1723. Wikipedia articles are usually unfilled: newline characters are not
  1724. used for breaking paragraphs into lines. Unfortunately, Emacs does not
  1725. handle word wrapping yet. As a workaround, wikipedia-mode turns on
  1726. longlines-mode automatically. In case something goes wrong, the
  1727. following commands may come in handy:
  1728. \\[mediawiki-fill-article] fills the buffer.
  1729. \\[mediawiki-unfill-article] unfills the buffer.
  1730. Be warned that function can be dead slow, better use mediawiki-unfill-paragraph-or-region.
  1731. \\[mediawiki-unfill-paragraph-or-region] unfills the paragraph
  1732. \\[mediawiki-unfill-paragraph-simple] doehe same but simpler.
  1733. The following commands put in markup structures.
  1734. \\[mediawiki-insert-strong-emphasis] inserts italics
  1735. \\[mediawiki-insert-bold] inserts bold text
  1736. \\[mediawiki-insert-italics] italics
  1737. \\[mediawiki-insert-header] header
  1738. \\[mediawiki-insert-link] inserts a link
  1739. The following commands are also defined:
  1740. \\[mediawiki-insert-user] inserts user name
  1741. \\[mediawiki-insert-signature] inserts ~~~~
  1742. \\[mediawiki-insert-enumerate] inserts enumerate type structures
  1743. \\[mediawiki-insert-itemize] inserts itemize type structures
  1744. \\[mediawiki-insert-hline] inserts a hline
  1745. The draft functionality
  1746. \\[mediawiki-draft]
  1747. \\[mediawiki-draft-region]
  1748. \\[mediawiki-draft-view-draft]
  1749. \\[mediawiki-draft-page]
  1750. \\[mediawiki-draft-buffer]
  1751. Replying and sending functionality
  1752. \\[mediawiki-reply-at-point-simple]
  1753. \\[mediawiki-draft-reply]
  1754. The register functionality
  1755. \\[mediawiki-copy-page-to-register]
  1756. \\[defun mediawiki-insert-page-to-register]
  1757. Some simple editing commands.
  1758. \\[mediawiki-enhance-indent]
  1759. \\[mediawiki-yank-prefix]
  1760. \\[mediawiki-unfill-paragraph-or-region]
  1761. \\[mediawiki-terminate-paragraph] starts a new list item or paragraph in a context-aware manner.
  1762. \\[mediawiki-next-header] moves to the next (sub)section header.
  1763. \\[mediawiki-prev-header] moves to the previous (sub)section header."
  1764. (make-local-variable 'change-major-mode-hook)
  1765. (make-local-variable 'mediawiki-edittoken)
  1766. (make-local-variable 'mediawiki-starttimestamp)
  1767. (make-local-variable 'mediawiki-basetimestamp)
  1768. (make-local-variable 'mediawiki-site)
  1769. (make-local-variable 'mediawiki-edit-form-vars)
  1770. (make-local-variable 'mediawiki-page-title)
  1771. (set (make-local-variable 'adaptive-fill-regexp) "[ ]*")
  1772. (set (make-local-variable 'comment-start-skip) "\\(?:<!\\)?-- *")
  1773. (set (make-local-variable 'comment-end-skip) " *--\\([ \n]*>\\)?")
  1774. (set (make-local-variable 'comment-start) "<!-- ")
  1775. (set (make-local-variable 'comment-end) " -->")
  1776. (set (make-local-variable 'paragraph-start)
  1777. "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")
  1778. (set (make-local-variable 'sentence-end-double-space) nil)
  1779. (set (make-local-variable 'font-lock-multiline) t)
  1780. (set (make-local-variable 'font-lock-defaults)
  1781. '(mediawiki-font-lock-keywords t nil nil nil))
  1782. (set (make-local-variable 'fill-nobreak-predicate)
  1783. 'mediawiki-link-fill-nobreak-p)
  1784. (set (make-local-variable 'auto-fill-inhibit-regexp) "^[ *#:|;]")
  1785. ;; Support for outline-minor-mode. No key conflicts, so we'll use
  1786. ;; the normal outline-mode prefix.
  1787. (set (make-local-variable 'outline-regexp) "==+")
  1788. (when (boundp 'outline-minor-mode-prefix)
  1789. (set (make-local-variable 'outline-minor-mode-prefix) "\C-c\C-o"))
  1790. ; (set (make-local-variable 'outline-regexp) "=+")
  1791. ; (set (make-local-variable 'outline-regexp) ":")
  1792. ;; Turn on the Imenu automatically.
  1793. (when menu-bar-mode
  1794. (set (make-local-variable 'imenu-generic-expression)
  1795. mediawiki-imenu-generic-expression)
  1796. (imenu-add-to-menubar "Contents"))
  1797. (let ((map (make-sparse-keymap "mediawiki")))
  1798. (define-key mediawiki-mode-map [menu-bar mediawiki]
  1799. (cons "MediaWiki" map))
  1800. (define-key map [unfill-article]
  1801. '("Unfill article" . mediawiki-unfill-article))
  1802. (define-key map [fill-article]
  1803. '("Fill article" . mediawiki-fill-article))
  1804. (define-key map [separator-fill] '("--"))
  1805. (define-key map [next-header]
  1806. '("Next header" . mediawiki-next-header))
  1807. (define-key map [prev-header]
  1808. '("Previous header" . mediawiki-prev-header))
  1809. (define-key map [separator-header] '("--"))
  1810. (define-key map [outline]
  1811. '("Toggle Outline Mode..." . outline-minor-mode))
  1812. (modify-syntax-entry ?< "(>" mediawiki-mode-syntax-table)
  1813. (modify-syntax-entry ?> ")<" mediawiki-mode-syntax-table)
  1814. (define-key mediawiki-mode-map "\M-n" 'mediawiki-next-header)
  1815. (define-key mediawiki-mode-map "\C-c\C-n" 'mediawiki-next-long-line)
  1816. (define-key mediawiki-mode-map "\M-p" 'mediawiki-prev-header)
  1817. (define-key mediawiki-mode-map [(meta down)] 'mediawiki-next-header)
  1818. (define-key mediawiki-mode-map [(meta up)] 'mediawiki-prev-header)
  1819. (define-key mediawiki-mode-map "\C-j" 'mediawiki-terminate-paragraph)
  1820. (define-key mediawiki-mode-map "\C-c\C-q" 'mediawiki-unfill-article)
  1821. (define-key mediawiki-mode-map "\C-c\M-q" 'mediawiki-fill-article)
  1822. (define-key mediawiki-mode-map "\C-c\M-u" 'mediawiki-unfill-paragraph-or-region)
  1823. (define-key mediawiki-mode-map "\C-c\C-u" 'mediawiki-unfill-paragraph-simple)
  1824. (define-key mediawiki-mode-map "\C-c\C-f\C-s" 'mediawiki-insert-strong-emphasis)
  1825. (define-key mediawiki-mode-map "\C-c\C-f\C-b" 'mediawiki-insert-bold)
  1826. (define-key mediawiki-mode-map "\C-c\C-f\C-i" 'mediawiki-insert-italics)
  1827. (define-key mediawiki-mode-map "\C-c\C-f\C-e" 'mediawiki-insert-header)
  1828. (define-key mediawiki-mode-map "\C-c\C-f\C-l" 'mediawiki-insert-link)
  1829. (define-key mediawiki-mode-map "\C-c\C-f\C-u" 'mediawiki-insert-user)
  1830. (define-key mediawiki-mode-map "\C-c\C-f\C-q" 'mediawiki-insert-quotation)
  1831. (define-key mediawiki-mode-map "\C-c\C-f\C-v" 'mediawiki-insert-bible-verse-template)
  1832. (define-key mediawiki-mode-map "\C-c\C-w" 'mediawiki-insert-signature)
  1833. (define-key mediawiki-mode-map "\C-c\C-l" 'mediawiki-insert-hline)
  1834. (define-key mediawiki-mode-map [(meta f7)] 'mediawiki-draft)
  1835. (define-key mediawiki-mode-map [(meta f8)] 'mediawiki-reply-at-point-simple)
  1836. (define-key mediawiki-mode-map [(meta f9)] 'mediawiki-draft-view-draft)
  1837. (define-key mediawiki-mode-map "\C-c\C-r" 'mediawiki-reply-at-point-simple)
  1838. (define-key mediawiki-mode-map "\C-cr" 'mediawiki-draft-region)
  1839. (define-key mediawiki-mode-map [(meta r)] 'mediawiki-draft-reply)
  1840. (define-key mediawiki-mode-map "\C-c\C-m" 'mediawiki-draft)
  1841. (define-key mediawiki-mode-map "\C-c\C-b" 'mediawiki-draft-region)
  1842. (define-key mediawiki-mode-map "\C-c\C-d" 'mediawiki-draft-buffer)
  1843. (define-key mediawiki-mode-map "\C-c\C-k" 'mediawiki-draft-buffer)
  1844. (define-key mediawiki-mode-map "\C-c\C-p" 'mediawiki-draft-copy-page-to-register)
  1845. (define-key mediawiki-mode-map "\C-c\C-c" 'mediawiki-draft-send)
  1846. (define-key mediawiki-mode-map "\C-c\C-s" 'mediawiki-draft-yank-page-to-register)
  1847. (define-key mediawiki-mode-map [(control meta prior)] 'mediawiki-enhance-indent)
  1848. (define-key mediawiki-mode-map [(control meta next)] 'mediawiki-yank-prefix)
  1849. (define-key mediawiki-mode-map [(meta return)] 'mediawiki-insert-enumerate)
  1850. (define-key mediawiki-mode-map [(meta control return)] 'mediawiki-insert-enumerate-nonewline)
  1851. ;; private setting
  1852. (define-key mediawiki-mode-map [(shift return)] 'newline-and-indent)
  1853. (define-key mediawiki-mode-map "\C-\\" 'mediawiki-insert-itemize)
  1854. (define-key mediawiki-mode-map [(control return)] 'mediawiki-insert-itemize)
  1855. (define-key mediawiki-mode-map "\C-ca" 'auto-capitalize-mode)
  1856. ; (define-key mediawiki-mode-map "\C-ci" 'set-input-method)
  1857. ; (define-key mediawiki-mode-map "\C-ct" 'toggle-input-method)
  1858. (define-key mediawiki-mode-map [(backtab)] 'mediawiki-goto-prev-link)
  1859. (define-key mediawiki-mode-map [(tab)] 'mediawiki-goto-next-link)
  1860. (define-key mediawiki-mode-map "\M-g" 'mediawiki-reload)
  1861. (define-key mediawiki-mode-map "\C-x\C-s" 'mediawiki-save)
  1862. (define-key mediawiki-mode-map "\C-c\C-c" 'mediawiki-save-and-bury)
  1863. (define-key mediawiki-mode-map "\C-x\C-w" 'mediawiki-save-as)
  1864. (define-key mediawiki-mode-map "\C-c\C-o" 'mediawiki-open)
  1865. (define-key mediawiki-mode-map "\M-p"
  1866. 'mediawiki-goto-previous-page)
  1867. (define-key mediawiki-mode-map "\M-n" 'mediawiki-goto-next-page)
  1868. (define-key mediawiki-mode-map [(control return)]
  1869. 'mediawiki-open-page-at-point)))
  1870. ;; (defvar mw-pagelist-mode-map
  1871. ;; (let ((map (make-sparse-keymap)))
  1872. ;; (suppress-keymap map)
  1873. ;; (define-key map [(return)] 'mw-pl-goto-page-at-point)
  1874. ;; (define-key map "n" 'mw-pl-page-down)
  1875. ;; (define-key map "C-v" 'mw-pl-page-down)
  1876. ;; (define-key map [(next)] 'mw-pl-page-down)
  1877. ;; (define-key map "p" 'mw-pl-page-up)
  1878. ;; (define-key map "M-v" 'mw-pl-page-up)
  1879. ;; (define-key map [(prior)] 'mw-pl-page-up)))
  1880. ;; (define-derived-mode mw-pagelist-mode special-mode "MW-PageList")
  1881. (provide 'mediawiki)
  1882. ;; Local Variables:
  1883. ;; time-stamp-pattern: "20/^;; Last Modified: <%%>$"
  1884. ;; End:
  1885. ;;; mediawiki.el ends here