aboutsummaryrefslogtreecommitdiffhomepage
path: root/mmm
diff options
context:
space:
mode:
authorGravatar David Aspinall <da@inf.ed.ac.uk>2006-09-22 16:45:50 +0000
committerGravatar David Aspinall <da@inf.ed.ac.uk>2006-09-22 16:45:50 +0000
commit50ed5b3a2487b818a0741a7c4fe7f5ec52d52d7c (patch)
tree3d64ad41cf6bc63e72226b34f44d138d952b3645 /mmm
parent8562a8f7c41b371228859767251528ddfd5c65a2 (diff)
Update to 0.4.8 from sourceforge.
Diffstat (limited to 'mmm')
-rw-r--r--mmm/AUTHORS19
-rw-r--r--mmm/FAQ100
-rw-r--r--mmm/NEWS31
-rw-r--r--mmm/README76
-rw-r--r--mmm/README.mmm-for-ProofGeneral2
-rw-r--r--mmm/TODO4
-rw-r--r--mmm/mmm-auto.el4
-rw-r--r--mmm/mmm-class.el126
-rw-r--r--mmm/mmm-cmds.el146
-rw-r--r--mmm/mmm-compat.el6
-rw-r--r--mmm/mmm-cweb.el101
-rw-r--r--mmm/mmm-mason.el11
-rw-r--r--mmm/mmm-mode.el219
-rw-r--r--mmm/mmm-noweb.el410
-rw-r--r--mmm/mmm-region.el543
-rw-r--r--mmm/mmm-sample.el102
-rw-r--r--mmm/mmm-utils.el39
-rw-r--r--mmm/mmm-vars.el412
-rw-r--r--mmm/mmm.texinfo313
-rw-r--r--mmm/version.texi7
20 files changed, 2006 insertions, 665 deletions
diff --git a/mmm/AUTHORS b/mmm/AUTHORS
index 0740e780..332e958a 100644
--- a/mmm/AUTHORS
+++ b/mmm/AUTHORS
@@ -1,3 +1,16 @@
-MMM Mode was designed and written by Michael Abraham Shulman
-<viritrilbia@users.sourceforge.net>. The original inspiration came
-from mmm.el for XEmacs by Gongquan Chen <chen@posc.org>.
+MMM Mode was originally designed and written by Michael Shulman
+<viritrilbia@users.sourceforge.net>.
+
+It was inspired by mmm.el for XEmacs by Gongquan Chen <chen@posc.org>.
+
+Recent contributors have included:
+
+bishop <bishop@platypus.bc.ca>
+Joe Kelsey <joe@zircon.seattle.wa.us>
+Alan Shutko <ats@acm.org>
+Michael Alan Dorman <mdorman@users.sourceforge.net>
+Brian P Templeton <plovre@users.sourceforge.net>
+Yann Dirson <ydirson@fr.alcove.com>
+Marcus Harnisch
+
+and others...
diff --git a/mmm/FAQ b/mmm/FAQ
index 3b1c93dd..20cb8e01 100644
--- a/mmm/FAQ
+++ b/mmm/FAQ
@@ -10,14 +10,15 @@ emacs mode or function. He does think, however, that `Mmm' looks
rather ugly, although that is how SourceForge insists on capitalizing
the name of the mailing list.
+
* How do I get rid of that ugly gray background color?
Put the following line in your Emacs initialization file:
- (set-face-background 'mmm-default-submode-face nil)
+ (setq mmm-submode-decoration-level 0)
You may want to try using MMM Mode for a while with the background
-highlight, however, or merely changing it to different color. There
+highlight, however, or merely changing it to a different color. There
are two reasons it's there by default:
1. MMM Mode isn't as smart as you might hope it would be about
@@ -26,7 +27,10 @@ are two reasons it's there by default:
2. Just like the rest of font-lock, it helps you mentally organize the
code; you can see at a glance that THIS code is executed as Perl,
- but THAT code is straight HTML (or whatever).
+ but THAT code is straight HTML (or whatever). You can get even
+ more help by setting the above variable to 2, in which case regions
+ will get a background color according to their function.
+
* I typed `<%' (or other delimiter) but I'm still in the wrong mode.
@@ -41,6 +45,26 @@ the need to type the delimiters as well as the need to reparse the
block: type `C-c % h' for a list of available insertion commands for
current submode class(es).
+
+* Why is the first character of the end delimiter in the submode region?
+
+It isn't. When your cursor looks like it is over that character, it
+is actually *before* that character and therefore inside the submode
+region. You can check that the offending character does not have the
+background highlight--that is, if you haven't set the decoration level
+to 0. For example, in the following text (where -!- represents the
+cursor position)
+
+ print <<END_TEXT;
+ here is some text
+ -!-END_TEXT
+
+The 'E' at the beginning of the END_TEXT line is not actually part of
+the submode region. But with the cursor as indicated (that is, the
+box is blinking over the `E' which follows the actual cursor
+position), Emacs is in text-mode.
+
+
* Why won't MMM Mode work with `foo-mode'?
Foo-mode probably has extra variables or states that need to be set
@@ -52,6 +76,7 @@ Either way, please contact the maintainer or the mailing list when
(if) you find something that works, so that in the future, folks can
use MMM Mode and foo-mode together more easily.
+
* I'm getting an emacs error, what did I do wrong?
Most likely nothing. MMM Mode is still more or less alpha software
@@ -76,19 +101,21 @@ point out errors, but only with your init code and a backtrace.
while loading emacs, invoke emacs with the `--debug-init' (Emacs)
or `-debug-init' (XEmacs) switch.
+
* Will MMM Mode work with (Emacs 19 / XEmacs 20 / XEmacs 21 / etc...)?
-MMM Mode is designed for FSF Emacs 20 and works best there, but it can
-work in other emacsen, although problems may arise. For instance, the
-font-lock support in XEmacs 20 is known to be broken and well-nigh
-unfixable; consider upgrading. Even XEmacs 21 has more problems with
-font-lock: for example, often apostrophes in a different submode
-region can cause code to be incorrectly font-locked as a string.
+MMM Mode was designed for FSF Emacs 20 and 21 and works best there.
+But don't let that stop you from trying it under other variants of
+emacs. If you encounter problems, feel free to ask the mailing list,
+but success is not guaranteed.
+
+For example, the font-lock support in XEmacs 20 is known to be broken
+and well-nigh unfixable; consider upgrading. XEmacs 21 also has
+problems with font-lock: for example, often apostrophes in a different
+submode region can cause code to be incorrectly font-locked as a
+string. I have given up trying to support Emacs 19; you should
+upgrade to Emacs 20 or 21.
-While not free of problems under Emacs 20, MMM Mode does tend to work
-best there, but don't let that stop you from trying it under other
-emacsen. If you encounter problems, feel free to ask the mailing
-list, but success is not guaranteed.
* XEmacs says `Symbol's function definition is void: make-indirect-buffer'.
@@ -98,7 +125,7 @@ when byte compiling, do the following:
$ cd mmm-mode-x.x.x
$ make distclean
-$ EMACS=/usr/bin/xemacs ./configure
+$ ./configure --with-xemacs=/path/to/xemacs
$ make
$ make install
@@ -107,9 +134,48 @@ compiled MMM Mode for the wrong emacs, but can never hurt. The exact
error message this problem produces may change with newer versions of
MMM Mode; always be sure you have compiled for the correct emacsen.
+
+* I want to install the CVS version, but there's no `configure' script.
+
+The `configure' script which is included in the official distributions
+is not present in CVS, because it is automatically generated by GNU
+Automake/Autoconf from files like `Makefile.am' and `configure.in'.
+To build the CVS version the same way as the official distributions,
+you must first run `autogen.sh':
+
+$ cd mmm-mode
+$ ./autogen.sh
+
+and then you can continue as usual:
+
+$ ./configure
+$ make
+$ make install
+
+Note that autogen.sh requires aclocal, automake, and autoconf, which
+may or may not be installed on your system, since they are considered
+developer tools rather than end-user tools. If you can't or don't
+want to install them, however, you can still use the CVS version of
+MMM Mode by manually copying all the `.el' files into a directory in
+your `load-path'. Optionally, you may also byte-compile them manually
+(this is what `make' normally does). Byte-compiling gives some speed
+improvement, but if you experience problems, the stack traces are
+sometimes more informative if you are using the source files only.
+
+The Info files `mmm.info-*' are also not included in CVS, since they
+are generated from `mmm.texinfo' by the program `makeinfo'. If you
+want to install the Info documentation from CVS, you will have to run
+this manually as well, and copy the resulting info files into the
+appropriate location for your system.
+
+The CVS version is, of course, even less guaranteed to be bug-free
+than the official distributions. But please report any problems you
+have with it, so they can be fixed for the next release.
+
+
* You haven't answered my question; how can I get more help?
At the MMM Mode web site, <http://mmm-mode.sourceforge.net>, there is
-a link to the sign-up page for the MMM Mode mailing list. When asking
-a question on the list, be sure to give the versions of emacs and MMM
-Mode you are using, and any other relevant information.
+a link to the subscription page for the MMM Mode mailing list. When
+asking a question on the list, be sure to give the versions of emacs
+and MMM Mode you are using, and any other relevant information.
diff --git a/mmm/NEWS b/mmm/NEWS
index fc48736c..41a15125 100644
--- a/mmm/NEWS
+++ b/mmm/NEWS
@@ -1,8 +1,35 @@
MMM Mode NEWS -- history of user-visible changes. -*-outline-*-
-Copyright (C) 2000 Michael Abraham Shulman
+Copyright (C) 2003, 2004 Michael Abraham Shulman
See the file COPYING for copying conditions.
-Please send MMM Mode bug reports to viritrilbia@users.sourceforge.net
+Please submit bug reports at http://sourceforge.net/projects/mmm-mode/
+
+* Changes in MMM Mode 0.4.8
+
+** Delimiter Regions
+
+The delimiters which mark off submode regions now have their own
+overlays. They can be highlighted if you so desire using appropriate
+class arguments and/or the variable mmm-delimiter-face. They are also
+in an appropriate major mode, or non-mode as the case may be.
+
+** Nested Submodes
+
+Nested submodes are now vaguely supported.
+
+** RPM Spec File
+
+An RPM spec file, contributed by <bishop@platypus.bc.ca>, is now
+included for people who wish to build their own SRPM to install from.
+
+** New Submode Classes
+
+Many thanks to Joe Kelsey for writing a very intelligent class for
+editing Noweb files, and to Alan Shutko for one for CWeb files. We
+also have a mode for SGML DTD definitions from Yann Dirson.
+
+** Numerous bugfixes and small improvements
+
* Changes in MMM Mode 0.4.7
diff --git a/mmm/README b/mmm/README
index eb45686c..fdcb8744 100644
--- a/mmm/README
+++ b/mmm/README
@@ -5,16 +5,19 @@
OVERVIEW
MMM Mode is a minor mode for Emacs that allows Multiple Major Modes
- (hence the name) to coexist in one buffer. It is particularly
- well-suited to editing embedded code, such as Mason server-side
- Perl, or HTML output in CGI scripts.
+ to coexist in one buffer. It is well-suited to editing:
+
+ * Preprocessed code, such as server-side Perl or PHP embedded in HTML
+ * Code generating code, such as HTML output by CGI scripts
+ * Embedded code, such as Javascript in HTML
+ * Literate programming: code interspersed with documentation, e.g. Noweb
INSTALLATION
MMM Mode has a standard GNU configure-driven installation. (See the
- file INSTALL for generic instructions.) To install mmm-mode in the
- standard locations, unpack the archive, `cd' to the mmm-mode-X.X.X
- directory created, and run these commands:
+ file INSTALL for generic instructions, most of which don't apply.)
+ To install in the standard locations, unpack the archive, `cd' to
+ the mmm-mode-X.X.X directory created, and run these commands:
./configure
make
@@ -27,6 +30,12 @@ INSTALLATION
installs the MMM Mode info manual in your site info directory, so if
you're installing manually, you might want to do that too.
+ If you're installing from the CVS version, you won't have the
+ configure script. If you have the automake/autoconf tools
+ installed, you can run the script `autogen.sh' first, and then
+ proceed as above. Otherwise, you'll have to copy the *.el files
+ manually as described above.
+
If you have more than one version of emacs installed and want to
use MMM in a version other than /usr/bin/emacs, you must set the
environment variable EMACS before running `configure', e.g.
@@ -44,43 +53,64 @@ CONFIGURATION
Once MMM Mode is installed, it has to be configured correctly. This
can be done in a site-start file or in user's initialization files;
- probably the latter is preferable, except possibly for autoloads.
-
- See the info file for full documentation on the available
- configuration options. To get started, however, MMM Mode needs to
- be loaded, either completely, with
+ usually the latter is preferable, except possibly for autoloads.
+ First the package needs to be loaded, with either
(require 'mmm-mode)
- or conditionally, as necessary, with
+ or instead, to save time during emacs startup,
(require 'mmm-auto)
- The second installs only the major-mode hooks and sets up MMM Mode
- to load itself automatically when necessary.
+ Then you will probably want to set something like this:
+
+ (setq mmm-global-mode 'maybe)
+ (mmm-add-mode-ext-class 'html-mode "\\.php\\'" 'html-php)
+
+ The first line tells MMM Mode to load itself whenever you open an
+ appropriate file, and the second is an example which says to notice
+ PHP regions in html-mode files having a `.php' extension. Both
+ lines are necessary.
+
+ You will, of course, want to change and duplicate the second line
+ according to your needs. either of the first two parameters can be
+ `nil', meaning not to consider that criterion. For example, if all
+ your html files, regardless of extension, are Mason components, you
+ will want something like:
+
+ (mmm-add-mode-ext-class 'html-mode nil 'mason)
+
+ whereas if all your files with a `.nw' extension, regardless of
+ primary mode (some may be LaTeX, others HTML, say) are Noweb, you
+ will prefer
+
+ (mmm-add-mode-ext-class nil "\\.nw\\'" 'noweb)
+
+ See the info file for more extensive documentation, and for other
+ configuration options.
DOCUMENTATION
- For further information, see (in order) the accompanying info file
- (as yet incomplete), the documentation strings of functions and
- variables, the comments in the source code, and the source code
- itself.
+ For further information, see (in order) the accompanying info file,
+ the documentation strings of functions and variables, the comments
+ in the source code, and the source code itself.
UPDATES
The latest version of MMM Mode should always be available from
- http://mmm-mode.sourceforge.net/.
+ http://sourceforge.net/projects/mmm-mode
BUG REPORTS
Bug reports and suggestions can be submitted at
- <http://sourceforge.net/bugs/?group_id=8658> or through email to
- viritrilbia@users.sourceforge.net.
+ <http://sourceforge.net/tracker/?group_id=8658&atid=108658>, or
+ through email to <viritrilbia@users.sourceforge.net>.
CONTACT INFO
- MMM Mode is written and maintained by Michael Abraham Shulman
- <viritrilbia@users.sourceforge.net>.
+ MMM Mode is written and maintained by Michael Shulman,
+ <viritrilbia@users.sourceforge.net>, and others; a list of some
+ contributors can be found on the Sourceforge project.
MAILING LIST
diff --git a/mmm/README.mmm-for-ProofGeneral b/mmm/README.mmm-for-ProofGeneral
index ad4f9dca..a79c84c7 100644
--- a/mmm/README.mmm-for-ProofGeneral
+++ b/mmm/README.mmm-for-ProofGeneral
@@ -2,7 +2,7 @@ The code in this directory is taken from
http://mmm-mode.sourceforge.net/
-This is version 0.4.7.
+This is version 0.4.8.
No changes have been made for Proof General.
Some files have not be included here.
diff --git a/mmm/TODO b/mmm/TODO
index 97c1dab8..e631145f 100644
--- a/mmm/TODO
+++ b/mmm/TODO
@@ -3,6 +3,10 @@ Hey Emacs, this is a -*-text-*- file!
To Do List for MMM Mode
=======================
+It would be nice to have a "split region" command which would insert
+a _back_ delimiter followed by a _front_ delimiter at point and split
+the current region into two regions. Say for PHP.
+
Custom mode functions like `mason-mode'.
Make Mason work a little better with PSGML. The fix I've found works,
diff --git a/mmm/mmm-auto.el b/mmm/mmm-auto.el
index eaca7848..a994eb4f 100644
--- a/mmm/mmm-auto.el
+++ b/mmm/mmm-auto.el
@@ -75,6 +75,10 @@
(file-variables "mmm-sample" nil)
(rpm-sh "mmm-rpm" t)
(rpm "mmm-rpm" nil)
+ (cweb "mmm-cweb" nil)
+ (sgml-dtd "mmm-sample" nil)
+ (noweb "mmm-noweb" nil)
+ (html-php "mmm-sample" nil)
)
"Alist of submode classes autoloaded from files.
Elements look like \(CLASS FILE PRIVATE) where CLASS is a submode
diff --git a/mmm/mmm-class.el b/mmm/mmm-class.el
index 46067fd9..d79cdbbf 100644
--- a/mmm/mmm-class.el
+++ b/mmm/mmm-class.el
@@ -1,8 +1,8 @@
;;; mmm-class.el --- MMM submode class variables and functions
-;; Copyright (C) 2000 by Michael Abraham Shulman
+;; Copyright (C) 2000, 2004 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -36,6 +36,7 @@
(require 'mmm-vars)
(require 'mmm-region)
+;;; CLASS SPECIFICATIONS
;;{{{ Get Class Specifications
(defun mmm-get-class-spec (class)
@@ -81,7 +82,10 @@ none is specified by CLASS."
(unless (eq class t)
(apply #'mmm-ify :start start :stop stop
(append (mmm-get-class-spec class)
- (list :face face)))))
+ (list :face face)))
+ (mmm-run-class-hook class)
+ ;; Hack in case class hook sets mmm-buffer-mode-display-name etc.
+ (mmm-set-mode-line)))
(defun* mmm-apply-classes
(classes &key (start (point-min)) (stop (point-max)) face)
@@ -109,27 +113,34 @@ The classes come from mode/ext, `mmm-classes', `mmm-global-classes',
and interactive history."
(mmm-clear-overlays start stop 'strict)
(mmm-apply-classes (mmm-get-all-classes t) :start start :stop stop)
- (mmm-update-current-submode)
+ (mmm-update-submode-region)
(mmm-refontify-maybe start stop))
;;}}}
+
+;;; BUFFER SCANNING
;;{{{ Scan for Regions
(defun* mmm-ify
- (&rest all &key classes handler submode face
+ (&rest all &key classes handler
+ submode match-submode
(start (point-min)) (stop (point-max))
front back save-matches (case-fold-search t)
(beg-sticky (not (number-or-marker-p front)))
(end-sticky (not (number-or-marker-p back)))
include-front include-back
(front-offset 0) (back-offset 0)
+ (front-delim nil) (back-delim nil)
+ (delimiter-mode mmm-delimiter-mode)
+ front-face back-face
front-verify back-verify
- front-form back-form creation-hook
- match-submode match-face
- (front-match 0)
- (back-match 0)
+ front-form back-form
+ creation-hook
+ face match-face
+ save-name match-name
+ (front-match 0) (back-match 0)
end-not-begin
- ;insert
+ ;insert private
&allow-other-keys
)
"Create submode regions from START to STOP according to arguments.
@@ -139,11 +150,12 @@ the rest of the arguments are for an actual class being applied. See
;; Make sure we get the default values in the `all' list.
(setq all (append
all
- (list :start start :stop stop :beg-sticky beg-sticky
- :end-sticky end-sticky :front-offset front-offset
- :back-offset back-offset
- :front-match 0
- :back-match 0)))
+ (list :start start :stop stop
+ :beg-sticky beg-sticky :end-sticky end-sticky
+ :front-offset front-offset :back-offset back-offset
+ :front-delim front-delim :back-delim back-delim
+ :front-match 0 :back-match 0
+ )))
(cond
;; If we have a class list, apply them all.
(classes
@@ -158,24 +170,34 @@ the rest of the arguments are for an actual class being applied. See
(t
(mmm-save-all
(goto-char start)
- (loop for (beg end matched-front matched-back
- matched-submode matched-face back-to resume-at) =
+ (loop for (beg end front-pos back-pos matched-front matched-back
+ matched-submode matched-face matched-name
+ invalid-resume ok-resume) =
(apply #'mmm-match-region :start (point) all)
while beg
- while (or (not end) (/= beg end)) ; Sanity check
- if end do ; match-submode, if present, succeeded.
+ if end ; match-submode, if present, succeeded.
+ do
(condition-case nil
(progn
- (apply #'mmm-make-region (or matched-submode submode)
- beg end :front matched-front :back matched-back
- :face (or matched-face face) all)
- (goto-char resume-at))
+ (mmm-make-region
+ (or matched-submode submode) beg end
+ :face (or matched-face face)
+ :front front-pos :back back-pos
+ :evaporation 'front
+ :match-front matched-front :match-back matched-back
+ :beg-sticky beg-sticky :end-sticky end-sticky
+ :name matched-name
+ :delimiter-mode delimiter-mode
+ :front-face front-face :back-face back-face
+ :creation-hook creation-hook
+ )
+ (goto-char ok-resume))
;; If our region is invalid, go back to the end of the
;; front match and continue on.
- (mmm-invalid-parent (goto-char back-to)))
+ (mmm-error (goto-char invalid-resume)))
;; If match-submode was unable to find a match, go back to
;; the end of the front match and continue on.
- else do (goto-char back-to)
+ else do (goto-char invalid-resume)
)))))
;;}}}
@@ -186,17 +208,22 @@ the rest of the arguments are for an actual class being applied. See
include-front include-back front-offset back-offset
front-form back-form save-matches match-submode match-face
front-match back-match end-not-begin
+ save-name match-name
&allow-other-keys)
"Find the first valid region between point and STOP.
-Return \(BEG END FRONT-FORM BACK-FORM SUBMODE FACE BACK-TO) specifying
-the region. See `mmm-match-and-verify' for the valid values of FRONT
-and BACK \(markers, regexps, or functions). A nil value for END means
-that MATCH-SUBMODE failed to find a valid submode. BACK-TO is the
-point at which the search should continue if the region is invalid."
+Return \(BEG END FRONT-POS BACK-POS FRONT-FORM BACK-FORM SUBMODE FACE
+NAME INVALID-RESUME OK-RESUME) specifying the region. See
+`mmm-match-and-verify' for the valid values of FRONT and BACK
+\(markers, regexps, or functions). A nil value for END means that
+MATCH-SUBMODE failed to find a valid submode. INVALID-RESUME is the
+point at which the search should continue if the region is invalid,
+and OK-RESUME if the region is valid."
(when (mmm-match-and-verify front start stop front-verify)
- (let ((beg (mmm-match->point include-front front-offset
- front-match back-match))
- (back-to (match-end front-match))
+ (let ((beg (mmm-match->point include-front front-offset front-match))
+ (front-pos (if front-delim
+ (mmm-match->point t front-delim front-match)
+ nil))
+ (invalid-resume (match-end front-match))
(front-form (mmm-get-form front-form)))
(let ((submode (if match-submode
(condition-case nil
@@ -205,8 +232,15 @@ point at which the search should continue if the region is invalid."
(mmm-no-matching-submode
(return-from
mmm-match-region
- (values nil nil nil nil nil back-to))))
+ (values beg nil nil nil nil nil nil nil nil
+ invalid-resume nil))))
nil))
+ (name (cond ((functionp match-name)
+ (mmm-save-all (funcall match-name front-form)))
+ ((stringp match-name)
+ (if save-name
+ (mmm-format-matches match-name)
+ match-name))))
(face (cond ((functionp match-face)
(mmm-save-all
(funcall match-face front-form)))
@@ -217,21 +251,27 @@ point at which the search should continue if the region is invalid."
(mmm-format-matches back)
back)
beg stop back-verify)
- (let* ((end (mmm-match->point (not include-back) back-offset
- front-match back-match))
+ (let* ((end (mmm-match->point (not include-back)
+ back-offset back-match))
+ (back-pos (if back-delim
+ (mmm-match->point nil back-delim back-match)
+ nil))
(back-form (mmm-get-form back-form))
- (resume-at (if end-not-begin
+ (ok-resume (if end-not-begin
(match-end back-match)
end)))
- (values beg end front-form back-form submode face back-to resume-at)))))))
+ (values beg end front-pos back-pos front-form back-form
+ submode face name
+ invalid-resume ok-resume)))))))
-(defun mmm-match->point (beginp offset front-match back-match)
+(defun mmm-match->point (beginp offset match)
"Find a point of starting or stopping from the match data. If
-BEGINP, start at \(match-beginning FRONT-MATCH), else \(match-end
-BACK-MATCH), and move OFFSET. Handles all values for OFFSET--see
-`mmm-classes-alist'."
+BEGINP, start at \(match-beginning MATCH), else \(match-end MATCH),
+and move OFFSET. Handles all values of OFFSET--see `mmm-classes-alist'."
(save-excursion
- (goto-char (if beginp (match-beginning front-match) (match-end back-match)))
+ (goto-char (if beginp
+ (match-beginning front-match)
+ (match-end back-match)))
(dolist (spec (if (listp offset) offset (list offset)))
(if (numberp spec)
(forward-char (or spec 0))
diff --git a/mmm/mmm-cmds.el b/mmm/mmm-cmds.el
index 82b2235c..e192101d 100644
--- a/mmm/mmm-cmds.el
+++ b/mmm/mmm-cmds.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2000 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -35,6 +35,7 @@
(require 'mmm-vars)
(require 'mmm-class)
+;; APPLYING CLASSES
;;{{{ Applying Predefined Classes
(defun mmm-ify-by-class (class)
@@ -44,18 +45,12 @@
(completing-read
"Submode Class: "
(remove-duplicates
- (remove nil
- (nconc
- (mapcar #'(lambda (spec)
- (if (plist-get (cdr spec) :private)
- nil
- (list (symbol-name (car spec)))))
- mmm-classes-alist)
- (mapcar #'(lambda (spec)
- (if (caddr spec)
- nil
- (list (symbol-name (car spec)))))
- mmm-autoloaded-classes))))
+ (mapcar #'(lambda (spec) (list (symbol-name (car spec))))
+ (append
+ (remove-if #'(lambda (spec) (plist-get (cdr spec) :private))
+ mmm-classes-alist)
+ (remove-if #'caddr mmm-autoloaded-classes)))
+ :test #'equal)
nil t))))
(unless (eq class (intern ""))
(mmm-apply-class class)
@@ -95,6 +90,8 @@ nNumber of matched substrings to save: ")
(mmm-enable-font-lock submode))
;;}}}
+
+;; EDITING WITH REGIONS
;;{{{ Re-parsing Areas
(defun mmm-parse-buffer ()
@@ -144,6 +141,25 @@ delimiter auto-insertion that MMM Mode provides. See, for example,
(point)))))
;;}}}
+;;{{{ Reparse Current Region
+
+(defun mmm-reparse-current-region ()
+ "Clear and reparse the area of the current submode region.
+Use this command if a submode region's boundaries have become wrong."
+ (interactive)
+ (let ((ovl (mmm-overlay-at (point) 'all)))
+ (when ovl
+ (let ((beg (save-excursion
+ (goto-char (mmm-front-start ovl))
+ (forward-line -1)
+ (point)))
+ (end (save-excursion
+ (goto-char (mmm-back-end ovl))
+ (forward-line 1)
+ (point))))
+ (mmm-parse-region beg end)))))
+
+;;}}}
;;{{{ Clear Submode Regions
;; See also `mmm-clear-history' which is interactive.
@@ -164,25 +180,6 @@ delimiter auto-insertion that MMM Mode provides. See, for example,
(mmm-clear-overlays))
;;}}}
-;;{{{ Reparse Current Region
-
-(defun mmm-reparse-current-region ()
- "Clear and reparse the area of the current submode region.
-Use this command if a submode region's boundaries have become wrong."
- (interactive)
- (let ((ovl (mmm-overlay-at (point) 'all)))
- (when ovl
- (let ((beg (save-excursion
- (goto-char (mmm-front-start ovl))
- (forward-line -1)
- (point)))
- (end (save-excursion
- (goto-char (mmm-back-end ovl))
- (forward-line 1)
- (point))))
- (mmm-parse-region beg end)))))
-
-;;}}}
;;{{{ End Current Region
(defun* mmm-end-current-region (&optional arg)
@@ -218,6 +215,22 @@ entire job of this function."
(save-excursion (forward-line 1) (point))))))
;;}}}
+;;{{{ Narrow to Region
+
+(defun mmm-narrow-to-submode-region (&optional pos)
+ "Narrow to the submode region at point."
+ (interactive)
+ ;; Probably don't use mmm-current-overlay here, because this is
+ ;; sometimes called from inside messy functions.
+ (let ((ovl (mmm-overlay-at pos)))
+ (when ovl
+ (narrow-to-region (overlay-start ovl) (overlay-end ovl)))))
+
+;; The inverse command is `widen', usually on `C-x n w'
+
+;;}}}
+
+;; INSERTING REGIONS
;;{{{ Insert regions by keystroke
;; This is the "default" binding in the MMM Mode keymap. Keys defined
@@ -254,7 +267,8 @@ or a symbol such as tab, return, etc. Note that if there are no
MODIFIERS, the dotted list becomes simply BASIC-KEY."
(multiple-value-bind (class skel str) (mmm-get-insertion-spec key)
(when skel
- (let ((after-change-functions nil))
+ (let ((after-change-functions nil)
+ (old-undo buffer-undo-list) undo)
;; XEmacs' skeleton doesn't manage positions by itself, so we
;; have to do it.
(if mmm-xemacs (setq skeleton-positions nil))
@@ -262,31 +276,65 @@ MODIFIERS, the dotted list becomes simply BASIC-KEY."
(destructuring-bind (back end beg front) skeleton-positions
;; TODO: Find a way to trap invalid-parent signals from
;; make-region and undo the skeleton insertion.
- (let* ((match-submode (plist-get class :match-submode))
- (front-str (buffer-substring front beg))
- (back-str (buffer-substring end back))
- (submode
- (if match-submode
- (mmm-save-all (funcall match-submode front-str))
- (plist-get class :submode)))
- (match-face (plist-get class :match-face))
- (face
+ (let ((match-submode (plist-get class :match-submode))
+ (match-face (plist-get class :match-face))
+ (match-name (plist-get class :match-name))
+ (front-form (regexp-quote (buffer-substring front beg)))
+ (back-form (regexp-quote (buffer-substring end back)))
+ submode face name)
+ (setq submode
+ (mmm-modename->function
+ (if match-submode
+ (mmm-save-all (funcall match-submode front-form))
+ (plist-get class :submode))))
+ (setq face
(cond ((functionp match-face)
(mmm-save-all
- (funcall match-face front-str)))
+ (funcall match-face front-form)))
(match-face
- (cdr (assoc front-str match-face)))
+ (cdr (assoc front-form match-face)))
(t
- (plist-get class :face)))))
- (setq submode (mmm-modename->function submode))
+ (plist-get class :face))))
+ (setq name
+ (cond ((plist-get class :skel-name)
+ ;; Optimize the name to the user-supplied str
+ ;; if we are so instructed.
+ str)
+ ;; Call it if it is a function
+ ((functionp match-name)
+ (mmm-save-all (funcall match-name front-form)))
+ ;; Now we know it's a string, does it need to
+ ;; be formatted?
+ ((plist-get class :save-name)
+ ;; Yes. Haven't done a match before, so
+ ;; match the front regexp against the given
+ ;; form to format the string
+ (string-match (plist-get class :front)
+ front-form)
+ (mmm-format-matches match-name front-form))
+ (t
+ ;; No, just use it as-is
+ match-name)))
(mmm-make-region
- submode beg end :front front-str :back back-str
- :face face
+ submode beg end
+ :face face
+ :name name
+ :front front :back back
+ :match-front front-form :match-back back-form
+ :evaporation 'front
;;; :beg-sticky (plist-get class :beg-sticky)
;;; :end-sticky (plist-get class :end-sticky)
:beg-sticky t :end-sticky t
:creation-hook (plist-get class :creation-hook))
- (mmm-enable-font-lock submode)))))))
+ (mmm-enable-font-lock submode)))
+ ;; Now get rid of intermediate undo boundaries, so that the entire
+ ;; insertion can be undone as one action. This should really be
+ ;; skeleton's job, but it doesn't do it.
+ (setq undo buffer-undo-list)
+ (while (not (eq (cdr undo) old-undo))
+ (when (eq (cadr undo) nil)
+ (setcdr undo (cddr undo)))
+ (setq undo (cdr undo)))))))
(defun mmm-get-insertion-spec (key &optional classlist)
"Get the insertion info for KEY from all classes in CLASSLIST.
diff --git a/mmm/mmm-compat.el b/mmm/mmm-compat.el
index d5809e60..d60570b3 100644
--- a/mmm/mmm-compat.el
+++ b/mmm/mmm-compat.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2000 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -28,8 +28,8 @@
;; This file provides a number of hacks that are necessary for MMM
;; Mode to function in different Emacsen. MMM Mode is designed for
-;; Emacs 20, but these hacks usually enable it to work almost
-;; perfectly in Emacs 19 and XEmacs 20 or 21.
+;; FSF Emacs 20 and 21, but these hacks usually enable it to work
+;; almost perfectly in Emacs 19 and XEmacs 20 or 21.
;;; Code:
diff --git a/mmm/mmm-cweb.el b/mmm/mmm-cweb.el
new file mode 100644
index 00000000..ac976344
--- /dev/null
+++ b/mmm/mmm-cweb.el
@@ -0,0 +1,101 @@
+;;; mmm-cweb.el --- MMM submode class for CWeb programs
+
+;; Copyright (C) 2001 by Alan Shutko
+
+;; Author: Alan Shutko <ats@acm.org>
+;; Version: $Id$
+
+;;{{{ GPL
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing CWeb programs.
+
+;;; Code:
+
+(require 'mmm-compat)
+(require 'mmm-vars)
+(require 'mmm-auto)
+
+(defvar mmm-cweb-section-tags
+ '("@ " "@*"))
+
+(defvar mmm-cweb-section-regexp
+ (concat "^" (mmm-regexp-opt mmm-cweb-section-tags t)))
+
+(defvar mmm-cweb-c-part-tags
+ '("@c" "@>=" "@>+=" "@p"))
+
+(defvar mmm-cweb-c-part-regexp
+ (concat (mmm-regexp-opt mmm-cweb-c-part-tags t)))
+
+(defun mmm-cweb-in-limbo (pos)
+ "Check to see if POS is in limbo, ie before any cweb sections."
+ (save-match-data
+ (save-excursion
+ (goto-char pos)
+ (not (re-search-backward mmm-cweb-section-regexp nil t)))))
+
+(defun mmm-cweb-verify-brief-c ()
+ "Verify function for cweb-brief-c class.
+Checks whether the match is in limbo."
+ (not (mmm-cweb-in-limbo (match-beginning 0))))
+
+(mmm-add-group
+ 'cweb
+ `(
+ (cweb-c-part
+ :submode c-mode
+ :front ,mmm-cweb-c-part-regexp
+ :back ,mmm-cweb-section-regexp)
+ (cweb-label
+ :submode tex-mode
+ :front "@<"
+ :back "@>"
+ :face mmm-comment-submode-face
+ :insert ((?l cweb-label nil @ "@<" @ "@>")))
+ (cweb-brief-c
+ :submode c-mode
+ :front "[^\\|]\\(|\\)[^|]"
+ :front-match 1
+ :front-verify mmm-cweb-verify-brief-c
+; :front-offset -1
+ :back "[^\\|]\\(|\\)"
+ :back-match 1
+; :back-offset 1
+ :end-not-begin t
+ :insert ((?| cweb-c-in-tex nil "|" @ "|")))
+ (cweb-comment
+ :submode tex-mode
+ :front "/[*]"
+ :back "[*]/"
+ :face mmm-comment-submode-face)
+))
+
+;; (add-to-list 'mmm-mode-ext-classes-alist
+;; '(plain-tex-mode "\\.w\\'" cweb))
+;; (add-to-list 'mmm-mode-ext-classes-alist
+;; '(latex-mode "\\.w\\'" cweb))
+;; (add-to-list 'auto-mode-alist '("\\.w\\'" . tex-mode))
+
+(provide 'mmm-cweb)
+
+;;; mmm-cweb.el ends here \ No newline at end of file
diff --git a/mmm/mmm-mason.el b/mmm/mmm-mason.el
index 3640726d..a0f57387 100644
--- a/mmm/mmm-mason.el
+++ b/mmm/mmm-mason.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2000 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -96,6 +96,8 @@ Saves the name of the tag matched.")
:front ,mmm-mason-perl-tags-regexp
:back "</%~1>"
:save-matches 1
+ :match-name "~1"
+ :save-name 1
:insert ((?, mason-<%TAG> "Perl section: " @ "<%" str ">" @
";\n" _ "\n" @ "</%" str ">" @)
(?< mason-<%TAG> ?, . nil)
@@ -161,6 +163,13 @@ Saves the name of the tag matched.")
(delete-char 1)))
;;}}}
+;;{{{ Set Mode Line
+
+(defun mmm-mason-set-mode-line ()
+ (setq mmm-buffer-mode-display-name "Mason"))
+(add-hook 'mmm-mason-class-hook 'mmm-mason-set-mode-line)
+
+;;}}}
(provide 'mmm-mason)
diff --git a/mmm/mmm-mode.el b/mmm/mmm-mode.el
index 46f470b7..d133b831 100644
--- a/mmm/mmm-mode.el
+++ b/mmm/mmm-mode.el
@@ -1,12 +1,12 @@
;;; mmm-mode.el --- Allow Multiple Major Modes in a buffer
-;; Copyright (C) 1999 by Michael Abraham Shulman
+;; Copyright (C) 1999, 2004 by Michael Abraham Shulman
;; Emacs Lisp Archive Entry
;; Package: mmm-mode
;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Keywords: convenience, faces, languages, tools
-;; Version: 0.4.7
+;; Version: 0.4.8
;; Revision: $Id$
@@ -78,11 +78,6 @@
;;; any default specified in the arglist will be ignored. Confusion of
;;; this type should be avoided when at all possible.
-;;; By the way, in Elisp CL, there is no reason to use `mapc' over
-;;; `mapcar' unless you need keyword parameters, in which case you
-;;; might as well use `mapcar*'. `mapcar' is an Elisp primitive, so
-;;; it's fast, and `mapc' uses it internally anyway.
-
;;}}}
;;; Code:
@@ -115,197 +110,30 @@ Commands Available:
BASIC CONCEPTS
The idea of MMM Mode is to allow multiple major modes to coexist in
-the same buffer. There is one \"dominant\" or \"default\" major mode
-that controls most of the buffer, and a number of \"submodes\" that
-each hold sway over certain regions. While the point is in a submode
-region, the following changes occur:
+the same buffer. There is one \"primary\" major mode that controls
+most of the buffer, and a number of \"submodes\" that each hold sway
+over certain regions. The submode regions are usually highlighted by
+a background color for ease of recognition. While the point is in a
+submode region, the following changes \(are supposed to) occur:
1. The local keymap is that of the submode.
2. The mode line changes to show what submode region is active.
-3. The major mode menu and popup are that of the submode.
+3. The major mode menu and mouse popup menu are that of the submode.
4. Some local variables of the submode shadow the default mode's.
5. The syntax table and indentation are those of the submode.
6. Font-lock fontifies correctly for the submode.
-7. The submode regions are highlighted by a background color.
-
-These changes are accomplished by adding Emacs Lisp objects called
-\"overlays\" to the buffer to mark the submode regions, and adding a
-`post-command-hook' to update the submode changes that Emacs won't do
-automatically. There are two ways to create the submode regions:
-interactively and automatically. Creating submode regions is referred
-to as \"mmm-ification.\"
-
-
-THE MMM MINOR MODE
-
-The MMM Minor Mode must be on in a buffer for submode regions to be
-effective. Fortunately, it is automagically turned on by any
-mmm-ification, interactive or automatic. When activated, it is denoted
-by \"MMM\" in the mode line. You can also turn it on manually with the
-function `mmm-mode', in which case it mmm-ifies the buffer
-automatically. Do not set the variable `mmm-mode' directly. Turning
-MMM Mode off automatically removes all submode regions from the
-buffer.
-
-MMM Mode has its own keymap, which is bound by default to the prefix
-key \"\\C-c%\". This is a good mnemonic for me since I use MMM Mode to
-edit HTML files with embedded languages such as HTML::Mason, which
-uses the character \"%\" to introduce server-side code. You can
-customize this with the variable `mmm-prefix-key'. When MMM Mode is
-activated, many of the functions discussed below have keyboard
-equivalents, given in parentheses after their name.
-
-
-GETTING STARTED
-
-There are six sample submode classes that come with MMM Mode: Embedded
-CSS in HTML \(requires `css-mode'), Embedded Javascript in HTML
-\(requires `javascript-mode'), HTML in Perl here-documents, the
-HTML::Mason syntax for server-side Perl in HTML, Emacs Lisp in
-\"eval\" file variables, and HTML in PL/SQL \(helpful to have some
-PL/SQL mode).
-
-If one of these is what you need, then all that's necessary is to put
-a line containing \"-*- mmm-classes: CLASS -*-\" at the top of each
-file you want to use MMM Mode in, where CLASS is one of embedded-css,
-javascript, html-here, mason, eval-elisp, or htp-p. After this edit
-you can type M-x normal-mode \(in order to re-parse the file
-variables) and then M-x mmm-mode to activate the appropriate submode
-regions \(assuming MMM Mode is loaded).
-
-I suggest reading my comments on whatever classes you are using. These
-can be found in the file \"mmm-mode\" at the bottom in the appropriate
-section. Hopefully in the future, these will become doc-strings.
-
-If you want to use more than one class in a file, simply set
-`mmm-classes' to a list of symbols rather than a single symbol. If you
-want MMM Mode to be activated automatically whenever you find a file
-with `mmm-classes' set, call `mmm-add-find-file-hook' in your Emacs
-initialization file. \(See \"Loading MMM Mode \", below)
-
-If you want to use one of these submode classes in all buffers with a
-certain major mode or file extension, call `mmm-add-mode-ext-class' in
-your Emacs initialization file. For example, if you want all files
-with the extension .mason to be in html-mode with the MMM class mason
-activated, try this:
-
-\(add-to-list 'auto-mode-alist '(\"\\\\.mason\\\\'\" . html-mode))
-\(mmm-add-mode-ext-class 'html-mode \"\\\\.mason\\\\'\" 'mason)
-
-If none of the supplied classes is what you need, you'll have to write
-your own. Reading through the documentation and looking at the
-supplied classes should help you. You may want to try interactive
-mmm-ification until your regexps or functions are perfected. If your
-class works well and you think others might find it useful, send it to
-me and maybe I'll include it in the next release.
-
-
-INTERACTIVE MMM-IFICATION
-
-There are four functions that create regions interactively:
-`mmm-ify-region' \(\\[mmm-ify-region]), `mmm-ify-by-regexp' \(\\[mmm-ify-by-regexp]),
-`mmm-ify-by-function' \(\\[mmm-ify-by-function]), and `mmm-ify-by-class' \(\\[mmm-ify-by-class]).
-The first adds a region between point and mark. The second adds
-regions throughout the file delimited by regexps. The third adds
-regions as computed by a user-defined function. The fourth adds
-regions as appropriate for a submode class. For more info, see the
-documentation for these functions.
-
-
-AUTOMATIC MMM-IFICATION
-
-Automatic mmm-ification is done by means of \"submode classes.\" A
-submode class is a set of submodes along with methods of adding
-regions for them. These methods can be either a set of regexps
-analogous to the arguments of `mmm-ify-by-regexp', a function which
-could be passed to `mmm-ify-by-function', or another submode class to
-invoke. Whenever automatic mmm-ification takes place \(see below for
-when this occurs), three things happen:
-
-1. All existing submode regions are removed.
-2. All recent interactive mmm-ification is reapplied.
-3. The buffer-local variables `mmm-classes' and `mmm-mode-ext-classes'
- are inspected for classes to mmm-ify the buffer with.
-
-Each class found in the third step is looked up in `mmm-classes-alist'
-to find its associated submode(s), method(s), and face(s), and
-appropriate submode regions are added. To create a class, simply add
-an element to `mmm-classes-alist'. See the documentation for that
-variable for the correct format of elements. The variable
-`mmm-classes' is suitable for setting in a file variables list.
-
-Automatic mmm-ification is done by the functions `mmm-parse-buffer'
-\(\\[mmm-parse-buffer]) and `mmm-parse-region'. These functions can be called
-interactively, and the first has a default key binding. The function
-`mmm-ify-by-all' sets `mmm-mode-ext-classes' appropriately for the
-current buffer by looking in `mmm-mode-ext-classes-alist'. The
-function `mmm-add-find-file-hook' adds `mmm-ify-by-all' to
-`find-file-hooks' for which it is well suited.
-
-
-LOADING MMM MODE
-
-Suggested lines for a .emacs file are:
-
-\(require 'mmm-mode)
-\(mmm-add-find-file-hook)
-
-Autoloading MMM Mode is not particularly useful if you want Automatic
-MMM-ification by classes to occur whenever you find a file which has
-the local variable `mmm-classes' set or a mode/extension in
-`mmm-mode-ext-classes-alist', since MMM Mode would have to be loaded
-as soon as you find a file. But if you only activate MMM Mode
-interactively, you can autoload it as follows:
-
-\(autoload 'mmm-mode \"mmm-mode\" \"Multiple Major Modes\" t)
-\(autoload 'mmm-parse-buffer \"mmm-mode\" \"Automatic MMM-ification\" t)
-
-and similar lines for any other functions you want to call directly.
-
-
-MISCELLANY
-
-After you type a new region that should be a submode, you can run the
-function `mmm-parse-block' \(\\[mmm-parse-block]) to detect it with automatic
-mmm-ification.
-
-The function `mmm-clear-overlays' \(\\[mmm-clear-overlays]) removes all submode regions
-in the current buffer, without turning off MMM Mode. It clears the
-history of interactive mmm-ification, but does not change the value of
-`mmm-classes'.
-
-
-CUSTOMIZATION
-
-Besides those already discussed, there are a number of variables that
-can be used to customize MMM Mode. The appearance can be customized
-with the variables `mmm-default-submode-face', `mmm-mode-string', and
-`mmm-submode-mode-line-format', which see for further information.
-
-The variable `mmm-save-local-variables' controls what buffer-local
-variables are saved for submodes. This is how comments are handled,
-for instance. You can add variable names to this list--see its
-documentation for details. Often something that seems like a problem
-with MMM Mode can be solved by simply saving an extra variable.
-
-When entering MMM Mode, the hook `mmm-mode-hook' is run. A hook named
-<major-mode>-mmm-hook is also run, if it exists. For example,
-`html-mode-mmm-hook' is run whenever MMM Mode is entered in HTML mode.
-Furhermore, a hook named <submode>-submode-hook is run whenever a
-submode region of a given mode is created. For example,
-`cperl-mode-submode-hook' is run whenever a CPerl mode submode region
-is created, in any buffer. When submode hooks are run, point is
-guaranteed to be at the start of the newly created submode region.
-
-All these, and some others, can be reached through M-x customize under
-Programming | Tools | Mmm, except the major mode and submode hooks
-\(obviously)."
+For further information, including installation and configuration
+instructions, see the Info file mmm.info which is included with the
+distribution of MMM Mode. Many of MMM's configuration variables are
+available through M-x customize under Programming | Tools | Mmm."
(interactive "P")
(if (if arg (> (prefix-numeric-value arg) 0) (not mmm-mode))
(mmm-mode-on)
(mmm-mode-off)))
+(add-to-list 'minor-mode-alist (list 'mmm-mode mmm-mode-string))
+
;;}}}
;;{{{ Mode On
@@ -319,6 +147,8 @@ Programming | Tools | Mmm, except the major mode and submode hooks
(mmm-valid-buffer
(unless mmm-mode
(setq mmm-primary-mode major-mode)
+ (when (fboundp 'c-make-styles-buffer-local)
+ (c-make-styles-buffer-local t))
(mmm-update-mode-info major-mode)
(setq mmm-region-saved-locals-for-dominant
(list* (list 'font-lock-cache-state nil)
@@ -336,13 +166,12 @@ Programming | Tools | Mmm, except the major mode and submode hooks
(setq mmm-mode t)
(condition-case err
(mmm-apply-all)
- (mmm-invalid-submode-class
+ (mmm-error
;; Complain, but don't die, since we want files to go ahead
;; and be opened anyway, and the mode to go ahead and be
;; turned on. Should we delete all previously made submode
;; regions when we find an invalid one?
(message "%s" (error-message-string err))))
- (mmm-update-current-submode)
(run-hooks 'mmm-mode-hook)
(mmm-run-major-hook))))
@@ -365,9 +194,11 @@ Programming | Tools | Mmm, except the major mode and submode hooks
(get mmm-primary-mode 'mmm-beginning-of-syntax-function))
(mmm-update-font-lock-buffer)
(mmm-refontify-maybe)
- (setq mmm-mode nil)))
-
-(add-to-list 'minor-mode-alist (list 'mmm-mode mmm-mode-string))
+ (setq mmm-mode nil)
+ ;; Restore the mode line
+ (setq mmm-primary-mode-display-name nil
+ mmm-buffer-mode-display-name nil)
+ (mmm-set-mode-line)))
;;}}}
;;{{{ Mode Keymap
@@ -381,8 +212,8 @@ Programming | Tools | Mmm, except the major mode and submode hooks
(defvar mmm-mode-menu-map (make-sparse-keymap "MMM")
"Keymap for MMM Minor Mode menu.")
-(defun mmm-define-key (key binding)
- (define-key mmm-mode-prefix-map
+(defun mmm-define-key (key binding &optional keymap)
+ (define-key (or keymap mmm-mode-prefix-map)
(vector (append mmm-command-modifiers (list key)))
binding))
@@ -402,6 +233,8 @@ Programming | Tools | Mmm, except the major mode and submode hooks
(mmm-define-key ?\ 'mmm-reparse-current-region)
(mmm-define-key ?e 'mmm-end-current-region)
+(mmm-define-key ?z 'mmm-narrow-to-submode-region)
+
;; This one is exact, since C-h is (usually) already used for help.
(define-key mmm-mode-prefix-map [?h] 'mmm-insertion-help)
diff --git a/mmm/mmm-noweb.el b/mmm/mmm-noweb.el
new file mode 100644
index 00000000..ec0e5d3e
--- /dev/null
+++ b/mmm/mmm-noweb.el
@@ -0,0 +1,410 @@
+;;; mmm-noweb.el --- MMM submode class for Noweb programs
+;;
+;; Copyright 2003, 2004 Joe Kelsey <joe@zircon.seattle.wa.us>
+;;
+;; The filling, completion and chunk motion commands either taken
+;; directly from or inspired by code in:
+;; noweb-mode.el - edit noweb files with GNU Emacs
+;; Copyright 1995 by Thorsten.Ohl @ Physik.TH-Darmstadt.de
+;; with a little help from Norman Ramsey <norman@bellcore.com>
+;;
+
+;;{{{ GPL
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing Noweb programs.
+
+;;; Code:
+
+(require 'mmm-region)
+(require 'mmm-vars)
+(require 'mmm-mode)
+
+;;{{{ Variables
+
+(defvar mmm-noweb-code-mode 'fundamental-mode
+ "*Major mode for editing code chunks.
+This is set to FUNDAMENTAL-MODE by default, but you might want to change
+this in the Local Variables section of your file to something more
+appropriate, like C-MODE, FORTRAN-MODE, or even INDENTED-TEXT-MODE.")
+
+(defvar mmm-noweb-quote-mode nil
+ "*Major mode for quoted code chunks within documentation chunks.
+If nil, defaults to `mmm-noweb-code-mode', which see.")
+
+(defvar mmm-noweb-quote-string "quote"
+ "*String used to form quoted code submode region names.
+See `mmm-noweb-quote'.")
+
+(defvar mmm-noweb-quote-number 0
+ "*Starting value appended to `mmm-noweb-quote-string'.
+See `mmm-noweb-quote'.")
+
+(defvar mmm-noweb-narrowing nil
+ "*Narrow the region to the current pair of chunks.")
+
+;;}}}
+;;{{{ Support for mmm submode stuff
+
+(defun mmm-noweb-chunk (form)
+ "Return the noweb code mode chosen by the user.
+If the next 100 characters of the buffer contain a string of the form
+\"-*- MODE -*-\", then return MODE as the chosen mode, otherwise
+return the value of `mmm-noweb-code-mode'."
+ ;; Look for -*- mode -*- in the first two lines.
+ ;; 120 chars = 40 chars for #! + 80 chars for following line...
+ (if (re-search-forward "-\\*-\\s +\\(\\S-+\\)\\s +-\\*-" (+ (point) 120) t)
+ (let* ((string (match-string-no-properties 1))
+ (modestr (intern (if (string-match "mode\\'" string)
+ string
+ (concat string "-mode")))))
+ (or (mmm-ensure-modename modestr)
+ mmm-noweb-code-mode))
+ mmm-noweb-code-mode))
+
+(defun mmm-noweb-quote (form)
+ "Create a unique name for a quoted code region within a documentation chunk."
+ (or mmm-noweb-quote-mode
+ mmm-noweb-code-mode))
+
+(defun mmm-noweb-quote-name (form)
+ "Create a unique name for a quoted code region within a documentation chunk."
+ (setq mmm-noweb-quote-number (1+ mmm-noweb-quote-number))
+ (concat mmm-noweb-quote-string "-"
+ (number-to-string mmm-noweb-quote-number)))
+
+(defun mmm-noweb-chunk-name (form)
+ "Get the chunk name from FRONT-FORM."
+ (string-match "<<\\(.*\\)>>=" form)
+ (match-string-no-properties 1 form))
+
+;;}}}
+;;{{{ mmm noweb submode group
+
+;; We assume that the global document mode is latex or whatever, the
+;; user wants. This class controls the code chunk submodes. We use
+;; match-submode to either return the value in mmm-noweb-code-mode or to
+;; look at the first line of the chunk for a submode setting. We reset
+;; case-fold-search because chunk names are case sensitive. The front
+;; string identifies the chunk name between the <<>>. Since this is
+;; done, name-match can use the same functions as save-matches for back.
+;; Our insert skeleton places a new code chunk and the skel-name lets us
+;; optimize the skelton naming to use the inserted string.
+
+(mmm-add-group
+ 'noweb
+ '((noweb-chunk
+ :match-submode mmm-noweb-chunk
+ :case-fold-search nil
+ :front "^<<\\(.*\\)>>="
+ :match-name "~1"
+ :save-name 1
+ :front-offset (end-of-line 1)
+ :back "^@\\( \\|$\\|\\( %def .*$\\)\\)"
+ :insert ((?c noweb-code "Code Chunk Name: "
+ "\n" @ "<<" str ">>=" @ "\n" _ "\n" @ "@ " @ "\n"))
+ :skel-name t
+ )
+ (noweb-quote
+ :match-submode mmm-noweb-quote
+ :face mmm-special-submode-face
+ :front "\\[\\["
+; :name-match mmm-noweb-quote-name
+ :back "\\]\\]"
+ :insert ((?q noweb-quote nil @ "[[" @ _ @ "]]" @))
+ )
+ ))
+
+;;}}}
+;;{{{ Noweb regions
+
+(defun mmm-noweb-regions (start stop regexp &optional delim)
+ "Return a liat of regions of the form \(NAME BEG END) that exclude
+names which match REGEXP."
+ (let* ((remove-next nil)
+ (regions
+ (maplist #'(lambda (pos-list)
+ (if (cdr pos-list)
+ (if remove-next
+ (setq remove-next nil)
+ (let ((name (or (mmm-name-at (car pos-list) 'beg)
+ (symbol-name mmm-primary-mode))))
+ (if (and regexp (string-match regexp name) )
+ (progn
+ (setq remove-next t)
+ nil)
+ (list name
+ (car pos-list) (cadr pos-list)))))))
+ (mmm-submode-changes-in start stop t delim))))
+ ;; The above loop leaves lots of nils in the list...
+ ;; Removing them saves us from having to do the (last x 2)
+ ;; trick that mmm-regions-in does.
+ (setq regions (delq nil regions))))
+
+;;}}}
+;;{{{ Filling, etc
+
+(defun mmm-noweb-narrow-to-doc-chunk ()
+ "Narrow to the current doc chunk.
+The current chunk includes all quoted code chunks (i.e., \[\[...\]\]).
+This function is only valid when called with point in a doc chunk or
+quoted code chunk."
+ (interactive)
+ (let ((name (mmm-name-at (point))))
+ (if (or (null name) (string-match "^quote" name))
+ (let ((prev (cond
+ ((= (point) (point-min)) (point))
+ (t (cadar (last (mmm-noweb-regions (point-min) (point)
+ "^quote"))))))
+ (next (cond
+ ((= (point) (point-max)) (point))
+ (t (save-excursion
+ (goto-char (cadr
+ (cadr (mmm-noweb-regions (point)
+ (point-max)
+ "^quote"))))
+ (forward-line -1)
+ (point))))))
+ (narrow-to-region prev next)))))
+
+(defun mmm-noweb-fill-chunk (&optional justify)
+ "Fill the current chunk according to mode.
+Run `fill-region' on documentation chunks and `indent-region' on code
+chunks."
+ (interactive "P")
+ (save-restriction
+ (let ((name (mmm-name-at (point))))
+ (if (and name (not (string-match "^quote" name)))
+ (if (or indent-region-function indent-line-function)
+ (progn
+ (mmm-space-other-regions)
+ (indent-region (overlay-start mmm-current-overlay)
+ (overlay-end mmm-current-overlay) nil))
+ (error "No indentation functions defined in %s!" major-mode))
+ (progn
+ (mmm-word-other-regions)
+ (fill-paragraph justify)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-fill-paragraph-chunk (&optional justify)
+ "Fill a paragraph in the current chunk."
+ (interactive "P")
+ (save-restriction
+ (let ((name (mmm-name-at (point))))
+ (if (and name (not (string-match "^quote" name)))
+ (progn
+ (mmm-space-other-regions)
+ (fill-paragraph justify))
+ (progn
+ (mmm-word-other-regions)
+ (fill-paragraph justify)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-fill-named-chunk (&optional justify)
+ "Fill the region containing the named chunk."
+ (interactive "P")
+ (save-restriction
+ (let* ((name (or (mmm-name-at) (symbol-name mmm-primary-mode)))
+ (list (cdr (assoc name (mmm-names-alist (point-min) (point-max))))))
+ (if (or (string= name (symbol-name mmm-primary-mode))
+ (string-match "^quote" name))
+ (progn
+ (mmm-word-other-regions)
+ (do-auto-fill))
+ (progn
+ (mmm-space-other-regions)
+ (indent-region (caar list) (cadar (last list)) nil)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-auto-fill-doc-chunk ()
+ "Replacement for `do-auto-fill'."
+ (save-restriction
+ (mmm-noweb-narrow-to-doc-chunk)
+ (mmm-word-other-regions)
+ (do-auto-fill)
+ (mmm-undo-syntax-other-regions)))
+
+(defun mmm-noweb-auto-fill-doc-mode ()
+ "Install the improved auto fill function, iff necessary."
+ (if auto-fill-function
+ (setq auto-fill-function 'mmm-noweb-auto-fill-doc-chunk)))
+
+(defun mmm-noweb-auto-fill-code-mode ()
+ "Install the default auto fill function, iff necessary."
+ (if auto-fill-function
+ (setq auto-fill-function 'do-auto-fill)))
+
+;;}}}
+;;{{{ Functions on named chunks
+
+(defun mmm-noweb-complete-chunk ()
+ "Try to complete the chunk name."
+ (interactive)
+ (let ((end (point))
+ (beg (save-excursion
+ (if (re-search-backward "<<"
+ (save-excursion
+ (beginning-of-line)
+ (point))
+ t)
+ (match-end 0)
+ nil))))
+ (if beg
+ (let* ((pattern (buffer-substring beg end))
+ (alist (mmm-names-alist (point-min) (point-max)))
+ (completion (try-completion pattern alist)))
+ (cond ((eq completion t))
+ ((null completion)
+ (message "Can't find completion for \"%s\"" pattern)
+ (ding))
+ ((not (string= pattern completion))
+ (delete-region beg end)
+ (insert completion)
+ (if (not (looking-at ">>"))
+ (insert ">>")))
+ (t
+ (message "Making completion list...")
+ (with-output-to-temp-buffer "*Completions*"
+ (display-completion-list
+ (all-completions pattern alist)))
+ (message "Making completion list...%s" "done"))))
+ (message "Not at chunk name..."))))
+
+(defvar mmm-noweb-chunk-history nil
+ "History for `mmm-noweb-goto-chunk'.")
+
+(defun mmm-noweb-goto-chunk ()
+ "Goto the named chunk."
+ (interactive)
+ (widen)
+ (let* ((completion-ignore-case t)
+ (alist (mmm-names-alist (point-min) (point-max)))
+ (chunk (completing-read
+ "Chunk: " alist nil t
+ (mmm-name-at (point))
+ mmm-noweb-chunk-history)))
+ (goto-char (caadr (assoc chunk alist)))))
+
+(defun mmm-noweb-goto-next (&optional cnt)
+ "Goto the continuation of the current chunk."
+ (interactive "p")
+ (widen)
+ (let ((name (mmm-name-at (point))))
+ (if name
+ (let ((list (cdr (assoc name (mmm-names-alist
+ (overlay-end mmm-current-overlay)
+ (point-max))))))
+ (if list
+ (goto-char (caar (nthcdr (1- cnt) list))))))))
+
+(defun mmm-noweb-goto-previous (&optional cnt)
+ "Goto the continuation of the current chunk."
+ (interactive "p")
+ (widen)
+ (let ((name (mmm-name-at (point))))
+ (if name
+ (let ((list (reverse
+ (cdr (assoc name
+ (mmm-names-alist (point-min)
+ (overlay-start
+ mmm-current-overlay)))))))
+ (if list
+ (goto-char (cadar (nthcdr cnt list))))))))
+
+;;}}}
+;;{{{ Key mappings
+
+(defvar mmm-noweb-map (make-sparse-keymap))
+(defvar mmm-noweb-prefix-map (make-sparse-keymap))
+(define-key mmm-noweb-map mmm-mode-prefix-key mmm-noweb-prefix-map)
+
+(mmm-define-key ?d 'mmm-noweb-narrow-to-doc-chunk mmm-noweb-prefix-map)
+(mmm-define-key ?n 'mmm-noweb-goto-next mmm-noweb-prefix-map)
+(mmm-define-key ?p 'mmm-noweb-goto-previous mmm-noweb-prefix-map)
+(mmm-define-key ?q 'mmm-noweb-fill-chunk mmm-noweb-prefix-map)
+;; Cannot use C-g as goto command, so use C-s.
+(mmm-define-key ?s 'mmm-noweb-goto-chunk mmm-noweb-prefix-map)
+
+(define-key mmm-noweb-prefix-map "\t" 'mmm-noweb-complete-chunk)
+
+;; Don't want to add to either the mmm mode map (used in other mmm
+;; buffers) or the local map (used in other major mode buffers), so we
+;; make a full-buffer spanning overlay and add the map there.
+(defun mmm-noweb-bind-keys ()
+ (save-restriction
+ (widen)
+ (let ((ovl (make-overlay (point-min) (point-max) nil nil t)))
+ ;; 'keymap', not 'local-map'
+ (overlay-put ovl 'keymap mmm-noweb-map))))
+
+(add-hook 'mmm-noweb-class-hook 'mmm-noweb-bind-keys)
+
+;; TODO: make this overlay go away if mmm is turned off
+
+;;}}}
+
+;; These functions below living here temporarily until a real place is
+;; found.
+
+(defun mmm-syntax-region-list (syntax regions)
+ "Apply SYNTAX to a list of REGIONS of the form (BEG END).
+If SYNTAX is not nil, set the syntax-table property of each region.
+If SYNTAX is nil, remove the region syntax-table property.
+See `mmm-syntax-region'."
+ (mapcar #'(lambda (reg)
+ (mmm-syntax-region (car reg) (cadr reg) syntax))
+ regions))
+
+(defun mmm-syntax-other-regions (syntax &optional name)
+ "Apply SYNTAX cell to other regions.
+Regions are separated by name, using either `mmm-name-at' or the
+optional NAME to determine the current region name."
+ (if (null name)
+ (setq name (or (mmm-name-at)
+ (symbol-name mmm-primary-mode))))
+ (mapcar #'(lambda (reg)
+ (if (not (string= (car reg) name))
+ (mmm-syntax-region-list syntax (cdr reg))))
+ (mmm-names-alist (point-min) (point-max))))
+
+(defun mmm-word-other-regions ()
+ "Give all other regions word syntax."
+ (interactive)
+ (mmm-syntax-other-regions '(2 . 0))
+ (setq parse-sexp-lookup-properties t))
+
+(defun mmm-space-other-regions ()
+ "Give all other regions space syntax."
+ (interactive)
+ (mmm-syntax-other-regions '(0 . 0))
+ (setq parse-sexp-lookup-properties t))
+
+(defun mmm-undo-syntax-other-regions ()
+ "Remove syntax-table property from other regions."
+ (interactive)
+ (mmm-syntax-other-regions nil)
+ (setq parse-sexp-lookup-properties nil))
+
+
+(provide 'mmm-noweb)
+
+;;; mmm-noweb.el ends here \ No newline at end of file
diff --git a/mmm/mmm-region.el b/mmm/mmm-region.el
index 073a658b..d1622a52 100644
--- a/mmm/mmm-region.el
+++ b/mmm/mmm-region.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2000 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -31,6 +31,9 @@
;; behave like the submode with respect to syntax tables, local maps,
;; font lock, etc.
+;; See mmm-class.el for functions which scan the buffer and decide
+;; where to create regions.
+
;;; Code:
(require 'cl)
@@ -48,54 +51,100 @@
;; end-stickiness to determine whether an endpoint is within an
;; extent. Here we want to act like XEmacs does.
-(defun mmm-overlay-at (&optional pos type)
+(defsubst mmm-overlay-at (&optional pos type)
"Return the highest-priority MMM Mode overlay at POS.
-TYPE is passed on to `mmm-overlays-at', which see."
- (car (mmm-overlays-at (or pos (point)) type)))
+See `mmm-included-p' for the values of TYPE."
+ (car (mmm-overlays-at pos type)))
(defun mmm-overlays-at (&optional pos type)
"Return a list of the MMM overlays at POS, in decreasing priority.
-TYPE should be nil, `beg', `end', `none', or `all'. If `none', return
-only overlays strictly including POS. If nil, return overlays starting
-at POS only if they are beg-sticky, and those ending at POS only if
-they are end-sticky. If `beg', return all overlays starting at POS but
-none ending at POS, if `end', return all overlays ending at POS
-but none starting at POS, and if `all', return both."
+See `mmm-included-p' for the values of TYPE."
(or pos (setq pos (point)))
- (remove-if-not #'(lambda (ovl)
- (mmm-included-p ovl pos type))
- (mmm-overlays-in (1- pos) (1+ pos))))
-
-(defun mmm-included-p (ovl pos type)
- (cond ((eql (overlay-start ovl) pos)
- (case type
- ((none end) nil)
- ((nil) (overlay-get ovl 'beg-sticky))
- ((beg all) t)))
- ((eql (overlay-end ovl) pos)
- (case type
- ((none beg) nil)
- ((nil) (overlay-get ovl 'end-sticky))
- ((end all) t)))
- (t t)))
-
-(defun mmm-overlays-in (start stop &optional strict delim)
- "Return the MMM overlays in START to STOP, in decreasing priority.
-If STRICT is non-nil, include only those overlays which are entirely
-contained in the region. In this case, if DELIM is non-nil, the
-region delimiters, if any, must also be included."
(mmm-sort-overlays
- (remove-if-not #'(lambda (ovl)
- (and (overlay-get ovl 'mmm)
- (or (not strict)
- (>= stop (if delim
- (mmm-back-end ovl)
- (overlay-end ovl)))
- (<= start (if delim
- (mmm-front-start ovl)
- (overlay-start ovl))))))
- (overlays-in (max start (point-min))
- (min stop (point-max))))))
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (mmm-included-p ovl pos type)))
+ ;; XEmacs complains about positions outside the buffer
+ (overlays-in (max (1- pos) (point-min))
+ (min (1+ pos) (point-max))))))
+
+(defun mmm-included-p (ovl pos &optional type)
+ "Return true if the overlay OVL contains POS.
+
+If OVL strictly contains POS, always return true. If OVL starts or
+ends at POS, return true or false based on the value of TYPE, which
+should be one of nil, `beg', `end', `none', or `all'.
+* If TYPE is nil, return true for an overlay starting at POS only if
+ it is beg-sticky, and for one ending at POS only if it is end-sticky.
+* If TYPE is `beg', return true for any overlay starting at POS but
+ false for any ending at POS.
+* If TYPE is `end', return true for any overlay ending at POS but
+ false for any starting at POS.
+* If TYPE is `all', return true for any overlay starting or ending at POS.
+* If TYPE is `none' \(or any other value), return false for any
+ overlay starting or ending at POS."
+ (let ((beg (overlay-start ovl))
+ (end (overlay-end ovl)))
+ (cond ((and (= beg pos) (= end pos))
+ ;; Do the Right Thing for zero-width overlays
+ (case type
+ ((nil) (and (overlay-get ovl 'beg-sticky)
+ (overlay-get ovl 'end-sticky)))
+ ((none) nil)
+ (t t)))
+ ((= beg pos)
+ (case type
+ ((nil) (overlay-get ovl 'beg-sticky))
+ ((beg all) t)
+ (t nil)))
+ ((= end pos)
+ (case type
+ ((nil) (overlay-get ovl 'end-sticky))
+ ((end all) t)
+ (t nil)))
+ ((and (> end pos) (< beg pos))
+ t))))
+
+;;; `mmm-overlays-in' has been retired as altogether too confusing a
+;;; name, when what is really meant is one of the following three:
+
+(defun mmm-overlays-containing (start stop)
+ "Return all MMM overlays containing the region START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (<= (overlay-start ovl) start)
+ (>= (overlay-end ovl) stop)))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
+
+(defun mmm-overlays-contained-in (start stop)
+ "Return all MMM overlays entirely contained in START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (>= (overlay-start ovl) start)
+ (<= (overlay-end ovl) stop)))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
+
+(defun mmm-overlays-overlapping (start stop)
+ "Return all MMM overlays overlapping the region START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (overlay-get ovl 'mmm))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
(defun mmm-sort-overlays (overlays)
"Sort OVERLAYS in order of decreasing priority."
@@ -127,9 +176,17 @@ Set by `mmm-update-current-submode'.")
(make-variable-buffer-local 'mmm-previous-submode)
(defun mmm-update-current-submode (&optional pos)
- "Update current and previous position variables to POS.
-Return non-nil if the current region changed."
- (let ((ovl (mmm-overlay-at (or pos (point)))))
+ "Update current and previous position variables to POS, or point.
+Return non-nil if the current region changed.
+
+Also deletes overlays that ought to evaporate because their delimiters
+have disappeared."
+ (mapc #'delete-overlay
+ (remove-if #'(lambda (ovl)
+ (or (not (eq (overlay-get ovl 'mmm-evap) 'front))
+ (overlay-buffer (overlay-get ovl 'front))))
+ (mmm-overlays-at pos)))
+ (let ((ovl (mmm-overlay-at pos)))
(if (eq ovl mmm-current-overlay)
nil
(setq mmm-previous-overlay mmm-current-overlay
@@ -138,6 +195,7 @@ Return non-nil if the current region changed."
mmm-current-submode (if ovl (overlay-get ovl 'mmm-mode)))
t)))
+;; This function is, I think, mostly for hacking font-lock.
(defun mmm-set-current-submode (mode &optional pos)
"Set the current submode to MODE and the current region to whatever
region of that mode is present at POS, or nil if none."
@@ -151,146 +209,258 @@ region of that mode is present at POS, or nil if none."
(defun mmm-submode-at (&optional pos type)
"Return the submode at POS \(or point), or NIL if none.
-TYPE is passed on to `mmm-overlays-at', which see."
- (let ((ovl (mmm-overlay-at (or pos (point)) type)))
+See `mmm-included-p' for values of TYPE."
+ (let ((ovl (mmm-overlay-at pos type)))
(if ovl (overlay-get ovl 'mmm-mode))))
;;}}}
-;;{{{ Match Front & Back
+;;{{{ Delimiter Matching and Boundaries
(defun mmm-match-front (ovl)
"Return non-nil if the front delimiter of OVL matches as it should.
-Sets the match data to the front delimiter, if it is a regexp,
-otherwise calls it as a function with point at the beginning of the
-overlay and one argument being the overlay. The function should return
-non-nil if the front delimiter matches correctly, and set the match
-data appropriately."
- (let ((front (overlay-get ovl 'front)))
- (save-excursion
- (goto-char (overlay-start ovl))
- (if (stringp front)
- ;; It's a regexp
- (mmm-looking-back-at front)
- ;; It's a function
- (funcall front ovl)))))
+Sets the match data to the front delimiter, if it is a regexp.
+Otherwise, calls it as a function with point at the beginning of the
+front delimiter overlay \(i.e. where the front delimiter ought to
+start) and one argument being the region overlay. The function should
+return non-nil if the front delimiter matches correctly, and set the
+match data appropriately."
+ (let* ((front-ovl (overlay-get ovl 'front))
+ (front (if front-ovl (overlay-get front-ovl 'match))))
+ (when front
+ (save-excursion
+ (goto-char (overlay-start front-ovl))
+ (if (stringp front)
+ ;; It's a regexp
+ (looking-at front)
+ ;; It's a function
+ (funcall front ovl))))))
(defun mmm-match-back (ovl)
"Return non-nil if the back delimiter of OVL matches as it should.
-Sets the match data to the back delimiter, if it is a regexp,
-otherwise calls it as a function with point at the end of the overlay
-and one argument being the overlay. The function should return non-nil
-if the back delimiter matches correctly, and set the match data
-appropriately."
- (let ((back (overlay-get ovl 'back)))
- (save-excursion
- (goto-char (overlay-end ovl))
- (if (stringp back)
- ;; It's a regexp
- (looking-at back)
- (funcall back ovl)))))
-
-;;}}}
-;;{{{ Delimiter Boundaries
+Sets the match data to the back delimiter, if it is a regexp.
+Otherwise, calls it as a function with point at the beginning of the
+back delimiter overlay \(i.e. where the back delimiter ought to start)
+and one argument being the region overlay. The function should return
+non-nil if the back delimiter matches correctly, and set the match
+data appropriately."
+ (let* ((back-ovl (overlay-get ovl 'back))
+ (back (if back-ovl (overlay-get back-ovl 'match))))
+ (when back
+ (save-excursion
+ (goto-char (overlay-start back-ovl))
+ (if (stringp back)
+ ;; It's a regexp
+ (looking-at back)
+ ;; It's a function
+ (funcall back ovl))))))
(defun mmm-front-start (ovl)
- "Return the position at which the front delimiter of OVL starts.
-If OVL is not front-bounded correctly, return its start position."
- (save-match-data
- (if (mmm-match-front ovl)
- (match-beginning 0)
+ "Return the position at which the front delimiter of OVL starts."
+ (let ((front (overlay-get ovl 'front)))
+ ;; Overlays which have evaporated become "overlays in no buffer"
+ (if (and front (overlay-buffer front))
+ (overlay-start front)
(overlay-start ovl))))
(defun mmm-back-end (ovl)
- "Return the position at which the back delimiter of OVL ends.
-If OVL is not back-bounded correctly, return its end position."
- (save-match-data
- (if (mmm-match-back ovl)
- (match-end 0)
+ "Return the position at which the back delimiter of OVL ends."
+ (let ((back (overlay-get ovl 'back)))
+ ;; Overlays which have evaporated become "overlays in no buffer"
+ (if (and back (overlay-buffer back))
+ (overlay-end back)
(overlay-end ovl))))
;;}}}
;; CREATION & DELETION
-;;{{{ Markers
-
-(defun mmm-make-marker (pos beg-p sticky-p)
- "Make a marker at POS that is or isn't sticky.
-BEG-P represents whether the marker delimits the beginning of a
-region \(or the end of it). STICKY-P is whether it should be sticky,
-i.e. whether text inserted at the marker should be inside the region."
- (let ((mkr (set-marker (make-marker) pos)))
- (set-marker-insertion-type mkr (if beg-p (not sticky-p) sticky-p))
- mkr))
-
-;;}}}
;;{{{ Make Submode Regions
+(defun mmm-valid-submode-region (submode beg end)
+ "Check if the region between BEG and END is valid for SUBMODE.
+This region must be entirely contained within zero or more existing
+submode regions, none of which start or end inside it, and it must be
+a valid child of the highest-priority of those regions, if any.
+Signals errors, returns `t' if no error."
+ ;; First check if the placement is valid. Every existing region
+ ;; that overlaps this one must contain it in its entirety.
+ (let ((violators (set-difference
+ (mmm-overlays-overlapping beg end)
+ (mmm-overlays-containing beg end))))
+ (if violators
+ (signal 'mmm-subregion-invalid-placement
+ violators)))
+ ;; Now check if it is inside a valid parent
+ (let ((parent-mode (mmm-submode-at beg 'beg)))
+ (and parent-mode
+ ;; TODO: Actually check parents here. For present purposes,
+ ;; we just make sure we aren't putting a submode inside one
+ ;; of the same type. Actually, what we should really be
+ ;; doing is checking classes/names of regions, not just the
+ ;; submodes.
+ (eq submode parent-mode)
+ (signal 'mmm-subregion-invalid-parent
+ (list parent-mode))))
+ t)
+
(defun* mmm-make-region
- (submode beg end &rest rest &key (front "") (back "")
- (beg-sticky t) (end-sticky t) face creation-hook
- &allow-other-keys
+ (submode beg end &key face
+ front back (evaporation 'front)
+ delimiter-mode front-face back-face
+ display-name
+ (match-front "") (match-back "")
+ (beg-sticky t) (end-sticky t)
+ name creation-hook
)
- "Make a submode region from BEG to END of SUBMODE in FACE.
-FRONT and BACK are regexps or functions to match the correct
-delimiters--see `mmm-match-front' and `mmm-match-back'. BEG-STICKY
-and END-STICKY determine whether the front and back of the region,
-respectively, are sticky with respect to new insertion. CREATION-HOOK
-should be a function to run after the region is created. All other
-keyword arguments are stored as properties of the overlay,
-un-keyword-ified."
- (setq rest (append rest (list :front front :back back :beg-sticky
- beg-sticky :end-sticky end-sticky)))
- (mmm-mode-on)
- ;; For now, complain about overlapping regions. Most callers should
- ;; trap this and continue on. In future, submode regions will be
- ;; allowed to sit inside others.
- (when (mmm-overlays-in beg end)
- (signal 'mmm-invalid-parent nil))
+ "Make a submode region from BEG to END of SUBMODE.
+
+BEG and END are buffer positions or markers with BEG <= END \(although
+see EVAPORATION below). SUBMODE is a major mode function or a valid
+argument to `mmm-modename->function'. FACE is a valid display face.
+
+FRONT and BACK specify the positions of the front and back delimiters
+for this region, if any. If FRONT is a buffer position or marker, the
+front delimiter runs from it to BEG. FRONT can also be a two-element
+list \(FRONT-BEG FRONT-END) specifying the exact position of the front
+delimiter. One must have FRONT-BEG < FRONT-END <= BEG.
+
+Similarly, BACK may be a buffer position or marker, in which case the
+back delimiter runs from END to BACK. BACK can also be a two-element
+list \(BACK-BEG BACK-END) specifying the exact position, in which case
+we must have END <= BACK-BEG < BACK-END.
+
+EVAPORATION specifies under what conditions this submode region should
+disappear.
+* If `nil', the region never disappears. This can cause serious
+ problems when using cut-and-paste and is not recommended.
+* If the value is t, the region disappears whenever it has zero
+ length. This is recommended for manually created regions used for
+ temporary editing convenience.
+* If the value is `front', the region will disappear whenever the text
+ in its front delimiter disappears, that is, whenever the overlay
+ which marks its front delimiter has zero width.
+The default value is `front'. However, if the parameter FRONT is nil,
+then this makes no sense, so the default becomes `t'. Note that if
+EVAPORATION is `t', then an error is signalled if BEG = END.
+
+MATCH-FRONT \(resp. MATCH-BACK) is a regexp or function to match the
+correct delimiters, see `mmm-match-front' \(resp. `mmm-match-back').
+It is ignored if FRONT \(resp. BACK) is nil. At present these are not
+used much.
+
+DELIMITER-MODE specifies the major mode to use for delimiter regions.
+A `nil' value means they remain in the primary mode.
+
+FACE, FRONT-FACE, and BACK-FACE, are faces to use for the region, the
+front delimiter, and the back delimiter, respectively, under high
+decoration \(see `mmm-submode-decoration-level').
+
+BEG-STICKY and END-STICKY determine whether the front and back of the
+region, respectively, are sticky with respect to new insertion. The
+default is yes.
+
+NAME is a string giving the \"name\" of this submode region. Submode
+regions with the same name are considered part of the same code
+fragment and formatted accordingly.
+
+DISPLAY-NAME is a string to display in the mode line when point is in
+this submode region. If nil or not given, the name associated with
+SUBMODE is used. In delimiter regions, \"--\" is shown.
+
+CREATION-HOOK should be a function to run after the region is created,
+with point at the start of the new region."
+ ;; Check placement of region and delimiters
+ (unless (if (eq evaporation t)
+ (< beg end)
+ (<= beg end))
+ (signal 'mmm-subregion-invalid-placement (list beg end)))
+ (when front
+ (unless (listp front)
+ (setq front (list front beg)))
+ (unless (and (< (car front) (cadr front))
+ (<= (cadr front) beg))
+ (signal 'mmm-subregion-invalid-placement front)))
+ (when back
+ (unless (listp back)
+ (setq back (list end back)))
+ (unless (and (< (car back) (cadr back))
+ (<= end (car back)))
+ (signal 'mmm-subregion-invalid-placement back)))
(setq submode (mmm-modename->function submode))
+ ;; Check embedding in existing regions
+ (mmm-valid-submode-region submode beg end)
+ (mmm-mode-on)
(when submode
(mmm-update-mode-info submode))
- ;; Conditionally sticky overlays are by default sticky. Then the
- ;; insert-in-front and -behind functions fix them.
- (let ((ovl (make-overlay beg end nil (not beg-sticky) end-sticky)))
- ;; Put our properties on the overlay
- (dolist (prop '(front back beg-sticky end-sticky))
- (overlay-put ovl prop (symbol-value prop)))
- ;; Put anything else the caller wants on the overlay
- (loop for (var val) on rest by #'cddr
- do (overlay-put ovl (intern (substring (symbol-name var) 1)) val))
- (mapcar #'(lambda (pair) (overlay-put ovl (car pair) (cadr pair)))
- `((mmm t) ; Mark our overlays
- (mmm-mode ,submode)
- (mmm-local-variables
- ;; Have to be careful to make new list structure here
- ,(list* (list 'font-lock-cache-state nil)
- (list 'font-lock-cache-position (make-marker))
- (copy-tree (cdr (assq submode mmm-region-saved-locals-defaults)))))
- ;; These have special meaning to Emacs
- (,mmm-evaporate-property t)
- (face ,(mmm-get-face face submode))
- ))
- (save-excursion
- (goto-char (overlay-start ovl))
- (mmm-set-current-submode submode)
- (mmm-set-local-variables submode)
- (mmm-run-submode-hook submode)
- (when creation-hook
- (funcall creation-hook))
- (mmm-save-changed-local-variables ovl submode))
+ (and (not front) (eq evaporation 'front) (setq evaporation t))
+ (let ((region-ovl
+ (mmm-make-overlay submode beg end name face beg-sticky end-sticky
+ (or (eq evaporation t) nil) display-name)))
+ ;; Save evaporation type for checking later
+ (overlay-put region-ovl 'mmm-evap evaporation)
+ ;; Calculate priority to supersede anything already there.
+ (overlay-put region-ovl 'priority (length (mmm-overlays-at beg)))
+ ;; Make overlays for the delimiters, with appropriate pointers.
+ (when front
+ (let ((front-ovl
+ (mmm-make-overlay delimiter-mode (car front) (cadr front)
+ nil front-face nil nil t "--" t)))
+ (overlay-put region-ovl 'front front-ovl)
+ (overlay-put front-ovl 'region region-ovl)
+ (overlay-put front-ovl 'match match-front)))
+ (when back
+ (let ((back-ovl
+ (mmm-make-overlay delimiter-mode (car back) (cadr back)
+ nil back-face nil nil t "--" t)))
+ (overlay-put region-ovl 'back back-ovl)
+ (overlay-put back-ovl 'region region-ovl)
+ (overlay-put back-ovl 'match match-back)))
+ ;; Update everything and run all the hooks
+ (mmm-save-all
+ (goto-char (overlay-start region-ovl))
+ (mmm-set-current-submode submode)
+ (mmm-set-local-variables submode)
+ (mmm-run-submode-hook submode)
+ (when creation-hook
+ (funcall creation-hook))
+ (mmm-save-changed-local-variables region-ovl submode))
(setq mmm-previous-submode submode
- mmm-previous-overlay ovl)
+ mmm-previous-overlay region-ovl)
(mmm-update-submode-region)
+ region-ovl))
+
+(defun mmm-make-overlay (submode beg end name face beg-sticky end-sticky evap
+ &optional display-name delim)
+ "Internal function to make submode overlays.
+Does not handle delimiters. Use `mmm-make-region'."
+ (let ((ovl (make-overlay beg end nil (not beg-sticky) end-sticky)))
+ (mapc
+ #'(lambda (pair) (overlay-put ovl (car pair) (cadr pair)))
+ `((mmm t) ; Mark all submode overlays
+ (mmm-mode ,submode)
+ ,@(if delim '((delim t)) nil)
+ (mmm-local-variables
+ ;; Have to be careful to make new list structure here
+ ,(list* (list 'font-lock-cache-state nil)
+ (list 'font-lock-cache-position (make-marker))
+ (copy-tree
+ (cdr (assq submode mmm-region-saved-locals-defaults)))))
+ (name ,name)
+ (display-name ,display-name)
+ ;; Need to save these, because there's no way of accessing an
+ ;; overlay's official "front-advance" parameter once it's created.
+ (beg-sticky ,beg-sticky)
+ (end-sticky ,end-sticky)
+ ;; These have special meaning to Emacs
+ (,mmm-evaporate-property ,evap)
+ (face ,(mmm-get-face face submode delim))
+ ))
ovl))
-(defun mmm-get-face (face submode)
- (case mmm-submode-decoration-level
- ((0) nil)
- ((1) (when submode
- 'mmm-default-submode-face))
- ((2) (or face
- (when submode
- 'mmm-default-submode-face)))))
+(defun mmm-get-face (face submode &optional delim)
+ (cond ((= mmm-submode-decoration-level 0) nil)
+ ((and (= mmm-submode-decoration-level 2) face) face)
+ (delim 'mmm-delimiter-face)
+ (submode 'mmm-default-submode-face)))
;;}}}
;;{{{ Clear Overlays
@@ -298,13 +468,15 @@ un-keyword-ified."
;; See also `mmm-clear-current-region'.
(defun mmm-clear-overlays (&optional start stop strict)
- "Clears all MMM overlays between START and STOP.
-If STRICT, only clear those strictly included, rather than partially."
+ "Clears all MMM overlays overlapping START and STOP.
+If STRICT, only clear those entirely included in that region."
(mapcar #'delete-overlay
- (mmm-overlays-in (or start (point-min))
- (or stop (point-max))
- strict))
- (mmm-update-current-submode))
+ (if strict
+ (mmm-overlays-contained-in (or start (point-min))
+ (or stop (point-max)))
+ (mmm-overlays-overlapping (or start (point-min))
+ (or stop (point-max)))))
+ (mmm-update-submode-region))
;;}}}
@@ -340,6 +512,7 @@ is non-nil, don't quit if the info is already there."
;; Now make a new temporary buffer.
(set-buffer (mmm-make-temp-buffer (current-buffer)
mmm-temp-buffer-name))
+ ;; Handle stupid modes that need the file name set
(if (memq mode mmm-set-file-name-for-modes)
(setq buffer-file-name filename)))
(funcall mode)
@@ -357,7 +530,8 @@ is non-nil, don't quit if the info is already there."
(not (memq major-mode
(cdr font-lock-global-modes)))
(memq major-mode font-lock-global-modes)))))
- ;; Don't actually fontify, but note that we should.
+ ;; Don't actually fontify in the temp buffer, but note
+ ;; that we should fontify when we use this mode.
(put mode 'mmm-font-lock-mode t))
;; Get the font-lock variables
(when mmm-font-lock-available-p
@@ -405,14 +579,11 @@ different keymaps, syntax tables, local variables, etc. for submodes."
(mmm-update-mode-info mode)
(mmm-set-local-variables mode)
(mmm-enable-font-lock mode))
- (if mmm-current-submode
- (setq mode-name
- (mmm-format-string
- mmm-submode-mode-line-format
- `(("~M" . ,(get mmm-primary-mode 'mmm-mode-name))
- ("~m" . ,(get mmm-current-submode 'mmm-mode-name)))))
- (setq mode-name (get mmm-primary-mode 'mmm-mode-name)))
- (force-mode-line-update)))
+ (mmm-set-mode-line)
+ (dolist (func (if mmm-current-overlay
+ (overlay-get mmm-current-overlay 'entry-hook)
+ mmm-primary-mode-entry-hook))
+ (ignore-errors (funcall func)))))
(defun mmm-add-hooks ()
(make-local-hook 'post-command-hook)
@@ -523,11 +694,11 @@ region and mode for the previous position."
(when mmm-font-lock-available-p
(if (some #'(lambda (mode)
(get mode 'mmm-font-lock-mode))
- (remove-duplicates
- (cons mmm-primary-mode
- (mapcar #'(lambda (ovl)
- (overlay-get ovl 'mmm-mode))
- (mmm-overlays-in (point-min) (point-max))))))
+ (cons mmm-primary-mode
+ (mapcar #'(lambda (ovl)
+ (overlay-get ovl 'mmm-mode))
+ (mmm-overlays-overlapping
+ (point-min) (point-max)))))
(font-lock-mode 1)
(font-lock-mode 0))))
@@ -542,22 +713,24 @@ region and mode for the previous position."
;;}}}
;;{{{ Get Submode Regions
+;;; In theory, these are general functions that have nothing to do
+;;; with font-lock, but they aren't used anywhere else, so we might as
+;;; well have them close.
+
(defun mmm-submode-changes-in (start stop)
"Return a list of all submode-change positions from START to STOP.
-The list is sorted in order of increasing buffer position, and the
-boundary positions are included."
+The list is sorted in order of increasing buffer position."
(sort (remove-duplicates
(list* start stop
(mapcan #'(lambda (ovl)
`(,(overlay-start ovl)
,(overlay-end ovl)))
- (mmm-overlays-in start stop t t))))
-
+ (mmm-overlays-overlapping start stop))))
#'<))
(defun mmm-regions-in (start stop)
"Return a list of regions of the form (MODE BEG END) whose disjoint
-union covers the region from START to STOP."
+union covers the region from START to STOP, including delimiters."
(let ((regions
(maplist #'(lambda (pos-list)
(if (cdr pos-list)
@@ -597,11 +770,13 @@ of the REGIONS covers START to STOP."
;; preventing `mmm-beginning-of-syntax' from doing The Right Thing.
;; I don't know why it does this, but let's undo it here.
(let ((font-lock-beginning-of-syntax-function 'mmm-beginning-of-syntax))
- (mapcar #'(lambda (elt)
+ (mapc #'(lambda (elt)
(when (get (car elt) 'mmm-font-lock-mode)
(mmm-fontify-region-list (car elt) (cdr elt))))
(mmm-regions-alist start stop)))
- (mmm-update-submode-region)
+ ;; With jit-lock, this causes blips in the mode line and menus.
+ ;; Shouldn't be necessary here, since it's in post-command-hook too.
+ ;;(mmm-update-submode-region)
(when loudly (message nil)))
(defun mmm-fontify-region-list (mode regions)
@@ -609,7 +784,7 @@ of the REGIONS covers START to STOP."
(save-excursion
(let (;(major-mode mode)
(func (get mode 'mmm-fontify-region-function)))
- (mapcar #'(lambda (reg)
+ (mapc #'(lambda (reg)
(goto-char (car reg))
;; Here we do the same sort of thing that
;; `mmm-update-submode-region' does, but we force it
diff --git a/mmm/mmm-sample.el b/mmm/mmm-sample.el
index 8de25057..fe327c95 100644
--- a/mmm/mmm-sample.el
+++ b/mmm/mmm-sample.el
@@ -1,8 +1,8 @@
;;; mmm-sample.el --- Sample MMM submode classes
-;; Copyright (C) 2000 by Michael Abraham Shulman
+;; Copyright (C) 2003, 2004 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -42,6 +42,7 @@
'((embedded-css
:submode css
:face mmm-declaration-submode-face
+ :delimiter-mode nil
:front "<style[^>]*>"
:back "</style>")))
@@ -56,7 +57,8 @@
'((js-tag
:submode javascript
:face mmm-code-submode-face
- :front "<script\[^>\]*>"
+ :delimiter-mode nil
+ :front "<script\[^>\]*\\(language=\"javascript\\([0-9.]*\\)\"\\|type=\"text/javascript\"\\)\[^>\]*>"
:back"</script>"
:insert ((?j js-tag nil @ "<script language=\"JavaScript\">"
@ "\n" _ "\n" @ "</script>" @))
@@ -64,7 +66,8 @@
(js-inline
:submode javascript
:face mmm-code-submode-face
- :front "on\w+=\""
+ :delimiter-mode nil
+ :front "on\\w+=\""
:back "\"")))
;;}}}
@@ -72,7 +75,7 @@
;; Here we match the here-document syntax used by Perl and shell
;; scripts. We try to be automagic about recognizing what mode the
-;; here-document should be in; to make sure that it is recognized
+;; here-document should be in. To make sure that it is recognized
;; correctly, the name of the mode, perhaps minus `-mode', in upper
;; case, and/or with hyphens converted to underscores, should be
;; separated from the rest of the here-document name by hyphens or
@@ -125,10 +128,11 @@ and MODE is a major mode function symbol.")
(mmm-add-classes
'((here-doc
- :front "<<\\([a-zA-Z0-9_-]+\\)"
+ :front "<<[\"\'\`]?\\([a-zA-Z0-9_-]+\\)"
:front-offset (end-of-line 1)
:back "^~1$"
:save-matches 1
+ :delimiter-mode nil
:match-submode mmm-here-doc-get-mode
:insert ((?d here-doc "Here-document Name: " @ "<<" str _ "\n"
@ "\n" @ str "\n" @))
@@ -144,6 +148,7 @@ and MODE is a major mode function symbol.")
:front "\\[\\([-\\+!\\*\\$]\\)"
:back "~1\\]"
:save-matches 1
+ :match-name "embperl"
:match-face (("[+" . mmm-output-submode-face)
("[-" . mmm-code-submode-face)
("[!" . mmm-init-submode-face)
@@ -171,20 +176,27 @@ and MODE is a major mode function symbol.")
(mmm-add-group
'eperl
- '((eperl-code
+ '((eperl-expr
+ :submode perl
+ :face mmm-output-submode-face
+ :front "<:="
+ :back ":>"
+ :insert ((?= eperl-expr nil @ "<:=" @ " " _ " " @ ":>" @)))
+ (eperl-code
:submode perl
:face mmm-code-submode-face
:front "<:"
:back "_?:>"
+ :match-name "eperl"
:insert ((?p eperl-code nil @ "<:" @ " " _ " " @ ":>" @)
(?: eperl-code ?p . nil)
(?_ eperl-code_ nil @ "<:" @ " " _ " " @ "_:>" @)))
- (eperl-expr
- :submode perl
- :face mmm-output-submode-face
- :front "<:="
- :back ":>"
- :insert ((?= eperl-expr nil @ "<:=" @ " " _ " " @ ":>" @)))))
+ (eperl-comment
+ :submode text
+ :face mmm-comment-submode-face
+ :front ":>//"
+ :back "\n")
+ ))
;;}}}
;;{{{ File Variables
@@ -229,19 +241,28 @@ and MODE is a major mode function symbol.")
:front-verify mmm-file-variables-verify
:back mmm-file-variables-find-back
:submode emacs-lisp-mode
+ :delimiter-mode nil
)))
;;}}}
;;{{{ JSP Pages
(mmm-add-group 'jsp
- `((jsp-code
+ `((jsp-comment
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "<%--"
+ :back "--%>"
+ :insert ((?- jsp-comment nil @ "<%--" @ " " _ " " @ "--%>" @))
+ )
+ (jsp-code
:submode java
:match-face (("<%!" . mmm-declaration-submode-face)
("<%=" . mmm-output-submode-face)
("<%" . mmm-code-submode-face))
:front "<%[!=]?"
:back "%>"
+ :match-name "jsp"
:insert ((?% jsp-code nil @ "<%" @ " " _ " " @ "%>" @)
(?! jsp-declaration nil @ "<%!" @ " " _ " " @ "%>" @)
(?= jsp-expression nil @ "<%=" @ " " _ " " @ "%>" @))
@@ -255,6 +276,55 @@ and MODE is a major mode function symbol.")
)))
;;}}}
+;;{{{ SGML DTD
+
+;; Thanks to Yann Dirson <ydirson@fr.alcove.com> for writing and
+;; contributing this submode class.
+
+(mmm-add-classes
+ '((sgml-dtd
+ :submode dtd-mode
+ :face mmm-declaration-submode-face
+ :delimiter-mode nil
+ :front "<! *doctype[^>[]*\\["
+ :back "]>")))
+
+;;}}}
+;;{{{ <Perl> in httpd.conf
+
+(mmm-add-classes
+ '((httpd-conf-perl
+ :submode perl
+ :delimiter-mode nil
+ :front "<Perl>"
+ :back "</Perl>")))
+
+;; Suggested Use:
+;; (mmm-add-mode-ext-class 'apache-generic-mode nil 'httpd-conf-perl)
+
+;;}}}
+;;{{{ PHP in HTML
+
+(mmm-add-group 'html-php
+ '((html-php-output
+ :submode php-mode
+ :face mmm-output-submode-face
+ :front "<\\?php *echo "
+ :back "\\?>"
+ :include-front t
+ :front-offset 5
+ :insert ((?e php-echo nil @ "<?php" @ " echo " _ " " @ "?>" @))
+ )
+ (html-php-code
+ :submode php-mode
+ :face mmm-code-submode-face
+ :front "<\\?\\(php\\)?"
+ :back "\\?>"
+ :insert ((?p php-section nil @ "<?php" @ " " _ " " @ "?>" @)
+ (?b php-block nil @ "<?php" @ "\n" _ "\n" @ "?>" @))
+ )))
+
+;;}}}
;; NOT YET UPDATED
;;{{{ HTML in PL/SQL;-COM-
@@ -301,8 +371,4 @@ and MODE is a major mode function symbol.")
(provide 'mmm-sample)
-
-;;; Local Variables:
-;;; End:
-
;;; mmm-sample.el ends here \ No newline at end of file
diff --git a/mmm/mmm-utils.el b/mmm/mmm-utils.el
index 8b5dcc2c..3d0a3741 100644
--- a/mmm/mmm-utils.el
+++ b/mmm/mmm-utils.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2000 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -81,22 +81,24 @@ substituted for the corresponding REGEXP wherever it matches."
(setq string (replace-match (cdr pair) t t string))))))
string)
-(defun mmm-format-matches (string)
+(defun mmm-format-matches (string &optional on-string)
"Format STRING by matches from the current match data.
Strings like ~N are replaced by the Nth subexpression from the last
-global match. Does nothing if STRING is not a string."
+global match. Does nothing if STRING is not a string.
+
+ON-STRING, if supplied, means to use the match data from a
+`string-match' on that string, rather than the global match data."
(when (stringp string)
(let ((old-data (match-data))
subexp)
(save-match-data
(while (string-match "~\\([0-9]\\)" string)
- (setq subexp (string-to-int (match-string 1 string))
- string
- (replace-match
- (save-match-data
- (set-match-data old-data)
- (match-string subexp))
- t t string))))))
+ (setq subexp (string-to-int (match-string-no-properties 1 string))
+ string (replace-match
+ (save-match-data
+ (set-match-data old-data)
+ (match-string-no-properties subexp on-string))
+ t t string))))))
string)
;;}}}
@@ -105,7 +107,7 @@ global match. Does nothing if STRING is not a string."
(defmacro mmm-save-keyword (param)
"If the value of PARAM as a variable is non-nil, return the list
\(:PARAM (symbol-value PARAM)), otherwise NIL. Best used only when it
-is important that nil valuess disappear."
+is important that nil values disappear."
`(if (and (boundp ',param) ,param)
(list (intern (concat ":" (symbol-name ',param))) ,param)
nil))
@@ -115,7 +117,7 @@ is important that nil valuess disappear."
\(let \(\(a 1) \(c 2)) \(mmm-save-keywords a b c)) ==> \(:a 1 :c 2)
Use of this macro can make code more readable when there are a lot of
PARAMS, but less readable when there are only a few. Also best used
-only when it is important that nil valuess disappear."
+only when it is important that nil values disappear."
`(append ,@(mapcar #'(lambda (param)
(macroexpand `(mmm-save-keyword ,param)))
params)))
@@ -137,6 +139,19 @@ string."
(match-end 0)))))
;;}}}
+;;{{{ Markers
+
+;; Mostly for remembering interactively made regions
+(defun mmm-make-marker (pos beg-p sticky-p)
+ "Make, and return, a marker at POS that is or isn't sticky.
+BEG-P represents whether the marker delimits the beginning of a
+region \(or the end of it). STICKY-P is whether it should be sticky,
+i.e. whether text inserted at the marker should be inside the region."
+ (let ((mkr (set-marker (make-marker) pos)))
+ (set-marker-insertion-type mkr (if beg-p (not sticky-p) sticky-p))
+ mkr))
+
+;;}}}
(provide 'mmm-utils)
diff --git a/mmm/mmm-vars.el b/mmm/mmm-vars.el
index 4fbf3579..7130e58b 100644
--- a/mmm/mmm-vars.el
+++ b/mmm/mmm-vars.el
@@ -1,8 +1,8 @@
;;; mmm-vars.el --- Variables for MMM Mode
-;; Copyright (C) 2000 by Michael Abraham Shulman
+;; Copyright (C) 2000, 2004 by Michael Abraham Shulman
-;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
;; Version: $Id$
;;{{{ GPL
@@ -39,6 +39,7 @@
;; Otherwise it complains about undefined variables.
(eval-when-compile
+ (defvar mmm-current-submode)
(defvar mmm-save-local-variables)
(defvar mmm-mode-string)
(defvar mmm-submode-mode-line-format)
@@ -51,15 +52,27 @@
;;}}}
;;{{{ Error Conditions
+;; Most of these should be caught internally and never seen by the
+;; user, except when the user is creating submode regions manually.
+
;; Signalled when we try to put a submode region inside one where it
;; isn't meant to go.
-(put 'mmm-invalid-parent
+(put 'mmm-subregion-invalid-parent
'error-conditions
- '(mmm-invalid-parent mmm-error error))
-(put 'mmm-invalid-parent
+ '(mmm-subregion-invalid-parent mmm-error error))
+(put 'mmm-subregion-invalid-parent
'error-message
"Invalid submode region parent")
+;; Signalled when we try to put a submode region overlapping others in
+;; an invalid way.
+(put 'mmm-subregion-invalid-placement
+ 'error-conditions
+ '(mmm-subregion-invalid-placement mmm-error error))
+(put 'mmm-subregion-invalid-placement
+ 'error-message
+ "Submode region placement invalid")
+
;; Signalled when we try to apply a submode class that doesn't exist.
(put 'mmm-invalid-submode-class
'error-conditions
@@ -69,8 +82,8 @@
"Invalid or undefined submode class")
;; Signalled by :match-submode functions when they are unable to
-;; resolve a submode. Should always be caught and never seen by the
-;; user.
+;; resolve a submode. This error should *always* be caught internally
+;; and never seen by the user.
(put 'mmm-no-matching-submode
'error-conditions
'(mmm-no-matching-submode mmm-error error))
@@ -91,7 +104,8 @@
;;{{{ Save Local Variables
(defvar mmm-c-derived-modes
- '(c-mode c++-mode objc-mode pike-mode java-mode jde-mode javascript-mode))
+ '(c-mode c++-mode objc-mode pike-mode java-mode jde-mode javascript-mode
+ php-mode))
(defvar mmm-save-local-variables
`(;; Don't use `function' (#') here!! We're already inside `quote'!
@@ -124,12 +138,156 @@
(c-extra-toplevel-key nil ,mmm-c-derived-modes)
(c-inexpr-class-key nil ,mmm-c-derived-modes)
(c-conditional-key nil ,mmm-c-derived-modes)
- ;; User indentation style control
- (((lambda () c-indentation-style) . c-set-style)
- nil ,mmm-c-derived-modes)
- ;; XEmacs makes this a local variable
- ,@(when mmm-xemacs
- '((c-offsets-alist nil ,mmm-c-derived-modes)))
+ semantic-bovinate-toplevel-override
+ semantic-toplevel-bovine-table
+ ;; Indentation style control variables.
+ ;; These have to be localized in Emacs: see `mmm-mode-on'.
+ ,@(mapcar
+ #'(lambda (var) (list var nil mmm-c-derived-modes))
+ '(c++-template-syntax-table
+ c-<-op-cont-regexp
+ c->-op-cont-regexp
+ c-after-suffixed-type-decl-key
+ c-after-suffixed-type-maybe-decl-key
+ c-any-class-key
+ c-any-class-key
+ c-asm-stmt-kwds
+ c-assignment-op-regexp
+ c-backslash-column
+ c-basic-offset
+ c-bitfield-kwds
+ c-block-comment-prefix
+ c-block-decls-with-vars
+ c-block-stmt-1-key
+ c-block-stmt-1-key
+ c-block-stmt-1-kwds
+ c-block-stmt-2-key
+ c-block-stmt-2-key
+ c-block-stmt-2-kwds
+ c-brace-list-key
+ c-cast-parens
+ c-class-key
+ c-class-key
+ c-class-kwds
+ c-cleanup-list
+ c-colon-type-list-re
+ c-comment-only-line-offset
+ c-comment-prefix-regexp
+ c-comment-start-regexp
+ c-comment-start-regexp
+ c-cpp-defined-fns
+ c-current-comment-prefix
+ c-decl-block-key
+ c-decl-block-key
+ c-decl-prefix-re
+ c-decl-spec-kwds
+ c-doc-comment-start-regexp
+ c-expr-kwds
+ c-file-offsets
+ c-file-style
+ c-hanging-braces-alist
+ c-hanging-colons-alist
+ c-hanging-comment-ender-p
+ c-hanging-comment-starter-p
+ c-hanging-semi\&comma-criteria
+ c-identifier-key
+ c-identifier-last-sym-match
+ c-identifier-start
+ c-identifier-syntax-modifications
+ c-identifier-syntax-table
+ c-in-comment-lc-prefix
+ c-indent-comment-alist
+ c-indent-comments-syntactically-p
+ c-indentation-style
+ c-inexpr-block-kwds
+ c-inexpr-class-kwds
+ c-keywords
+ c-keywords-obarray
+ c-keywords-regexp
+ c-keywords-regexp
+ c-known-type-key
+ c-label-key
+ c-label-key
+ c-label-kwds
+ c-label-kwds-regexp
+ c-label-kwds-regexp
+ c-label-minimum-indentation
+ c-lambda-kwds
+ c-literal-start-regexp
+ c-nonsymbol-chars
+ c-nonsymbol-token-regexp
+ c-not-decl-init-keywords
+ c-offsets-alist
+ c-opt-<>-arglist-start
+ c-opt-<>-arglist-start-in-paren
+ c-opt-<>-sexp-key
+ c-opt-access-key
+ c-opt-access-key
+ c-opt-asm-stmt-key
+ c-opt-asm-stmt-key
+ c-opt-bitfield-key
+ c-opt-bitfield-key
+ c-opt-block-decls-with-vars-key
+ c-opt-block-stmt-key
+ c-opt-block-stmt-key
+ c-opt-cpp-prefix
+ c-opt-cpp-start
+ c-opt-decl-spec-key
+ c-opt-friend-key
+ c-opt-friend-key
+ c-opt-identifier-concat-key
+ c-opt-inexpr-block-key
+ c-opt-inexpr-block-key
+ c-opt-inexpr-brace-list-key
+ c-opt-inexpr-class-key
+ c-opt-inexpr-class-key
+ c-opt-lambda-key
+ c-opt-lambda-key
+ c-opt-method-key
+ c-opt-method-key
+ c-opt-postfix-decl-spec-key
+ c-opt-type-component-key
+ c-opt-type-concat-key
+ c-opt-type-modifier-key
+ c-opt-type-suffix-key
+ c-other-decl-block-key
+ c-other-decl-block-key
+ c-other-decl-block-kwds
+ c-other-decl-kwds
+ c-overloadable-operators-regexp
+ c-paragraph-separate
+ c-paragraph-start
+ c-paren-stmt-key
+ c-primary-expr-regexp
+ c-primitive-type-key
+ c-primitive-type-kwds
+ c-protection-kwds
+ c-recognize-<>-arglists
+ c-recognize-knr-p
+ c-recognize-knr-p
+ c-recognize-paren-inits
+ c-recognize-typeless-decls
+ c-regular-keywords-regexp
+ c-simple-stmt-key
+ c-simple-stmt-kwds
+ c-special-brace-lists
+ c-special-brace-lists
+ c-specifier-key
+ c-specifier-kwds
+ c-stmt-delim-chars
+ c-stmt-delim-chars-with-comma
+ c-symbol-key
+ c-symbol-key
+ c-symbol-start
+ c-syntactic-eol
+ c-syntactic-ws-end
+ c-syntactic-ws-start
+ c-type-decl-prefix-key
+ c-type-decl-suffix-key
+ c-type-prefix-key
+ comment-end
+ comment-start
+ comment-start-skip))
;; Skeleton insertion
skeleton-transformation
;; Abbrev mode
@@ -138,6 +296,8 @@
;; And finally the syntax table and local map.
((syntax-table . set-syntax-table))
((current-local-map . use-local-map) buffer)
+ paragraph-separate
+ paragraph-start
)
"Which local variables to save for major mode regions.
Each element has the form \(VARIABLE [TYPE [MODES]]), causing VARIABLE
@@ -203,12 +363,16 @@ with font-lock."
(defcustom mmm-submode-decoration-level 1
"*Amount of coloring to use in submode regions.
Should be either 0, 1, or 2, representing None, Low, and High amounts
-of coloring. None means to use no coloring at all. Low means to use
-a single face \(`mmm-default-submode-face') for all submode regions,
-\(except for \"non-submode\" regions). High means to use different
-faces for different types of submode regions, such as initialization
-code, expressions that are output, declarations, and so on. The
-default face is still used for regions that do not specify a face."
+of coloring respectively.
+* None (0) means to use no coloring at all.
+* Low (1) means to use `mmm-default-submode-face' for all submode
+ regions \(except for \"non-submode\" regions, i.e. those that are of
+ the primary mode) and `mmm-delimiter-face' for region delimiters.
+* High (2) means to use different faces for different types of submode
+ regions and delimiters, such as initialization code, expressions that
+ are output, declarations, and so on, as specified by the submode
+ class. The default faces are still used for regions that do not
+ specify a face."
:group 'mmm-faces
:type '(choice (const :tag "None" 0)
(const :tag "Low" 1)
@@ -247,6 +411,10 @@ default face is still used for regions that do not specify a face."
Also used at decoration level 2 for submodes not specifying a type."
:group 'mmm-faces)
+(defface mmm-delimiter-face nil
+ "Face used to mark submode delimiters."
+ :group 'mmm-faces)
+
;;}}}
;;{{{ Mode Line Format
@@ -256,12 +424,54 @@ Also used at decoration level 2 for submodes not specifying a type."
:type 'string)
(defcustom mmm-submode-mode-line-format "~M[~m]"
- "*Format of the Major Mode Mode-line display when point is in a
-submode region. ~M means the name of the default major mode, ~m means
-the name of the submode."
+ "*Format of the mode-line display when point is in a submode region.
+
+~M is replaced by the name of the primary major mode \(which may be
+replaced by a combined-mode function, see the info documentation).
+
+~m is replaced by the submode region overlay's `display-name'
+property, if it has one. Otherwise it is replaced by the mode name of
+the submode region.
+
+If `mmm-primary-mode-display-name' is non-nil, then this variable is
+used even when point is not in a submode region \(i.e. it is in a
+primary mode region), with ~m being replaced by the value of that
+variable."
:group 'mmm
:type 'string)
+(defvar mmm-primary-mode-display-name nil
+ "If non-nil, displayed as the primary mode name in the mode line.
+See also `mmm-buffer-mode-display-name'.")
+(make-variable-buffer-local 'mmm-primary-mode-display-name)
+
+(defvar mmm-buffer-mode-display-name nil
+ "If non-nil, displayed in the mode line instead of the primary mode
+name, which is then shown next to it as if it were a submode when in a
+primary mode region, i.e. outside all submode regions.")
+(make-variable-buffer-local 'mmm-buffer-mode-display-name)
+
+(defun mmm-set-mode-line ()
+ "Set the mode line display correctly for the current submode,
+according to `mmm-submode-mode-line-format'."
+ (let ((primary (or mmm-primary-mode-display-name
+ (get mmm-primary-mode 'mmm-mode-name)))
+ (submode (and mmm-current-overlay
+ (or (overlay-get mmm-current-overlay 'display-name)
+ (get mmm-current-submode 'mmm-mode-name)))))
+ (if mmm-buffer-mode-display-name
+ (setq mode-name
+ (mmm-format-string mmm-submode-mode-line-format
+ `(("~M" . ,mmm-buffer-mode-display-name)
+ ("~m" . ,(or submode primary)))))
+ (if submode
+ (setq mode-name
+ (mmm-format-string mmm-submode-mode-line-format
+ `(("~M" . ,primary)
+ ("~m" . ,submode))))
+ (setq mode-name primary))))
+ (force-mode-line-update))
+
;;}}}
;;{{{ Submode Classes
@@ -361,6 +571,16 @@ first `fboundp' element of the `cdr' is returned, or nil if none."
(cdr (assq mode mmm-major-mode-preferences))))))
;;}}}
+;;{{{ Delimiter Regions
+
+(defcustom mmm-delimiter-mode 'fundamental-mode
+ "Major mode used by default for delimiter regions.
+Classes are encouraged to override this by providing a delimiter-mode
+parameter-- see `mmm-classes-alist'."
+ :group 'mmm
+ :type 'function)
+
+;;}}}
;;{{{ Key Bindings
(defcustom mmm-mode-prefix-key [(control ?c) ?%]
@@ -425,7 +645,7 @@ HTML mode the dominant mode.
A hook named mmm-<submode>-submode-hook is run when a submode region
of a given mode is created. For example, `mmm-cperl-mode-submode-hook'
is run whenever a CPerl mode submode region is created, in any buffer.
-When submode hooks are run, point is guaranteed to be at the start of
+When this hooks are run, point is guaranteed to be at the start of
the newly created submode region.
Finally, a hook named mmm-<class>-class-hook is run whenever a buffer
@@ -459,6 +679,18 @@ the current buffer.")
(mmm-run-constructed-hook class "class")
(add-to-list 'mmm-class-hooks-run class)))
+(defvar mmm-primary-mode-entry-hook nil
+ "Hook run when point moves into a region of the primary mode.
+Each submode region can have an `entry-hook' property which is run
+when they are entered, but since primary mode regions have no overlay
+to store properties, this is a buffer-local variable.
+
+N.B. This variable is not a standard Emacs hook. Unlike Emacs'
+\"local hooks\" it has *no* global value, only a local one. Its value
+should always be a list of functions \(possibly empty) and never a
+single function. It may be used with `add-hook', however.")
+(make-variable-buffer-local 'mmm-primary-mode-entry-hook)
+
;;}}}
;;{{{ Major Mode Hook
@@ -483,6 +715,12 @@ an existing buffer."
;;}}}
;;{{{ MMM Global Mode
+;;; There's a point to be made that this variable should default to
+;;; `maybe' (i.e. not nil and not t), because that's what practically
+;;; everyone wants. I subscribe, however, to the view that simply
+;;; *loading* a lisp extension should not change the (user-visible)
+;;; behavior of Emacs, until it is configured or turned on in some
+;;; way, which dictates that the default for this must be nil.
(defcustom mmm-global-mode nil
"*Specify in which buffers to turn on MMM Mode automatically.
@@ -497,9 +735,8 @@ an existing buffer."
(other :tag "Maybe" maybe))
:require 'mmm-mode)
-;;}}}
-;;{{{ "Never" Modes
-
+;; These are not traditional editing modes, so mmm makes no sense, and
+;; can mess things up seriously if it doesn't know not to try.
(defcustom mmm-never-modes
'(
help-mode
@@ -519,10 +756,10 @@ an existing buffer."
;;{{{ Buffer File Name
(defvar mmm-set-file-name-for-modes '(mew-draft-mode)
- "List of modes for which temporary buffers have a file name.
-If so, it is the same as that of the parent buffer. In general, this
-has been found to cause more problems than it solves, but some modes
-require it.")
+ "List of modes for which the temporary buffers MMM creates have a
+file name. In these modes, this file name is the same as that of the
+parent buffer. In general, this has been found to cause more problems
+than it solves, but some modes require it.")
;;}}}
@@ -544,33 +781,42 @@ Do not set this variable directly; use the function `mmm-mode'.")
;;}}}
;;{{{ Classes Alist
-;; :parent could be an all-class argument. Same with :keymap.
+;; Notes:
+;; 1. :parent could be an all-class argument. Same with :keymap.
+;; 2. :match-submode really does have to be distinct from :submode,
+;; because 'functionp' isn't enough to distinguish which is meant.
(defvar mmm-classes-alist nil
"Alist containing all defined mmm submode classes.
-Each element looks like \(CLASS . ARGS) where CLASS is a symbol
-representing the submode class and ARGS is a list of keyword
+A submode class is a named recipe for parsing a document into submode
+regions, and sometimes for inserting new ones while editing.
+
+Each element of this alist looks like \(CLASS . ARGS) where CLASS is a
+symbol naming the submode class and ARGS is a list of keyword
arguments, called a \"class specifier\". There are a large number of
-accepted keyword arguments.
+accepted keyword arguments in the class specifier.
The argument CLASSES, if supplied, must be a list of other submode
-classes \(or class specifiers), representing other classes to call.
-FACE, if supplied, overrides FACE arguments to these classes, but all
-other arguments to this class are ignored.
-
-The argument HANDLER, if supplied, overrides any other processing. It
-must be a function, and all the arguments are passed to it as
+class names, or class specifiers, representing other classes to call
+recursively. The FACE arguments of these classes are overridden by
+the FACE argument of this class. If the argument CLASSES is supplied,
+all other arguments to this class are ignored. That is, \"grouping\"
+classes can do nothing but group other classes.
+
+The argument HANDLER, if supplied, also overrides any other processing.
+It must be a function, and all the arguments are passed to it as
keywords, and it must do everything. See `mmm-ify' for what sorts of
things it must do. This back-door interface should be cleaned up.
-The argument FACE, if supplied, specifies the display face of the
-submode regions under decoration level 2. It must be a valid face.
-The standard faces used for submode regions are `mmm-*-submode-face'
-where * is one of `init', `cleanup', `declaration', `comment',
-`output', `special', or `code'. A more flexible alternative is the
-argument MATCH-FACE. MATCH-FACE can be a function, which is called
-with one argument, the form of the front delimiter \(found from
-FRONT-FORM, below), and should return the face to use. It can also be
-an alist, each element of the form \(DELIM . FACE).
+The optional argument FACE gives the display face of the submode
+regions under high decoration (see `mmm-submode-decoration-level').
+It must be a valid face. The standard faces used for submode regions
+are `mmm-*-submode-face' where * is one of `init', `cleanup',
+`declaration', `comment', `output', `special', or `code'. A more
+flexible alternative is the argument MATCH-FACE. MATCH-FACE can be a
+function, which is called with one argument, the form of the front
+delimiter \(found from FRONT-FORM, below), and should return the face
+to use. It can also be an alist, with each element of the form
+\(DELIM . FACE).
If neither CLASSES nor HANDLER are supplied, either SUBMODE or
MATCH-SUBMODE must be. SUBMODE specifies the submode to use for the
@@ -590,14 +836,19 @@ named classes. \(Unnamed classes are created by interactive commands
in `mmm-interactive-history').
If FRONT is a regexp, then that regexp is searched for, and the end of
-its match \(or the beginning, if INCLUDE-FRONT is non-nil), plus
-FRONT-OFFSET, becomes the beginning of the submode region. If FRONT
-is a function, that function is called instead, and must act somewhat
-like a search, in that it should start at point, take one argument as
-a search bound, and set the match data. A similar pattern is followed
-for BACK \(the search starts at the beginning of the submode region),
-save that the beginning of its match \(or the end, if INCLUDE-BACK is
-non-nil) becomes the end of the submode region, plus BACK-OFFSET.
+its FRONT-MATCH'th match \(or the beginning thereof, if INCLUDE-FRONT
+is non-nil), plus FRONT-OFFSET, becomes the beginning of the submode
+region. If FRONT is a function, that function is called instead, and
+must act somewhat like a search, in that it should start at point,
+take one argument as a search bound, and set the match data. A
+similar pattern is followed for BACK \(the search starts at the
+beginning of the submode region), save that the beginning of its
+BACK-MATCH'th match \(or the end, if INCLUDE-BACK is non-nil) becomes
+the end of the submode region, plus BACK-OFFSET.
+
+If SAVE-MATCHES is non-nil, then BACK, if it is a regexp, is formatted
+by replacing strings of the form \"~N\" by the corresponding value of
+\(match-string n) after matching FRONT.
FRONT-MATCH and BACK-MATCH default to zero. They specify which
sub-match of the FRONT and BACK regexps to treat as the delimiter.
@@ -616,9 +867,19 @@ FRONT-VERIFY and BACK-VERIFY, if supplied, must be functions that
inspect the match data to see if a match found by FRONT or BACK
respectively is valid.
-If SAVE-MATCHES is non-nil, BACK, if it is a regexp, is formatted by
-replacing strings of the form \"~N\" by the corresponding value of
-\(match-string n) after matching FRONT.
+FRONT-DELIM \(resp. BACK-DELIM), if supplied, can take values like
+those of FRONT-OFFSET \(resp. BACK-OFFSET), specifying the offset from
+the start \(resp. end) of the match for FRONT \(resp. BACK) to use as
+the starting \(resp. ending) point for the front \(resp. back)
+delimiter. If nil, it means not to make a region for the respective
+delimiter at all.
+
+DELIMITER-MODE, if supplied, specifies what submode to use for the
+delimiter regions, if any. If `nil', the primary mode is used. If
+not supplied, `mmm-delimiter-mode' is used.
+
+FRONT-FACE and BACK-FACE specify faces to use for displaying the
+delimiter regions, under high decoration.
FRONT-FORM and BACK-FORM, if given, must supply a regexp used to match
the *actual* delimiter. If they are strings, they are used as-is. If
@@ -661,6 +922,20 @@ the end of the submode region, and the end of the back delimiter.
If END-NOT-BEGIN is non-nil, it specifies that a BACK delimiter cannot
begin a new submode region.
+MATCH-NAME, if supplied, specifies how to determine the \"name\" for
+each submode region. It must be a string or a function. If it is a
+function, it is passed the value of FRONT-FORM and must return the
+name to use. If it is a string, it is used as-is unless SAVE-NAME has
+a non-nil value, in which case, the string is interpreted the same as
+BACK when SAVE-MATCHES is non-nil. If MATCH-NAME is not specified,
+the regions are unnamed. Regions with the same name are considered
+part of the same chunk of code, and formatted as such, while unnamed
+regions are not grouped with any others.
+
+As a special optimization for insertion, if SKEL-NAME is non-nil, the
+insertion code will use the user-prompted string value as the region
+name, instead of going through the normal matching procedure.
+
PRIVATE, if supplied and non-nil, means that this class is a private
or internal class, usually one invoked by another class via :classes,
and is not for the user to see.")
@@ -671,7 +946,7 @@ and is not for the user to see.")
(add-to-list 'mmm-classes-alist class)))
(defun mmm-add-group (group classes)
- "Add CLASSES and a group named GROUP containing them all.
+ "Add CLASSES and a \"grouping class\" named GROUP which calls them all.
The CLASSES are all made private, i.e. non-user-visible."
(mmm-add-classes (mapcar #'(lambda (class)
(append class
@@ -680,10 +955,21 @@ The CLASSES are all made private, i.e. non-user-visible."
(add-to-list 'mmm-classes-alist
(list group :classes (mapcar #'first classes))))
+(defun mmm-add-to-group (group classes)
+ "Add CLASSES to the \"grouping class\" named GROUP.
+The CLASSES are all made private, i.e. non-user-visible."
+ (mmm-add-classes (mapcar #'(lambda (class)
+ (append class
+ '(:private t)))
+ classes))
+ (mmm-set-class-parameter group :classes
+ (append (mmm-get-class-parameter group :classes)
+ (mapcar #'first classes))))
+
;;}}}
;;{{{ Version Number
-(defconst mmm-version "0.4.7"
+(defconst mmm-version "0.4.8"
"Current version of MMM Mode.")
(defun mmm-version ()
diff --git a/mmm/mmm.texinfo b/mmm/mmm.texinfo
index 2a8ff603..aa0b0eaf 100644
--- a/mmm/mmm.texinfo
+++ b/mmm/mmm.texinfo
@@ -147,6 +147,7 @@ Supplied Submode Classes
* ePerl:: A general Perl-embedding syntax.
* JSP:: Java code embedded in HTML.
* RPM:: Shell scripts in RPM Spec Files.
+* Noweb:: Noweb literate programs.
Writing Submode Classes
@@ -157,8 +158,9 @@ Writing Submode Classes
* Calculated Submodes:: Deciding the submode at run-time.
* Calculated Faces:: Deciding the display face at run-time.
* Insertion Commands:: Inserting regions automatically.
+* Region Names:: Naming regions for syntax grouping.
* Other Hooks:: Running code at arbitrary points.
-* Delimiter Forms:: Storing the form of the delimiters.
+* Delimiters:: Controlling delimiter overlays.
* Misc Keywords:: Other miscellaneous options.
Indices
@@ -184,25 +186,46 @@ major mode is a customization of Emacs for editing a certain type of
text, such as code for a specific programming language. @xref{Major
Modes, , , emacs, The Emacs Manual}, for details.
-MMM Mode is a general extension to Emacs which has many uses. Currently,
-its most common usage is to edit Mason components. Mason is a
-``Perl-based web site development and delivery engine'' which executes
-Perl code embedded in HTML and other types of documents. For more
-information, see @uref{http://www.masonhq.com}. MMM Mode comes with a
-submode class (@pxref{Submode Classes}) for editing Mason components
-(@pxref{Mason}).
-
-More generally, however, MMM Mode is useful whenever one file contains
-text in two or more programming languages, or that should be in two or
-more different modes. For example, CGI scripts written in any language,
-such as Perl or PL/SQL, may want to output verbatim HTML, and the writer
-of such scripts may want to use Emacs' html-mode to edit this HTML code.
+MMM Mode is a general extension to Emacs which is useful whenever one
+file contains text in two or more programming languages, or that
+should be in two or more different modes. For example:
+
+@itemize @bullet
+@item
+CGI scripts written in any language, from Perl to PL/SQL, may want to
+output verbatim HTML, and the writer of such scripts may want to use
+Emacs' html-mode or sgml-mode to edit this HTML code, while remaining
+in the appropriate programming language mode for the rest of the
+file. @xref{Here-documents}, for example.
+
+@item
+There are now many ``content delivery systems'' which turn the CGI
+script idea around and simply add extra commands to an HTML file,
+often in some programming language, which are interpreted on the
+server. @xref{Mason}, @xref{Embperl}, @xref{ePerl}, @xref{JSP}.
+
+@item
HTML itself can also contain embedded languages such as Javascript and
-CSS styles, for which Emacs has different major modes. Emacs also allows
-files of any type to contain `local variables', which can include Emacs
-Lisp code to be evaluated. @xref{File Variables, , , emacs, The Emacs
-Manual}. It may be easier to edit this code in Emacs Lisp mode than in
-whatever mode is used for the rest of the file.
+CSS styles, for which Emacs has different major modes.
+@xref{Javascript}, and @xref{Embedded CSS}, for example.
+
+@item
+The idea of ``literate programming'' requires the same file to contain
+documentation (written as text, html, latex, etc.) and code (in an
+appropriate programming language). @xref{Noweb}, for example.
+
+@item
+Emacs allows files of any type to contain `local variables', which can
+include Emacs Lisp code to be evaluated. @xref{File Variables, , ,
+emacs, The Emacs Manual}. It may be easier to edit this code in Emacs
+Lisp mode than in whatever mode is used for the rest of the file.
+@xref{File Variables}.
+
+@item
+There are many more possible uses for MMM Mode. RPM spec files can
+contain shell scripts (@pxref{RPM}). Email or newsgroup messages may
+contain sample code. And so on. We encourage you to experiment.
+@end itemize
@menu
* Basic Concepts:: A simple explanation of how it works.
@@ -386,10 +409,7 @@ mmm-ified.
You can now read the rest of this manual to learn more about how MMM
Mode works and how to configure it to your preferences. If none of the
supplied submode classes fit your needs, then you can try to write your
-own. There will eventually be a chapter on how to do that, but for now,
-see the documentation for the variable `mmm-classes-alist'.
-
-@c @xref{Writing Classes}, for more information.
+own. @xref{Writing Classes}, for more information.
@node Basics, Customizing, Overview, Top
@comment node-name, next, previous, up
@@ -989,7 +1009,7 @@ mode to use for the submodes:
@defopt mmm-major-mode-preferences
The elements of this list are cons cells of the form
@code{(@var{language} . @var{mode})}. @var{language} should be a symbol
-such as @code{perl}, @code{javascript}, or @code{java}, while @var{mode}
+such as @code{perl}, @code{html-js}, or @code{java}, while @var{mode}
should be the name of a major mode such as @code{perl-mode},
@code{cperl-mode}, @code{javascript-mode}, or @code{c++-mode}.
@@ -1203,6 +1223,7 @@ Mode.
* ePerl:: A general Perl-embedding syntax.
* JSP:: Java code embedded in HTML.
* RPM:: Shell scripts in RPM Spec Files.
+* Noweb:: Noweb literate programs.
@end menu
@node Mason, File Variables, Supplied Classes, Supplied Classes
@@ -1246,8 +1267,15 @@ In addition, some users have reported that the CPerl indentation
sometimes does not work. This problem has not yet been tracked down,
however, and more data about when it happens would be helpful.
-Michael Alan Dorman has reported problems using PSGML with Mason. He
-suggests adding these lines to @file{.emacs} to turn it off.
+Some people have reported problems using PSGML with Mason. Adding the
+following line to a @file{.emacs} file should suffice to turn PSGML off
+and cause emacs to use a simpler HTML mode:
+
+@lisp
+(autoload 'html-mode "sgml-mode" "HTML Mode" t)
+@end lisp
+
+Earlier versions of PSGML may require instead the following fix:
@lisp
(delete '("\\.html$" . sgml-html-mode) auto-mode-alist)
@@ -1255,11 +1283,12 @@ suggests adding these lines to @file{.emacs} to turn it off.
@end lisp
Other users report using PSGML with Mason and MMM Mode without
-difficulty. If you don't have problems and want to use PSGML, simply
-replace @code{html-mode} everywhere in the suggested code with
-@code{sgml-html-mode} or @code{sgml-mode}. Similarly, if you are using
-XEmacs and want to use the alternate HTML mode @code{hm--html-mode},
-replace @code{html-mode} with that symbol.
+difficulty. If you don't have problems and want to use PSGML, you may
+need to replace @code{html-mode} in the suggested code with
+@code{sgml-html-mode}. (Depending on your version of PSGML, this may
+not be necessary.) Similarly, if you are using XEmacs and want to use
+the alternate HTML mode @code{hm--html-mode}, replace @code{html-mode}
+with that symbol.
One problem that crops up when using PSGML with Mason is that even
ignoring the special tags and Perl code (which, as I've said, haven't
@@ -1418,7 +1447,7 @@ specified by the user; @xref{Preferred Modes}. The default is
@code{jde-mode} if present, otherwise @code{java-mode}.
-@node RPM, , JSP, Supplied Classes
+@node RPM, Noweb, JSP, Supplied Classes
@comment node-name, next, previous, up
@section RPM Spec Files
@@ -1439,6 +1468,94 @@ Suggested setup code:
Thanks to Marcus Harnisch <Marcus.Harnisch@@gmx.net> for contributing
this submode class.
+@node Noweb, , RPM, Supplied Classes
+@comment node-name, next, previous, up
+@section Noweb literate programming
+
+@file{mmm-noweb.el} contains the definition of an MMM Mode submode
+class for editing Noweb documents. Most Noweb documents use \LaTeX
+for the documentation chunks. Code chunks in Noweb are
+document-specific, and the mode may be set with a local variable
+setting in the document. The variable @var{mmm-noweb-code-mode}
+controls the global code chunk mode. Since Noweb files may have many
+languages in their code chunks, this mode also allows setting the mode
+by specifying a mode in the first line or two of a code chunk, using
+the normal Emacs first-line mode setting syntax. Note that this
+first-line mode setting only matches a single word for the mode name,
+and does not support the variable name setting of the generalized
+first file line syntax.
+
+@verbatim
+% -*- mode: latex; mmm-noweb-code-mode: c++; -*-
+% First chunk delimiter!
+@
+\noweboptions{smallcode}
+
+\title{Sample Noweb File}
+\author{Joe Kelsey\\
+\nwanchorto{mailto:bozo@bozo.bozo}{\tt bozo@bozo.bozo}}
+\maketitle
+
+@
+\section{Introduction}
+Normal noweb documentation for the required [[*]] chunk.
+<<*>>=
+// C++ mode here!
+// We might list the program here, or simply included chunks.
+<<myfile.cc>>
+@ %def myfile.cc
+
+@
+\section{[[myfile.cc]]}
+This is [[myfile.cc]]. MMM noweb-mode understands code quotes in
+documentation.
+<<myfile.cc>>=
+// This section is indented separately from previous.
+@
+
+@
+\section{A Perl Chunk}
+We need a Perl chunk.
+<<myfile.pl>>=
+#!/usr/bin/perl
+# -*- perl -*-
+# Each differently named chunk is flowed separately.
+@
+
+\section{Finish [[myfile.cc]]}
+When we resume a previously defined chunk, they are indented together.
+<<myfile.cc>>=
+// Pick up where we left off...
+@
+
+@end verbatim
+
+The quoted code chunks inside documentation chunks are given the mode
+found in the variable @var{mmm-noweb-quote-mode}, if set, or the value
+in @var{mmm-noweb-code-mode} otherwise. Also, each quoted chunk is
+set to have a unique name to prevent them from being indented as a
+unit.
+
+Suggested setup code:
+@lisp
+(mmm-add-mode-ext-class 'latex-mode "\\.nw\\'" 'noweb)
+(add-to-list 'auto-mode-alist '("\\.nw\\'" . latex-mode))
+@end lisp
+
+In mmm-noweb buffers, each differently-named code chunk has a
+different @code{:name}, allowing all chunks with the same name to get
+indented together.
+
+This mode also supplies special paragraph filling operations for use
+in documentation areas of the buffer. From a primary-mode
+(@code{latex-mode, , emacs}) region, pressing @kbd{C-c % C-q} will mark all
+submode regions with word syntax (@code{mmm-word-other-regions}), fill
+the current paragraph (@code{(fill-paragraph justify)}), and remove the
+syntax markings (@code{mmm-undo-syntax-other-regions}).
+
+Thanks to Joe Kelsey <joe@@zircon.seattle.wa.us> for contributing this
+class.
+
@node Writing Classes, Indices, Supplied Classes, Top
@comment node-name, next, previous, up
@@ -1458,8 +1575,9 @@ with examples.
* Calculated Submodes:: Deciding the submode at run-time.
* Calculated Faces:: Deciding the display face at run-time.
* Insertion Commands:: Inserting regions automatically.
+* Region Names:: Naming regions for syntax grouping.
* Other Hooks:: Running code at arbitrary points.
-* Delimiter Forms:: Storing the form of the delimiters.
+* Delimiters:: Controlling delimiter overlays.
* Misc Keywords:: Other miscellaneous options.
@end menu
@@ -1634,10 +1752,11 @@ such as @samp{<%perl>...</%perl>}, inline output expressions bounded by
``umbrella'' class, to turn all these classes on or off together.
@defun mmm-add-group @var{group} @var{classes}
-The submode classes @var{classes}, which should be a list just as might
-be passed to @code{mmm-add-classes}, are added just as by that function.
-Furthermore, another class named @var{group} is added, which encompasses
-all the classes in @var{classes}.
+The submode classes @var{classes}, which should be a list of lists,
+similar to what might be passed to @code{mmm-add-classes}, are added
+just as by that function. Furthermore, another class named
+@var{group} is added, which encompasses all the classes in
+@var{classes}.
@end defun
Technically, an group class is specified with a @code{:classes} keyword
@@ -1645,6 +1764,21 @@ argument, and the subsidiary classes are given a non-nil @code{:private}
keyword argument to make them invisible. But in general, all you should
ever need to know is how to invoke the function above.
+@defun mmm-add-to-group @var{group} @var{classes}
+Adds a list of classes to an already existing group. This can be
+used, for instance, to add a new quoting definition to @var{html-js}
+using this example to add the quote characters ``%=%'':
+
+@lisp
+(mmm-add-to-group 'html-js '((js-html
+ :submode javascript
+ :face mmm-code-submode-face
+ :front "%=%"
+ :back "%=%"
+ :end-not-begin t)))
+@end lisp
+@end defun
+
@node Calculated Submodes, Calculated Faces, Submode Groups, Writing Classes
@comment node-name, next, previous, up
@@ -1668,7 +1802,7 @@ It is invoked immediately after a match is found for @code{:front}, and
is passed one argument: a string representing the front delimiter.
Normally this string is simply whatever was matched by @code{:front},
but this can be changed with the keyword @code{:front-form}
-(@pxref{Delimiter Forms}). The function should then return a symbol
+(@pxref{Delimiters}). The function should then return a symbol
that would be a valid argument to @code{:submode}: either the name of a
mode, or that of a language to look up a preferred mode. If it detects
an invalid match---for example, the user has specified a mode which is
@@ -1725,10 +1859,12 @@ highlighted with @var{face}. For example, here is an excerpt from the
Thus, regions beginning with @samp{[+} are highlighted as output
expressions, which they are, while @samp{[-} and @samp{[*} regions are
-highlighted as simple executed code, and so on.
+highlighted as simple executed code, and so on. Note that
+@var{mmm-submode-decoration-level} must be set to 2 (high decoration)
+for different faces to be displayed.
-@node Insertion Commands, Other Hooks, Calculated Faces, Writing Classes
+@node Insertion Commands, Region Names, Calculated Faces, Writing Classes
@comment node-name, next, previous, up
@section Specifying Insertion Commands
@@ -1790,7 +1926,34 @@ fourth (dotted) element (@code{"+"}) as the `str' variable; the user is
not prompted.
-@node Other Hooks, Delimiter Forms, Insertion Commands, Writing Classes
+@node Region Names, Other Hooks, Insertion Commands, Writing Classes
+@comment node-name, next, previous, up
+@section Giving Names to Submode Regions for Grouping
+
+Submode regions can be given ``names'' which are used for grouping.
+Names are always strings and are compared as strings. Regions with
+the same name are considered part of the same chunk of code. This is
+used by the syntax and fontification functions. Unnamed regions are
+not grouped with any others.
+
+By default, regions are nameless, but with the @code{:match-name}
+keyword argument a name can be supplied. This argument must be a
+string or a function. If it is a function, it is passed a string
+representing the front delimiter found, and must return the name to
+use. If it is a string, it is used as-is for the name, unless
+@code{:save-name} has a non-nil value, in which case expressions such
+as @samp{~1} are substituted with the corresponding matched
+subexpression from @code{:front}. This is the same as how
+@code{:back} is interpreted when @code{:save-matches} is non-nil.
+
+As a special optimization for region insertion (@pxref{Insertion
+Commands}), the argument @code{:skel-name} can be set to a non-nil
+value, in which case the insertion code will use the user-prompted
+string value as the region name, instead of going through the normal
+matching procedure.
+
+
+@node Other Hooks, Delimiters, Region Names, Writing Classes
@comment node-name, next, previous, up
@section Other Hooks into the Scanning Process
@@ -1829,16 +1992,66 @@ write a handler function, I suggest looking at the source for
@code{mmm-ify} to get an idea of what must be done.
-@node Delimiter Forms, Misc Keywords, Other Hooks, Writing Classes
+@node Delimiters, Misc Keywords, Other Hooks, Writing Classes
@comment node-name, next, previous, up
-@section Controlling the Form of the Delimiters
+@section Controlling the Delimiter Regions and Forms
+
+MMM also makes overlays for the delimiter regions, to keep track of
+their position and form. Normally, the front delimiter overlay starts
+at the beginning of the match for @code{:front} and ends at the
+beginning of the submode region overlay, while the back delimiter
+overlay starts at the end of the submode region overlay and ends at
+the end of the match for @code{:back}. You can supply offsets from
+these positions using the keyword arguments @code{:front-delim} and
+@code{:back-delim}, which take values of the same sort as
+@code{:front-offset} and @code{:back-offset}.
+
+In addition, the delimiter regions can be in a major mode of their
+own. There are usually only two meaningful modes to use: the primary
+mode or a non-mode like fundamental-mode. These correspond to the
+following two situations:
+
+@itemize
+@item
+If the delimiter syntax which specifies the submode regions is
+something @emph{added to} the syntax of the primary mode by a
+pre-interpreter, then the delimiter regions should be in a non-mode.
+This is the case, for example, with all server-side HTML script
+extensions, such as @xref{Mason}, @xref{Embperl}, and @xref{ePerl}.
+It is also the case for literate programming such as @xref{Noweb}.
+This is the default behavior. The non-mode used is controlled by the
+variable @code{mmm-delimiter-mode}, which defaults to
+fundamental-mode.
-On each submode region overlay, MMM Mode stores the ``form'' of the
-front and back delimiters, which are regular expressions that match the
-delimiters. At present these are not used for much, but in the future
-they may be used to help with automatic updating of regions as you type.
-Normally, the form stored is the result of evaluating the expression
-@code{(regexp-quote (match-string 0))} after each match is found.
+@item
+If, on the other hand, the delimiter syntax and inclusion of different
+modes is an @emph{intrinsic part} of the primary mode, then the
+delimiter regions should remain in the primary mode. This is the
+case, for example, with @xref{Embedded CSS}, and @xref{Javascript},
+since the @code{<style>} and @code{<script>} tags are perfectly valid
+HTML. In this case, you should give the keyword parameter
+@code{:delimiter-mode} with a value of @code{nil}, meaning to use the
+primary mode.
+@end itemize
+
+The keyword parameter @code{:delimiter-mode} can be given any major
+mode as an argument, but the above two situations should cover the
+vast majority of cases.
+
+The delimiter regions can also be highlighted, if you wish. The
+keyword parameters @code{:front-face} and @code{:back-face} may be
+faces specifying how to highlight these regions under high
+decoration. Under low decoration, the value of the variable
+@code{mmm-delimiter-face} is used (by default, nothing), and of course
+under no decoration there is no coloring.
+
+Finally, for each submode region overlay, MMM Mode stores the ``form''
+of the front and back delimiters, which are regular expressions that
+match the delimiters. At present these are not used for much, but in
+the future they may be used to help with automatic updating of regions
+as you type. Normally, the form stored is the result of evaluating
+the expression @code{(regexp-quote (match-string 0))} after each match
+is found.
You can customize this with the keyword argument @code{:front-form}
(respectively, @code{:back-form}). If it is a string, it is used
@@ -1855,7 +2068,7 @@ adjust the overlay; if nil it means to match the delimiter and return
the result in the match data.
-@node Misc Keywords, , Delimiter Forms, Writing Classes
+@node Misc Keywords, , Delimiters, Writing Classes
@comment node-name, next, previous, up
@section Miscellaneous Other Keyword Arguments
diff --git a/mmm/version.texi b/mmm/version.texi
index b62e6859..2b6392f8 100644
--- a/mmm/version.texi
+++ b/mmm/version.texi
@@ -1,3 +1,4 @@
-@set UPDATED 18 February 2001
-@set EDITION 0.4.7
-@set VERSION 0.4.7
+@set UPDATED 9 March 2003
+@set UPDATED-MONTH March 2003
+@set EDITION 0.4.8
+@set VERSION 0.4.8