From 82b8ca280905ea284730f228ae082c42c348e818 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Thu, 17 Mar 2011 11:36:56 +0100 Subject: Big emacs cleanup, must be lighter --- emacs.d/elisp/muse/muse.el | 881 --------------------------------------------- 1 file changed, 881 deletions(-) delete mode 100644 emacs.d/elisp/muse/muse.el (limited to 'emacs.d/elisp/muse/muse.el') diff --git a/emacs.d/elisp/muse/muse.el b/emacs.d/elisp/muse/muse.el deleted file mode 100644 index 4d4a0b9..0000000 --- a/emacs.d/elisp/muse/muse.el +++ /dev/null @@ -1,881 +0,0 @@ -;;; muse.el --- an authoring and publishing tool for Emacs - -;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 -;; Free Software Foundation, Inc. - -;; Emacs Lisp Archive Entry -;; Filename: muse.el -;; Version: 3.20 -;; Date: Sun 31 Jan-2010 -;; Keywords: hypermedia -;; Author: John Wiegley -;; Maintainer: Michael Olson -;; Description: An authoring and publishing tool for Emacs -;; URL: http://mwolson.org/projects/EmacsMuse.html -;; Compatibility: Emacs21 XEmacs21 Emacs22 - -;; This file is part of Emacs Muse. It is not part of GNU Emacs. - -;; Emacs Muse is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published -;; by the Free Software Foundation; either version 3, or (at your -;; option) any later version. - -;; Emacs Muse is distributed in the hope that it will be useful, but -;; WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;; General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with Emacs Muse; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; Muse is a tool for easily authoring and publishing documents. It -;; allows for rapid prototyping of hyperlinked text, which may then be -;; exported to multiple output formats -- such as HTML, LaTeX, -;; Texinfo, etc. - -;; The markup rules used by Muse are intended to be very friendly to -;; people familiar with Emacs. See the included manual for more -;; information. - -;;; Contributors: - -;;; Code: - -;; Indicate that this version of Muse supports nested tags -(provide 'muse-nested-tags) - -(defvar muse-version "3.20" - "The version of Muse currently loaded") - -(defun muse-version (&optional insert) - "Display the version of Muse that is currently loaded. -If INSERT is non-nil, insert the text instead of displaying it." - (interactive "P") - (if insert - (insert muse-version) - (message muse-version))) - -(defgroup muse nil - "Options controlling the behavior of Muse. -The markup used by Muse is intended to be very friendly to people -familiar with Emacs." - :group 'hypermedia) - -(defvar muse-under-windows-p (memq system-type '(ms-dos windows-nt))) - -(provide 'muse) - -(condition-case nil - (require 'derived) - (error nil)) -(require 'wid-edit) -(require 'muse-regexps) - -(defvar muse-update-values-hook nil - "Hook for values that are automatically generated. -This is to be used by add-on modules for Muse. -It is run just before colorizing or publishing a buffer.") - -(defun muse-update-values () - "Update various values that are automatically generated. - -Call this after changing `muse-project-alist'." - (interactive) - (run-hooks 'muse-update-values-hook) - (dolist (buffer (buffer-list)) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (when (derived-mode-p 'muse-mode) - (and (boundp 'muse-current-project) - (fboundp 'muse-project-of-file) - (setq muse-current-project nil) - (setq muse-current-project (muse-project-of-file)))))))) - -;; Default file extension - -;; By default, use the .muse file extension. -;;;###autoload (add-to-list 'auto-mode-alist '("\\.muse\\'" . muse-mode-choose-mode)) - -;; We need to have this at top-level, as well, so that any Muse or -;; Planner documents opened during init will just work. -(add-to-list 'auto-mode-alist '("\\.muse\\'" . muse-mode-choose-mode)) - -(eval-when-compile - (defvar muse-ignored-extensions)) - -(defvar muse-ignored-extensions-regexp nil - "A regexp of extensions to omit from the ending of a Muse page name. -This is autogenerated from `muse-ignored-extensions'.") - -(defun muse-update-file-extension (sym val) - "Update the value of `muse-file-extension'." - (let ((old (and (boundp sym) (symbol-value sym)))) - (set sym val) - (when (and (featurep 'muse-mode) - (or (not (stringp val)) - (not (stringp old)) - (not (string= old val)))) - ;; remove old auto-mode-alist association - (when (and (boundp sym) (stringp old)) - (setq auto-mode-alist - (delete (cons (concat "\\." old "\\'") - 'muse-mode-choose-mode) - auto-mode-alist))) - ;; associate the new file extension with muse-mode - (when (stringp val) - (add-to-list 'auto-mode-alist - (cons (concat "\\." val "\\'") - 'muse-mode-choose-mode))) - ;; update the ignored extensions regexp - (when (fboundp 'muse-update-ignored-extensions-regexp) - (muse-update-ignored-extensions-regexp - 'muse-ignored-extensions muse-ignored-extensions))))) - -(defcustom muse-file-extension "muse" - "File extension of Muse files. Omit the period at the beginning. -If you don't want Muse files to have an extension, set this to nil." - :type '(choice - (const :tag "None" nil) - (string)) - :set 'muse-update-file-extension - :group 'muse) - -(defcustom muse-completing-read-function 'completing-read - "Function to call when prompting user to choose between a list of options. -This should take the same arguments as `completing-read'." - :type 'function - :group 'muse) - -(defun muse-update-ignored-extensions-regexp (sym val) - "Update the value of `muse-ignored-extensions-regexp'." - (set sym val) - (if val - (setq muse-ignored-extensions-regexp - (concat "\\.\\(" - (regexp-quote (or muse-file-extension "")) "\\|" - (mapconcat 'identity val "\\|") - "\\)\\'")) - (setq muse-ignored-extensions-regexp - (if muse-file-extension - (concat "\\.\\(" muse-file-extension "\\)\\'") - nil)))) - -(add-hook 'muse-update-values-hook - (lambda () - (muse-update-ignored-extensions-regexp - 'muse-ignored-extensions muse-ignored-extensions))) - -(defcustom muse-ignored-extensions '("bz2" "gz" "[Zz]") - "A list of extensions to omit from the ending of a Muse page name. -These are regexps. - -Don't put a period at the beginning of each extension unless you -understand that it is part of a regexp." - :type '(repeat (regexp :tag "Extension")) - :set 'muse-update-ignored-extensions-regexp - :group 'muse) - -(defun muse-update-file-extension-after-init () - ;; This is short, but it has to be a function, otherwise Emacs21 - ;; does not load it properly when running after-init-hook - (unless (string= muse-file-extension "muse") - (let ((val muse-file-extension) - (muse-file-extension "muse")) - (muse-update-file-extension 'muse-file-extension val)))) - -;; Once the user's init file has been processed, determine whether -;; they want a file extension -(add-hook 'after-init-hook 'muse-update-file-extension-after-init) - -;; URL protocols - -(require 'muse-protocols) - -;; Helper functions - -(defsubst muse-delete-file-if-exists (file) - (when (file-exists-p file) - (delete-file file) - (message "Removed %s" file))) - -(defsubst muse-time-less-p (t1 t2) - "Say whether time T1 is less than time T2." - (or (< (car t1) (car t2)) - (and (= (car t1) (car t2)) - (< (nth 1 t1) (nth 1 t2))))) - -(eval-when-compile - (defvar muse-publishing-current-file nil)) - -(defun muse-current-file () - "Return the name of the currently visited or published file." - (or (and (boundp 'muse-publishing-current-file) - muse-publishing-current-file) - (buffer-file-name) - (concat default-directory (buffer-name)))) - -(defun muse-page-name (&optional name) - "Return the canonical form of a Muse page name. - -What this means is that the directory part of NAME is removed, -and the file extensions in `muse-ignored-extensions' are also -removed from NAME." - (save-match-data - (unless (and name (not (string= name ""))) - (setq name (muse-current-file))) - (if name - (let ((page (file-name-nondirectory name))) - (if (and muse-ignored-extensions-regexp - (string-match muse-ignored-extensions-regexp page)) - (replace-match "" t t page) - page))))) - -(defun muse-display-warning (message) - "Display the given MESSAGE as a warning." - (if (fboundp 'display-warning) - (display-warning 'muse message - (if (featurep 'xemacs) - 'warning - :warning)) - (let ((buf (get-buffer-create "*Muse warnings*"))) - (with-current-buffer buf - (goto-char (point-max)) - (insert "Warning (muse): " message) - (unless (bolp) - (newline))) - (display-buffer buf) - (sit-for 0)))) - -(defun muse-eval-lisp (form) - "Evaluate the given form and return the result as a string." - (require 'pp) - (save-match-data - (condition-case err - (let ((object (eval (read form)))) - (cond - ((stringp object) object) - ((and (listp object) - (not (eq object nil))) - (let ((string (pp-to-string object))) - (substring string 0 (1- (length string))))) - ((numberp object) - (number-to-string object)) - ((eq object nil) "") - (t - (pp-to-string object)))) - (error - (muse-display-warning (format "%s: Error evaluating %s: %s" - (muse-page-name) form err)) - "; INVALID LISP CODE")))) - -(defmacro muse-with-temp-buffer (&rest body) - "Create a temporary buffer, and evaluate BODY there like `progn'. -See also `with-temp-file' and `with-output-to-string'. - -Unlike `with-temp-buffer', this will never attempt to save the -temp buffer. It is meant to be used along with -`insert-file-contents' or `muse-insert-file-contents'. - -The undo feature will be disabled in the new buffer. - -If `debug-on-error' is set to t, keep the buffer around for -debugging purposes rather than removing it." - (let ((temp-buffer (make-symbol "temp-buffer"))) - `(let ((,temp-buffer (generate-new-buffer " *muse-temp*"))) - (buffer-disable-undo ,temp-buffer) - (unwind-protect - (if debug-on-error - (with-current-buffer ,temp-buffer - ,@body) - (condition-case err - (with-current-buffer ,temp-buffer - ,@body) - (error - (if (and (boundp 'muse-batch-publishing-p) - muse-batch-publishing-p) - (progn - (message "%s: Error occured: %s" - (muse-page-name) err) - (backtrace)) - (muse-display-warning - (format (concat "An error occurred while publishing" - " %s:\n %s\n\nSet debug-on-error to" - " `t' if you would like a backtrace.") - (muse-page-name) err)))))) - (when (buffer-live-p ,temp-buffer) - (with-current-buffer ,temp-buffer - (set-buffer-modified-p nil)) - (unless debug-on-error (kill-buffer ,temp-buffer))))))) - -(put 'muse-with-temp-buffer 'lisp-indent-function 0) -(put 'muse-with-temp-buffer 'edebug-form-spec '(body)) - -(defun muse-insert-file-contents (filename &optional visit) - "Insert the contents of file FILENAME after point. -Do character code conversion and end-of-line conversion, but none -of the other unnecessary things like format decoding or -`find-file-hook'. - -If VISIT is non-nil, the buffer's visited filename -and last save file modtime are set, and it is marked unmodified. -If visiting and the file does not exist, visiting is completed -before the error is signaled." - (let ((format-alist nil) - (after-insert-file-functions nil) - (inhibit-file-name-handlers - (append '(jka-compr-handler image-file-handler epa-file-handler) - inhibit-file-name-handlers)) - (inhibit-file-name-operation 'insert-file-contents)) - (insert-file-contents filename visit))) - -(defun muse-write-file (filename &optional nomessage) - "Write current buffer into file FILENAME. -Unlike `write-file', this does not visit the file, try to back it -up, or interact with vc.el in any way. - -If the file was not written successfully, return nil. Otherwise, -return non-nil. - -If the NOMESSAGE argument is non-nil, suppress the \"Wrote file\" -message." - (when nomessage (setq nomessage 'nomessage)) - (let ((backup-inhibited t) - (buffer-file-name filename) - (buffer-file-truename (file-truename filename))) - (save-current-buffer - (save-restriction - (widen) - (if (not (file-writable-p buffer-file-name)) - (prog1 nil - (muse-display-warning - (format "Cannot write file %s:\n %s" buffer-file-name - (let ((dir (file-name-directory buffer-file-name))) - (if (not (file-directory-p dir)) - (if (file-exists-p dir) - (format "%s is not a directory" dir) - (format "No directory named %s exists" dir)) - (if (not (file-exists-p buffer-file-name)) - (format "Directory %s write-protected" dir) - "File is write-protected")))))) - (let ((coding-system-for-write - (or (and (boundp 'save-buffer-coding-system) - save-buffer-coding-system) - coding-system-for-write))) - (write-region (point-min) (point-max) buffer-file-name - nil nomessage)) - (when (boundp 'last-file-coding-system-used) - (when (boundp 'buffer-file-coding-system-explicit) - (setq buffer-file-coding-system-explicit - last-coding-system-used)) - (if save-buffer-coding-system - (setq save-buffer-coding-system last-coding-system-used) - (setq buffer-file-coding-system last-coding-system-used))) - t))))) - -(defun muse-collect-alist (list element &optional test) - "Collect items from LIST whose car is equal to ELEMENT. -If TEST is specified, use it to compare ELEMENT." - (unless test (setq test 'equal)) - (let ((items nil)) - (dolist (item list) - (when (funcall test element (car item)) - (setq items (cons item items)))) - items)) - -(defmacro muse-sort-with-closure (list predicate closure) - "Sort LIST, stably, comparing elements using PREDICATE. -Returns the sorted list. LIST is modified by side effects. -PREDICATE is called with two elements of list and CLOSURE. -PREDICATE should return non-nil if the first element should sort -before the second." - `(sort ,list (lambda (a b) (funcall ,predicate a b ,closure)))) - -(put 'muse-sort-with-closure 'lisp-indent-function 0) -(put 'muse-sort-with-closure 'edebug-form-spec '(form function-form form)) - -(defun muse-sort-by-rating (rated-list &optional test) - "Sort RATED-LIST according to the rating of each element. -The rating is stripped out in the returned list. -Default sorting is highest-first. - -If TEST if specified, use it to sort the list. The default test is '>." - (unless test (setq test '>)) - (mapcar (function cdr) - (muse-sort-with-closure - rated-list - (lambda (a b closure) - (let ((na (numberp (car a))) - (nb (numberp (car b)))) - (cond ((and na nb) (funcall closure (car a) (car b))) - (na (not nb)) - (t nil)))) - test))) - -(defun muse-escape-specials-in-string (specials string &optional reverse) - "Apply the transformations in SPECIALS to STRING. - -The transforms should form a fully reversible and non-ambiguous -syntax when STRING is parsed from left to right. - -If REVERSE is specified, reverse an already-escaped string." - (let ((rules (mapcar (lambda (rule) - (cons (regexp-quote (if reverse - (cdr rule) - (car rule))) - (if reverse (car rule) (cdr rule)))) - specials))) - (save-match-data - (with-temp-buffer - (insert string) - (goto-char (point-min)) - (while (not (eobp)) - (unless (catch 'found - (dolist (rule rules) - (when (looking-at (car rule)) - (replace-match (cdr rule) t t) - (throw 'found t)))) - (forward-char))) - (buffer-string))))) - -(defun muse-trim-whitespace (string) - "Return a version of STRING with no initial nor trailing whitespace." - (muse-replace-regexp-in-string - (concat "\\`[" muse-regexp-blank "]+\\|[" muse-regexp-blank "]+\\'") - "" string)) - -(defun muse-path-sans-extension (path) - "Return PATH sans final \"extension\". - -The extension, in a file name, is the part that follows the last `.', -except that a leading `.', if any, doesn't count. - -This differs from `file-name-sans-extension' in that it will -never modify the directory part of the path." - (concat (file-name-directory path) - (file-name-nondirectory (file-name-sans-extension path)))) - -;; The following code was extracted from cl - -(defun muse-const-expr-p (x) - (cond ((consp x) - (or (eq (car x) 'quote) - (and (memq (car x) '(function function*)) - (or (symbolp (nth 1 x)) - (and (eq (and (consp (nth 1 x)) - (car (nth 1 x))) 'lambda) 'func))))) - ((symbolp x) (and (memq x '(nil t)) t)) - (t t))) - -(put 'muse-assertion-failed 'error-conditions '(error)) -(put 'muse-assertion-failed 'error-message "Assertion failed") - -(defun muse-list* (arg &rest rest) - "Return a new list with specified args as elements, cons'd to last arg. -Thus, `(list* A B C D)' is equivalent to `(nconc (list A B C) D)', or to -`(cons A (cons B (cons C D)))'." - (cond ((not rest) arg) - ((not (cdr rest)) (cons arg (car rest))) - (t (let* ((n (length rest)) - (copy (copy-sequence rest)) - (last (nthcdr (- n 2) copy))) - (setcdr last (car (cdr last))) - (cons arg copy))))) - -(defmacro muse-assert (form &optional show-args string &rest args) - "Verify that FORM returns non-nil; signal an error if not. -Second arg SHOW-ARGS means to include arguments of FORM in message. -Other args STRING and ARGS... are arguments to be passed to `error'. -They are not evaluated unless the assertion fails. If STRING is -omitted, a default message listing FORM itself is used." - (let ((sargs - (and show-args - (delq nil (mapcar - (function - (lambda (x) - (and (not (muse-const-expr-p x)) x))) - (cdr form)))))) - (list 'progn - (list 'or form - (if string - (muse-list* 'error string (append sargs args)) - (list 'signal '(quote muse-assertion-failed) - (muse-list* 'list (list 'quote form) sargs)))) - nil))) - -;; Compatibility functions - -(if (fboundp 'looking-back) - (defalias 'muse-looking-back 'looking-back) - (defun muse-looking-back (regexp &optional limit &rest ignored) - (save-excursion - (re-search-backward (concat "\\(?:" regexp "\\)\\=") limit t)))) - -(eval-and-compile - (if (fboundp 'line-end-position) - (defalias 'muse-line-end-position 'line-end-position) - (defun muse-line-end-position (&optional n) - (save-excursion (end-of-line n) (point)))) - - (if (fboundp 'line-beginning-position) - (defalias 'muse-line-beginning-position 'line-beginning-position) - (defun muse-line-beginning-position (&optional n) - (save-excursion (beginning-of-line n) (point)))) - - (if (fboundp 'match-string-no-properties) - (defalias 'muse-match-string-no-properties 'match-string-no-properties) - (defun muse-match-string-no-properties (num &optional string) - (match-string num string)))) - -(defun muse-replace-regexp-in-string (regexp replacement text &optional fixedcase literal) - "Replace REGEXP with REPLACEMENT in TEXT. - -Return a new string containing the replacements. - -If fourth arg FIXEDCASE is non-nil, do not alter case of replacement text. -If fifth arg LITERAL is non-nil, insert REPLACEMENT literally." - (cond - ((and (featurep 'xemacs) (fboundp 'replace-in-string)) - (and (fboundp 'replace-in-string) ; stupid byte-compiler warning - (replace-in-string text regexp replacement literal))) - ((fboundp 'replace-regexp-in-string) - (replace-regexp-in-string regexp replacement text fixedcase literal)) - (t (error (concat "Neither `replace-in-string' nor " - "`replace-regexp-in-string' was found"))))) - -(if (fboundp 'add-to-invisibility-spec) - (defalias 'muse-add-to-invisibility-spec 'add-to-invisibility-spec) - (defun muse-add-to-invisibility-spec (element) - "Add ELEMENT to `buffer-invisibility-spec'. -See documentation for `buffer-invisibility-spec' for the kind of elements -that can be added." - (if (eq buffer-invisibility-spec t) - (setq buffer-invisibility-spec (list t))) - (setq buffer-invisibility-spec - (cons element buffer-invisibility-spec)))) - -(if (fboundp 'read-directory-name) - (defalias 'muse-read-directory-name 'read-directory-name) - (defun muse-read-directory-name (prompt &optional dir default-dirname mustmatch initial) - "Read directory name - see `read-file-name' for details." - (unless dir - (setq dir default-directory)) - (read-file-name prompt dir (or default-dirname - (if initial (expand-file-name initial dir) - dir)) - mustmatch initial))) - -(defun muse-file-remote-p (file) - "Test whether FILE specifies a location on a remote system. -Return non-nil if the location is indeed remote. - -For example, the filename \"/user@host:/foo\" specifies a location -on the system \"/user@host:\"." - (cond ((fboundp 'file-remote-p) - (file-remote-p file)) - ((fboundp 'tramp-handle-file-remote-p) - (tramp-handle-file-remote-p file)) - ((and (boundp 'ange-ftp-name-format) - (string-match (car ange-ftp-name-format) file)) - t) - (t nil))) - -(if (fboundp 'delete-and-extract-region) - (defalias 'muse-delete-and-extract-region 'delete-and-extract-region) - (defun muse-delete-and-extract-region (start end) - "Delete the text between START and END and return it." - (prog1 (buffer-substring start end) - (delete-region start end)))) - -(if (fboundp 'delete-dups) - (defalias 'muse-delete-dups 'delete-dups) - (defun muse-delete-dups (list) - "Destructively remove `equal' duplicates from LIST. -Store the result in LIST and return it. LIST must be a proper list. -Of several `equal' occurrences of an element in LIST, the first -one is kept." - (let ((tail list)) - (while tail - (setcdr tail (delete (car tail) (cdr tail))) - (setq tail (cdr tail)))) - list)) - -;; Set face globally in a predictable fashion -(defun muse-copy-face (old new) - "Copy face OLD to NEW." - (if (featurep 'xemacs) - (copy-face old new 'all) - (copy-face old new))) - -;; Widget compatibility functions - -(defun muse-widget-type-value-create (widget) - "Convert and instantiate the value of the :type attribute of WIDGET. -Store the newly created widget in the :children attribute. - -The value of the :type attribute should be an unconverted widget type." - (let ((value (widget-get widget :value)) - (type (widget-get widget :type))) - (widget-put widget :children - (list (widget-create-child-value widget - (widget-convert type) - value))))) - -(defun muse-widget-child-value-get (widget) - "Get the value of the first member of :children in WIDGET." - (widget-value (car (widget-get widget :children)))) - -(defun muse-widget-type-match (widget value) - "Non-nil if the :type value of WIDGET matches VALUE. - -The value of the :type attribute should be an unconverted widget type." - (widget-apply (widget-convert (widget-get widget :type)) :match value)) - -;; Link-handling functions and variables - -(defun muse-get-link (&optional target) - "Based on the match data, retrieve the link. -Use TARGET to get the string, if it is specified." - (muse-match-string-no-properties 1 target)) - -(defun muse-get-link-desc (&optional target) - "Based on the match data, retrieve the link description. -Use TARGET to get the string, if it is specified." - (muse-match-string-no-properties 2 target)) - -(defvar muse-link-specials - '(("[" . "%5B") - ("]" . "%5D") - ("%" . "%%")) - "Syntax used for escaping and unescaping links. -This allows brackets to occur in explicit links as long as you -use the standard Muse functions to create them.") - -(defun muse-link-escape (text) - "Escape characters in TEXT that conflict with the explicit link -regexp." - (when (stringp text) - (muse-escape-specials-in-string muse-link-specials text))) - -(defun muse-link-unescape (text) - "Un-escape characters in TEXT that conflict with the explicit -link regexp." - (when (stringp text) - (muse-escape-specials-in-string muse-link-specials text t))) - -(defun muse-handle-url (&optional string) - "If STRING or point has a URL, match and return it." - (if (if string (string-match muse-url-regexp string) - (looking-at muse-url-regexp)) - (match-string 0 string))) - -(defcustom muse-implicit-link-functions '(muse-handle-url) - "A list of functions to handle an implicit link. -An implicit link is one that is not surrounded by brackets. - -By default, Muse handles URLs only. -If you want to handle WikiWords, load muse-wiki.el." - :type 'hook - :options '(muse-handle-url) - :group 'muse) - -(defun muse-handle-implicit-link (&optional link) - "Handle implicit links. If LINK is not specified, look at point. -An implicit link is one that is not surrounded by brackets. -By default, Muse handles URLs only. -If you want to handle WikiWords, load muse-wiki.el. - -This function modifies the match data so that match 0 is the -link. - -The match data is restored after each unsuccessful handler -function call. If LINK is specified, only restore at very end. - -This behavior is needed because the part of the buffer that -`muse-implicit-link-regexp' matches must be narrowed to the part -that is an accepted link." - (let ((funcs muse-implicit-link-functions) - (res nil) - (data (match-data t))) - (while funcs - (setq res (funcall (car funcs) link)) - (if res - (setq funcs nil) - (unless link (set-match-data data)) - (setq funcs (cdr funcs)))) - (when link (set-match-data data)) - res)) - -(defcustom muse-explicit-link-functions nil - "A list of functions to handle an explicit link. -An explicit link is one [[like][this]] or [[this]]." - :type 'hook - :group 'muse) - -(defun muse-handle-explicit-link (&optional link) - "Handle explicit links. If LINK is not specified, look at point. -An explicit link is one that looks [[like][this]] or [[this]]. - -The match data is preserved. If no handlers are able to process -LINK, return LINK (if specified) or the 1st match string. If -LINK is not specified, it is assumed that Muse has matched -against `muse-explicit-link-regexp' before calling this -function." - (let ((funcs muse-explicit-link-functions) - (res nil)) - (save-match-data - (while funcs - (setq res (funcall (car funcs) link)) - (if res - (setq funcs nil) - (setq funcs (cdr funcs))))) - (muse-link-unescape - (if res - res - (or link (muse-get-link)))))) - -;; Movement functions - -(defun muse-list-item-type (str) - "Determine the type of list given STR. -Returns either 'ul, 'ol, 'dl-term, 'dl-entry, or nil." - (save-match-data - (cond ((or (string= str "") - (< (length str) 2)) - nil) - ((string-match muse-dl-entry-regexp str) - 'dl-entry) - ((string-match muse-dl-term-regexp str) - 'dl-term) - ((string-match muse-ol-item-regexp str) - 'ol) - ((string-match muse-ul-item-regexp str) - 'ul) - (t nil)))) - -(defun muse-list-item-critical-point (&optional offset) - "Figure out where the important markup character for the -currently-matched list item is. - -If OFFSET is specified, it is the number of groupings outside of -the contents of `muse-list-item-regexp'." - (unless offset (setq offset 0)) - (if (match-end (+ offset 2)) - ;; at a definition list - (match-end (+ offset 2)) - ;; at a different kind of list - (match-beginning (+ offset 1)))) - -(defun muse-forward-paragraph (&optional pattern) - "Move forward safely by one paragraph, or according to PATTERN." - (when (get-text-property (point) 'muse-end-list) - (goto-char (next-single-property-change (point) 'muse-end-list))) - (setq pattern (if pattern - (concat "^\\(?:" pattern "\\|\n\\|\\'\\)") - "^\\s-*\\(\n\\|\\'\\)")) - (let ((next-list-end (or (next-single-property-change (point) 'muse-end-list) - (point-max)))) - (forward-line 1) - (if (re-search-forward pattern nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max))) - (when (> (point) next-list-end) - (goto-char next-list-end)))) - -(defun muse-forward-list-item-1 (type empty-line indented-line) - "Determine whether a nested list item is after point." - (if (match-beginning 1) - ;; if we are given a dl entry, skip past everything on the same - ;; level, except for other dl entries - (and (eq type 'dl-entry) - (not (eq (char-after (match-beginning 2)) ?\:))) - ;; blank line encountered with no list item on the same - ;; level after it - (let ((beg (point))) - (forward-line 1) - (if (save-match-data - (and (looking-at indented-line) - (not (looking-at empty-line)))) - ;; found that this blank line is followed by some - ;; indentation, plus other text, so we'll keep - ;; going - t - (goto-char beg) - nil)))) - -(defun muse-forward-list-item (type indent &optional no-skip-nested) - "Move forward to the next item of TYPE. -Return non-nil if successful, nil otherwise. -The beginning indentation is given by INDENT. - -If NO-SKIP-NESTED is non-nil, do not skip past nested items. -Note that if you desire this behavior, you will also need to -provide a very liberal INDENT value, such as -\(concat \"[\" muse-regexp-blank \"]*\")." - (let* ((list-item (format muse-list-item-regexp indent)) - (empty-line (concat "^[" muse-regexp-blank "]*\n")) - (indented-line (concat "^" indent "[" muse-regexp-blank "]")) - (list-pattern (concat "\\(?:" empty-line "\\)?" - "\\(" list-item "\\)"))) - (while (progn - (muse-forward-paragraph list-pattern) - ;; make sure we don't go past boundary - (and (not (or (get-text-property (point) 'muse-end-list) - (>= (point) (point-max)))) - ;; move past markup that is part of another construct - (or (and (match-beginning 1) - (or (get-text-property - (muse-list-item-critical-point 1) 'muse-link) - (and (derived-mode-p 'muse-mode) - (get-text-property - (muse-list-item-critical-point 1) - 'face)))) - ;; skip nested items - (and (not no-skip-nested) - (muse-forward-list-item-1 type empty-line - indented-line)))))) - (cond ((or (get-text-property (point) 'muse-end-list) - (>= (point) (point-max))) - ;; at a list boundary, so stop - nil) - ((let ((str (when (match-beginning 2) - ;; get the entire line - (save-excursion - (goto-char (match-beginning 2)) - (buffer-substring (muse-line-beginning-position) - (muse-line-end-position)))))) - (and str (eq type (muse-list-item-type str)))) - ;; same type, so indicate that there are more items to be - ;; parsed - (goto-char (match-beginning 1))) - (t - (when (match-beginning 1) - (goto-char (match-beginning 1))) - ;; move to just before foreign list item markup - nil)))) - -(defun muse-goto-tag-end (tag nested) - "Move forward past the end of TAG. - -If NESTED is non-nil, look for other instances of this tag that -may be nested inside of this tag, and skip past them." - (if (not nested) - (search-forward (concat "") nil t) - (let ((nesting 1) - (tag-regexp (concat "\\(<\\(/?\\)" tag "\\([ >]\\)\\)")) - (match-found nil)) - (while (and (> nesting 0) - (setq match-found (re-search-forward tag-regexp nil t))) - ;; for the sake of font-locking code, skip matches in comments - (unless (get-text-property (match-beginning 0) 'muse-comment) - (if (string-equal (match-string 2) "/") - (and (string-equal (match-string 3) ">") - (setq nesting (1- nesting))) - (setq nesting (1+ nesting))))) - match-found))) - -;;; muse.el ends here -- cgit v1.2.3-54-g00ecf