diff --git a/contrib/oddmuse-curl.el b/contrib/oddmuse-curl.el index 2bc959b3..a4710c41 100644 --- a/contrib/oddmuse-curl.el +++ b/contrib/oddmuse-curl.el @@ -23,11 +23,11 @@ ;;; Commentary: ;; -;; A simple mode to edit pages on Oddmuse wikis using Emacs and the command-line -;; HTTP client `curl'. +;; A mode to edit pages on Oddmuse wikis using Emacs and the +;; command-line HTTP client `curl'. ;; -;; Since text formatting rules depend on the wiki you're writing for, the -;; font-locking can only be an approximation. +;; Since text formatting rules depend on the wiki you're writing for, +;; the font-locking can only be an approximation. ;; ;; Put this file in a directory on your `load-path' and ;; add this to your init file: @@ -107,63 +107,33 @@ USERNAME, your optional username to provide. It defaults to (string :tag "specify")))) :group 'oddmuse) -(defcustom oddmuse-username user-full-name - "Username to use when posting. -Setting a username is the polite thing to do." - :type '(string) - :group 'oddmuse) - -(defcustom oddmuse-password "" - "Password to use when posting. -You only need this if you want to edit locked pages and you -know an administrator password." - :type '(string) - :group 'oddmuse) - -(defcustom oddmuse-use-always-minor nil - "When t, set all the minor mode bit to all editions. -This can be changed for each edition using `oddmuse-toggle-minor'." - :type '(boolean) - :group 'oddmuse) - (defvar oddmuse-get-command "curl --silent %w --form action=browse --form raw=2 --form id=%t" "Command to use for publishing pages. It must print the page to stdout. -%w URL of the wiki as provided by `oddmuse-wikis' -%t URL encoded pagename, eg. HowTo, How_To, or How%20To - -See `oddmuse-format-command' for other options.") +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-history-command "curl --silent %w --form action=history --form raw=1 --form id=%t" "Command to use for reading the history of a page. It must print the history to stdout. -%w URL of the wiki as provided by `oddmuse-wikis' -%t URL encoded pagename, eg. HowTo, How_To, or How%20To - -See `oddmuse-format-command' for other options.") +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-rc-command "curl --silent %w --form action=rc --form raw=1" "Command to use for Recent Changes. It must print the RSS 3.0 text format to stdout. -%w URL of the wiki as provided by `oddmuse-wikis' - -See `oddmuse-format-command' for other options.") +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-search-command "curl --silent %w --form search='%r' --form raw=1" "Command to use for Recent Changes. It must print the RSS 3.0 text format to stdout. -%w URL of the wiki as provided by `oddmuse-wikis' -%r Regular expression to search for - -See `oddmuse-format-command' for other options.") +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-post-command (concat "curl --silent --write-out '%{http_code}'" @@ -180,16 +150,7 @@ See `oddmuse-format-command' for other options.") It must accept the page on stdin and print the HTTP status code on stdout. -%t pagename -%s summary -%u username -%p password -%q question-asker cookie -%m minor edit -%o oldtime, a timestamp provided by Oddmuse -%w URL of the wiki as provided by `oddmuse-wikis' - -See `oddmuse-format-command' for other options.") +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-preview-command (concat "curl --silent" @@ -205,20 +166,46 @@ See `oddmuse-format-command' for other options.") "Command to use for previewing pages. It must accept the page on stdin and print the HTML on stdout. -%t pagename -%u username -%p password -%q question-asker cookie -%m minor edit -%o oldtime, a timestamp provided by Oddmuse -%w URL of the wiki as provided by `oddmuse-wikis' +See `oddmuse-format-command' for the formatting options.") -See `oddmuse-format-command' for other options.") +(defvar oddmuse-get-index-command + "curl --silent %w --form action=index --form raw=1" + "Command to use for publishing index pages. +It must print the page to stdout. + +See `oddmuse-format-command' for the formatting options.") + +(defvar oddmuse-get-history-command + "curl --silent %w --form action=history --form id=%t --form raw=1" + "Command to use to get the history of a page. +It must print the page to stdout. + +See `oddmuse-format-command' for the formatting options.") (defvar oddmuse-link-pattern "\\<[[:upper:]]+[[:lower:]]+\\([[:upper:]]+[[:lower:]]*\\)+\\>" "The pattern used for finding WikiName.") +(defcustom oddmuse-username user-full-name + "Username to use when posting. +Setting a username is the polite thing to do. You can override +this in `oddmuse-wikis'." + :type '(string) + :group 'oddmuse) + +(defcustom oddmuse-password "" + "Password to use when posting. +You only need this if you want to edit locked pages and you +know an administrator password." + :type '(string) + :group 'oddmuse) + +(defcustom oddmuse-use-always-minor nil + "If set, all edits will be minor edits by default. +This is the default for `oddmuse-minor'." + :type '(boolean) + :group 'oddmuse) + (defvar oddmuse-wiki nil "The current wiki. Must match a key from `oddmuse-wikis'.") @@ -227,16 +214,8 @@ Must match a key from `oddmuse-wikis'.") "Pagename of the current buffer.") (defvar oddmuse-pages-hash (make-hash-table :test 'equal) - "The wiki-name / pages pairs.") - -(defvar oddmuse-index-get-command - "curl --silent %w --form action=index --form raw=1" - "Command to use for publishing index pages. -It must print the page to stdout. - -%w URL of the wiki as provided by `oddmuse-wikis' - -See `oddmuse-format-command' for other options.") + "The wiki-name / pages pairs. +Refresh using \\[oddmuse-reload].") (defvar oddmuse-minor nil "Is this edit a minor change?") @@ -245,6 +224,123 @@ See `oddmuse-format-command' for other options.") "The timestamp of the current page's ancestor. This is used by Oddmuse to merge changes.") +(defvar oddmuse-revisions nil + "An alist to store the current revision we have per page. +An alist wikis containing an alist of pages and revisions. +Example: + + ((\"Alex\" ((\"Contact\" . \"58\"))))") + +(defun oddmuse-revision-put (wiki page rev) + "Store REV for WIKI and PAGE in `oddmuse-revisions'." + (let ((w (assoc wiki oddmuse-revisions))) + (unless w + (setq w (list wiki) + oddmuse-revisions (cons w oddmuse-revisions))) + (let ((p (assoc page w))) + (unless p + (setq p (list page)) + (setcdr w (cons p (cdr w)))) + (setcdr p rev)))) + +(defun oddmuse-revision-get (wiki page) + "Get revision for WIKI and PAGE in `oddmuse-revisions'." + (let ((w (assoc wiki oddmuse-revisions))) + (when w + (cdr (assoc page w))))) + +(defun oddmuse-url (wiki pagename) + "Get the URL of oddmuse wiki." + (condition-case v + (concat (or (cadr (assoc wiki oddmuse-wikis)) (error)) "/" + (url-hexify-string pagename)) + (error nil))) + +(defun oddmuse-read-pagename (wiki &optional require default) + "Read a pagename of WIKI with completion. +Optional arguments REQUIRE and DEFAULT are passed on to `completing-read'. +Typically you would use t and a `oddmuse-page-name', if that makes sense." + (let ((completion-ignore-case t)) + (completing-read (if default + (concat "Pagename [" default "]: ") + "Pagename: ") + (oddmuse-make-completion-table wiki) + nil require nil nil default))) + +(defun oddmuse-pagename (&optional arg) + "Return the wiki and pagename the user wants to edit or follow. +This cannot be the current pagename! If given the optional +argument ARG, read it from the minibuffer. Otherwise, try to get +a pagename at point. If this does not yield a pagename, ask the +user for a page. Also, if no wiki has been give, ask for that, +too. The pagename returned does not necessarily exist! + +Use this function when following links in regular wiki buffers, +in Recent Changes, History Buffers, and also in text files and +the like." + (let* ((wiki (or (and (not arg) oddmuse-wiki) + (completing-read "Wiki: " oddmuse-wikis nil t))) + (pagename (or (and arg (oddmuse-read-pagename wiki)) + (oddmuse-pagename-at-point) + (oddmuse-read-pagename wiki nil (word-at-point))))) + (list wiki pagename))) + +(defun oddmuse-current-free-link-contents () + "The page name in a free link at point. +This returns \"foo\" for [[foo]] and [[foo|bar]]." + (save-excursion + (let* ((pos (point)) + (start (when (search-backward "[[" nil t) + (match-end 0))) + (end (when (search-forward "]]" (line-end-position) t) + (match-beginning 0)))) + (and start end (>= end pos) + (replace-regexp-in-string + " " "_" + (car (split-string + (buffer-substring-no-properties start end) "|"))))))) + +(defun oddmuse-pagename-at-point () + "Page name at point. +It's either a [[free link]] or a WikiWord based on +`oddmuse-current-free-link-contents' or `oddmuse-wikiname-p'." + (let ((pagename (word-at-point))) + (or (oddmuse-current-free-link-contents) + (oddmuse-wikiname-p pagename)))) + +(defun oddmuse-wikiname-p (pagename) + "Whether PAGENAME is WikiName or not." + (when pagename + (let (case-fold-search) + (when (string-match (concat "^" oddmuse-link-pattern "$") pagename) + pagename)))) + +(defun oddmuse-make-completion-table (wiki) + "Create pagename completion table for WIKI. +If available, return precomputed one." + (or (gethash wiki oddmuse-pages-hash) + (oddmuse-reload wiki))) + +(defun oddmuse-reload (&optional wiki-arg) + "Really fetch the list of pagenames from WIKI. +This command is used to reflect new pages to `oddmuse-pages-hash'." + (interactive) + (let* ((wiki (or wiki-arg + (completing-read "Wiki: " oddmuse-wikis nil t oddmuse-wiki))) + (url (cadr (assoc wiki oddmuse-wikis))) + (command (oddmuse-format-command oddmuse-get-index-command)) + table) + (message "Getting index of all pages...") + (prog1 + (setq table (split-string (shell-command-to-string command))) + (puthash wiki table oddmuse-pages-hash) + (message "Getting index of all pages...done")))) + +;; (oddmuse-wikiname-p nil) +;; (oddmuse-wikiname-p "WikiName") +;; (oddmuse-wikiname-p "not-wikiname") +;; (oddmuse-wikiname-p "notWikiName") + (defun oddmuse-mode-initialize () (add-to-list 'auto-mode-alist `(,(expand-file-name oddmuse-directory) . oddmuse-mode))) @@ -491,6 +587,13 @@ both the character before and after point have it, don't break." (add-to-list 'minor-mode-alist '(oddmuse-minor " [MINOR]")) +;;;###autoload +(defun oddmuse-insert-pagename (pagename) + "Insert a PAGENAME of current wiki with completion. +Replaces _ with spaces again." + (interactive (list (oddmuse-read-pagename oddmuse-wiki))) + (insert (replace-regexp-in-string "_" " " pagename))) + (defun oddmuse-format-command (command) "Format COMMAND, replacing placeholders with variables. Best used with `with-oddmuse-wiki-and-pagename' and similar @@ -523,9 +626,48 @@ macros. (when (and (eq sym 'summary) (string-match "'" value)) ;; form summary='A quote is '"'"' this!' - (setq value (replace-regexp-in-string "'" "'\"'\"'" value t t)))))) + (setq value (replace-regexp-in-string "'" "'\"'\"'" value t t))))))) (replace-regexp-in-string "&" "%26" command t t)) +(defun oddmuse-run (mesg command &optional buf send-buffer expected-code) + "Print MESG and run COMMAND on the current buffer. +MESG should be appropriate for the following uses: + \"MESG...\" + \"MESG...done\" + \"MESG failed: REASON\" +Save outpout in BUF and report an appropriate error. +If BUF is not provided, use the current buffer. + +SEND-BUFFER indicates whether the commands needs the content of +the current buffer on STDIN---such as when posting---or whether +it just runs by itself such as when loading a page. + +If SEND-BUFFER is not nil, the command output is compared to +EXPECTED-CODE. The command is supposed to print the HTTP status +code on stdout, so usually we want to provide either 302 or 200 +as EXPECTED-CODE." + (setq buf (or buf (current-buffer))) + (let ((max-mini-window-height 1)) + (message "%s using %s..." mesg command) + (when (numberp expected-code) + (setq expected-code (number-to-string expected-code))) + ;; If SEND-BUFFER, the resulting HTTP CODE is found in BUF, so check + ;; that, too. + (if (and (= 0 (if send-buffer + (shell-command-send-buffer (point-min) (point-max) command buf) + (shell-command command buf))) + (or (not send-buffer) + (not expected-code) + (string= expected-code + (with-current-buffer buf + (buffer-string))))) + (message "%s...done" mesg) + (let ((err "Unknown error")) + (with-current-buffer buf + (when (re-search-forward "

\\(.*?\\)\\.?

" nil t) + (setq err (match-string 1)))) + (error "Error %s: %s" mesg err))))) + (defmacro with-oddmuse-file (file &rest body) "Bind some variables needed for `oddmuse-run' based on FILE. These are: `oddmuse-wiki' and `oddmuse-page-name', plus the @@ -597,39 +739,6 @@ Use a prefix argument to force a reload of the page." (goto-address) (view-mode))))) -(defvar oddmuse-revisions nil - "An alist to store the current revision we have per page. -An alist wikis containing an alist of pages and revisions. -Example: - - ((\"Alex\" ((\"Contact\" . \"58\"))))") - -(defun oddmuse-revision-put (wiki page rev) - "Store REV for WIKI and PAGE in `oddmuse-revisions'." - (let ((w (assoc wiki oddmuse-revisions))) - (unless w - (setq w (list wiki) - oddmuse-revisions (cons w oddmuse-revisions))) - (let ((p (assoc page w))) - (unless p - (setq p (list page)) - (setcdr w (cons p (cdr w)))) - (setcdr p rev)))) - -(defun oddmuse-revision-get (wiki page) - "Get revision for WIKI and PAGE in `oddmuse-revisions'." - (let ((w (assoc wiki oddmuse-revisions))) - (when w - (cdr (assoc page w))))) - -(defvar oddmuse-get-history-command - "curl --silent %w --form action=history --form id=%t --form raw=1" - "Command to use to get the history of a page. -It must print the page to stdout. - -%w URL of the wiki as provided by `oddmuse-wikis' -%t Page title as provided by `oddmuse-page-name'") - (defun oddmuse-get-latest-revision () "Return the latest revision as a string, eg. \"5\". Requires all the variables to be bound for @@ -699,98 +808,6 @@ and call `oddmuse-edit' on it." (interactive (oddmuse-pagename)) (oddmuse-edit wiki pagename)) -(defun oddmuse-pagename (&optional arg) - "Return the wiki and pagename the user wants to edit or follow. -This cannot be the current pagename! If given the optional -argument ARG, read it from the minibuffer. Otherwise, try to get -a pagename at point. If this does not yield a pagename, ask the -user for a page. Also, if no wiki has been give, ask for that, -too. The pagename returned does not necessarily exist! - -Use this function when following links in regular wiki buffers, -in Recent Changes, History Buffers, and also in text files and -the like." - (let* ((wiki (or (and (not arg) oddmuse-wiki) - (completing-read "Wiki: " oddmuse-wikis nil t))) - (pagename (or (and arg (oddmuse-read-pagename wiki)) - (oddmuse-pagename-at-point) - (oddmuse-read-pagename wiki nil (word-at-point))))) - (list wiki pagename))) - -(defun oddmuse-pagename-at-point () - "Page name at point. -It's either a [[free link]] or a WikiWord based on -`oddmuse-current-free-link-contents' or `oddmuse-wikiname-p'." - (let ((pagename (word-at-point))) - (or (oddmuse-current-free-link-contents) - (oddmuse-wikiname-p pagename)))) - -(defun oddmuse-current-free-link-contents () - "The page name in a free link at point. -This returns \"foo\" for [[foo]] and [[foo|bar]]." - (save-excursion - (let* ((pos (point)) - (start (when (search-backward "[[" nil t) - (match-end 0))) - (end (when (search-forward "]]" (line-end-position) t) - (match-beginning 0)))) - (and start end (>= end pos) - (replace-regexp-in-string - " " "_" - (car (split-string - (buffer-substring-no-properties start end) "|"))))))) - -(defun oddmuse-wikiname-p (pagename) - "Whether PAGENAME is WikiName or not." - (when pagename - (let (case-fold-search) - (when (string-match (concat "^" oddmuse-link-pattern "$") pagename) - pagename)))) - -;; (oddmuse-wikiname-p nil) -;; (oddmuse-wikiname-p "WikiName") -;; (oddmuse-wikiname-p "not-wikiname") -;; (oddmuse-wikiname-p "notWikiName") - -(defun oddmuse-run (mesg command &optional buf on-region expected-code) - "Print MESG and run COMMAND on the current buffer. -MESG should be appropriate for the following uses: - \"MESG...\" - \"MESG...done\" - \"MESG failed: REASON\" -Save outpout in BUF and report an appropriate error. -If BUF is not provided, use the current buffer. - -ON-REGION indicates whether the commands runs on the region -such as when posting, or whether it just runs by itself such -as when loading a page. - -If ON-REGION is not nil, the command output is compared to -EXPECTED-CODE. The command is supposed to print the HTTP status -code on stdout, so usually we want to provide either 302 or 200 -as EXPECTED-CODE." - (setq buf (or buf (current-buffer))) - (let ((max-mini-window-height 1)) - (message "%s using %s..." mesg command) - (when (numberp expected-code) - (setq expected-code (number-to-string expected-code))) - ;; If ON-REGION, the resulting HTTP CODE is found in BUF, so check - ;; that, too. - (if (and (= 0 (if on-region - (shell-command-on-region (point-min) (point-max) command buf) - (shell-command command buf))) - (or (not on-region) - (not expected-code) - (string= expected-code - (with-current-buffer buf - (buffer-string))))) - (message "%s...done" mesg) - (let ((err "Unknown error")) - (with-current-buffer buf - (when (re-search-forward "

\\(.*?\\)\\.?

" nil t) - (setq err (match-string 1)))) - (error "Error %s: %s" mesg err))))) - ;;;###autoload (defun oddmuse-post (summary) "Post the current buffer to the current wiki. @@ -803,6 +820,9 @@ The current wiki is taken from `oddmuse-wiki'." (when (not oddmuse-page-name) (set (make-local-variable 'oddmuse-page-name) (read-from-minibuffer "Pagename: " (buffer-name)))) + (let ((list (gethash oddmuse-wiki oddmuse-pages-hash))) + (when (not (member oddmuse-page-name list)) + (puthash oddmuse-wiki (cons oddmuse-page-name list) oddmuse-pages-hash))) (let* ((list (assoc oddmuse-wiki oddmuse-wikis)) (url (nth 1 list)) (oddmuse-minor (if oddmuse-minor "on" "off")) @@ -874,40 +894,6 @@ node as returned by `libxml-parse-html-region' or (when result (return result))))))) -(defun oddmuse-make-completion-table (wiki) - "Create pagename completion table for WIKI. -If available, return precomputed one." - (or (gethash wiki oddmuse-pages-hash) - (oddmuse-compute-pagename-completion-table wiki))) - -(defalias 'oddmuse-reload 'oddmuse-compute-pagename-completion-table) - -(defun oddmuse-compute-pagename-completion-table (&optional wiki-arg) - "Really fetch the list of pagenames from WIKI. -This command is used to reflect new pages to `oddmuse-pages-hash'." - (interactive) - (let* ((wiki (or wiki-arg - (completing-read "Wiki: " oddmuse-wikis nil t oddmuse-wiki))) - (url (cadr (assoc wiki oddmuse-wikis))) - (command (oddmuse-format-command oddmuse-index-get-command)) - table) - (message "Getting index of all pages...") - (prog1 - (setq table (split-string (shell-command-to-string command))) - (puthash wiki table oddmuse-pages-hash) - (message "Getting index of all pages...done")))) - -(defun oddmuse-read-pagename (wiki &optional require default) - "Read a pagename of WIKI with completion. -Optional arguments REQUIRE and DEFAULT are passed on to `completing-read'. -Typically you would use t and a `oddmuse-page-name', if that makes sense." - (let ((completion-ignore-case t)) - (completing-read (if default - (concat "Pagename [" default "]: ") - "Pagename: ") - (oddmuse-make-completion-table wiki) - nil require nil nil default))) - ;;;###autoload (defun oddmuse-search (regexp) "Search the wiki." @@ -990,13 +976,6 @@ With universal argument, reload." (let ((current-prefix-arg 4)) (oddmuse-edit oddmuse-wiki oddmuse-page-name)))) -;;;###autoload -(defun oddmuse-insert-pagename (pagename) - "Insert a PAGENAME of current wiki with completion. -Replaces _ with spaces again." - (interactive (list (oddmuse-read-pagename oddmuse-wiki))) - (insert (replace-regexp-in-string "_" " " pagename))) - ;;;###autoload (defun emacswiki-post (&optional pagename summary) "Post the current buffer to the EmacsWiki. @@ -1015,13 +994,6 @@ This command is intended to post current EmacsLisp program easily." (summary (or summary (read-string "Summary: ")))) (oddmuse-post summary))) -(defun oddmuse-url (wiki pagename) - "Get the URL of oddmuse wiki." - (condition-case v - (concat (or (cadr (assoc wiki oddmuse-wikis)) (error)) "/" - (url-hexify-string pagename)) - (error nil))) - ;;;###autoload (defun oddmuse-browse-page (wiki pagename) "Ask a WWW browser to load an Oddmuse page.