diff options
author | 2003-02-17 22:33:16 +0000 | |
---|---|---|
committer | 2003-02-17 22:33:16 +0000 | |
commit | 38bfe396e0cf99529fcf0310c12aa7e0f112478f (patch) | |
tree | 364737b26459d6cc05a6c6887703283eb04577c8 /mmm | |
parent | 0c8b0ff62b33ad5709c1b00c971104cb1d751b42 (diff) |
New files.
Diffstat (limited to 'mmm')
-rw-r--r-- | mmm/AUTHORS | 3 | ||||
-rw-r--r-- | mmm/COPYING | 340 | ||||
-rw-r--r-- | mmm/FAQ | 115 | ||||
-rw-r--r-- | mmm/INSTALL | 182 | ||||
-rw-r--r-- | mmm/NEWS | 220 | ||||
-rw-r--r-- | mmm/README | 92 | ||||
-rw-r--r-- | mmm/TODO | 63 | ||||
-rw-r--r-- | mmm/mmm-auto.el | 174 | ||||
-rw-r--r-- | mmm/mmm-class.el | 285 | ||||
-rw-r--r-- | mmm/mmm-cmds.el | 398 | ||||
-rw-r--r-- | mmm/mmm-compat.el | 193 | ||||
-rw-r--r-- | mmm/mmm-mason.el | 167 | ||||
-rw-r--r-- | mmm/mmm-mode.el | 463 | ||||
-rw-r--r-- | mmm/mmm-region.el | 642 | ||||
-rw-r--r-- | mmm/mmm-rpm.el | 81 | ||||
-rw-r--r-- | mmm/mmm-sample.el | 308 | ||||
-rw-r--r-- | mmm/mmm-univ.el | 64 | ||||
-rw-r--r-- | mmm/mmm-utils.el | 143 | ||||
-rw-r--r-- | mmm/mmm-vars.el | 764 | ||||
-rw-r--r-- | mmm/mmm.texinfo | 1904 | ||||
-rw-r--r-- | mmm/version.texi | 3 |
21 files changed, 6604 insertions, 0 deletions
diff --git a/mmm/AUTHORS b/mmm/AUTHORS new file mode 100644 index 00000000..0740e780 --- /dev/null +++ b/mmm/AUTHORS @@ -0,0 +1,3 @@ +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>. diff --git a/mmm/COPYING b/mmm/COPYING new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/mmm/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/mmm/FAQ b/mmm/FAQ new file mode 100644 index 00000000..3b1c93dd --- /dev/null +++ b/mmm/FAQ @@ -0,0 +1,115 @@ +-*-outline-*- + Frequently Asked Questions about MMM Mode + ========================================= + +* How do I write/capitalize the name of this package/mode? + +However you want. The author says `MMM Mode' (and occasionally `MMM') +when discussing the entire package, and `mmm-mode' when discussing the +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) + +You may want to try using MMM Mode for a while with the background +highlight, however, or merely changing it to 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 + recognizing new submode regions, so the presence or absence of the + highlight can let you know at a glance where it thinks they are. + +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). + +* I typed `<%' (or other delimiter) but I'm still in the wrong mode. + +MMM Mode isn't that smart yet. You have to tell it explicitly to +reparse (`C-c % C-5' or `C-c % C-b') when you add new submode regions, +and both delimiters have to be present. Hopefully a future version +will be able to automatically recognize new regions an you type them, +but that version is not yet here. + +However, most submode classes provide insertion commands that remove +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 won't MMM Mode work with `foo-mode'? + +Foo-mode probably has extra variables or states that need to be set +up, that MMM Mode doesn't yet know about. Often this sort of problem +can be fixed by adding elements to `mmm-save-local-variables'. If you +know some Elisp, you may want to try and track down the problem +yourself, or you can contact the mailing list and ask for help. +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 +and is quite likely to contain bugs; probably something in your +configuration has brought a new bug to light. Please send the text of +the error, along with a stack backtrace (1) and the relevant portions +of your emacs initialization file, to either the maintainer or the +mailing list, and hopefully a fix can be worked out. + +Of course, it's also possible that there is an error in your +configuration. Double-check the elisp syntax in your init file, or +inspect the backtrace yourself. If the error happens while loading +your init code, try manually evaluating it line by line (`C-x C-e') to +see where the error occurs. Folks on the mailing list can also help +point out errors, but only with your init code and a backtrace. + +(1) To get a stack backtrace of an error, set the emacs variable + `debug-on-error' to non-nil (type `M-x set-variable RET + debug-on-error RET t RET' or `M-: (setq debug-on-error t) RET'), + then repeat the actions which caused the error. A stack backtrace + should pop up which you can select and copy. If the error occurs + 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. + +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'. + +You probably used FSF Emacs to compile MMM as it is the one used by +default if both are installed. To explicitly set the emacs to use +when byte compiling, do the following: + +$ cd mmm-mode-x.x.x +$ make distclean +$ EMACS=/usr/bin/xemacs ./configure +$ make +$ make install + +Running `make distclean' is only necessary if you have already +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. + +* 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. diff --git a/mmm/INSTALL b/mmm/INSTALL new file mode 100644 index 00000000..b42a17ac --- /dev/null +++ b/mmm/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/mmm/NEWS b/mmm/NEWS new file mode 100644 index 00000000..fc48736c --- /dev/null +++ b/mmm/NEWS @@ -0,0 +1,220 @@ +MMM Mode NEWS -- history of user-visible changes. -*-outline-*- +Copyright (C) 2000 Michael Abraham Shulman +See the file COPYING for copying conditions. + +Please send MMM Mode bug reports to viritrilbia@users.sourceforge.net + +* Changes in MMM Mode 0.4.7 + +** Multiple Decoration Levels + +You now have finer control over how colorful your submode regions are, +via `mmm-submode-decoration-level'. Level 0 turns coloring off--no +messing around with faces required. Level 1 (default) is the same as +in previous versions. Level 2 colors regions according to function: +initialization, cleanup, output, declaration, comment, etc. + +** Preferred Major Modes + +The variable `mmm-major-mode-preferences' lets you tell MMM what modes +you prefer for different programming languages and they will be used +by all submode classes. + +** New Submode Classes + +New submode classes for JSP and ePerl are included. A major bug in +the handling of embedded Java (and other C-type languages) was fixed, +so the JSP class should work consistently. + + +* MMM Mode 0.4.6 is a bug-fix release with one user-visible change: + +** New Submode Class for RPM Spec Files + +Contributed by Marcus Harnisch, the `rpm' submode class allows editing +appropriate parts of RPM spec files in shell-script mode. + + +* Changes in MMM Mode 0.4.5 + +** Font-Lock works again in XEmacs + +The MMM code to handle font-locking broke in XEmacs several versions +back due to differences in the font-lock implementation between Emacs +and XEmacs. It appears to be working once again. + +** Here-Document submode class improved + +Here-document names such as <<TEXT_EOF and <<END_PERL_CODE are now +correctly recognized, and `mmm-here-doc-mode-alist' allows you to +define your own mappings from here-document names to submodes. + + +* Changes in MMM Mode 0.4.4 + +** Tab Completion in `mmm-ify-by-class' (`C-c % C-c') + +When interactively specifying a submode class, completion on all +defined public (not internal/private) submode classes is available. + +** Submode classes can now be autoloaded + +You don't need (require 'mmm-mason) or (require 'mmm-sample) in your +.emacs file any more; all the supplied submode classes that are not +automatically loaded are autoloaded from their files of definition. + +** Here-Document submode class can now recognize any submode + +As long as the name of the here-document is or begins with the name of +the appropriate submode, suitably mangled, such as <<HTML or +<<HTML_MODE or <<HTML_MODE_EOF, it should be correctly recognized. + +** New File Variables submode class + +Actually, this is an old submode class that now works (better than +before) with the new post-0.3.8 syntax for class definition. It is a +good candidate for membership in `mmm-global-classes' if you use many +file-local variables, but is not there by default. + +** New flags :include-{front,back} + +If the keywords INCLUDE-FRONT or INCLUDE-BACK are set to non-nil +values in a submode class definition, the corresponding delimiter will +be included inside the submode region. + +** New values for :{front,back}-offset + +The keywords FRONT-OFFSET and BACK-OFFSET can now be function to call, +such as `beginning-of-line' or `end-of-line', or lists of values to +apply in sequence, such as (end-of-line 1). + +** Search for next region now starts at end of previous one + +...rather than at the end of the previous region's ending delimiter. +This allows matching regions ended only by the start of the next one. + + +* Changes in MMM Mode 0.4.3 + +** Syntax of Universal Class Changed + +Instead of %[MODE]% ... %[/MODE]%, the universal class now uses +{%MODE%} ... {%/MODE%} which isn't quite as ugly and doesn't to my +knowledge conflict with any other syntax. + +** Some Bugs under Emacs 19 and XEmacs Fixed + + +* Changes in MMM Mode 0.4.2 + +** Global Classes and `Universal' Class + +The new variable `mmm-global-classes' is the inverse of `mmm-classes' +in that it contains submode classes which apply to all MMM Mode +buffers unless turned off manually with file-local variables. By +default, it contains the class `universal', which defines the syntax +%[MODE]% ... %[/MODE]% to specify regions of any mode. This allows, +for instance, example code embedded in an email to be both edited by +the sender and viewed by the receiver in an appropriate mode. + +** New Embperl Submode Class + +The new supplied submode class `embperl', which can be loaded with +(require 'mmm-sample), detects the Embperl syntax [+...+] (and so on) +for embedded Perl code. + + +* Changes in MMM Mode 0.4.1 + +** Font Lock Parsing Speed Improved + +Extra regions were being parsed due to an error in finding the right +regions, slowing down the parsing considerably. This has been fixed. + + +* Changes in MMM Mode 0.4.0 + +** Improved Local Variable Saving + +Local variables can now be saved for only some major modes, as well as +both globally, per-buffer, or per-submode region. This facility is +now used to save the font-lock cache state, possible improving the +font-lock support. See the docs for `mmm-save-local-variables'. + +** Get and Set Class Parameters + +The functions `mmm-[get,set]-class-parameters' do just that. The +latter modifies the definition of a submode class, affecting all +subsequent applications of that class. + +** New Implementation for MMM Global Mode + +The implementation of MMM Global Mode has been changed from the +"stack-walk" method to the "post-command-hook" method used by +global-font-lock-mode. This is arguably cleaner, but more +importantly, waits until after all local variables and text are loaded +before trying to enabling MMM Mode. + + +* MMM Mode 0.3.10 is a bug-fix release with no user-visible changes + + +* MMM Mode 0.3.9 is a bug-fix release with no user-visible changes + + +* Changes in MMM Mode 0.3.8 + +** IMPORTANT: Default key bindings have changed. + +The MMM Mode commands, including interactive MMM-ification and +re-parsing buffer regions, are now bound by default to key sequences +of the form `C-c % C-<letter>', rather than `C-c % <letter>' as +in previous versions. Key sequences of the form `C-c % <letter>' are +now reserved for submode region insertion. The old behavior can be +restored by setting the variable `mmm-use-old-command-keys' to a +non-nil value before MMM Mode is loaded--then insertion commands are +bound to `C-c % C-<letter>' sequences. + +** New Global Mode added + +MMM Global Mode can now turn MMM Mode on automatically in all buffers, +or only in buffers that have associated submode classes. It replaces +the previous function `mmm-add-find-file-hook', which still works for +now. A side effect of this change is that it is no longer necessary +to use `mmm-add-mode-ext-class': `mmm-mode-ext-classes-alist' can be +modified directly. + +The hack used by MMM Global Mode to insinuate itself into all buffers +is different from, but vaguely similar to, the one used by FSF Emacs' +Global Font Lock Mode. In order that future writers of global modes +don't have to reinvent the wheel, MMM Global Mode provides the hook +`mmm-major-mode-hook' which is run (in theory) whenever a major mode +starts up. Perhaps in future this will be provided in a separate +package. + +** Automatic submode region insertion commands + +Submode classes can now define skeletons for automatic insertion of +submode regions with delimiters. For example, when using the Mason +class, the key sequence `C-c % %' will (by default) insert the text +`<% -!- %>' with point where indicated and submode region already +present. These commands also wrap around words as described in the +documentation of `skeleton-insert'. + +** Info Documentation File + +MMM Mode now has an (admittedly incomplete) manual in Texinfo format. +It can be found in the files `mmm.info' or `mmm.texinfo' in the +distribution. + +** Automatic Installation + +MMM Mode now uses GNU automake/autoconf for ease of installation. See +the files README and INSTALL for more information. + +** Changed submode class specification format + +This change affects only people who define their own submode classes. +The format for defining submode classes has changed; it now uses +keyword arguments for clarity and has a few more possible arguments, +including skeletons for submode region insertion. diff --git a/mmm/README b/mmm/README new file mode 100644 index 00000000..eb45686c --- /dev/null +++ b/mmm/README @@ -0,0 +1,92 @@ + + MMM Mode for Emacs + ================== + +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. + +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: + + ./configure + make + make install + + Alternately, since currently MMM Mode is written in pure Emacs Lisp, + you could just copy all the *.el files in the distribution to a + directory in your `load-path', and optionally byte-compile them + manually (see the Emacs Manual). The configure installation also + 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 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. + + EMACS=/usr/bin/xemacs ./configure + make + make install + + If you want to use MMM in more than one version of emacs, you must + either have separate site-lisp directories (such as Debian does), or + load it from source every time; byte-compiled files are not portable + between emacsen. + +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 + + (require 'mmm-mode) + + or conditionally, as necessary, with + + (require 'mmm-auto) + + The second installs only the major-mode hooks and sets up MMM Mode + to load itself automatically when necessary. + +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. + +UPDATES + + The latest version of MMM Mode should always be available from + http://mmm-mode.sourceforge.net/. + +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. + +CONTACT INFO + + MMM Mode is written and maintained by Michael Abraham Shulman + <viritrilbia@users.sourceforge.net>. + +MAILING LIST + + To subscribe to the MMM Mode mailing list, visit + <http://lists.sourceforge.net/mailman/listinfo/mmm-mode-discuss>. + The mailing list receives announcements of new releases and provides + a forum for discussion of bugs and features. + + Thanks for using MMM Mode! diff --git a/mmm/TODO b/mmm/TODO new file mode 100644 index 00000000..97c1dab8 --- /dev/null +++ b/mmm/TODO @@ -0,0 +1,63 @@ +Hey Emacs, this is a -*-text-*- file! + + To Do List for MMM Mode + ======================= + +Custom mode functions like `mason-mode'. + +Make Mason work a little better with PSGML. The fix I've found works, +but it would be nifty if MMM could do it automatically. Maybe the +custom-mode thing could set the variables, or a hook somewhere. + +Apostrophes mess up Perl parsing in XEmacs but not Emacs. I thought +it was because XEmacs sets `font-lock-beginning-of-syntax-function' +after MMM does, but changing that that didn't fix it. + +Improve re-parsing current region to use inclusion/offsets/etc. + +Support for: ASP, PHP + +DEB and/or RPM packages would be nice. + +The local-variables improvements can probably be used to set minor +modes locally to submode regions. This could replace tmmofl, +especially if we search for regions other than by regexps, say by +syntax properties. + +Trap paragraph motion commands to stop at submode boundaries? + +On text insertion (in `after-change-functions'), do two things. +First, if inside in a region, or after a hanging one, scan for its +back and adjust if necessary. Second, scan both for complete regions +and for hanging fronts. In the latter case, we may insert the back or +start a hanging region; user option. Don't just scan the inserted +text, but backwards, using `mmm-looking-back-at'. Remember to handle +delimiter inclusion and offsets as best possible. + +It would be nice if C-j ended a Mason one-liner and began a new one on +the next line. This is a rather Mason-specific thing, but other +classes might have similar single-line regions. Add a new submode +class argument, such as KEYMAP, or even ONE-LINE? + +Allow a submode class to specify its allowable "parent" submode +classes. This could also be used to implement htp.p, by first +scanning for the function calls as a major-mode submode region, then +requiring that parent type for the HTML mode class. Nested submodes +alternate highlight colors, say with `mmm-secondary-submode-face'. + +Ought %text in Mason to be a non-submode, since any Mason tags inside +it will probably be /edited/ as Perl (being, say, code examples)? +Only problem is it might confuse the programmer into thinking that +code will get executed. Maybe use a different face. Could do that +with another grouping class, say uneval-mason, that overrides the +faces of mason and has :parent mason-text, and allow a mode to specify +what about it changes depending on its parent, or a parent to specify +changes to its children, or a group to specify changes to its members. + +If font-locking needs more help, try narrowing the region before +fontifying, or even advising `parse-partial-sexp' and friends. At +present, it seems good enough, though. + +It'd be nice if submode regions could preserve the indentation of the +dominant major mode code around them. For example, Perl code embedded +in HTML where the HTML is indented such as for a table. diff --git a/mmm/mmm-auto.el b/mmm/mmm-auto.el new file mode 100644 index 00000000..eaca7848 --- /dev/null +++ b/mmm/mmm-auto.el @@ -0,0 +1,174 @@ +;;; mmm-auto.el --- loading and enabling MMM Mode automatically + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 functions and hooks to load and enable MMM Mode +;; automatically. It sets up autoloads for the main MMM Mode functions +;; and interactive commands, and also sets up MMM Global Mode. + +;;{{{ Comments on MMM Global Mode + +;; This is a kludge borrowed from `global-font-lock-mode'. The idea +;; is the same: we have a function (here `mmm-mode-on-maybe') that we +;; want to be run whenever a major mode starts. Unfortunately, there +;; is no hook (like, say `major-mode-hook') that all major modes run +;; when they are finished. `post-command-hook', however, is run after +;; *every* command, so we do our work in there. (Actually, using +;; `post-command-hook' is even better than being run by major mode +;; functions, since it is run after all local variables and text are +;; loaded, which may not be true in certain cases for the other.) + +;; In order to do this magic, we rely on the fact that there *is* a +;; hook that all major modes run when *beginning* their work. They +;; call `kill-all-local-variables' (unless they are broken), which in +;; turn runs `change-major-mode-hook'. So we add a function to *that* +;; hook which saves the current buffer and temporarily adds a function +;; to `post-command-hook' which processes that buffer. + +;; Actually, in the interests of generality, what that function does +;; is run the hook `mmm-major-mode-hook'. Our desired function +;; `mmm-mode-on-maybe' is then added to that hook. This way, if the +;; user wants to run something else on every major mode, they can just +;; add it to `mmm-major-mode-hook' and take advantage of this hack. + +;;}}} + +;;; Code: + +(require 'cl) +(require 'mmm-vars) + +;;{{{ Autoload Submode Classes + +(defvar mmm-autoloaded-classes + '((mason "mmm-mason" nil) + (embedded-css "mmm-sample" nil) + (html-js "mmm-sample" nil) + (here-doc "mmm-sample" nil) + (embperl "mmm-sample" nil) + (eperl "mmm-sample" nil) + (jsp "mmm-sample" nil) + (file-variables "mmm-sample" nil) + (rpm-sh "mmm-rpm" t) + (rpm "mmm-rpm" nil) + ) + "Alist of submode classes autoloaded from files. +Elements look like \(CLASS FILE PRIVATE) where CLASS is a submode +class symbol, FILE is a string suitable for passing to `load', and +PRIVATE is non-nil if the class is invisible to the user. Classes can +be added to this list with `mmm-autoload-class'.") + +(defun mmm-autoload-class (class file &optional private) + "Autoload submode class CLASS from file FILE. +PRIVATE, if non-nil, means the class is user-invisible. In general, +private classes need not be autoloaded, since they will usually be +invoked by a public class in the same file." + ;; Don't autoload already defined classes + (unless (assq class mmm-classes-alist) + (add-to-list 'mmm-autoloaded-classes + (list class file private)))) + +;;}}} +;;{{{ Autoload Functions + +;; To shut up the byte compiler. +(eval-and-compile + (autoload 'mmm-mode-on "mmm-mode" "Turn on MMM Mode. See `mmm-mode'.") + (autoload 'mmm-mode-off "mmm-mode" "Turn off MMM Mode. See `mmm-mode'.") + (autoload 'mmm-update-font-lock-buffer "mmm-region") + (autoload 'mmm-ensure-fboundp "mmm-utils") + (autoload 'mmm-mode "mmm-mode" + "Minor mode to allow multiple major modes in one buffer. +Without ARG, toggle MMM Mode. With ARG, turn MMM Mode on iff ARG is +positive and off otherwise." t)) + +;; These may actually be used. +(autoload 'mmm-ify-by-class "mmm-cmds" "" t) +(autoload 'mmm-ify-by-regexp "mmm-cmds" "" t) +(autoload 'mmm-ify-region "mmm-cmds" "" t) +(autoload 'mmm-parse-buffer "mmm-cmds" "" t) +(autoload 'mmm-parse-region "mmm-cmds" "" t) +(autoload 'mmm-parse-block "mmm-cmds" "" t) +(autoload 'mmm-clear-current-region "mmm-cmds" "" t) +(autoload 'mmm-reparse-current-region "mmm-cmds" "" t) +(autoload 'mmm-end-current-region "mmm-cmds" "" t) +(autoload 'mmm-insertion-help "mmm-cmds" "" t) +(autoload 'mmm-insert-region "mmm-cmds" "" t) + +;;}}} +;;{{{ MMM Global Mode + +(defvar mmm-changed-buffers-list () + "Buffers that need to be checked for running the major mode hook.") + +(defun mmm-major-mode-change () + "Add this buffer to `mmm-changed-buffers-list' for checking. +When the current command is over, MMM Mode will be turned on in this +buffer depending on the value of `mmm-global-mode'. Actually, +everything in `mmm-major-mode-hook' will be run." + (and (boundp 'mmm-mode) + mmm-mode + (mmm-mode-off)) + (add-to-list 'mmm-changed-buffers-list (current-buffer)) + (add-hook 'post-command-hook 'mmm-check-changed-buffers)) + +(add-hook 'change-major-mode-hook 'mmm-major-mode-change) + +(defun mmm-check-changed-buffers () + "Run major mode hook for the buffers in `mmm-changed-buffers-list'." + (remove-hook 'post-command-hook 'mmm-check-changed-buffers) + (dolist (buffer mmm-changed-buffers-list) + (when (buffer-live-p buffer) + (save-excursion + (set-buffer buffer) + (mmm-run-major-mode-hook)))) + (setq mmm-changed-buffers-list '())) + +(defun mmm-mode-on-maybe () + "Conditionally turn on MMM Mode. +Turn on MMM Mode if `global-mmm-mode' is non-nil and there are classes +to apply, or always if `global-mmm-mode' is t." + (cond ((eq mmm-global-mode t) (mmm-mode-on)) + ((not mmm-global-mode)) + ((mmm-get-all-classes nil) (mmm-mode-on))) + (when mmm-mode + (mmm-update-font-lock-buffer))) + +(add-hook 'mmm-major-mode-hook 'mmm-mode-on-maybe) + +(defalias 'mmm-add-find-file-hooks 'mmm-add-find-file-hook) +(defun mmm-add-find-file-hook () + "Equivalent to \(setq mmm-global-mode 'maybe). +This function is deprecated and may be removed in future." + (message "Warning: `mmm-add-find-file-hook' is deprecated.") + (setq mmm-global-mode 'maybe)) + +;;}}} + +(provide 'mmm-auto) + +;;; mmm-auto.el ends here
\ No newline at end of file diff --git a/mmm/mmm-class.el b/mmm/mmm-class.el new file mode 100644 index 00000000..46067fd9 --- /dev/null +++ b/mmm/mmm-class.el @@ -0,0 +1,285 @@ +;;; mmm-class.el --- MMM submode class variables and functions + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 variable and function definitions for +;; manipulating and applying MMM submode classes. See `mmm-vars.el' +;; for variables that list classes. + +;;; Code: + +(require 'cl) +(require 'mmm-vars) +(require 'mmm-region) + +;;{{{ Get Class Specifications + +(defun mmm-get-class-spec (class) + "Get the class specification for CLASS. +CLASS can be either a symbol to look up in `mmm-classes-alist' or a +class specifier itself." + (cond ((symbolp class) ; A symbol must be looked up + (or (cdr (assq class mmm-classes-alist)) + (and (cadr (assq class mmm-autoloaded-classes)) + (load (cadr (assq class mmm-autoloaded-classes))) + (cdr (assq class mmm-classes-alist))) + (signal 'mmm-invalid-submode-class (list class)))) + ((listp class) ; A list must be a class spec + class) + (t (signal 'mmm-invalid-submode-class (list class))))) + +;;}}} +;;{{{ Get and Set Class Parameters + +(defun mmm-get-class-parameter (class param) + "Get the value of the parameter PARAM for CLASS, or nil if none." + (cadr (member param (mmm-get-class-spec class)))) + +(defun mmm-set-class-parameter (class param value) + "Set the value of the parameter PARAM for CLASS to VALUE. +Creates a new parameter if one is not present." + (let* ((spec (mmm-get-class-spec class)) + (current (member param spec))) + (if current + (setcar (cdr current) value) + (nconc spec (list param value))))) + +;;}}} +;;{{{ Apply Classes + +(defun* mmm-apply-class + (class &optional (start (point-min)) (stop (point-max)) face) + "Apply the submode class CLASS from START to STOP in FACE. +If FACE is nil, the face for CLASS is used, or the default face if +none is specified by CLASS." + ;; The "special" class t means do nothing. It is used to turn on + ;; MMM Mode without applying any classes. + (unless (eq class t) + (apply #'mmm-ify :start start :stop stop + (append (mmm-get-class-spec class) + (list :face face))))) + +(defun* mmm-apply-classes + (classes &key (start (point-min)) (stop (point-max)) face) + "Apply all submode classes in CLASSES, in order. +All classes are applied regardless of any errors that may occur in +other classes. If any errors occur, `mmm-apply-classes' exits with an +error once all classes have been applied." + (let (invalid-classes) + (dolist (class classes) + (condition-case err + (mmm-apply-class class start stop face) + (mmm-invalid-submode-class + ;; Save the name of the invalid class, so we can report them + ;; all together at the end. + (add-to-list 'invalid-classes (second err))))) + (when invalid-classes + (signal 'mmm-invalid-submode-class invalid-classes)))) + +;;}}} +;;{{{ Apply All Classes + +(defun* mmm-apply-all (&key (start (point-min)) (stop (point-max))) + "MMM-ify from START to STOP by all submode classes. +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-refontify-maybe start stop)) + +;;}}} +;;{{{ Scan for Regions + +(defun* mmm-ify + (&rest all &key classes handler submode face + (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-verify back-verify + front-form back-form creation-hook + match-submode match-face + (front-match 0) + (back-match 0) + end-not-begin + ;insert + &allow-other-keys + ) + "Create submode regions from START to STOP according to arguments. +If CLASSES is supplied, it must be a list of valid CLASSes. Otherwise, +the rest of the arguments are for an actual class being applied. See +`mmm-classes-alist' for information on what they all mean." + ;; 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))) + (cond + ;; If we have a class list, apply them all. + (classes + (mmm-apply-classes classes :start start :stop stop :face face)) + ;; Otherwise, apply this class. + ;; If we have a handler, call it. + (handler + (apply handler all)) + ;; Otherwise, we search from START to STOP for submode regions, + ;; continuining over errors, until we don't find any more. If FRONT + ;; and BACK are number-or-markers, this should only execute once. + (t + (mmm-save-all + (goto-char start) + (loop for (beg end matched-front matched-back + matched-submode matched-face back-to resume-at) = + (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. + (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)) + ;; If our region is invalid, go back to the end of the + ;; front match and continue on. + (mmm-invalid-parent (goto-char back-to))) + ;; 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) + ))))) + +;;}}} +;;{{{ Match Regions + +(defun* mmm-match-region + (&key start stop front back front-verify back-verify + 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 + &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." + (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)) + (front-form (mmm-get-form front-form))) + (let ((submode (if match-submode + (condition-case nil + (mmm-save-all + (funcall match-submode front-form)) + (mmm-no-matching-submode + (return-from + mmm-match-region + (values nil nil nil nil nil back-to)))) + nil)) + (face (cond ((functionp match-face) + (mmm-save-all + (funcall match-face front-form))) + (match-face + (cdr (assoc front-form match-face)))))) + (when (mmm-match-and-verify + (if save-matches + (mmm-format-matches back) + back) + beg stop back-verify) + (let* ((end (mmm-match->point (not include-back) back-offset + front-match back-match)) + (back-form (mmm-get-form back-form)) + (resume-at (if end-not-begin + (match-end back-match) + end))) + (values beg end front-form back-form submode face back-to resume-at))))))) + +(defun mmm-match->point (beginp offset front-match back-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'." + (save-excursion + (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)) + (funcall spec))) + (point))) + +(defun mmm-match-and-verify (pos start stop &optional verify) + "Find first match for POS between point and STOP satisfying VERIFY. +Return non-nil if a match was found, and set match data. POS can be a +number-or-marker, a regexp, or a function. + +If POS is a number-or-marker, it is used as-is. If it is a string, it +is searched for as a regexp until VERIFY returns non-nil. If it is a +function, it is called with argument STOP and must return non-nil iff +a match is found, and set the match data. Note that VERIFY is ignored +unless POS is a regexp." + (cond + ;; A marker can be used as-is, but only if it's in bounds. + ((and (number-or-marker-p pos) (>= pos start) (<= pos stop)) + (goto-char pos) + (looking-at "")) ; Set the match data + ;; Strings are searched for as regexps. + ((stringp pos) + (loop always (re-search-forward pos stop 'limit) + until (or (not verify) (mmm-save-all (funcall verify))))) + ;; Otherwise it must be a function. + ((functionp pos) + (funcall pos stop)))) + +;;}}} +;;{{{ Get Delimiter Forms + +(defun mmm-get-form (form) + "Return the delimiter form specified by FORM. +If FORM is nil, call `mmm-default-get-form'. If FORM is a string, +return it. If FORM is a function, call it. If FORM is a list, return +its `car' \(usually in this case, FORM is a one-element list +containing a function to be used as the delimiter form." + (cond ((stringp form) form) + ((not form) (mmm-default-get-form)) + ((functionp form) (mmm-save-all (funcall form))) + ((listp form) (car form)))) + +(defun mmm-default-get-form () + (regexp-quote (match-string 0))) + +;;}}} + +(provide 'mmm-class) + +;;; mmm-class.el ends here
\ No newline at end of file diff --git a/mmm/mmm-cmds.el b/mmm/mmm-cmds.el new file mode 100644 index 00000000..82b2235c --- /dev/null +++ b/mmm/mmm-cmds.el @@ -0,0 +1,398 @@ +;;; mmm-cmds.el --- MMM Mode interactive commands and keymap + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 interactive commands for MMM Mode. + +;;; Code: + +(require 'font-lock) +(require 'mmm-compat) +(require 'mmm-vars) +(require 'mmm-class) + +;;{{{ Applying Predefined Classes + +(defun mmm-ify-by-class (class) + "Add submode regions according to an existing submode class." + (interactive + (list (intern + (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)))) + nil t)))) + (unless (eq class (intern "")) + (mmm-apply-class class) + (mmm-add-to-history class) + (mmm-update-font-lock-buffer))) + +;;}}} +;;{{{ Applying by the Region + +(defun mmm-ify-region (submode front back) + "Add a submode region for SUBMODE coinciding with current region." + (interactive "aSubmode: \nr") + (mmm-ify :submode submode :front front :back back) + (setq front (mmm-make-marker front t nil) + back (mmm-make-marker back nil nil)) + (mmm-add-to-history `(:submode ,submode :front ,front :back ,back)) + (mmm-enable-font-lock submode)) + +;;}}} +;;{{{ Applying Simple Regexps + +(defun mmm-ify-by-regexp + (submode front front-offset back back-offset save-matches) + "Add SUBMODE regions to the buffer delimited by FRONT and BACK. +With prefix argument, prompts for all additional keywords arguments. +See `mmm-classes-alist'." + (interactive "aSubmode: +sFront Regexp: +nOffset from Front Regexp: +sBack Regexp: +nOffset from Back Regexp: +nNumber of matched substrings to save: ") + (let ((args (mmm-save-keywords submode front back front-offset + back-offset save-matches))) + (apply #'mmm-ify args) + (mmm-add-to-history args)) + (mmm-enable-font-lock submode)) + +;;}}} +;;{{{ Re-parsing Areas + +(defun mmm-parse-buffer () + "Re-apply all applicable submode classes to current buffer. +Clears all current submode regions, reapplies all past interactive +mmm-ification, and applies `mmm-classes' and mode-extension classes." + (interactive) + (message "MMM-ifying buffer...") + (mmm-apply-all) + (message "MMM-ifying buffer...done")) + +(defun mmm-parse-region (start stop) + "Re-apply all applicable submode classes between START and STOP. +Clears all current submode regions, reapplies all past interactive +mmm-ification, and applies `mmm-classes' and mode-extension classes." + (interactive "r") + (message "MMM-ifying region...") + (mmm-apply-all :start start :stop stop) + (message "MMM-ifying region...done")) + +(defun mmm-parse-block (&optional lines) + "Re-parse LINES lines before and after point \(default 1). +Clears all current submode regions, reapplies all past interactive +mmm-ification, and applies `mmm-classes' and mode-extension classes. + +This command is intended for use when you have just typed what should +be the delimiters of a submode region and you want to create the +region. However, you may want to look into the various types of +delimiter auto-insertion that MMM Mode provides. See, for example, +`mmm-insert-region'." + (interactive "p") + (message "MMM-ifying block...") + (destructuring-bind (start stop) (mmm-get-block lines) + (when (< start stop) + (mmm-apply-all :start start :stop stop))) + (message "MMM-ifying block...done")) + +(defun mmm-get-block (lines) + (let ((inhibit-point-motion-hooks t)) + (list (save-excursion + (forward-line (- lines)) + (beginning-of-line) + (point)) + (save-excursion + (forward-line lines) + (end-of-line) + (point))))) + +;;}}} +;;{{{ Clear Submode Regions + +;; See also `mmm-clear-history' which is interactive. + +(defun mmm-clear-current-region () + "Deletes the submode region point is currently in, if any." + (interactive) + (delete-overlay (mmm-overlay-at (point) 'all))) + +(defun mmm-clear-regions (start stop) + "Deletes all submode regions from START to STOP." + (interactive "r") + (mmm-clear-overlays start stop)) + +(defun mmm-clear-all-regions () + "Deletes all submode regions in the current buffer." + (interactive) + (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) + "End current submode region. +If ARG is nil, end it at the most appropriate place, usually its +current back boundary. If ARG is non-nil, end it at point. If the +current region is correctly bounded, the first does nothing, but the +second deletes that delimiter as well. + +If the region's BACK property is a string, it is inserted as above and +the overlay moved if necessary. If it is a function, it is called with +two arguments--the overlay, and \(if ARG 'middle t)--and must do the +entire job of this function." + (interactive "P") + (let ((ovl (mmm-overlay-at))) + (when ovl + (combine-after-change-calls + (save-match-data + (save-excursion + (when (mmm-match-back ovl) + (if arg + (replace-match "") + (return-from mmm-end-current-region))))) + (let ((back (overlay-get ovl 'back))) + (cond ((stringp back) + (save-excursion + (unless arg (goto-char (overlay-end ovl))) + (save-excursion (insert back)) + (move-overlay ovl (overlay-start ovl) (point)))) + ((functionp back) + (funcall back ovl (if arg 'middle t)))))) + (mmm-refontify-maybe (save-excursion (forward-line -1) (point)) + (save-excursion (forward-line 1) (point)))))) + +;;}}} +;;{{{ Insert regions by keystroke + +;; This is the "default" binding in the MMM Mode keymap. Keys defined +;; by classes should be control keys, to avoid conflicts with MMM +;; commands. +(defun mmm-insert-region (arg) + "Insert a submode region based on last character in invoking keys. +Keystrokes after `mmm-mode-prefix-key' which are not bound to an MMM +Mode command \(see `mmm-command-modifiers') are passed on to this +function. If they have the modifiers `mmm-insert-modifiers', then they +are looked up, sans those modifiers, in all current submode classes to +find an insert skeleton. For example, in Mason, `p' \(with appropriate +prefix and modifiers) will insert a <%perl>...</%perl> region." + (interactive "P") + (let* ((seq (this-command-keys)) + (event (aref seq (1- (length seq)))) + (mods (event-modifiers event)) + (key (mmm-event-key event))) + (if (subsetp mmm-insert-modifiers mods) + (mmm-insert-by-key + (append (set-difference mods mmm-insert-modifiers) + key) + arg)))) + +(defun mmm-insert-by-key (key &optional arg) + "Insert a submode region based on event KEY. +Inspects all the classes of the current buffer to find a matching +:insert key sequence. See `mmm-classes-alist'. ARG, if present, is +passed on to `skeleton-proxy-new' to control wrapping. + +KEY must be a list \(MODIFIERS... . BASIC-KEY) where MODIFIERS are +symbols such as shift, control, etc. and BASIC-KEY is a character code +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)) + ;; XEmacs' skeleton doesn't manage positions by itself, so we + ;; have to do it. + (if mmm-xemacs (setq skeleton-positions nil)) + (skeleton-proxy-new skel str arg) + (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 + (cond ((functionp match-face) + (mmm-save-all + (funcall match-face front-str))) + (match-face + (cdr (assoc front-str match-face))) + (t + (plist-get class :face))))) + (setq submode (mmm-modename->function submode)) + (mmm-make-region + submode beg end :front front-str :back back-str + :face face +;;; :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))))))) + +(defun mmm-get-insertion-spec (key &optional classlist) + "Get the insertion info for KEY from all classes in CLASSLIST. +Return \(CLASS SKEL STR) where CLASS is the class spec a match was +found in, SKEL is the skeleton to insert, and STR is the argument. +CLASSLIST defaults to the return value of `mmm-get-all-classes', +including global classes." + (loop for classname in (or classlist (mmm-get-all-classes t)) + for class = (mmm-get-class-spec classname) + for inserts = (plist-get class :insert) + for skel = (cddr (assoc key inserts)) + with str + ;; If SKEL is a dotted pair, it means call another key's + ;; insertion spec with an argument. + unless (consp (cdr skel)) + do (setq str (cdr skel) + skel (cddr (assoc (car skel) inserts))) + if skel return (list class skel str) + ;; If we have a group class, recurse. + if (plist-get class :classes) + if (mmm-get-insertion-spec key it) + return it + else + return nil)) + +;;}}} +;;{{{ Help on Insertion + +(defun mmm-insertion-help () + "Display help on currently available MMM insertion commands." + (interactive) + (with-output-to-temp-buffer "*Help*" + (princ "Available MMM Mode Insertion Commands:\n") + (princ "Key Inserts\n") + (princ "--- -------\n\n") + (mapcar #'mmm-display-insertion-key + (mmm-get-all-insertion-keys)))) + +(defun mmm-display-insertion-key (spec) + "Print an insertion binding to standard output. +SPEC should be \(KEY NAME ...) where KEY is an insertion key and NAME +is a symbol naming the insertion." + (let* ((str (make-string 16 ?\ )) + ;; This gets us a dotted list, because of the way insertion + ;; keys are specified. + (key (append mmm-insert-modifiers (car spec))) + (lastkey (nthcdr (max (1- (safe-length key)) 0) key))) + ;; Now we make it a true list + (if (consp key) + (setcdr lastkey (list (cdr lastkey))) + (setq key (list key))) + ;; Get the spacing right + (store-substring str 0 + (key-description + (apply #'vector (append mmm-mode-prefix-key (list key))))) + (princ str) + ;; Now print the binding symbol + (princ (cadr spec)) + (princ "\n"))) + +(defun mmm-get-all-insertion-keys (&optional classlist) + "Return an alist of all currently available insertion keys. +Elements look like \(KEY NAME ...) where KEY is an insertion key and +NAME is a symbol naming the insertion." + (remove-duplicates + (loop for classname in (or classlist (mmm-get-all-classes t)) + for class = (mmm-get-class-spec classname) + append (plist-get class :insert) into keys + ;; If we have a group class, recurse. + if (plist-get class :classes) + do (setq keys (append keys (mmm-get-all-insertion-keys it))) + finally return keys) + :test #'equal + :key #'(lambda (x) (cons (car x) (cadr x))) + :from-end t)) + +;;}}} + +;;{{{ Auto Insertion (copied from interactive session);-COM- +;-COM- +;-COM-;; Don't use `mmm-ify-region' of course. And rather than having +;-COM-;; classes define their own functions, we should have them pass a +;-COM-;; skeleton as an attribute. Then our insert function can turn off +;-COM-;; after-change hooks and add the submode region afterward. +;-COM- +;-COM-(define-skeleton mmm-see-inline +;-COM- "" nil +;-COM- -1 @ " " _ " " @ "%>" +;-COM- '(apply #'mmm-ify-region 'cperl-mode (reverse skeleton-positions))) +;-COM- +;-COM-(define-skeleton mmm-see-other +;-COM- "" nil +;-COM- @ ";\n" _ "\n" @ "<%/" str ">" +;-COM- '(apply #'mmm-ify-region 'cperl-mode (reverse skeleton-positions))) +;-COM- +;-COM-(make-local-hook 'after-change-functions) +;-COM-(add-hook 'after-change-functions 'mmm-detect t) +;-COM- +;-COM-(defun mmm-detect (beg end length) +;-COM- (when (mmm-looking-back-at "<% ") +;-COM- (mmm-see-inline)) +;-COM- (when (mmm-looking-back-at "<%\\(\\w+\\)>") +;-COM- (mmm-see-other (match-string 1)))) +;-COM- +;;}}} + +(provide 'mmm-cmds) + +;;; mmm-cmds.el ends here
\ No newline at end of file diff --git a/mmm/mmm-compat.el b/mmm/mmm-compat.el new file mode 100644 index 00000000..d5809e60 --- /dev/null +++ b/mmm/mmm-compat.el @@ -0,0 +1,193 @@ +;;; mmm-compat.el --- MMM Hacks for compatibility with other Emacsen + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 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. + +;;; Code: + +(require 'cl) + +;;{{{ Emacsen Detection + +(defvar mmm-xemacs (featurep 'xemacs) + "Whether we are running XEmacs.") + +;;}}} +;;{{{ Keywords (Emacs 19) + +;; Emacs 19 doesn't automatically set keyword variables to themselves. +;; We shouldn't have to do any more than these, since CL automatically +;; defines all keywords used for function arguments. +(defvar mmm-keywords-used + '(:group :regexp :region :function :insert :classes :private) + "List of extra keywords used by MMM Mode.") + +(dolist (keyword mmm-keywords-used) + (set keyword keyword)) + +;;}}} +;;{{{ Customization (Emacs 19) + +(condition-case () + (require 'custom) + (error nil)) + +(unless (and (featurep 'custom) + (fboundp 'custom-declare-variable)) + (defmacro defgroup (&rest args) + nil) + (defmacro defface (var values doc &rest args) + (` (make-face (quote (, var))))) + (defmacro defcustom (var value doc &rest args) + (` (defvar (, var) (, value) (, doc))))) + +;;}}} +;;{{{ Regexp-Opt (Emacs 19) + +(condition-case () + (require 'regexp-opt) + (error nil)) + +(unless (and (featurep 'regexp-opt) + (fboundp 'regexp-opt)) + ;; No regexp-opt; create one + (defun regexp-opt (strings &optional paren) + (concat (if paren "\\(" "") + (mapconcat 'regexp-quote strings "\\|") + (if paren "\\)" "")))) + +;;}}} +;;{{{ Regexp-Opt (XEmacs) + +(defmacro mmm-regexp-opt (strings paren) + "Act like FSF Emacs' `regexp-opt', whichever Emacs we're in. +XEmacs' `regexp-opt' requires an extra parameter to do grouping." + (if (featurep 'xemacs) + `(regexp-opt ,strings ,paren t) + `(regexp-opt ,strings ,paren))) + +;;}}} +;;{{{ Overlays (XEmacs) + +;; The main thing we use from FSF Emacs that XEmacs doesn't support +;; are overlays. XEmacs uses extents instead, but comes with a package +;; to emulate overlays. +(when mmm-xemacs + ;; This does almost everything we need. + (require 'overlay)) + +;; We also use a couple "special" overlay properties which have +;; different names for XEmacs extents. +(defvar mmm-evaporate-property + (if (featurep 'xemacs) 'detachable 'evaporate) + "The name of the overlay property controlling evaporation.") + +;; We don't use this any more, since its behavior is different in FSF +;; and XEmacs: in the one it replaces the buffer's local map, but in +;; the other it gets stacked on top of it. Instead we just set the +;; buffer's local map temporarily. +;;;(defvar mmm-keymap-property +;;; (if (featurep 'xemacs) 'keymap 'local-map) +;;; "The name of the overlay property controlling keymaps.") + +;;}}} +;;{{{ Keymaps and Events (XEmacs) + +;; In XEmacs, keymaps are a primitive type, while in FSF Emacs, they +;; are a list whose car is the symbol `keymap'. Among other things, +;; this means that they handle default bindings differently. +(defmacro mmm-set-keymap-default (keymap binding) + (if (featurep 'xemacs) + `(set-keymap-default-binding ,keymap ,binding) + `(define-key ,keymap [t] ,binding))) + +;; In XEmacs, events are a primitive type, while in FSF Emacs, they +;; are represented by characters or vectors. We treat them as vectors. +;; We can use `event-modifiers' in both Emacsen to extract the +;; modifiers, but the function to extract the basic key is different. +(defmacro mmm-event-key (event) + (if (featurep 'xemacs) + `(event-key ,event) + `(event-basic-type ,event))) + +;;}}} +;;{{{ Skeleton (XEmacs) + +;; XEmacs' `skeleton' package doesn't provide `@' to record positions. +(defvar skeleton-positions ()) +(defun mmm-fixup-skeleton () + "Add `@' to `skeleton-further-elements' if XEmacs and not there. +This makes `@' in skeletons act approximately like it does in FSF." + (and (featurep 'xemacs) + (defvar skeleton-further-elements ()) + (not (assoc '@ skeleton-further-elements)) + (add-to-list 'skeleton-further-elements + '(@ ''(push (point) skeleton-positions))))) + +;;}}} +;;{{{ Make Temp Buffers (XEmacs) + +(defmacro mmm-make-temp-buffer (buffer name) + "Return a buffer called NAME including the text of BUFFER. +This text should not be modified." + (if (fboundp 'make-indirect-buffer) + `(make-indirect-buffer ,buffer ,name) + `(save-excursion + (set-buffer (get-buffer-create ,name)) + (insert-buffer ,buffer) + (current-buffer)))) + +;;}}} +;;{{{ Font Lock Available (Emacs w/o X) + +(defvar mmm-font-lock-available-p (or window-system mmm-xemacs) + "Whether font-locking is available. +Emacs 19 and 20 only provide font-lock with a window system in use.") + +;;}}} +;;{{{ Font Lock Defaults (XEmacs) + +(defmacro mmm-set-font-lock-defaults () + "Set font-lock defaults without trying to turn font-lock on. +In XEmacs, `font-lock-set-defaults' calls `font-lock-set-defaults-1' +to do the real work but then `turn-on-font-lock', which in turn calls +`font-lock-mode', which unsets the defaults if running in a hidden +buffer \(name begins with a space). So in XEmacs, we just call +`font-lock-set-defaults-1' directly." + (if mmm-xemacs + `(font-lock-set-defaults-1) + `(font-lock-set-defaults))) + +;;}}} + +(provide 'mmm-compat) + +;;; mmm-compat.el ends here
\ No newline at end of file diff --git a/mmm/mmm-mason.el b/mmm/mmm-mason.el new file mode 100644 index 00000000..3640726d --- /dev/null +++ b/mmm/mmm-mason.el @@ -0,0 +1,167 @@ +;;; mmm-mason.el --- MMM submode class for Mason components + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 Mason components. See the file README.Mason for more +;; details. + +;;; Code: + +(require 'mmm-compat) +(require 'mmm-vars) +(require 'mmm-auto) + +;;{{{ Perl Tags + +(defvar mmm-mason-perl-tags + '("perl" "init" "cleanup" "once" "filter" "shared" + "perl_init" "perl_cleanup" "perl_once" "perl_filter")) + +(defvar mmm-mason-pseudo-perl-tags + '("args" "perl_args" "attr" "flags")) + +(defvar mmm-mason-non-perl-tags + '("doc" "perl_doc" "text" "perl_text" "def" "perl_def" "method")) + +(defvar mmm-mason-perl-tags-regexp + (concat "<%" (mmm-regexp-opt mmm-mason-perl-tags t) ">") + "Matches tags beginning Mason sections containing Perl code. +Saves the name of the tag matched.") + +(defvar mmm-mason-pseudo-perl-tags-regexp + (concat "<%" (mmm-regexp-opt mmm-mason-pseudo-perl-tags t) ">") + "Match tags beginning Mason sections that look like Perl but aren't. +Saves the name of the tag matched.") + +(defvar mmm-mason-tag-names-regexp + (regexp-opt (append mmm-mason-perl-tags mmm-mason-non-perl-tags) t) + "Matches any Mason tag name after the \"<%\". Used to verify that a +\"<%\" sequence starts an inline section.") + +(defun mmm-mason-verify-inline () + (not (looking-at mmm-mason-tag-names-regexp))) + +;;}}} +;;{{{ Add Classes + +(mmm-add-group + 'mason + `((mason-text + :submode nil + :front "<%text>" + :back "</%text>" + :insert ((?t mason-<%text> nil @ "<%text>" @ "\n" + _ "\n" @ "</%text>" @))) + (mason-doc + :submode text-mode + :face mmm-comment-submode-face + :front "<%doc>" + :back "</%doc>" + :face nil + :insert ((?d mason-<%doc> nil @ "<%doc>" @ "\n" + _ "\n" @ "</%doc>" @))) + (mason-perl + :submode perl + :match-face (("<%perl>" . mmm-code-submode-face) + ("<%init>" . mmm-init-submode-face) + ("<%cleanup>" . mmm-cleanup-submode-face) + ("<%once>" . mmm-init-submode-face) + ("<%filter>" . mmm-special-submode-face) + ("<%shared>" . mmm-init-submode-face)) + :front ,mmm-mason-perl-tags-regexp + :back "</%~1>" + :save-matches 1 + :insert ((?, mason-<%TAG> "Perl section: " @ "<%" str ">" @ + ";\n" _ "\n" @ "</%" str ">" @) + (?< mason-<%TAG> ?, . nil) + (?p mason-<%perl> ?, . "perl") + (?i mason-<%init> ?, . "init") + (?c mason-<%cleanup> ?, . "cleanup") + (?o mason-<%once> ?, . "once") + (?l mason-<%filter> ?, . "filter") + (?s mason-<%shared> ?, . "shared"))) + (mason-pseudo-perl + :submode perl + :face mmm-declaration-submode-face + :front ,mmm-mason-pseudo-perl-tags-regexp + :back "</%~1>" + :save-matches 1 + :insert ((?. mason-pseudo-<%TAG> "Pseudo-perl section: " @ "<%" str ">" @ + "\n" _ "\n" @ "</%" str ">" @) + (?> mason-pseudo-<%TAG> ?, . nil) + (?a mason-<%args> ?. . "args") + (?f mason-<%flags> ?. . "flags") + (?r mason-<%attr> ?. . "attr"))) + (mason-inline + :submode perl + :face mmm-output-submode-face + :front "<%" + :front-verify mmm-mason-verify-inline + :back "%>" + :insert ((?% mason-<%-%> nil @ "<%" @ " " _ " " @ "%>" @) + (?5 mason-<%-%> ?% . nil))) + (mason-call + :submode perl + :face mmm-special-submode-face + :front "<&" + :back "&>" + :insert ((?& mason-<&-&> nil @ "<&" @ " " _ " " @ "&>" @) + (?7 mason-<&-&> ?% . nil))) + (mason-one-line-comment + :submode text-mode + :face mmm-comment-submode-face + :front "^%#" + :back "\n" + :insert ((?# mason-%-comment nil (mmm-mason-start-line) + @ "%" @ "# " _ @ '(mmm-mason-end-line) "\n" @) + (?3 mason-%-comment ?# . nil))) + (mason-one-line + :submode perl + :face mmm-code-submode-face + :front "^%" + :back "\n" + :insert ((return mason-%-line nil (mmm-mason-start-line) + @ "%" @ " " _ @ '(mmm-mason-end-line) "\n" @))))) + +;;}}} +;;{{{ One-line Sections + +(defun mmm-mason-start-line () + (if (bolp) + "" + "\n")) + +(defun mmm-mason-end-line () + (if (eolp) + (delete-char 1))) + +;;}}} + +(provide 'mmm-mason) + +;;; mmm-mason.el ends here
\ No newline at end of file diff --git a/mmm/mmm-mode.el b/mmm/mmm-mode.el new file mode 100644 index 00000000..46f470b7 --- /dev/null +++ b/mmm/mmm-mode.el @@ -0,0 +1,463 @@ +;;; mmm-mode.el --- Allow Multiple Major Modes in a buffer + +;; Copyright (C) 1999 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 + +;; Revision: $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: + +;;; MMM Mode is a minor mode that allows multiple major modes to +;;; coexist in a single buffer. Refer to the documentation of the +;;; function `mmm-mode' for more detailed information. This file +;;; contains mode on/off functions and the mode keymap, but mostly +;;; just loads all the subsidiary files. + +;;{{{ Parameter Naming + +;;; Since version 0.3.7, I've tried to use a uniform scheme for naming +;;; parameters. Here's a brief summary. + +;;; BEG and END refer to the beginning and end of a region. +;;; FRONT and BACK refer to the respective delimiters of a region. +;;; FRONT- and BACK-OFFSET are the offsets from delimiter matches. +;;; FRONT-BEG through BACK-END are the endings of the delimiters. +;;; START and STOP bound actions, like searching, fontification, etc. + +;;}}} +;;{{{ CL and Parameters + +;;; Keyword parameters can be nice because it makes it easier to see +;;; what's getting passed as what. But I try not to use them in user +;;; functions, because CL doesn't make good documentation strings. +;;; Similarly, any hook or callback function can't take keywords, +;;; since Emacs as a whole doesn't use them. And for small parameter +;;; lists, they are overkill. So I use them only for a large number of +;;; optional parameters, such as `mmm-make-region'. + +;;; An exception is the various submode class application functions, +;;; which all take all their arguments as keywords, for consistency +;;; and so the classes alist looks nice. + +;;; When using keyword arguments, defaults should *always* be supplied +;;; in all arglists. (This pertains mostly to :start and :stop +;;; arguments, usually defaulting to (point-min) and (point-max) +;;; respectively.) `mmm-save-keywords' should only be used for lists +;;; with more than four arguments, such as in `mmm-ify-by-regexp'. + +;;; In general, while I have no qualms about using things from CL like +;;; `mapl', `loop' and `destructuring-bind', I try not to use `defun*' +;;; more than I have to. For one, it sometimes makes bad documentation +;;; strings. Furthermore, to a `defun'ned function, a nil argument is +;;; the same as no argument, so it will use its (manual) default, but +;;; to a `defun*'ned function, a nil argument *is* the argument, so +;;; 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: + +(require 'cl) +;; If we don't load font-lock now, but it is loaded later, the +;; necessary mmm-font-lock-* properties may not be there. +(require 'font-lock) +(require 'mmm-compat) +(require 'mmm-utils) +(require 'mmm-vars) +(require 'mmm-auto) +(require 'mmm-region) +(require 'mmm-class) +;; This file is set up to autoload by `mmm-auto.el'. +;; (require 'mmm-cmds) +(require 'mmm-univ) + +;;{{{ Toggle Function + +(defun mmm-mode (&optional arg) + "Minor mode to allow multiple major modes in one buffer. +Without ARG, toggle MMM Mode. With ARG, turn MMM Mode on iff ARG is +positive and off otherwise. + +Commands Available: +\\<mmm-mode-map> +\\{mmm-mode-map} + +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: + +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. +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)." + (interactive "P") + (if (if arg (> (prefix-numeric-value arg) 0) (not mmm-mode)) + (mmm-mode-on) + (mmm-mode-off))) + +;;}}} +;;{{{ Mode On + +(defun mmm-mode-on () + "Turn on MMM Mode. See `mmm-mode'." + (interactive) + ;; This function is called from mode hooks, so we need to make sure + ;; we're not in a temporary buffer. We don't need to worry about + ;; recursively ending up in ourself, however, since by that time the + ;; variable `mmm-mode' will already be set. + (mmm-valid-buffer + (unless mmm-mode + (setq mmm-primary-mode major-mode) + (mmm-update-mode-info major-mode) + (setq mmm-region-saved-locals-for-dominant + (list* (list 'font-lock-cache-state nil) + (list 'font-lock-cache-position (make-marker)) + (copy-tree (cdr (assq major-mode mmm-region-saved-locals-defaults))))) + ;; Without the next line, the (make-marker) above gets replaced + ;; with the starting value of nil, and all comes to naught. + (mmm-set-local-variables major-mode) + (mmm-add-hooks) + (mmm-fixup-skeleton) + (make-local-variable 'font-lock-fontify-region-function) + (make-local-variable 'font-lock-beginning-of-syntax-function) + (setq font-lock-fontify-region-function 'mmm-fontify-region + font-lock-beginning-of-syntax-function 'mmm-beginning-of-syntax) + (setq mmm-mode t) + (condition-case err + (mmm-apply-all) + (mmm-invalid-submode-class + ;; 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)))) + +;;}}} +;;{{{ Mode Off + +(defun mmm-mode-off () + "Turn off MMM Mode. See `mmm-mode'." + (interactive) + (when mmm-mode + (mmm-remove-hooks) + (mmm-clear-overlays) + (mmm-clear-history) + (mmm-clear-mode-ext-classes) + (mmm-clear-local-variables) + (mmm-update-submode-region) + (setq font-lock-fontify-region-function + (get mmm-primary-mode 'mmm-fontify-region-function) + font-lock-beginning-of-syntax-function + (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)) + +;;}}} +;;{{{ Mode Keymap + +(defvar mmm-mode-map (make-sparse-keymap) + "Keymap for MMM Minor Mode.") + +(defvar mmm-mode-prefix-map (make-sparse-keymap) + "Keymap for MMM Minor Mode after `mmm-mode-prefix-key'.") + +(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 + (vector (append mmm-command-modifiers (list key))) + binding)) + +(when mmm-use-old-command-keys + (mmm-use-old-command-keys)) + +(mmm-define-key ?c 'mmm-ify-by-class) +(mmm-define-key ?x 'mmm-ify-by-regexp) +(mmm-define-key ?r 'mmm-ify-region) + +(mmm-define-key ?b 'mmm-parse-buffer) +(mmm-define-key ?g 'mmm-parse-region) +(mmm-define-key ?% 'mmm-parse-block) +(mmm-define-key ?5 'mmm-parse-block) + +(mmm-define-key ?k 'mmm-clear-current-region) +(mmm-define-key ?\ 'mmm-reparse-current-region) +(mmm-define-key ?e 'mmm-end-current-region) + +;; This one is exact, since C-h is (usually) already used for help. +(define-key mmm-mode-prefix-map [?h] 'mmm-insertion-help) + +;; Default bindings to do insertion (dynamic) +(mmm-set-keymap-default mmm-mode-prefix-map 'mmm-insert-region) + +;; Set up the prefix help command, since otherwise the default binding +;; overrides it. +(define-key mmm-mode-prefix-map (vector help-char) prefix-help-command) + +;; And put it all onto the prefix key +(define-key mmm-mode-map mmm-mode-prefix-key mmm-mode-prefix-map) + +;; Order matters for the menu bar. +(define-key mmm-mode-menu-map [off] + '("MMM Mode Off" . mmm-mode-off)) +(define-key mmm-mode-menu-map [sep0] '(menu-item "----")) + +(define-key mmm-mode-menu-map [clhist] + '("Clear History" . mmm-clear-history)) +(define-key mmm-mode-menu-map [end] + '("End Current" . mmm-end-current-region)) +(define-key mmm-mode-menu-map [clear] + '("Clear Current" . mmm-clear-current-region)) +(define-key mmm-mode-menu-map [reparse] + '("Reparse Current" . mmm-reparse-current-region)) + +(define-key mmm-mode-menu-map [sep10] '(menu-item "----")) + +(define-key mmm-mode-menu-map [ins-help] + '("List Insertion Keys" . mmm-insertion-help)) + +(define-key mmm-mode-menu-map [sep20] '(menu-item "----")) + +(define-key mmm-mode-menu-map [region] + '(menu-item "MMM-ify Region" mmm-ify-region :enable mark-active)) +(define-key mmm-mode-menu-map [regexp] + '("MMM-ify by Regexp" . mmm-ify-by-regexp)) +(define-key mmm-mode-menu-map [class] + '("Apply Submode Class" . mmm-ify-by-class)) + +(define-key mmm-mode-menu-map [sep30] '(menu-item "----")) + +(define-key mmm-mode-menu-map [parse-region] + '(menu-item "Parse Region" mmm-parse-region :enable mark-active)) +(define-key mmm-mode-menu-map [parse-buffer] + '("Parse Buffer" . mmm-parse-buffer)) +(define-key mmm-mode-menu-map [parse-block] + '("Parse Block" . mmm-parse-block)) + +(define-key mmm-mode-map [menu-bar mmm] (cons "MMM" mmm-mode-menu-map)) + +(add-to-list 'minor-mode-map-alist (cons 'mmm-mode mmm-mode-map)) + +;;}}} + +(provide 'mmm-mode) + +;;; mmm-mode.el ends here
\ No newline at end of file diff --git a/mmm/mmm-region.el b/mmm/mmm-region.el new file mode 100644 index 00000000..073a658b --- /dev/null +++ b/mmm/mmm-region.el @@ -0,0 +1,642 @@ +;;; mmm-region.el --- Manipulating and behavior of MMM submode regions + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 provides the functions and variables to create, delete, +;; and inspect submode regions, as well as functions that make them +;; behave like the submode with respect to syntax tables, local maps, +;; font lock, etc. + +;;; Code: + +(require 'cl) +(require 'font-lock) +(require 'mmm-compat) +(require 'mmm-utils) +(require 'mmm-auto) +(require 'mmm-vars) + +;; INSPECTION +;;{{{ Current Overlays + +;; Emacs counts an overlay starting at POS as "at" POS, but not an +;; overlay ending at POS. XEmacs is more sensible and uses beg- and +;; 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) + "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))) + +(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." + (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)))))) + +(defun mmm-sort-overlays (overlays) + "Sort OVERLAYS in order of decreasing priority." + (sort (copy-list overlays) + #'(lambda (x y) (> (or (overlay-get x 'priority) 0) + (or (overlay-get y 'priority) 0))))) + +;;}}} +;;{{{ Current Submode + +(defvar mmm-current-overlay nil + "What submode region overlay we think we are currently in. +May be out of date; call `mmm-update-current-submode' to correct it.") +(make-variable-buffer-local 'mmm-current-overlay) + +(defvar mmm-previous-overlay nil + "What submode region overlay we were in just before this one. +Set by `mmm-update-current-submode'.") +(make-variable-buffer-local 'mmm-previous-overlay) + +(defvar mmm-current-submode nil + "What submode we think we are currently in. +May be out of date; call `mmm-update-current-submode' to correct it.") +(make-variable-buffer-local 'mmm-current-submode) + +(defvar mmm-previous-submode nil + "What submode we were in just before this one. +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))))) + (if (eq ovl mmm-current-overlay) + nil + (setq mmm-previous-overlay mmm-current-overlay + mmm-previous-submode mmm-current-submode) + (setq mmm-current-overlay ovl + mmm-current-submode (if ovl (overlay-get ovl 'mmm-mode))) + t))) + +(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." + (setq mmm-previous-overlay mmm-current-overlay + mmm-previous-submode mmm-current-submode) + (setq mmm-current-submode mode + mmm-current-overlay + (find-if #'(lambda (ovl) + (eq (overlay-get ovl 'mmm-mode) mode)) + (mmm-overlays-at (or pos (point)) 'all)))) + +(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))) + (if ovl (overlay-get ovl 'mmm-mode)))) + +;;}}} +;;{{{ Match Front & Back + +(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))))) + +(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 + +(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) + (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) + (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-make-region + (submode beg end &rest rest &key (front "") (back "") + (beg-sticky t) (end-sticky t) face creation-hook + &allow-other-keys + ) + "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)) + (setq submode (mmm-modename->function submode)) + (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)) + (setq mmm-previous-submode submode + mmm-previous-overlay ovl) + (mmm-update-submode-region) + 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))))) + +;;}}} +;;{{{ Clear Overlays + +;; 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." + (mapcar #'delete-overlay + (mmm-overlays-in (or start (point-min)) + (or stop (point-max)) + strict)) + (mmm-update-current-submode)) + +;;}}} + +;; BASIC UPDATING +;;{{{ Submode Info + +(defun mmm-update-mode-info (mode &optional force) + "Save the global-saved and buffer-saved variables for MODE. +Global saving is done on properties of the symbol MODE and buffer +saving in `mmm-buffer-saved-locals'. This function must be called for +both the dominant mode and all submodes, in each file. Region-saved +variables are initialized from `mmm-region-saved-locals-defaults', +which is set here as well. See `mmm-save-local-variables'. If FORCE +is non-nil, don't quit if the info is already there." + (let ((buffer-entry (assq mode mmm-buffer-saved-locals)) + (region-entry (assq mode mmm-region-saved-locals-defaults)) + global-vars buffer-vars region-vars + ;; kludge for XEmacs 20 + (html-helper-build-new-buffer nil)) + (unless (and (not force) + (get mode 'mmm-local-variables) + buffer-entry + region-entry) + (save-excursion + (let ((filename (buffer-file-name))) + ;; On errors, the temporary buffers don't get deleted, so here + ;; we get rid of any old ones that may be hanging around. + (when (buffer-live-p (get-buffer mmm-temp-buffer-name)) + (save-excursion + (set-buffer (get-buffer mmm-temp-buffer-name)) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer)))) + ;; Now make a new temporary buffer. + (set-buffer (mmm-make-temp-buffer (current-buffer) + mmm-temp-buffer-name)) + (if (memq mode mmm-set-file-name-for-modes) + (setq buffer-file-name filename))) + (funcall mode) + (when (featurep 'font-lock) + ;; XEmacs doesn't have global-font-lock-mode (or rather, it + ;; has nothing but global-font-lock-mode). + (when (or mmm-xemacs + ;; Code copied from font-lock.el to detect when font-lock + ;; should be on via global-font-lock-mode. + (and (or font-lock-defaults + (assq major-mode font-lock-defaults-alist) + (assq major-mode font-lock-keywords-alist)) + (or (eq font-lock-global-modes t) + (if (eq (car-safe font-lock-global-modes) 'not) + (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. + (put mode 'mmm-font-lock-mode t)) + ;; Get the font-lock variables + (when mmm-font-lock-available-p + ;; To fool `font-lock-add-keywords' + (let ((font-lock-mode t)) + (mmm-set-font-lock-defaults))) + ;; These can't be in the local variables list, because we + ;; replace their actual values, but we want to use their + ;; original values elsewhere. + (unless (and mmm-xemacs (= emacs-major-version 20)) + ;; XEmacs 20 doesn't have this variable. This effectively + ;; prevents the MMM font-lock support from working, but we + ;; just ignore it and go on, to prevent an error message. + (put mode 'mmm-fontify-region-function + font-lock-fontify-region-function)) + (put mode 'mmm-beginning-of-syntax-function + font-lock-beginning-of-syntax-function)) + ;; Get variables + (setq global-vars (mmm-get-locals 'global) + buffer-vars (mmm-get-locals 'buffer) + region-vars (mmm-get-locals 'region)) + (put mode 'mmm-mode-name mode-name) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer))) + (put mode 'mmm-local-variables global-vars) + (if buffer-entry + (setcdr buffer-entry buffer-vars) + (push (cons mode buffer-vars) mmm-buffer-saved-locals)) + (if region-entry + (setcdr region-entry region-vars) + (push (cons mode region-vars) + mmm-region-saved-locals-defaults))))) + +;;}}} +;;{{{ Updating Hooks + +(defun mmm-update-submode-region () + "Update all MMM properties correctly for the current position. +This function and those it calls do the actual work of setting the +different keymaps, syntax tables, local variables, etc. for submodes." + (when (mmm-update-current-submode) + (mmm-save-changed-local-variables mmm-previous-overlay + mmm-previous-submode) + (let ((mode (or mmm-current-submode mmm-primary-mode))) + (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))) + +(defun mmm-add-hooks () + (make-local-hook 'post-command-hook) + (add-hook 'post-command-hook 'mmm-update-submode-region nil 'local)) + +(defun mmm-remove-hooks () + (remove-hook 'post-command-hook 'mmm-update-submode-region 'local)) + +;;}}} +;;{{{ Local Variables + +(defun mmm-get-local-variables-list (type mode) + "Filter `mmm-save-local-variables' to match TYPE and MODE. +Return a list \(VAR ...). In some cases, VAR will be a cons cell +\(GETTER . SETTER) -- see `mmm-save-local-variables'." + (mapcan #'(lambda (element) + (and (if (and (consp element) + (cdr element) + (cadr element)) + (eq (cadr element) type) + (eq type 'global)) + (if (and (consp element) + (cddr element) + (not (eq (caddr element) t))) + (if (functionp (caddr element)) + (funcall (caddr element)) + (member mode (caddr element))) + t) + (list (if (consp element) (car element) element)))) + mmm-save-local-variables)) + +(defun mmm-get-locals (type) + "Get the local variables and values for TYPE from this buffer. +Return \((VAR VALUE) ...). In some cases, VAR will be of the form +\(GETTER . SETTER) -- see `mmm-save-local-variables'." + (mapcan #'(lambda (var) + (if (consp var) + `((,var ,(funcall (car var)))) + (and (boundp var) + ;; This seems logical, but screws things up. + ;;(local-variable-p var) + `((,var ,(symbol-value var)))))) + (mmm-get-local-variables-list type major-mode))) + +(defun mmm-get-saved-local (mode var) + "Get the value of the local variable VAR saved for MODE, if any." + (cadr (assq var (mmm-get-saved-local-variables mode)))) + +(defun mmm-set-local-variables (mode) + "Set all the local variables saved for MODE. +Looks up both global, buffer, and region saves." + (mapcar #'(lambda (var) + ;; (car VAR) may be (GETTER . SETTER) + (if (consp (car var)) + (funcall (cdar var) (cadr var)) + (make-local-variable (car var)) + (set (car var) (cadr var)))) + (mmm-get-saved-local-variables mode))) + +(defun mmm-get-saved-local-variables (mode) + (append (get mode 'mmm-local-variables) + (cdr (assq mode mmm-buffer-saved-locals)) + (let ((ovl (mmm-overlay-at (point)))) + (if ovl + (overlay-get ovl 'mmm-local-variables) + mmm-region-saved-locals-for-dominant)))) + +(defun mmm-save-changed-local-variables (ovl mode) + "Save by-buffer and by-region variables for OVL and MODE. +Called when we move to a new submode region, with OVL and MODE the +region and mode for the previous position." + (let ((buffer-vars (cdr (assq (or mode mmm-primary-mode) + mmm-buffer-saved-locals))) + (region-vars (if ovl + (overlay-get ovl 'mmm-local-variables) + mmm-region-saved-locals-for-dominant)) + (set-local-value + #'(lambda (var) + (setcar (cdr var) + ;; (car VAR) may be (GETTER . SETTER) + (if (consp (car var)) + (funcall (caar var)) + (symbol-value (car var))))))) + (mapc set-local-value buffer-vars) + (mapc set-local-value region-vars))) + +(defun mmm-clear-local-variables () + "Clear all buffer- and region-saved variables for current buffer." + (setq mmm-buffer-saved-locals () + mmm-region-saved-locals-defaults () + mmm-region-saved-locals-for-dominant ())) + +;;}}} + +;; FONT LOCK +;;{{{ Enable Font Lock + +(defun mmm-enable-font-lock (mode) + "Turn on font lock if it is not already on and MODE enables it." + (mmm-update-mode-info mode) + (and mmm-font-lock-available-p + (not font-lock-mode) + (get mode 'mmm-font-lock-mode) + (font-lock-mode 1))) + +(defun mmm-update-font-lock-buffer () + "Turn on font lock iff any mode in the buffer enables it." + (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)))))) + (font-lock-mode 1) + (font-lock-mode 0)))) + +(defun mmm-refontify-maybe (&optional start stop) + "Re-fontify from START to STOP, or entire buffer, if enabled." + (and font-lock-mode + (if (or start stop) + (font-lock-fontify-region (or start (point-min)) + (or stop (point-max))) + (font-lock-fontify-buffer)))) + +;;}}} +;;{{{ Get Submode Regions + +(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." + (sort (remove-duplicates + (list* start stop + (mapcan #'(lambda (ovl) + `(,(overlay-start ovl) + ,(overlay-end ovl))) + (mmm-overlays-in start stop t t)))) + + #'<)) + +(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." + (let ((regions + (maplist #'(lambda (pos-list) + (if (cdr pos-list) + (list (or (mmm-submode-at (car pos-list) 'beg) + mmm-primary-mode) + (car pos-list) (cadr pos-list)))) + (mmm-submode-changes-in start stop)))) + (setcdr (last regions 2) nil) + regions)) + + +(defun mmm-regions-alist (start stop) + "Return a list of lists of the form \(MODE . REGIONS) where REGIONS +is a list of elements of the form \(BEG END). The disjoint union all +of the REGIONS covers START to STOP." + (let ((regions (mmm-regions-in start stop))) + (mapcar #'(lambda (mode) + (cons mode + (mapcan #'(lambda (region) + (if (eq mode (car region)) + (list (cdr region)))) + regions))) + ;; All the modes + (remove-duplicates (mapcar #'car regions))))) + +;;}}} +;;{{{ Fontify Regions + +(defun mmm-fontify-region (start stop &optional loudly) + "Fontify from START to STOP keeping track of submodes correctly." + (when loudly + (message "Fontifying %s with submode regions..." (buffer-name))) + ;; Necessary to catch changes in font-lock cache state and position. + (mmm-save-changed-local-variables + mmm-current-overlay mmm-current-submode) + ;; For some reason `font-lock-fontify-block' binds this to nil, thus + ;; 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) + (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) + (when loudly (message nil))) + +(defun mmm-fontify-region-list (mode regions) + "Fontify REGIONS, each like \(BEG END), in mode MODE." + (save-excursion + (let (;(major-mode mode) + (func (get mode 'mmm-fontify-region-function))) + (mapcar #'(lambda (reg) + (goto-char (car reg)) + ;; Here we do the same sort of thing that + ;; `mmm-update-submode-region' does, but we force it + ;; to use a specific mode, and don't save anything, + ;; fontify, or change the mode line. + (mmm-set-current-submode mode) + (mmm-set-local-variables mode) + (funcall func (car reg) (cadr reg) nil) + ;; Catch changes in font-lock cache. + (mmm-save-changed-local-variables + mmm-current-overlay mmm-current-submode)) + regions)))) + +;;}}} +;;{{{ Beginning of Syntax + +(defun mmm-beginning-of-syntax () + (goto-char + (let ((ovl (mmm-overlay-at (point))) + (func (get (or mmm-current-submode mmm-primary-mode) + 'mmm-beginning-of-syntax-function))) + (max (if ovl (overlay-start ovl) (point-min)) + (if func (progn (funcall func) (point)) (point-min)) + (point-min))))) + +;;}}} + +(provide 'mmm-region) + +;;; mmm-region.el ends here
\ No newline at end of file diff --git a/mmm/mmm-rpm.el b/mmm/mmm-rpm.el new file mode 100644 index 00000000..0661e1ad --- /dev/null +++ b/mmm/mmm-rpm.el @@ -0,0 +1,81 @@ +;;; mmm-rpm.el --- MMM submode class for RPM spec files + +;; Copyright (C) 2000 by Marcus Harnisch <Marcus.Harnisch@gmx.net> + +;; Author: Marcus Harnisch <Marcus.Harnisch@gmx.net> +;; 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 shell script sections within RPM (Redhat Package Manager) +;; spec files. I recommend to use it in combination with +;; rpm-spec-mode.el by Stig Bjørlykke <stigb@tihlde.hist.no> and Steve +;; Sanbeg <sanbeg@dset.com> (http://www.xemacs.org/~stigb/rpm-spec-mode.el) + +;;; Installation: + +;; 1. Copy this file where Emacs can find it. +;; +;; 2. Add the following lines to one of your startup files (e.g. ~/.emacs): +;; +;; (add-to-list 'mmm-mode-ext-classes-alist +;; '(rpm-spec-mode "\\.spec\\'" rpm-sh)) + +;;; Code: + +(require 'mmm-auto) + +(defconst mmm-rpm-sh-start-tags + '("prep" "build" "install" "clean" "preun" "postun" "pre" + "post" "triggerin" "triggerun" "triggerpostun") + "List containing RPM tags that start a shell-script section in a spec file") + +(defvar mmm-rpm-sh-end-tags + (append '("files" "description" "package") mmm-rpm-sh-start-tags) + "List containing RPM tags that end a shell-script section in a spec file") + +(defvar mmm-rpm-sh-start-regexp + (concat "^%" (mmm-regexp-opt mmm-rpm-sh-start-tags t) "\\b.*$") + "Regexp matching RPM tags that start a shell-script section in a spec file") + +(defvar mmm-rpm-sh-end-regexp + (concat "\\'\\|^%" (mmm-regexp-opt mmm-rpm-sh-end-tags t) "\\b.*$") + "Regexp matching RPM tags that end a shell-script section in a spec file") + +(mmm-add-group + 'rpm + `((rpm-sh + :submode sh-mode + :face mmm-code-submode-face + ;; match tags that starts sh-script region + :front ,mmm-rpm-sh-start-regexp + ;; match end of buffer or next tag that ends sh-script region + :back ,mmm-rpm-sh-end-regexp + :front-offset 1 + :back-offset 0 + :save-matches 0 + ))) + +(provide 'mmm-rpm) + +;;; mmm-rpm.el ends here
\ No newline at end of file diff --git a/mmm/mmm-sample.el b/mmm/mmm-sample.el new file mode 100644 index 00000000..8de25057 --- /dev/null +++ b/mmm/mmm-sample.el @@ -0,0 +1,308 @@ +;;; mmm-sample.el --- Sample MMM submode classes + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 several sample submode classes for use with MMM +;; Mode. For a more detailed and useful example, see `mmm-mason.el'. + +;;; Code: + +(require 'mmm-auto) +(require 'mmm-vars) + +;;{{{ CSS embedded in HTML + +;; This is the simplest example. Many applications will need no more +;; than a simple regexp. +(mmm-add-classes + '((embedded-css + :submode css + :face mmm-declaration-submode-face + :front "<style[^>]*>" + :back "</style>"))) + +;;}}} +;;{{{ Javascript in HTML + +;; We use two classes here, one for code in a <script> tag and another +;; for code embedded as a property of an HTML tag, then another class +;; to group them together. +(mmm-add-group + 'html-js + '((js-tag + :submode javascript + :face mmm-code-submode-face + :front "<script\[^>\]*>" + :back"</script>" + :insert ((?j js-tag nil @ "<script language=\"JavaScript\">" + @ "\n" _ "\n" @ "</script>" @)) + ) + (js-inline + :submode javascript + :face mmm-code-submode-face + :front "on\w+=\"" + :back "\""))) + +;;}}} +;;{{{ Here-documents + +;; 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 +;; 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 +;; underscores. + +(defvar mmm-here-doc-mode-alist '() + "Alist associating here-document name regexps to submodes. +Normally, this variable is unnecessary, as the `here-doc' submode +class tries to automagically recognize the right submode. If you use +here-document names that it doesn't recognize, however, then you can +add elements to this alist. Each element is \(REGEXP . MODE) where +REGEXP is a regular expression matched against the here-document name +and MODE is a major mode function symbol.") + +(defun mmm-here-doc-get-mode (string) + (string-match "[a-zA-Z_-]+" string) + (setq string (match-string 0 string)) + (or (mmm-ensure-modename + ;; First try the user override variable. + (some #'(lambda (pair) + (if (string-match (car pair) string) (cdr pair) nil)) + mmm-here-doc-mode-alist)) + (let ((words (split-string (downcase string) "[_-]+"))) + (or (mmm-ensure-modename + ;; Try the whole name, stopping at "mode" if present. + (intern + (mapconcat #'identity + (nconc (ldiff words (member "mode" words)) + (list "mode")) + "-"))) + ;; Try each word by itself (preference list) + (some #'(lambda (word) + (mmm-ensure-modename (intern word))) + words) + ;; Try each word with -mode tacked on + (some #'(lambda (word) + (mmm-ensure-modename + (intern (concat word "-mode")))) + words) + ;; Try each pair of words with -mode tacked on + (loop for (one two) on words + if (mmm-ensure-modename + (intern (concat one two "-mode"))) + return it) + ;; I'm unaware of any modes whose names, minus `-mode', + ;; are more than two words long, and if the entire mode + ;; name (perhaps minus `-mode') doesn't occur in the + ;; here-document name, we can give up. + (signal 'mmm-no-matching-submode nil))))) + +(mmm-add-classes + '((here-doc + :front "<<\\([a-zA-Z0-9_-]+\\)" + :front-offset (end-of-line 1) + :back "^~1$" + :save-matches 1 + :match-submode mmm-here-doc-get-mode + :insert ((?d here-doc "Here-document Name: " @ "<<" str _ "\n" + @ "\n" @ str "\n" @)) + ))) + +;;}}} +;;{{{ Embperl + +(mmm-add-group + 'embperl + '((embperl-perl + :submode perl + :front "\\[\\([-\\+!\\*\\$]\\)" + :back "~1\\]" + :save-matches 1 + :match-face (("[+" . mmm-output-submode-face) + ("[-" . mmm-code-submode-face) + ("[!" . mmm-init-submode-face) + ("[*" . mmm-code-submode-face) + ("[$" . mmm-special-submode-face)) + :insert ((?p embperl "Region Type (Character): " @ "[" str + @ " " _ " " @ str "]" @) + (?+ embperl+ ?p . "+") + (?- embperl- ?p . "-") + (?! embperl! ?p . "!") + (?* embperl* ?p . "*") + (?$ embperl$ ?p . "$") + ) + ) + (embperl-comment + :submode text-mode + :face mmm-comment-submode-face + :front "\\[#" + :back "#\\]" + :insert ((?# embperl-comment nil @ "[#" @ " " _ " " @ "#]" @)) + ))) + +;;}}} +;;{{{ ePerl + +(mmm-add-group + 'eperl + '((eperl-code + :submode perl + :face mmm-code-submode-face + :front "<:" + :back "_?:>" + :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 @ "<:=" @ " " _ " " @ ":>" @))))) + +;;}}} +;;{{{ File Variables + +;; This submode class puts file local variable values, specified with +;; a `Local Variables:' line as in (emacs)File Variables, into Emacs +;; Lisp Mode. It is a good candidate to put in `mmm-global-classes'. + +(defun mmm-file-variables-verify () + ;; It would be nice to cache this somehow, which could be done in a + ;; buffer-local variable with markers for positions, but the trick + ;; is knowing when to expire the cache. + (let ((bounds + (save-excursion + (save-match-data + (goto-char (point-max)) + (backward-page) + (and (re-search-forward "^\\(.*\\)Local Variables:" nil t) + (list (match-string 1) + (progn (end-of-line) (point)) + (and (search-forward + (format "%sEnd:" (match-string 1)) + nil t) + (progn (beginning-of-line) + (point))))))))) + (and bounds (caddr bounds) + (save-match-data + (string-match (format "^%s" (regexp-quote (car bounds))) + (match-string 0))) + (> (match-beginning 0) (cadr bounds)) + (< (match-end 0) (caddr bounds))))) + +(defun mmm-file-variables-find-back (bound) + (forward-sexp) + (if (> (point) bound) + nil + (looking-at ""))) + +(mmm-add-classes + '((file-variables + :front ".+:" + :front-verify mmm-file-variables-verify + :back mmm-file-variables-find-back + :submode emacs-lisp-mode + ))) + +;;}}} +;;{{{ JSP Pages + +(mmm-add-group 'jsp + `((jsp-code + :submode java + :match-face (("<%!" . mmm-declaration-submode-face) + ("<%=" . mmm-output-submode-face) + ("<%" . mmm-code-submode-face)) + :front "<%[!=]?" + :back "%>" + :insert ((?% jsp-code nil @ "<%" @ " " _ " " @ "%>" @) + (?! jsp-declaration nil @ "<%!" @ " " _ " " @ "%>" @) + (?= jsp-expression nil @ "<%=" @ " " _ " " @ "%>" @)) + ) + (jsp-directive + :submode text-mode + :face mmm-special-submode-face + :front "<%@" + :back "%>" + :insert ((?@ jsp-directive nil @ "<%@" @ " " _ " " @ "%>" @)) + ))) + +;;}}} + +;; NOT YET UPDATED +;;{{{ HTML in PL/SQL;-COM- +;-COM- +;-COM-;; This one is the most complex example. In PL/SQL, HTML is generally +;-COM-;; output as a (single quote delimited) string inside a call to htp.p or +;-COM-;; its brethren. The problem is that there may be strings outside of +;-COM-;; htp.p calls that should not be HTML, so we need to only look inside +;-COM-;; these calls. The situation is complicated by PL/SQL's rule that two +;-COM-;; sequential single quotes in a string mean to put a single quote +;-COM-;; inside the string. +;-COM- +;-COM-;; These functions have not been thoroughly tested, and always search +;-COM-;; the entire buffer, ignoring START and END. +;-COM- +;-COM-(defun mmm-html-in-plsql (start end) +;-COM- (save-match-data +;-COM- (let ((case-fold-search t)) +;-COM- (and (re-search-forward "htp.p\\(\\|rn\\|rint\\)1?(" nil t) +;-COM- (mmm-html-in-plsql-in-htp +;-COM- ;; Find the end of the procedure call +;-COM- (save-excursion (forward-char -1) (forward-sexp) (point)) +;-COM- start end))))) +;-COM- +;-COM-(defun mmm-html-in-plsql-in-htp (htp-end start end) +;-COM- (let (beg end) +;-COM- (or (and (re-search-forward "'" htp-end 'limit) +;-COM- (setf beg (match-end 0)) +;-COM- ;; Find an odd number of 's to end the string. +;-COM- (do ((lgth 0 (length (match-string 0)))) +;-COM- ((oddp lgth) t) +;-COM- (re-search-forward "'+" nil t)) +;-COM- (setf end (1- (match-end 0))) +;-COM- (cons (cons beg end) +;-COM- (mmm-html-in-plsql-in-htp htp-end start end))) +;-COM- ;; No more strings in the procedure call; look for another. +;-COM- (and (eql (point) htp-end) +;-COM- (mmm-html-in-plsql start end))))) +;-COM- +;-COM-(add-to-list 'mmm-classes-alist +;-COM- '(htp-p (:function html-mode mmm-html-in-plsql))) +;-COM- +;;}}} + +(provide 'mmm-sample) + + +;;; Local Variables: +;;; End: + +;;; mmm-sample.el ends here
\ No newline at end of file diff --git a/mmm/mmm-univ.el b/mmm/mmm-univ.el new file mode 100644 index 00000000..7c16df20 --- /dev/null +++ b/mmm/mmm-univ.el @@ -0,0 +1,64 @@ +;;; mmm-univ.el --- The "Universal" Submode Class + +;; Copyright (C) 2000 by Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> + +;;{{{ 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 defines the "universal" submode class, the default value +;; of `mmm-global-classes', which specifies a standard way to indicate +;; that part of a buffer should be in a different mode--for example, +;; in an email message. + +;;; Code: + +(require 'mmm-auto) +(require 'mmm-vars) + +(defun mmm-univ-get-mode (string) + (string-match "[a-zA-Z-]+" string) + (setq string (match-string 0 string)) + (let ((modestr (intern (if (string-match "mode\\'" string) + string + (concat string "-mode"))))) + (or (mmm-ensure-modename modestr) + (signal 'mmm-no-matching-submode nil)))) + +(mmm-add-classes + `((universal + :front "{%\\([a-zA-Z-]+\\)%}" + :back "{%/~1%}" + :insert ((?/ universal "Submode: " @ "{%" str "%}" @ "\n" _ "\n" + @ "{%/" str "%}" @)) + :match-submode mmm-univ-get-mode + :save-matches 1 + ))) + +(provide 'mmm-univ) + + +;;; Local Variables: +;;; mmm-global-classes: nil +;;; End: + +;;; mmm-univ.el ends here
\ No newline at end of file diff --git a/mmm/mmm-utils.el b/mmm/mmm-utils.el new file mode 100644 index 00000000..8b5dcc2c --- /dev/null +++ b/mmm/mmm-utils.el @@ -0,0 +1,143 @@ +;;; mmm-utils.el --- Coding Utilities for MMM Mode + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 provides a number of macros and other coding utilities +;; for MMM Mode. + +;;; Code: + +(require 'cl) + +;;{{{ Valid Buffer + +;; We used to wrap almost everything in this, but I realized that +;; only `mmm-mode-on' really needs it. Kept it as a macro, though, +;; for modularity and in case we need it somewhere else. +(defmacro mmm-valid-buffer (&rest body) + "Execute BODY if in a valid buffer for MMM Mode to be enabled. This +means not hidden, not a minibuffer, not in batch mode, and not in of +`mmm-never-modes'." + `(unless (or (eq (aref (buffer-name) 0) ?\ ) + (window-minibuffer-p (selected-window)) + (memq major-mode mmm-never-modes) + noninteractive + ;; Unnecessary as now hidden +;;; (equal (buffer-name) mmm-temp-buffer-name) + ) + ,@body)) + +;;;(def-edebug-spec mmm-valid-buffer t) + +;;}}} +;;{{{ Save Everything + +;; Never trust callback functions to preserve anything. +(defmacro mmm-save-all (&rest body) + "Execute BODY forms, then restoring point, mark, current buffer, +restrictions, and match data." + `(save-excursion + (save-restriction + (save-match-data + ,@body)))) + +;;;(def-edebug-spec mmm-save-all t) + +;;}}} +;;{{{ String Formatting + +(defun mmm-format-string (string arg-pairs) + "Format STRING by replacing arguments as specified by ARG-PAIRS. +Each element of ARG-PAIRS is \(REGEXP . STR) where each STR is to be +substituted for the corresponding REGEXP wherever it matches." + (let ((case-fold-search nil)) + (save-match-data + (dolist (pair arg-pairs) + (while (string-match (car pair) string) + (setq string (replace-match (cdr pair) t t string)))))) + string) + +(defun mmm-format-matches (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." + (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)))))) + string) + +;;}}} +;;{{{ Save Keywords + +(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." + `(if (and (boundp ',param) ,param) + (list (intern (concat ":" (symbol-name ',param))) ,param) + nil)) + +(defmacro mmm-save-keywords (&rest params) + "Return a list saving the non-nil elements of PARAMS. E.g. +\(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." + `(append ,@(mapcar #'(lambda (param) + (macroexpand `(mmm-save-keyword ,param))) + params))) + +;;}}} +;;{{{ Looking Back At + +(defun mmm-looking-back-at (regexp &optional bound) + "Return t if text before point matches REGEXP. +Modifies the match data. If supplied, BOUND means not to look farther +back that that many characters before point. Otherwise, it defaults to +\(length REGEXP), which is good enough when REGEXP is a simple +string." + (eq (point) + (save-excursion + (and (re-search-backward regexp + (- (point) (or bound (length regexp))) + t) + (match-end 0))))) + +;;}}} + +(provide 'mmm-utils) + +;;; mmm-utils.el ends here
\ No newline at end of file diff --git a/mmm/mmm-vars.el b/mmm/mmm-vars.el new file mode 100644 index 00000000..4fbf3579 --- /dev/null +++ b/mmm/mmm-vars.el @@ -0,0 +1,764 @@ +;;; mmm-vars.el --- Variables for MMM Mode + +;; Copyright (C) 2000 by Michael Abraham Shulman + +;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net> +;; 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 provides the definitions for the variables used by MMM +;; Mode, as well as several functions to manipulate them. It also +;; defines the errors that MMM Mode can signal. + +;;; Code: + +(require 'mmm-compat) + +;; MISCELLANEOUS +;;{{{ Shut up the Byte Compiler + +;; Otherwise it complains about undefined variables. +(eval-when-compile + (defvar mmm-save-local-variables) + (defvar mmm-mode-string) + (defvar mmm-submode-mode-line-format) + (defvar mmm-mode-ext-classes-alist) + (defvar mmm-mode-prefix-key) + (defvar mmm-global-mode) + (defvar mmm-primary-mode) + (defvar mmm-classes-alist)) + +;;}}} +;;{{{ Error Conditions + +;; Signalled when we try to put a submode region inside one where it +;; isn't meant to go. +(put 'mmm-invalid-parent + 'error-conditions + '(mmm-invalid-parent mmm-error error)) +(put 'mmm-invalid-parent + 'error-message + "Invalid submode region parent") + +;; Signalled when we try to apply a submode class that doesn't exist. +(put 'mmm-invalid-submode-class + 'error-conditions + '(mmm-invalid-submode-class mmm-error error)) +(put 'mmm-invalid-submode-class + 'error-message + "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. +(put 'mmm-no-matching-submode + 'error-conditions + '(mmm-no-matching-submode mmm-error error)) +(put 'mmm-no-matching-submode + 'error-message + "Internal error: no matching submode.") + +;;}}} + +;; USER VARIABLES +;;{{{ Customization Group + +(defgroup mmm nil + "Multiple Major Modes in one buffer." + :group 'tools) + +;;}}} +;;{{{ Save Local Variables + +(defvar mmm-c-derived-modes + '(c-mode c++-mode objc-mode pike-mode java-mode jde-mode javascript-mode)) + +(defvar mmm-save-local-variables + `(;; Don't use `function' (#') here!! We're already inside `quote'! + major-mode + comment-start + comment-end + (comment-line-start-skip buffer (fortran-mode)) + comment-start-skip + (comment-column buffer) + comment-indent-function + comment-line-break-function + sentence-end + ,@(when mmm-xemacs + '(mode-popup-menu + (((lambda () current-menubar) . set-buffer-menubar)) + )) + font-lock-keywords + font-lock-keywords-only + font-lock-keywords-case-fold-search + font-lock-syntax-table + font-lock-mark-block-function ; Override this? + font-lock-syntactic-keywords + indent-line-function + parse-sexp-ignore-comments ; Fixes indentation in PHP-mode? + ;; Can be different in different buffers + (c-basic-offset + buffer (c-mode c++-mode objc-mode pike-mode java-mode jde-mode)) + ;; These are necessary for C syntax parsing + (c-class-key nil ,mmm-c-derived-modes) + (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))) + ;; Skeleton insertion + skeleton-transformation + ;; Abbrev mode + abbrev-mode + local-abbrev-table + ;; And finally the syntax table and local map. + ((syntax-table . set-syntax-table)) + ((current-local-map . use-local-map) buffer) + ) + "Which local variables to save for major mode regions. +Each element has the form \(VARIABLE [TYPE [MODES]]), causing VARIABLE +to be saved for all major modes in the list MODES. If MODES is t or +absent, the variable is saved for all major modes. MODES can also be +a function of no arguments which returns non-nil whenever the variable +should be saved. + +TYPE should be either the symbol `global', meaning to save the +variable globally, the symbol `buffer', meaning to save it per buffer, +or the symbol `region', meaning to save it for each submode region. +If TYPE has any other value, such as nil, or is absent, the variable +is saved globally. If all optional parameters are omitted, the +element may be simply VARIABLE instead of \(VARIABLE). + +It is possible for VARIABLE to be not a symbol but a cons cell of the +form \(GETTER . SETTER), thus specifying special functions to set and +get the value of the \"variable\". This is used for objects like +local maps, syntax tables, etc. which need to be installed in a +special way. GETTER should be a function of no arguments, and SETTER +a function of one. In this case, even if TYPE and MODES are omitted, +the list cannot be flattened--it must be \((GETTER . SETTER)). +\"Variables\" of this type cannot be seen with `mmm-get-saved-local'. + +A single variable may appear more than once in this list, with +different modes and/or types. If the same mode appears more than once +for the same variable with different types, the behavior is undefined. +Changing the value of this variable after MMM Mode has been activated +in some buffer may produce unpredictable results. + +Globally saved variables are saved in the mmm-local-variables property +of the mode symbol. Buffer saved variables are saved in the alist +`mmm-buffer-saved-locals'. Region saved variables are saved in the +mmm-local-variables property of the overlay.") + +(defvar mmm-buffer-saved-locals () + "Stores saved local variables for this buffer, by mode. +Each element looks like \(MODE \(VAR VALUE) ...).") +(make-variable-buffer-local 'mmm-buffer-saved-locals) + +(defvar mmm-region-saved-locals-defaults () + "Stores saved defaults for region-saved locals, by mode. +Each element looks like \(MODE \(VAR VALUE) ...). Used to initialize +new submode regions.") +(make-variable-buffer-local 'mmm-region-saved-locals-defaults) + +(defvar mmm-region-saved-locals-for-dominant () + "Stores saved region locals for the dominant major mode. +The dominant major mode is considered to be one region for purposes of +saving region variables. Region-saved variables for submode regions +are saved as overlay properties.") +(make-variable-buffer-local 'mmm-region-saved-locals-for-dominant) + +;;}}} +;;{{{ Submode Faces + +(defgroup mmm-faces nil + "Faces and coloring for submode regions. +In general, only background colors should be set, to avoid interfering +with font-lock." + :group 'mmm) + +(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." + :group 'mmm-faces + :type '(choice (const :tag "None" 0) + (const :tag "Low" 1) + (const :tag "High" 2))) + +(defface mmm-init-submode-face '((t (:background "Pink"))) + "Face used for submodes containing initialization code." + :group 'mmm-faces) + +(defface mmm-cleanup-submode-face '((t (:background "Wheat"))) + "Face used for submodes containing cleanup code." + :group 'mmm-faces) + +(defface mmm-declaration-submode-face '((t (:background "Aquamarine"))) + "Face used for submodes containing declarations." + :group 'mmm-faces) + +(defface mmm-comment-submode-face '((t (:background "SkyBlue"))) + "Face used for submodes containing comments and documentation." + :group 'mmm-faces) + +(defface mmm-output-submode-face '((t (:background "Plum"))) + "Face used for submodes containing expression that are output." + :group 'mmm-faces) + +(defface mmm-special-submode-face '((t (:background "MediumSpringGreen"))) + "Face used for special submodes not fitting any other category." + :group 'mmm-faces) + +(defface mmm-code-submode-face '((t (:background "LightGray"))) + "Face used for submodes containing ordinary code." + :group 'mmm-faces) + +(defface mmm-default-submode-face '((t (:background "gray85"))) + "Face used for all submodes at decoration level 1. +Also used at decoration level 2 for submodes not specifying a type." + :group 'mmm-faces) + +;;}}} +;;{{{ Mode Line Format + +(defcustom mmm-mode-string " MMM" + "*String to display in mode line as MMM minor mode indicator." + :group 'mmm + :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." + :group 'mmm + :type 'string) + +;;}}} +;;{{{ Submode Classes + +(defvar mmm-classes nil + "*List of submode classes that apply to a buffer. +Generally set in a file local variables list. Can either be one +symbol, or a list of symbols. Automatically buffer-local.") +(make-variable-buffer-local 'mmm-classes) + +(defvar mmm-global-classes '(universal) + "*List of submode classes that apply to all buffers. +Can be overridden in a file local variables list.") + +;;}}} +;;{{{ Modes and Extensions + +(defcustom mmm-mode-ext-classes-alist nil + "Alist of submode classes for major modes and/or file extensions. +This variable can now be directly modified. + +Elements look like \(MODE EXT CLASS), where MODE is a major mode, EXT +is a regexp to match a filename such as in `auto-mode-alist', and +CLASS is a submode class. CLASS is activated in all buffers in mode +MODE \(if non-nil) and whose filenames match EXT \(if non-nil). If +both MODE and EXT are nil, CLASS is activated in all buffers. If CLASS +is the symbol t, MMM Mode is turned on in all buffers matching MODE +and EXT, but no classes are activated. + +See `mmm-global-mode'." + :group 'mmm + :type '(repeat (list (symbol :tag "Major Mode") + (string :tag "Filename Regexp") + (symbol :tag "Class"))) + :require 'mmm-mode) + +(defun mmm-add-mode-ext-class (mode ext class) + "Add an element to `mmm-mode-ext-classes-alist', which see. +That variable can now be directly modified, so this function is +unnecessary. It probably won't go away, though." + (add-to-list 'mmm-mode-ext-classes-alist (list mode ext class))) + +;;}}} +;;{{{ Preferred Major Modes + +(defcustom mmm-major-mode-preferences + '((perl cperl-mode perl-mode) + (javascript javascript-mode c++-mode) + (java jde-mode java-mode c++-mode) + (css css-mode c++-mode)) + "User preferences about what major modes to use. +Each element has the form \(LANGUAGE . MODES) where LANGUAGE is the +name of a programming language such as `perl' as a symbol, and MODES +is a list of possible major modes to use, such as `cperl-mode' or +`perl-mode'. The first element of MODES which is `fboundp' is used +for submodes of LANGUAGE. The last element of MODES should be a mode +which will always be available." + :group 'mmm + :type '(repeat (cons symbol + (repeat + (restricted-sexp :match-alternatives + (fboundp)))))) + +(defun mmm-add-to-major-mode-preferences (language mode &optional default) + "Set the preferred major mode for LANGUAGE to MODE. +This sets the value of `mmm-major-mode-preferences'. If DEFAULT is +nil or unsupplied, MODE is added at the front of the list of modes for +LANGUAGE. If DEFAULT is non-nil, then it is added at the end. This +may be used by packages to ensure that some mode is present, but not +override any user-specified mode." + (let ((pair (assq language mmm-major-mode-preferences))) + (if pair + ;; Existing mode preferences + (if default + (setcdr pair (cons mode (cdr pair))) + (setcdr pair (append (cdr pair) (list mode)))) + ;; No existing mode preference + (add-to-list 'mmm-major-mode-preferences (list language mode))))) + +(defun mmm-ensure-modename (symbol) + "Return SYMBOL if it is a valid submode name, else nil. +Valid submode names are either `fboundp' or present as the `car' of an +element in `mmm-major-mode-preferences'." + (if (or (fboundp symbol) + (assq symbol mmm-major-mode-preferences)) + symbol + nil)) + +(defun mmm-modename->function (mode) + "Convert MODE to a mode function, nil if impossible. +Valid submode names are either `fboundp' or present as the `car' of an +element in `mmm-major-mode-preferences'. In the latter case, the +first `fboundp' element of the `cdr' is returned, or nil if none." + (if (fboundp mode) + mode + (car (remove-if-not + #'fboundp + (cdr (assq mode mmm-major-mode-preferences)))))) + +;;}}} +;;{{{ Key Bindings + +(defcustom mmm-mode-prefix-key [(control ?c) ?%] + "Prefix key for the MMM Minor Mode Keymap." + :group 'mmm + :type 'vector) + +(defcustom mmm-command-modifiers '(control) + "List of key modifiers for MMM command keys. +The MMM commands in the MMM Mode map, after `mmm-mode-prefix-key', +are bound to default keys with these modifiers added. This variable +must be set before MMM Mode is loaded to have an effect. + +It is suggested that the value of this variable be either nil or +\(control), as the default keys are either plain keys or have only a +meta modifier. The shift modifier is not particularly portable between +Emacsen. The values of this variable and `mmm-insert-modifiers' should +be disjoint." + :group 'mmm + :type '(repeat (symbol :tag "Modifier"))) + +(defcustom mmm-insert-modifiers '() + "List of key modifiers for MMM submode insertion keys. +When a key pressed after `mmm-mode-prefix-key' has no MMM Mode command +binding, and its modifiers include these, then its basic type, plus any +modifiers in addition to these, is looked up in classes' :insert +specifications. + +It is suggested that the value of this variable be either nil or +\(control), allowing submode classes to specify the presence or +absence of the meta modifier. The shift modifier is not particularly +portable between Emacsen. The values of `mmm-command-modifiers' and +this variable should be disjoint." + :group 'mmm + :type '(repeat (symbol :tag "Modifier"))) + +(defcustom mmm-use-old-command-keys nil + "Non-nil means to Use the old command keys for MMM Mode. +MMM Mode commands then have no modifier while insertion commands have +a control modifier, i.e. `mmm-command-modifiers' is set to nil and +`mmm-insert-modifiers' is set to \(control). If nil, the values of +these variables are as the default, or whatever the user has set them +to. This variable must be set before MMM Mode is loaded." + :group 'mmm + :type 'boolean) + +(defun mmm-use-old-command-keys () + "Use the old command keys \(no control modifer) in MMM Mode." + (setq mmm-command-modifiers '() + mmm-insert-modifiers '(control))) + +;;}}} +;;{{{ MMM Hooks + +(defcustom mmm-mode-hook () + "Hook run when MMM Mode is enabled in a buffer. + +A hook named mmm-<major-mode>-hook is also run, if it exists. For +example, `mmm-html-mode-hook' is run whenever MMM Mode is entered with +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 +the newly created submode region. + +Finally, a hook named mmm-<class>-class-hook is run whenever a buffer +is first mmm-ified with a given submode class. For example, +`mmm-mason-class-hook' is run whenever the `mason' class is first +applied in a buffer." + :group 'mmm + :type 'hook) + +(defun mmm-run-constructed-hook (body &optional suffix) + "Run the hook named `mmm-<BODY>-<SUFFIX>-hook', if it exists. +If SUFFIX is nil or unsupplied, run `mmm-<BODY>-hook' instead." + (let ((hook (intern-soft (if suffix + (format "mmm-%s-%s-hook" body suffix) + (format "mmm-%s-hook" body))))) + (if hook (run-hooks hook)))) + +(defun mmm-run-major-hook () + (mmm-run-constructed-hook mmm-primary-mode)) + +(defun mmm-run-submode-hook (submode) + (mmm-run-constructed-hook submode "submode")) + +(defvar mmm-class-hooks-run () + "List of submode classes for which hooks have already been run in +the current buffer.") +(make-variable-buffer-local 'mmm-class-hooks-run) + +(defun mmm-run-class-hook (class) + (unless (member class mmm-class-hooks-run) + (mmm-run-constructed-hook class "class") + (add-to-list 'mmm-class-hooks-run class))) + +;;}}} +;;{{{ Major Mode Hook + +(defcustom mmm-major-mode-hook () + "Hook run whenever a new major mode is finished starting up. +MMM Mode implements this with a hack \(see comments in the source) so +that `mmm-global-mode' will function correctly, but makes this hook +available so that others can take advantage of the hack as well. + +Note that file local variables have *not* been processed by the time +this hook is run. If a function needs to inspect them, it should also +be added to `find-file-hooks'. However, `find-file-hooks' is not run +when creating a non-file-based buffer, or when changing major modes in +an existing buffer." + :group 'mmm + :type 'hook) + +(defun mmm-run-major-mode-hook () + (dolist (func mmm-major-mode-hook) + (ignore-errors (funcall func)))) + +;;}}} +;;{{{ MMM Global Mode + +(defcustom mmm-global-mode nil + "*Specify in which buffers to turn on MMM Mode automatically. + +- If nil, MMM Mode is never enabled automatically. +- If t, MMM Mode is enabled automatically in all buffers. +- If any other symbol, MMM mode is enabled only in those buffers that + have submode classes associated with them. See `mmm-classes' and + `mmm-mode-ext-classes-alist' for more information." + :group 'mmm + :type '(choice (const :tag "Always" t) + (const :tag "Never" nil) + (other :tag "Maybe" maybe)) + :require 'mmm-mode) + +;;}}} +;;{{{ "Never" Modes + +(defcustom mmm-never-modes + '( + help-mode + Info-mode + dired-mode + comint-mode + telnet-mode + shell-mode + eshell-mode + forms-mode + ) + "List of modes in which MMM Mode is never activated." + :group 'mmm + :type '(repeat (symbol :tag "Mode"))) + +;;}}} +;;{{{ 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.") + +;;}}} + +;; NON-USER VARIABLES +;;{{{ Mode Variable + +(defvar mmm-mode nil + "Non-nil means MMM Mode is turned on in this buffer. +Do not set this variable directly; use the function `mmm-mode'.") +(make-variable-buffer-local 'mmm-mode) + +;;}}} +;;{{{ Primary Mode + +(defvar mmm-primary-mode nil + "The primary major mode in the current buffer.") +(make-variable-buffer-local 'mmm-primary-mode) + +;;}}} +;;{{{ Classes Alist + +;; :parent could be an all-class argument. Same with :keymap. +(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 +arguments, called a \"class specifier\". There are a large number of +accepted keyword arguments. + +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 +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). + +If neither CLASSES nor HANDLER are supplied, either SUBMODE or +MATCH-SUBMODE must be. SUBMODE specifies the submode to use for the +submode regions, a symbol such as `cperl-mode' or `emacs-lisp-mode', +while MATCH-SUBMODE must be a function to be called immediately after +a match is found for FRONT, which is passed one argument, the form of +the front delimiter \(found from FRONT-FORM, below), and return a +symbol such as SUBMODE would be set to. If MATCH-SUBMODE detects an +invalid match--for example a specified mode which is not `fboundp'--it +should \(signal 'mmm-no-matching-submode nil). + +FRONT and BACK are the means to find the submode regions, and can be +either buffer positions \(number-or-markers), regular expressions, or +functions. If they are absolute buffer positions, only one submode +region is created, from FRONT to BACK. This is generally not used in +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. + +FRONT-MATCH and BACK-MATCH default to zero. They specify which +sub-match of the FRONT and BACK regexps to treat as the delimiter. +This number will be passed to any calls to `match-beginning' and +company. + +FRONT- and BACK-OFFSET default to 0. In addition to numbers, they can +also be functions to call which should move point to the correct +position for the beginning or end of the submode region. Common +choices include `beginning-of-line' and `end-of-line', and new +functions can of course be written. They can also be lists which will +be applied in sequence, such as \(end-of-line 1) meaning move to end +of line and then forward one character. + +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-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 +they are functions, they are called and must inspect the match data. +If they are lists, their `car' is taken as the delimiter. The default +for both is \(regexp-quote \(match-string 0)). + +The last case--them being a list--is usually used to set the delimiter +to a function. Such a function must take 1-2 arguments, the first +being the overlay in question, and the second meaning to insert the +delimiter and adjust the overlay rather than just matching the +delimiter. See `mmm-match-front', `mmm-match-back', and +`mmm-end-current-region'. + +CASE-FOLD-SEARCH, if specified, controls whether the search is +case-insensitive. See `case-fold-search'. It defaults to `t'. + +CREATION-HOOK, if specified, should be a function which is run +whenever a submode region is created, with point at the beginning of +the new region. One use for it is to set region-saved local variables +\(see `mmm-save-local-variables'). + +INSERT specifies the keypress insertion spec for such submode regions. +INSERT's value should be list of elements of the form \(KEY NAME . +SPEC). Each KEY should be either a character, a function key symbol, +or a dotted list \(MOD . KEY) where MOD is a symbol for a modifier +key. The use of any other modifier than meta is discouraged, as +`mmm-insert-modifiers' is sometimes set to \(control), and other +modifiers are not very portable. Each NAME should be a symbol +representing the insertion for that key. Each SPEC can be either a +skeleton, suitable for passing to `skeleton-insert' to create a +submode region, or a dotted pair \(OTHER-KEY . ARG) meaning to use the +skeleton defined for OTHER-KEY but pass it the argument ARG as the +`str' variable, possible replacing a prompt string. Skeletons for +insertion should have the symbol `_' where point \(or wrapped text) +should go, and the symbol `@' in four different places: at the +beginning of the front delimiter, the beginning of the submode region, +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. + +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.") + +(defun mmm-add-classes (classes) + "Add the submode classes CLASSES to `mmm-classes-alist'." + (dolist (class classes) + (add-to-list 'mmm-classes-alist class))) + +(defun mmm-add-group (group classes) + "Add CLASSES and a group named GROUP containing them all. +The CLASSES are all made private, i.e. non-user-visible." + (mmm-add-classes (mapcar #'(lambda (class) + (append class + '(:private t))) + classes)) + (add-to-list 'mmm-classes-alist + (list group :classes (mapcar #'first classes)))) + +;;}}} +;;{{{ Version Number + +(defconst mmm-version "0.4.7" + "Current version of MMM Mode.") + +(defun mmm-version () + (interactive) + (message "MMM Mode version %s by Michael Abraham Shulman" mmm-version)) + +;;}}} +;;{{{ Temp Buffer Name + +(defvar mmm-temp-buffer-name " *mmm-temp*" + "Name for temporary buffers created by MMM Mode.") + +;;}}} +;;{{{ Interactive History + +(defvar mmm-interactive-history nil + "History of interactive mmm-ification in the current buffer. +Elements are either submode class symbols or class specifications. See +`mmm-classes-alist' for more information.") +(make-variable-buffer-local 'mmm-interactive-history) + +(defun mmm-add-to-history (class) + (add-to-list 'mmm-interactive-history class)) + +(defun mmm-clear-history () + "Clears history of interactive mmm-ification in current buffer." + (interactive) + (setq mmm-interactive-history nil)) + +;;}}} +;;{{{ Mode/Ext Manipulation + +(defvar mmm-mode-ext-classes () + "List of classes associated with current buffer by mode and filename. +Set automatically from `mmm-mode-ext-classes-alist'.") +(make-variable-buffer-local 'mmm-mode-ext-classes) + +(defun mmm-get-mode-ext-classes () + "Return classes for current buffer from major mode and filename. +Uses `mmm-mode-ext-classes-alist' to find submode classes." + (or mmm-mode-ext-classes + (setq mmm-mode-ext-classes + (mapcar #'third + (remove-if-not #'mmm-mode-ext-applies + mmm-mode-ext-classes-alist))))) + +(defun mmm-clear-mode-ext-classes () + "Clear classes added by major mode and filename." + (setq mmm-mode-ext-classes nil)) + +(defun mmm-mode-ext-applies (element) + (destructuring-bind (mode ext class) element + (and (if mode + (eq mode + ;; If MMM is on in this buffer, use the primary mode, + ;; otherwise use the normal indicator. + (or mmm-primary-mode major-mode)) + t) + (if ext + (and (buffer-file-name) + (save-match-data + (string-match ext (buffer-file-name)))) + t)))) + +(defun mmm-get-all-classes (global) + "Return a list of all classes applicable to the current buffer. +These come from mode/ext associations, `mmm-classes', and interactive +history, as well as `mmm-global-classes' if GLOBAL is non-nil." + (append mmm-interactive-history + (if (listp mmm-classes) mmm-classes (list mmm-classes)) + (if global mmm-global-classes ()) + (mmm-get-mode-ext-classes))) + +;;}}} + +(provide 'mmm-vars) + +;;; mmm-vars.el ends here diff --git a/mmm/mmm.texinfo b/mmm/mmm.texinfo new file mode 100644 index 00000000..2a8ff603 --- /dev/null +++ b/mmm/mmm.texinfo @@ -0,0 +1,1904 @@ +\input texinfo +@c %**start of header +@setfilename mmm.info +@settitle MMM Mode Manual +@c %**end of header +@syncodeindex vr fn +@set MASON_VERSION 0.896 + +@dircategory GNU Emacs Lisp +@direntry +* MMM-Mode: (mmm). Multiple Major Modes for Emacs +@end direntry + +@include version.texi + +@ifinfo +This is edition @value{EDITION} of the MMM Mode Manual, last updated +@value{UPDATED}. It documents version @value{VERSION} of MMM Mode. + +Copyright 2000 Michael Abraham Shulman. + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Copying'' and ``GNU General Public License'' are +included exactly as in the original, and provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by the Free Software Foundation. + +@end ifinfo + +@titlepage +@title MMM Mode Manual +@subtitle Multiple Major Modes for Emacs +@subtitle Edition @value{EDITION} +@subtitle @value{UPDATED} +@author Michael Abraham Shulman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 2000 Michael Abraham Shulman. + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Copying'' and ``GNU General Public License'' are +included exactly as in the original, and provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by the Free Software Foundation. + +@end titlepage + +@ifinfo +@node Top, Overview, (dir), (dir) +@top MMM Mode + +MMM Mode is a minor mode for Emacs which allows Multiple Major Modes to +coexist in a single buffer. + +This is edition @value{EDITION} of the MMM Mode Manual, last updated +@value{UPDATED}, which documents version @value{VERSION} of MMM Mode. + +@end ifinfo + +@menu +* Overview:: An overview and introduction to MMM Mode. +* Basics:: The basics of how to use it. +* Customizing:: Customizing how it works to your needs. +* Supplied Classes:: The supplied submode classes. +* Writing Classes:: Writing your own submode classes. +* Indices:: Just that. + +@detailmenu + --- The Detailed Node Listing --- + +Overview of MMM Mode + +* Basic Concepts:: A simple explanation of how it works. +* Installation:: How to install MMM Mode. +* Quick Start:: Getting started using MMM Mode quickly. + +MMM Mode Basics + +* MMM Minor Mode:: The Emacs minor mode that manages it all. +* Submode Classes:: What they are and how to use them. +* Selecting Classes:: How MMM Mode knows what classes to use. +* Insertion:: Inserting new submode regions automatically. +* Re-parsing:: Re-scanning for submode regions. +* Interactive:: Adding submode regions manually. +* Global Mode:: Turning MMM Mode on automatically. + +The MMM Minor Mode + +* Enabling MMM Mode:: Turning MMM Mode on and off. +* MMM Mode Keys:: Default key bindings in MMM Mode. + +How MMM Mode selects submode classes + +* File Classes:: Classes for a single file. +* Mode-Ext Classes:: Classes for a given mode or extension. +* Global Classes:: Classes for all MMM Mode buffers. + +MMM Global Mode + +* Major Mode Hook:: Using MMM's Major Mode Hook + +Customizing MMM Mode + +* Region Coloring:: Changing or removing background colors. +* Preferred Modes:: Choosing which major modes to use. +* Mode Line:: What is displayed in the mode line. +* Key Bindings:: Customizing the MMM Mode key bindings. +* Local Variables:: What local variables are saved for submodes. +* Changing Classes:: Changing the supplied submode classes. +* Hooks:: How to make MMM Mode run your code. + +Supplied Submode Classes + +* Mason:: Mason server-side Perl in HTML. +* File Variables:: Elisp code in File Variables. +* Here-documents:: Code in shell and Perl here-documents. +* Javascript:: Javascript embedded in HTML. +* Embedded CSS:: CSS Styles embedded in HTML. +* Embperl:: Another syntax for Perl in HTML. +* ePerl:: A general Perl-embedding syntax. +* JSP:: Java code embedded in HTML. +* RPM:: Shell scripts in RPM Spec Files. + +Writing Submode Classes + +* Basic Classes:: Writing a simple submode class. +* Paired Delimiters:: Matching paired delimiters. +* Region Placement:: Placing the region more accurately. +* Submode Groups:: Grouping several classes together. +* Calculated Submodes:: Deciding the submode at run-time. +* Calculated Faces:: Deciding the display face at run-time. +* Insertion Commands:: Inserting regions automatically. +* Other Hooks:: Running code at arbitrary points. +* Delimiter Forms:: Storing the form of the delimiters. +* Misc Keywords:: Other miscellaneous options. + +Indices + +* Concept Index:: Index of MMM Mode Concepts. +* Function Index:: Index of functions and variables. +* Keystroke Index:: Index of key bindings in MMM Mode. + +@end detailmenu +@end menu + +@node Overview, Basics, Top, Top +@comment node-name, next, previous, up +@chapter Overview of MMM Mode +@cindex overview of mmm-mode +@cindex mmm-mode, overview of + +MMM Mode is a minor mode for Emacs which allows Multiple Major Modes to +coexist in a single buffer. The name is an abbreviation of `Multiple +Major Modes'@footnote{The name is derived from @file{mmm.el} for XEmacs +by Gongquan Chen <chen@@posc.org>, from which MMM Mode was adapted.}. A +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. +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. + +@menu +* Basic Concepts:: A simple explanation of how it works. +* Installation:: How to install MMM Mode. +* Quick Start:: Getting started using MMM Mode quickly. +@end menu + +@node Basic Concepts, Installation, Overview, Overview +@comment node-name, next, previous, up +@section Basic Concepts +@cindex dominant major mode +@cindex major mode, dominant +@cindex default major mode +@cindex major mode, default +@cindex submode regions +@cindex regions, submode +@cindex overlays, submode +@cindex submode overlays +@cindex mmm-ification + +The way MMM Mode works is as follows. Each buffer has a @dfn{dominant} +or @dfn{default} major mode, which is chosen as major modes normally +are: the user can set it interactively, or it can be chosen +automatically with `auto-mode-alist' (@pxref{Choosing Modes, , , emacs, +The Emacs Manual}). Within the file, MMM Mode creates @dfn{submode +regions} within which other major modes are in effect. While the point +is in a submode region, the following changes occur: + +@enumerate +@item +The local keymap is that of the submode. This means the key bindings for +the submode are available, while those of the dominant mode are not. +@item +The mode line (@pxref{Mode Line, , , emacs, The Emacs Manual}) changes +to show which submode region is active. This can be configured; see +@ref{Mode Line}. +@item +The major mode menu, both on the menu bar and the mouse popup, are that +of the submode. +@item +Some local variables of the submode shadow those of the default mode +(@pxref{Local Variables}). For the user, this serves to help make Emacs +behave as if the submode were the major mode. +@item +The syntax table and indentation are those of the submode. +@item +Font-lock (@pxref{Font Lock, , , emacs, The Emacs Manual}) fontifies +correctly for the submode. +@item +The submode regions are highlighted by a background color; see +@ref{Region Coloring}. + +@end enumerate + +The submode regions are represented internally by Emacs Lisp objects +known as @dfn{overlays}. Some of the above are implemented by overlay +properties, and others are updated by an MMM Mode function in +`post-command-hook'. You don't need to know this to use MMM Mode, but it +may make any error messages you come across more understandable. +@xref{Overlays, , , elisp, The GNU Emacs Lisp Reference Manual}, for +more information on overlays. + +Because overlays are not saved with a file, every time a file is opened, +they must be created. Creating submode regions is occasionally referred +to as @dfn{mmm-ification}. (I've never had occasion to pronounce this, +but if I did I would probably say `mummification'. Like what they did in +ancient Egypt.) You can mmm-ify a buffer interactively, but most often +MMM Mode will find and create submode regions automatically based on a +buffer's file extension, dominant mode, or local variables. + + +@node Installation, Quick Start, Basic Concepts, Overview +@comment node-name, next, previous, up +@section Installing MMM Mode + +MMM Mode has a standard installation process. See the file INSTALL for +generic information on this process. To summarize, unpack the archive, +@command{cd} to the created MMM Mode directory, type @samp{./configure}, +then @samp{make}, then @samp{make install}. If all goes correctly, this +will compile the MMM Mode elisp files, install them in your local +site-lisp directory, and install the MMM Mode info file @file{mmm.info} +in your local info directory. + +Now you need to configure your Emacs initialization file (usually +@file{~/.emacs}) to use MMM Mode. First, Emacs has to know where to +find MMM Mode. In other words, the MMM Mode directory has to be in +@code{load-path}. This can be done in the parent directory's +@file{subdirs.el} file, or in the init file with a line such as: + +@lisp +(add-to-list 'load-path "/path/to/site-lisp/mmm/") +@end lisp + +Once @code{load-path} is configured, MMM Mode must be loaded. You can +load all of MMM Mode with the line + +@lisp +(require 'mmm-mode) +@end lisp + +@noindent +but if you use MMM Mode only rarely, it may not be desirable to load all +of it at the beginning of every editing session. You can load just +enough of MMM Mode so it will turn itself on when necessary and load the +rest of itself, by using instead the line + +@lisp +(require 'mmm-auto) +@end lisp + +@noindent +in your initialization file. + +One more thing you may want to do right now is to set the variable +@code{mmm-global-mode}. If this variable is @code{nil} (the default), +MMM Mode will never turn itself on. If it is @code{t}, MMM Mode will +turn itself on in every buffer. Probably the most useful value for it, +however, is the symbol @code{maybe} (actually, anything that is not +@code{nil} and not @code{t}), which causes MMM Mode to turn itself on in +precisely those buffers where it would be useful. You can do this with +a line such as: + +@lisp +(setq mmm-global-mode 'maybe) +@end lisp + +@noindent +in your initialization file. @xref{Global Mode}, for more detailed +information. + + +@node Quick Start, , Installation, Overview +@comment node-name, next, previous, up +@section Getting Started Quickly + +Perhaps the simplest way to create submode regions is to do it +interactively by specifying a region. First you must turn MMM Mode +on---say, with @kbd{M-x mmm-mode}---then place point and mark around the +area you want to make into a submode region, type @kbd{C-c % C-r}, and +enter the desired major mode. @xref{Interactive}, for more details. + +A better way to add submode regions is by using submode classes, which +store a lot of useful information for MMM Mode about how to add and +manipulate the regions created. @xref{Submode Classes}, for more +details. There are several sample submode classes that come with MMM +Mode, which are documented later in this manual. Look through these and +determine if one of them fits your needs. If so, I suggest reading the +comments on that mode. Then come back here to find out to use it. + +To apply a submode class to a buffer interactively, turn MMM Mode on as +above, then type @kbd{C-c % C-c} and enter the name of the class. +Submode regions should be added automatically, if there are any regions +in the buffer appropriate to the submode class. + +If you want a given file to always use a given submode class, you can +express this in a file variable: add a line containing the string +@samp{-*- mmm-classes: @var{class} -*-} at the top of the file. +@xref{File Variables, , , emacs, The Emacs Manual}, for more information +and other methods. Now whenever MMM Mode is turned on in that file, it +will be mmm-ified according to @var{class}. If @code{mmm-global-mode} is +non-nil, then MMM Mode will turn itself on whenever a file with a +@code{mmm-classes} local variable is opened. @xref{Global Mode}, for more +information. + +If you want a submode class to apply to @emph{all} files in a certain +major mode or with a certain extension, add a line such as this to your +initialization file: + +@lisp +(mmm-add-mode-ext-class @var{mode} @var{extension} @var{class}) +@end lisp + +@noindent +After this call, any file opened whose name matches the regular +expression @var{extension} @emph{and} whose default mode is @var{mode} +will be automatically mmm-ified according to @var{class} (assuming +@code{mmm-global-mode} is non-nil). If one of @var{extension} or +@var{mode} is @code{nil}, a file need only satisfy the other one to be +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. + +@node Basics, Customizing, Overview, Top +@comment node-name, next, previous, up +@chapter MMM Mode Basics + +This chapter explains the most important parts of how to use MMM Mode. + +@menu +* MMM Minor Mode:: The Emacs minor mode that manages it all. +* Submode Classes:: What they are and how to use them. +* Selecting Classes:: How MMM Mode knows what classes to use. +* Insertion:: Inserting new submode regions automatically. +* Re-parsing:: Re-scanning for submode regions. +* Interactive:: Adding submode regions manually. +* Global Mode:: Turning MMM Mode on automatically. +@end menu + +@node MMM Minor Mode, Submode Classes, Basics, Basics +@comment node-name, next, previous, up +@section The MMM Minor Mode +@cindex mode, mmm minor +@cindex minor mode, mmm +@cindex mmm minor mode + +An Emacs minor mode is an optional feature which can be turned on or off +in a given buffer, independently of the major mode. @xref{Minor Modes, , +, emacs, The Emacs Manual}. MMM Mode is implemented as a minor mode +which manages the submode regions. This minor mode must be turned on in +a buffer for submode regions to be effective. When activated, the MMM +Minor mode is denoted by @samp{MMM} in the mode line (@pxref{Mode +Line}). + +@menu +* Enabling MMM Mode:: Turning MMM Mode on and off. +* MMM Mode Keys:: Default key bindings in MMM Mode. +@end menu + + +@node Enabling MMM Mode, MMM Mode Keys, MMM Minor Mode, MMM Minor Mode +@comment node-name, next, previous, up +@subsection Enabling MMM Mode +@cindex mmm mode, turning on +@cindex mmm mode, turning off +@cindex turning on mmm mode +@cindex turning off mmm mode +@cindex mmm mode, enabling +@cindex mmm mode, disabling +@cindex enabling mmm mode +@cindex disabling mmm mode + +If @code{mmm-global-mode} is non-@code{nil} (@pxref{Global Mode}), +then the MMM minor mode will be turned on automatically whenever a file +with associated submode classes is opened (@pxref{Selecting Classes}). +It is also turned on by interactive mmm-ification (@pxref{Interactive}), +although the interactive commands do not have key bindings when it is +not on and must be invoked via @kbd{M-x}. You can also turn it on (or +off) manually with @kbd{M-x mmm-mode}, in which case it applies all +submode classes associated with the buffer. Turning MMM Mode off +automatically removes all submode regions from the buffer. + +@deffn Command mmm-mode @var{arg} +Toggle the state of MMM Mode in the current buffer. If @var{arg} is +supplied, turn MMM Mode on if and only if @var{arg} is positive. +@end deffn + +@defun mmm-mode-on +Turn MMM Mode on unconditionally in the current buffer. +@end defun + +@defun mmm-mode-off +Turn MMM Mode off unconditionally in the current buffer. +@end defun + +@defvar mmm-mode +This variable represents whether MMM Mode is on in the current buffer. +Do not set this variable directly; use one of the above functions. +@end defvar + + +@node MMM Mode Keys, , Enabling MMM Mode, MMM Minor Mode +@comment node-name, next, previous, up +@subsection Key Bindings in MMM Mode +@cindex mmm mode key bindings +@cindex key bindings in mmm mode +@findex mmm-insertion-help +@kindex C-c % h + +When MMM Mode is on, it defines a number of key bindings. By default, +these are bound after the prefix sequence @kbd{C-c %}. Minor mode +keymaps are supposed to use @kbd{C-c @var{punctuation}} sequences, and I +find this one to be a good mnemonic because @samp{%} is used by Mason to +denote special tags. This prefix key can be customized; @ref{Key +Bindings}. + +There are two types of key bindings in MMM Mode: @dfn{commands} and +@dfn{insertions}. Command bindings run MMM Mode interactive functions to +do things like re-parse the buffer or end the current submode region, +and are defined statically as normal Emacs key-bindings. Insertion +bindings insert submode region skeletons with delimiters into the +buffer, and are defined dynamically, according to which submode classes +(@pxref{Submode Classes}) are in effect, via a keymap default binding. + +To distinguish between the two, MMM Mode uses distinct modifier keys for +each. By default, command bindings use the control key (e.g. @kbd{C-c % +C-b} re-parses the buffer), and insertion bindings do not (e.g. @kbd{C-c +% p}, when the Mason class is in effect, inserts a +@samp{<%perl>...</%perl>} region). This makes the command bindings +different from in previous versions, however, so the variable +@code{mmm-use-old-bindings} is provided. If this variable is set to `t' +before MMM Mode is loaded, the bindings will be reversed: insertion +bindings will use the control key and command bindings will not. + +Normally, Emacs gives help on a prefix command if you type @kbd{C-h} +after that command (e.g. @kbd{C-x C-h} displays all key bindings +starting with @kbd{C-x}). Because of how insertion bindings are +implemented dynamically with a default binding, they do not show up when +you hit @kbd{C-c % C-h}. For this reason, MMM Mode defines the command +@kbd{C-c % h} which displays a list of all currently valid insertion key +sequences. If you use the defaults for command and insertion bindings, +the @kbd{C-h} and @kbd{h} should be mnemonic. + +In the rest of this manual, I will assume you are using the defaults for +the mode prefix (@kbd{C-c %}) and the command and insertion modifiers. +You can customize them, however; @ref{Key Bindings}. + + +@node Submode Classes, Selecting Classes, MMM Minor Mode, Basics +@comment node-name, next, previous, up +@section Understanding Submode Classes +@cindex submode classes +@cindex classes, submode + +A submode class represents a ``type'' of submode region. It specifies +how to find the regions, what their delimiters look like, what submode +they should be, how to insert them, and how they behave in other ways. +It is represented by a symbol, such as @code{mason} or +@code{eval-elisp}. + +For example, in the Mason set of classes, there is one class +representing all @samp{<%...%>} inline Perl regions, and one +representing regions such as @samp{<%perl>...</%perl>}, +@samp{<%init>...</%init>}, and so on. These are different to Mason, but +to Emacs they are all just Perl sections, so they are covered by the +same submode class. + +But it would be tedious if whenever we wanted to use the Mason classes, +we had to specify both of these. (Actually, this is a simplification: +there are some half a dozen Mason submode classes.) So submode classes +can also ``group'' others together, and we can refer to the @code{mason} +class and mean all of them. + +The way a submode class is used is to @dfn{apply} it to a buffer. This +scans the buffer for regions which should be submode regions according +to that class, and also remembers the class for later, so that new +submode regions can be inserted and scanned for later. + + +@node Selecting Classes, Insertion, Submode Classes, Basics +@comment node-name, next, previous, up +@section How MMM Mode selects submode classes + +Submode classes that apply to a buffer come from three sources: +mode/extension-associated classes, file-local classes, and interactive +MMM-ification (@pxref{Interactive}). Whenever MMM Mode is turned on in a +buffer (@pxref{MMM Minor Mode}, and @ref{Global Mode}), it inspects the +value of two variables to determine which classes to automatically apply +to the buffer. This covers the first two sources; the latter is covered +in a later chapter. + +@menu +* File Classes:: Classes for a single file. +* Mode-Ext Classes:: Classes for a given mode or extension. +* Global Classes:: Classes for all MMM Mode buffers. +@end menu + + +@node File Classes, Mode-Ext Classes, Selecting Classes, Selecting Classes +@comment node-name, next, previous, up +@subsection File-Local Submode Classes + +@defvar mmm-classes +This variable is always buffer-local when set. Its value should be +either a single symbol or a list of symbols. Each symbol represents a +submode class that is applied to the buffer. +@end defvar + +@code{mmm-classes} is usually set in a file local variables list. +@xref{File Variables, , , emacs, The Emacs Manual}. The easiest way to +do this is for the first line of the file to contain the string +@samp{-*- mmm-classes: @var{classes} -*-}, where @var{classes} is the +desired value of @code{mmm-classes} for the file in question. It can +also be done with a local variables list at the end of the file. + + +@node Mode-Ext Classes, Global Classes, File Classes, Selecting Classes +@comment node-name, next, previous, up +@subsection Submode Classes Associated with Modes and Extensions + +@defopt mmm-mode-ext-classes-alist +This global variable associates certain submode classes with major modes +and/or file extensions. Its value is a list of elements of the form +@code{(@var{mode} @var{ext} @var{class})}. Any buffer whose major mode +is @var{mode} (a symbol) @emph{and} whose file name matches @var{ext} (a +regular expression) will automatically have the submode class +@var{class} applied to it. + +If @var{mode} is @code{nil}, then only @var{ext} is considered to +determine if a buffer fits the criteria, and vice versa. Thus if both +@var{mode} and @var{ext} are nil, then @var{class} is applied to +@emph{all} buffers in which MMM Mode is on. Note that @var{ext} can be +any regular expression, although its name indicates that it most often +refers to the file extension. + +If @var{class} is the symbol @code{t}, then no submode class is actually +applied for this association. However, if @code{mmm-global-mode} is +non-@code{nil} and non-@code{t}, MMM Mode will be turned on in matching +buffers even if there are no actual submode classes being applied. +@xref{Global Mode}. +@end defopt + +@defun mmm-add-mode-ext-class @var{mode} @var{ext} @var{class} +This function adds an element to @code{mmm-mode-ext-classes-alist}, +associating the submode class @var{class} with the major mode @var{mode} +and extension @var{ext}. + +Older versions of MMM Mode required this function to be used to control +the value of @code{mmm-mode-ext-classes-alist}, rather than setting it +directly. In this version it is provided purely for convenience and +backward compatibility. +@end defun + + +@node Global Classes, , Mode-Ext Classes, Selecting Classes +@comment node-name, next, previous, up +@subsection Globally Applied Classes and the Universal Class + +In addition to file-local and mode-ext-associated submode classes, MMM +Mode also allows you to specify that certain submode classes apply to +@emph{all} buffers in which MMM Mode is enabled. + +@defopt mmm-global-classes +This variable's value should be a list of submode classes that apply to +all buffers with MMM Mode on. It can be overriden in a file local +variables list, such as to disable global class for a specific file. +Its default value is @code{(universal)}. +@end defopt + +The default global class is the ``universal class'', which is defined in +the file @file{mmm-univ.el} (loaded automatically), and allows the +author of text to specify that a certain section of it be in a specific +major mode. Thus, for example, when writing an email message that +includes sample code, the author can allow readers of the message (who +use emacs and MMM) to view the code in the appropriate major mode. The +syntax used is @samp{@{%@var{mode}%@} ... @{%/@var{mode}%@}}, where +@var{mode} should be the name of the major mode, with or without the +customary @samp{-mode} suffix: for example, both @samp{cperl} and +@samp{cperl-mode} are acceptable. + +The universal class also defines an insertion key, @samp{/}, which +prompts for the submode to use. @xref{Insertion}. The universal class +is most useful when @code{mmm-global-mode} is set to @code{t}; +@ref{Global Mode}. + + +@node Insertion, Re-parsing, Selecting Classes, Basics +@comment node-name, next, previous, up +@section Inserting new submode regions + +So much for noticing submode regions already present when you open a +file. When editing a file with MMM Mode on, you will often want to add a +new submode region. MMM Mode provides several facilities to help you. +The simplest is to just hit a few keys and have the region and its +delimiters inserted for you. + +Each submode class can define an association of keystrokes with +``skeletons'' to insert a submode region. If there are several submode +classes enabled in a buffer, it is conceivable that the keys they use +for insertion might conflict, but unlikely as most buffers will not use +more than one or two submode classes groups. + +As an example of how insertion works, consider the Mason classes. In a +buffer with MMM Mode enabled and Mason associated, the key sequence +@kbd{C-c % p} inserts the following perl section (the semicolon is to +prevent CPerl Mode from getting confused---@pxref{Mason}): + +@example +<%perl>-<-; +-!- +->-</%perl> +@end example + +In this schematic representation, the string @samp{-!-} represents the +position of point (the cursor), @samp{-<-} represents the beginning of +the submode region, and @samp{->-} its end. + +All insertion keys come after the MMM Mode prefix keys (by default +@kbd{C-c %}; @pxref{Key Bindings}) and are by default single characters +such as @kbd{p}, @kbd{%}, and @kbd{i}. To avoid confusion, all the MMM +Mode commands are bound by default to control characters (after the same +prefix keys), such as @kbd{C-b}, @kbd{C-%} and @kbd{C-r}. This is a +change from earlier versions of MMM Mode, and can be customized; see +@ref{Key Bindings}. + +To find out what insertion keys are available, consult the documentation +for the submode class you are using. If it is one of the classes +supplied with MMM Mode, you can find it in this Info file. + +Because insertion keys are implemented with a ``default binding'' for +flexibility, they do not show up in the output of @kbd{C-h m} and cannot +be found with @kbd{C-h k}. For this reason, MMM Mode supplies the +command @kbd{C-c % h} (@code{mmm-insertion-help} to view the available +insertion keys. + + +@node Re-parsing, Interactive, Insertion, Basics +@comment node-name, next, previous, up +@section Re-Parsing Submode Regions +@cindex re-parsing submode regions +@cindex parsing submode regions +@cindex submode regions, re-parsing +@cindex regions, submode, re-parsing +@cindex submode regions, clearing +@cindex clearing submode regions +@cindex regions, submode, clearing +@kindex C-c % C-b +@kindex C-c % C-g +@kindex C-c % C-% +@kindex C-c % C-5 +@kindex C-c % C-k + +Describe @code{mmm-parse-buffer}, @code{mmm-parse-region}, +@code{mmm-parse-block}, and @code{mmm-clear-current-region}. + +@node Interactive, Global Mode, Re-parsing, Basics +@comment node-name, next, previous, up +@section Interactive MMM-ification Functions +@cindex interactive mmm-ification +@cindex mmm-ification, interactive +@cindex mmm-ification by region +@cindex mmm-ification by regexp +@cindex mmm-ification by class +@cindex region, mmm-ification by +@cindex regexp, mmm-ification by +@cindex class, mmm-ification by +@kindex C-c % C-r +@kindex C-c % C-c +@kindex C-c % C-x +@cindex mmm-ification, interactive history +@cindex history of interactive mmm-ification +@cindex interactive mmm-ification, history of + +There are several commands you can use to create submode regions +interactively, rather than by applying a submode class to a buffer. +These commands (in particular, @code{mmm-ify-region}), can be useful +when editing a file or email message containing a snippet of code in +some other language. Also see @ref{Global Classes}, for an alternate +approach to the same problem. + +@table @kbd +@item C-c % C-r +Creates a submode region between point and mark. Prompts for the submode +to use, which must be a valid Emacs major mode name, such as +@code{emacs-lisp-mode} or @code{cperl-mode}. Adds markers to the +interactive history. (@code{mmm-ify-region}) + +@item C-c % C-c +Applies an already-defined submode class to the buffer, which it prompts +for. Adds this class to the interactive history. +(@code{mmm-ify-by-class}) + +@item C-c % C-x +Scans the buffer for submode regions (prompts for the submode) using +front and back regular expressions that it also prompts for. Briefly, it +starts at the beginning of the buffer and searches for the front regexp. +If it finds a match, it searches for the back regexp. If it finds a +match for that as well, it makes a submode region between the two +matches and continues searching until no more matches are found. Adds +the regexps to the interactive history. (@code{mmm-ify-by-regexp}) + +@end table + +These commands are also useful when designing a new submode class +(@pxref{Submode Classes}). Working with the regexps interactively can +make it easier to debug and tune the class before starting to use it on +automatic. All these commands also add to value of the following +variable. + +@defvar mmm-interactive-history +Stores a history of all interactive mmm-ification that has been +performed in the current buffer. This way, for example, the re-parsing +functions (@pxref{Re-parsing}) will respect interactively added regions, +and the insertion keys for classes that were added interactively are +available. +@end defvar + +If for any reason you want to ``wipe the slate clean'', this command +should help you. By default, it has no key binding, so you must invoke +it with @kbd{M-x mmm-clear-history @key{RET}}. + +@deffn Command mmm-clear-history +Clears all history of interactive mmm-ification in the current buffer. +This command does not affect existing submode regions; to remove them, +you may want to re-parse the buffer with @kbd{C-c % C-b} +(@code{mmm-parse-buffer}). +@end deffn + + +@node Global Mode, , Interactive, Basics +@comment node-name, next, previous, up +@section MMM Global Mode +@cindex mode, mmm global +@cindex global mmm mode +@cindex mmm global mode +@vindex mmm-never-modes + +When a file has associated submode classes (@pxref{Selecting Classes}), +you may want MMM Mode to turn itself on and parse that file for submode +regions automatically whenever it is opened in an Emacs buffer. The +value of the following variable controls when MMM Mode turns itself on +automatically. + +@defopt mmm-global-mode +Do not be misled by the fact that this variable's name ends in +@samp{-mode}: it is not a simple on/off switch. There are three possible +(meanings of) values for it: @code{t}, @code{nil}, and anything else. + +When this variable is @code{nil}, MMM Mode is never enabled +automatically. If it is enabled manually, such as by typing @kbd{M-x +mmm-mode}, any submode classes associated with the buffer will still be +used, however. + +When this variable is @code{t}, MMM Mode is enabled automatically in +@emph{all} buffers, including those not visiting files, except those +whose major mode is an element of @code{mmm-never-modes}. The default +value of this variable contains modes such as @code{help-mode} and +@code{dired-mode} in which most users would never want MMM Mode, and +in which MMM might cause problems. + +When this variable is neither @code{nil} nor @code{t}, MMM Mode is +enabled automatically in all buffers that would have associated submode +classes; i.e. only if there would be something for it to do. The value +of @code{mmm-never-modes} is still respected, however. Note that this +can include buffers not visiting files, if that buffer's major mode is +present in @code{mmm-mode-ext-classes-alist} with a @code{nil} value for +@var{ext} (@pxref{Mode-Ext Classes}). Submode class values of @code{t} +in @code{mmm-mode-ext-classes-alist} cause MMM Mode to be enabled in +matching buffers, but supply no submode classes to be applied. +@end defopt + +@menu +* Major Mode Hook:: Using MMM's Major Mode Hook +@end menu + + +@node Major Mode Hook, , Global Mode, Global Mode +@comment node-name, next, previous, up +@subsection The Major Mode Hook +@cindex hook, major mode +@cindex major mode hook +@vindex mmm-major-mode-hook + +This section is intended for users who understand Emacs Lisp and want to +know how MMM Global Mode is implemented, and perhaps use the same +technique. In fact, MMM Mode exports a hook variable that you can use +easily, without understanding any of the details---see below. + +In order to enable itself in @emph{all} buffers, however, MMM Mode has +to hook itself into all major modes. Global Font Lock Mode from the +standard Emacs distribution (@pxref{Font Lock, , , emacs, The Emacs +Manual}) has a similar problem, and solves it by adding a function to +@code{change-major-mode-hook}, which is run by +@code{kill-all-local-variables}, which is run in turn by all major mode +functions at the @emph{beginning}. This function stores a list of which +buffers need fontification. It then adds a different function to +@code{post-command-hook}, which checks if the current buffer needs +fontification, and if so performs it. MMM Global Mode uses the same +technique. + +In the interests of generality, and for your use, the function that MMM +Mode runs in @code{post-command-hook} (@code{mmm-run-major-mode-hook}) +is not specific to MMM Mode, but rather runs the hook variable +@code{mmm-major-mode-hook}, which by default contains a function +(@code{mmm-mode-on-maybe}) which possibly turns MMM Mode on, depending +on the value of @code{mmm-global-mode}. Thus, to run another function +in all major modes, all you need to do is add it to this hook. For +example, the following line in an initialization file will turn on Auto +Fill Mode (@pxref{Auto Fill, , , emacs, The Emacs Manual}) in all +buffers: + +@lisp +(add-hook 'mmm-major-mode-hook 'turn-on-auto-fill) +@end lisp + +@node Customizing, Supplied Classes, Basics, Top +@comment node-name, next, previous, up +@chapter Customizing MMM Mode + +This chapter explains how to customize the appearance and functioning of +MMM Mode however you want. + +@menu +* Region Coloring:: Changing or removing background colors. +* Preferred Modes:: Choosing which major modes to use. +* Mode Line:: What is displayed in the mode line. +* Key Bindings:: Customizing the MMM Mode key bindings. +* Local Variables:: What local variables are saved for submodes. +* Changing Classes:: Changing the supplied submode classes. +* Hooks:: How to make MMM Mode run your code. +@end menu + +@node Region Coloring, Preferred Modes, Customizing, Customizing +@comment node-name, next, previous, up +@section Customizing Region Coloring +@cindex faces, submode +@cindex submode faces +@cindex customizing submode faces +@cindex default submode face + +By default, MMM Mode highlights all submode regions with a background +color. There are three levels of this decoration, controlled by the +following variable: + +@defopt mmm-submode-decoration-level +This variable controls the level of coloring of submode regions. It +should be one of the integers 0, 1, or 2, representing (respectively) +none, low, and high coloring. +@end defopt + +No coloring means exactly that. Submode regions have the same +background as the rest of the text. This produces the minimal +interference with font-lock coloration. In particular, if you want to +use background colors for font-lock, this may be a good idea, because +the submode highlight, if present, overrides any font-lock background +coloring. + +Low coloring uses the same background color for all submode regions. +This color is specified with the face @code{mmm-default-submode-face} +(@pxref{Faces, , , emacs, The Emacs Manual}) which can be customized, +either through the Emacs ``customize'' interface or using direct Lisp +commands such as @code{set-face-background}. Of course, other aspects +of the face can also be set, such as the foreground color, bold, +underline, etc. These are more likely to conflict with font-lock, +however, so only a background color is recommended. + +High coloring uses multiple background colors, depending on the function +of the submode region. The recognized functions and their meanings are +as follows: + +@table @samp +@item init +Code that is executed at the beginning of (something), as initialization +of some sort. + +@item cleanup +Code that is executed at the end of (something), as some sort of clean +up facility. + +@item declaration +Code that provides declarations of some sort, perhaps global or local +arguments, variables, or methods. + +@item comment +Text that is not executed as code, but instead serves to document the +code around it. Submode regions of this function often use a mode such +as Text Mode rather than a programming language mode. + +@item output +An expression that is evaluated and its value interpolated into the +output produced. + +@item code +Executed code not falling under any other category. + +@item special +Submode regions not falling under any other category, such as component +calls. + +@end table + +The different background colors are provided by the faces +@code{mmm-@var{function}-submode-face}, which can be customized in the +same way as @code{mmm-default-submode-face}. + + +@node Preferred Modes, Mode Line, Region Coloring, Customizing +@comment node-name, next, previous, up +@section Preferred Major Modes + +Certain of the supplied submode classes know only the language that +certain sections are written in, but not what major mode you prefer to +use to edit such code. For example, many people prefer CPerl mode over +Perl mode; you may have a special mode for Javascript or just use C++ +mode. This variable allows you to tell submodes such as Mason +(@pxref{Mason}) and Embedded Javascript (@pxref{Javascript}) what major +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} +should be the name of a major mode such as @code{perl-mode}, +@code{cperl-mode}, @code{javascript-mode}, or @code{c++-mode}. + +You probably won't have to set this variable at all; MMM tries to make +intelligent guesses about what modes you prefer. For example, if a +function called @code{javascript-mode} exists, it is chosen, otherwise +@code{c++-mode} is used. Similarly for @code{jde-mode} and +@code{java-mode}. +@end defopt + +If you do need to change the defaults, you may find the following +function convenient. + +@defun mmm-set-major-mode-preferences @var{language} @var{mode} &optional @var{default} +Set the preferred major mode for LANGUAGE to MODE. If there is already +a mode specified for LANGUAGE, and DEFAULT is nil or unsupplied, then it +is changed. If DEFAULT is non-nil, then any existing mode is unchanged. +This is used by packages to ensure that some mode is present, but not +override any user-specified mode. If you are not writing a submode +class, you should ignore the third argument. +@end defun + +Thus, for example, to use @code{my-java-mode} for Java code, you would +use the following line: + +@lisp +(mmm-set-major-mode-preferences 'java 'my-java-mode) +@end lisp + + +@node Mode Line, Key Bindings, Preferred Modes, Customizing +@comment node-name, next, previous, up +@section Customizing the Mode Line Display + +By default, when in a submode region, MMM Mode changes the section of +the mode line (@pxref{Mode Line, , , emacs, The Emacs Manual}) that +normally displays the major mode name---for example, @samp{HTML}---to +instead show both the dominant major mode and the currently active +submode---for example, @samp{HTML[CPerl]}. You can change this format, +however. + +@defopt mmm-submode-mode-line-format +The value of this variable should be a string containing one or both of +the escape sequences @samp{~M} and @samp{~m}. The string displayed in +the major mode section of the mode line when in a submode is obtained by +replacing all occurrences of @samp{~M} with the dominant major mode name +and @samp{~m} with the currently active submode name. For example, to +display only the currently active submode, set this variable to +@samp{~m}. The default value is @samp{~M[~m]}. +@end defopt + +The MMM minor mode also normally displays the string @samp{MMM} in the +minor mode section of the mode line to indicate when it is active. You +can customize or disable this as well. + +@defopt mmm-mode-string +This string is displayed in the minor mode section of the mode line when +the MMM minor mode is active. If nonempty, it should begin with a space +to separate the MMM indicator from that of other minor modes. To +eliminate the indicator entirely, set this variable to the empty string. +@end defopt + + +@node Key Bindings, Local Variables, Mode Line, Customizing +@comment node-name, next, previous, up +@section Customizing the MMM Mode Key Bindings + +The default MMM Mode key bindings are explained in @ref{MMM Mode Keys}, +and in @ref{Insertion}. There are a couple of ways to customize these +bindings. + +@defopt mmm-mode-prefix-key +The value of this variable (default is @kbd{C-c %}) should be a key +sequence to use as the prefix for the MMM Mode keymap. Minor modes +typically use @kbd{C-c} followed by a punctuation character, but you can +change it to any user-available key sequence. To have an effect, this +variable should be set before MMM Mode is loaded. +@end defopt + +@defopt mmm-use-old-command-keys +When this variable is @code{nil}, MMM Mode commands use the control +modifier and insertion keys no modifier. Any other value switches the +two, so that @code{mmm-parse-buffer}, for example, is bound to @kbd{C-c +% b}, while perl-section insertion in the Mason class is bound to +@kbd{C-c % C-p}. This variable should be set before MMM Mode is loaded +to have an effect. +@end defopt + +When MMM is loaded, it uses the value of @code{mmm-use-old-command-keys} +to set the values of the variables @code{mmm-command-modifiers} and +@code{mmm-insert-modifiers}, so if you prefer you can set these +variables instead. They should each be a list of key modifiers, such as +@code{(control)} or @code{()}. The Meta modifier is used in some of the +command and insertion keys, so it should not be used, and the Shift +modifier is not particularly portable between Emacsen---if it works for +you, feel free to use it. Other modifiers, such as Hyper and Super, are +not universally available, but are valid when present. + + +@node Local Variables, Changing Classes, Key Bindings, Customizing +@comment node-name, next, previous, up +@section Changing Saved Local Variables + +A lot of the functionality of MMM Mode---that which makes the major mode +appear to change---is implemented by saving and restoring the values of +local variables, or pseudo-variables. You can customize what variables +are saved, and how, with the following variable. + +@defvar mmm-save-local-variables +At its simplest, this is a list each of whose elements is a buffer-local +variable whose value is saved and restored for each major mode. Each +elements can also, however, be a list whose first element is the +variable symbol and whose subsequent elements specify how and where the +variable is to be saved. The second element of the list, if present, +should be one of the symbols @code{global}, @code{buffer}, or +@code{region}. If not present, the default value is @code{global}. The +third element, if present, should be a list of major mode symbols in +which to save the variable. In the list form, the variable symbol +itself can be replaced with a cons cell of two functions, one to get the +value and one to set the value. This is called a ``pseudo-variable''. +@end defvar + +Globally saved variables are the same in all (MMM-controlled) buffers +and submode regions of each major mode listed in the third argument, or +all major modes if it is @code{t} or not present. Buffer-saved +variables are the same in all submode regions of a given major mode in +each buffer, and region-saved variables can be different for each +submode region. + +Pseudo-variables are used, for example, to save and restore the syntax +table (@pxref{Syntax, , , emacs, The Emacs Manual}) and mode keymaps +(@pxref{Keymaps, , , emacs, The Emacs Manual}). + + +@node Changing Classes, Hooks, Local Variables, Customizing +@comment node-name, next, previous, up +@section Changing the Supplied Submode Classes + +If you need to use MMM with a syntax for which a submode class is not +supplied, and you have some facility with Emacs Lisp, you can write your +own; see @ref{Writing Classes}. However, sometimes you will only want +to make a slight change to one of the supplied submode classes. You can +do this, after that class is loaded, with the following functions. + +@defun mmm-set-class-parameter @var{class} @var{param} @var{value} +Set the value of the keyword parameter @var{param} of the submode class +@var{class} to @var{value}. @xref{Writing Classes}, for an explanation +of the meaning of each keyword parameter. This creates a new parameter +if one is not already present in the class. +@end defun + +@defun mmm-get-class-parameter @var{class} @var{param} +Get the value of the keyword parameter @var{param} for the submode class +@var{class}. Returns @code{nil} if there is no such parameter. +@end defun + + + +@node Hooks, , Changing Classes, Customizing +@comment node-name, next, previous, up +@section Hooks Provided by MMM Mode + +MMM Mode defines several hook variables (@pxref{Hooks, , , emacs, The +Emacs Manual}) which are run at different times. The most often used is +@code{mmm-major-mode-hook} which is described in @ref{Major Mode Hook}, +but there are a couple others. + +@defvar mmm-mode-hook +This normal hook is run whenever MMM Mode is enabled in a buffer. +@end defvar + +@defvar mmm-@var{major-mode}-hook +This is actually a whole set of hook variables, a different one for +every major mode. Whenever MMM Mode is enabled in a buffer, the +corresponding hook variable for the dominant major mode is run. +@end defvar + +@defvar mmm-@var{submode}-submode-hook +Again, this is a set of one hook variable per major mode. These hooks +are run whenever a submode region of the corresponding major mode is +created in any buffer, with point at the start of the new submode +region. +@end defvar + +@defvar mmm-@var{class}-class-hook +This is a set of one hook variable per submode class. These hooks are +run when a submode class is first applied to a given buffer. +@end defvar + +Submode classes also have a @code{:creation-hook} parameter which should +be a function to run whenever a submode region is created with that +class, with point at the beginning of the submode region. This can be +set for supplied submode classes with @code{mmm-set-class-parameter}; +@ref{Changing Classes}. + + +@node Supplied Classes, Writing Classes, Customizing, Top +@comment node-name, next, previous, up +@chapter Supplied Submode Classes + +This chapter describes the submode classes that are supplied with MMM +Mode. + +@menu +* Mason:: Mason server-side Perl in HTML. +* File Variables:: Elisp code in File Variables. +* Here-documents:: Code in shell and Perl here-documents. +* Javascript:: Javascript embedded in HTML. +* Embedded CSS:: CSS Styles embedded in HTML. +* Embperl:: Another syntax for Perl in HTML. +* ePerl:: A general Perl-embedding syntax. +* JSP:: Java code embedded in HTML. +* RPM:: Shell scripts in RPM Spec Files. +@end menu + +@node Mason, File Variables, Supplied Classes, Supplied Classes +@comment node-name, next, previous, up +@section Mason: Perl in HTML + +Mason is a syntax to embed Perl code in HTML and other documents. See +@uref{http://www.masonhq.com} for more information. The submode class +for Mason components is called `mason' and is loaded on demand from +`mmm-mason.el'. The current Mason class is intended to correctly +recognize all syntax valid in Mason @value{MASON_VERSION}. There are +insertion keys for most of the available syntax; use +@code{mmm-insertion-help} (@kbd{C-c % h} by default) with Mason on to +get a list. + +If you want to have mason submodes automatically in all Mason files, you +can use automatic mode and filename associations; the details depend on +what you call your Mason components and what major mode you use. +@xref{Mode-Ext Classes}. If you use an extension for your Mason files +that emacs does not automatically place in your preferred HTML Mode, you +will probably want to associate that extension with your HTML Mode as +well; @ref{Choosing Modes, , , emacs, The Emacs Manual}. This also goes +for ``special'' Mason files such as autohandlers and dhandlers. + +The Perl mode used is controlled by the user: @xref{Preferred Modes}. +The default is to use CPerl mode, if present. Unfortunately, there are +also certain problems with CPerl mode in submode regions. (Not to say +that the original perl-mode would do any better---it hasn't been much +tried.) First of all, the first line of a Perl section is usually +indented as if it were a continuation line. A fix for this is to start +with a semicolon on the first line. The insertion key commands do this +whenever the Mason syntax allows it. + +@example +<%perl>; +print $var; +</%perl> +@end example + +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. + +@lisp +(delete '("\\.html$" . sgml-html-mode) auto-mode-alist) +(delete '("\\.shtml$" . sgml-html-mode) auto-mode-alist) +@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. + +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 +caused me any problems), Mason components often are not a complete SGML +document. For instance, my autohandlers often say + +@example +<body> + <% $m->call_next %> +</body> +@end example + +in which case the actual components contain no doctype declaration, +@code{<html>}, @code{<head>}, or @code{<body>}, confusing PSGML. One +solution I've found is to use the variable @code{sgml-parent-document} +in such incomplete components; try, for example, these lines at the end +of a component. + +@example +%# Local Variables: +%# sgml-parent-document: ("autohandler" "body" nil ("body")) +%# sgml-doctype: "/top/level/autohandler" +%# End: +@end example + +This tells PSGML that the current file is a sub-document of the file +@file{autohandler} and is included inside a @code{<body>} tag, thus +alleviating its confusion. + + +@node File Variables, Here-documents, Mason, Supplied Classes +@comment node-name, next, previous, up +@section Elisp in a Local Variables List + +Emacs allows the author of a file to specify major and minor modes to be +used while editing that file, as well as specifying values for other +local Elisp variables, with a File Variables list. @xref{File +Variables, , , emacs, The Emacs Manual}. Since file variables values +are Elisp objects (and with the @code{eval} special ``variable'', they +are forms to be evaluated), one might want to edit them in +@code{emacs-lisp-mode}. The submode class @code{file-variables} allows +this, and is suitable for turning on in a given file with +@code{mmm-classes}, or in all files with @code{mmm-global-classes}. + + +@node Here-documents, Javascript, File Variables, Supplied Classes +@comment node-name, next, previous, up +@section Here-documents + +One of the long-time standard syntaxes for outputting large amounts of +code (or text, or HTML, or whatever) from a script (notably shell +scripts and Perl scripts) is the here-document syntax: + +@example +print <<END_HTML; +<html> + <head> + <title>Test Page</title> + </head> + <body> +END_HTML +@end example + +The @code{here-doc} submode class recognizes this syntax, and can even +guess the correct submode to use in many cases. For instance, it would +put the above example in @code{html-mode}, noticing the string +@samp{HTML} in the name of the here-document. If you use less than +evocative here-document names, or if the submode is recognized +incorrectly for any other reason, you can tell it explicitly what +submode to use. + +@defopt mmm-here-doc-mode-alist +The value of this variable should be an alist, each element a cons pair +associating a regular expression to a submode symbol. Whenever a +here-document name matches one of these regexps, the corresponding +submode is applied. For example, if this variable contains the element +@code{("CODE" . cc-mode)}, then any here-document whose name contains +the string @samp{CODE} will be put in @code{cc-mode}. The value of this +variable overrides any guessing that the @code{here-doc} submode class +would do otherwise. +@end defopt + + +@node Javascript, Embedded CSS, Here-documents, Supplied Classes +@comment node-name, next, previous, up +@section Javascript in HTML + +The submode class @code{html-js} allows for embedding Javascript code in +HTML documents. It recognizes both this syntax: + +@example +<script language="Javascript"> +function foo(...) @{ + ... +@} +</script> +@end example + +and this syntax: + +@example +<input type="button" onClick="validate();"> +@end example + +The mode used for Javascript regions is controlled by the user; +@xref{Preferred Modes}. + + +@node Embedded CSS, Embperl, Javascript, Supplied Classes +@comment node-name, next, previous, up +@section CSS embedded in HTML + +CSS (Cascading Style Sheets) can also be embedded in HTML. The +@code{embedded-css} submode class recognizes this syntax: + +@example +<style> +h1 @{ + ... +@} +</style> +@end example + +It uses @code{css-mode} if present, @code{c++-mode} otherwise. This can +be customized: @xref{Preferred Modes}. + + +@node Embperl, ePerl, Embedded CSS, Supplied Classes +@comment node-name, next, previous, up +@section Embperl: More Perl in HTML + +Embperl is another syntax for embedding Perl in HTML. See +@uref{http://perl.apache.org/embperl} for more information. The +@code{embperl} submode class recognizes most if not all of the Embperl +embedding syntax. Its Perl mode is also controllable by the user; +@xref{Preferred Modes}. + + +@node ePerl, JSP, Embperl, Supplied Classes +@comment node-name, next, previous, up +@section ePerl: General Perl Embedding + +Yet another syntax for embedding Perl is called ePerl. See +@uref{http://www.engelschall.com/sw/eperl/} for more information. The +@code{eperl} submode class handles this syntax, using the Perl mode +specified by the user; @xref{Preferred Modes}. + + +@node JSP, RPM, ePerl, Supplied Classes +@comment node-name, next, previous, up +@section JSP: Java Embedded in HTML + +JSP (Java Server Pages) is a syntax for embedding Java code in HTML. +The submode class @code{jsp} handles this syntax, using a Java mode +specified by the user; @xref{Preferred Modes}. The default is +@code{jde-mode} if present, otherwise @code{java-mode}. + + +@node RPM, , JSP, Supplied Classes +@comment node-name, next, previous, up +@section RPM Spec Files + +@file{mmm-rpm.el} contains the definition of an MMM Mode submode class +for editing shell script sections within RPM (Redhat Package Manager) +spec files. It is recommended for use in combination with +@file{rpm-spec-mode.el} by Stig Bjørlykke <stigb@@tihlde.hist.no> and +Steve Sanbeg <sanbeg@@dset.com> +(@uref{http://www.xemacs.org/~stigb/rpm-spec-mode.el}). + +Suggested setup code: + +@lisp +(add-to-list 'mmm-mode-ext-classes-alist + '(rpm-spec-mode "\\.spec\\'" rpm-sh)) +@end lisp + +Thanks to Marcus Harnisch <Marcus.Harnisch@@gmx.net> for contributing +this submode class. + + +@node Writing Classes, Indices, Supplied Classes, Top +@comment node-name, next, previous, up +@chapter Writing Submode Classes + +Sometimes (perhaps often) you may want to use MMM with a syntax for +which it is suited, but for which no submode is supplied. In such cases +you may have to write your own submode class. This chapter briefly +describes how to write a submode class, from the basic to the advanced, +with examples. + +@menu +* Basic Classes:: Writing a simple submode class. +* Paired Delimiters:: Matching paired delimiters. +* Region Placement:: Placing the region more accurately. +* Submode Groups:: Grouping several classes together. +* Calculated Submodes:: Deciding the submode at run-time. +* Calculated Faces:: Deciding the display face at run-time. +* Insertion Commands:: Inserting regions automatically. +* Other Hooks:: Running code at arbitrary points. +* Delimiter Forms:: Storing the form of the delimiters. +* Misc Keywords:: Other miscellaneous options. +@end menu + +@node Basic Classes, Paired Delimiters, Writing Classes, Writing Classes +@comment node-name, next, previous, up +@section Writing Basic Submode Classes +@cindex simple submode classes +@cindex submode classes, simple + +Writing a submode class can become rather complex, if the syntax to +match is complicated and you want to take advantage of some of MMM +Mode's extra features. But a simple submode class is not particularly +difficult to write. This section describes the basics of writing +submode classes. + +Submode classes are stored in the variable @code{mmm-classes-alist}. +Each element of this list represents a single submode class. For +convenience, the function @code{mmm-add-classes} takes a list of submode +classes and adds them all to this alist. Each class is represented by a +list containing the class name---a symbol such as @code{mason} or +@code{html-js}---followed by pairs of keywords and arguments called a +@dfn{class specifier}. For example, consider the specifier for the +submode class @code{embedded-css}: + +@lisp +(mmm-add-classes + '((embedded-css + :submode css + :face mmm-declaration-submode-face + :front "<style[^>]*>" + :back "</style>"))) +@end lisp + +The name of the submode is @code{embedded-css}, the first element of the +list. The rest of the list consists of pairs of keywords (symbols +beginning with a colon) such as @code{:submode} and @code{:front}, and +arguments, such as @code{css} and @code{"<style[^>]*>"}. It is the +keywords and arguments that specify how the submode works. The order of +keywords is not important; all that matters is the arguments that follow +them. + +The three most important keywords are @code{:submode}, @code{:front}, +and @code{:back}. The argument following @code{:submode} names the +major mode to use in submode regions. It can be either a symbol naming +a major mode, such as @code{text-mode} or @code{c++-mode}, or a symbol +to look up in @code{mmm-major-mode-preferences} (@pxref{Preferred +Modes}) such as @code{css}, as in this case. + +The arguments following @code{:front} and @code{:back} are regular +expressions (@pxref{Regexps, , , emacs, The Emacs Manual}) that should +match the delimiter strings which begin and end the submode regions. In +our example, CSS regions begin with a @samp{<style>} tag, possibly with +parameters, and end with a @samp{</style>} tag. + +The argument following @code{:face} specifies the face (background +color) to use when @code{mmm-submode-decoration-level} is 2 (high +coloring). @xref{Region Coloring}, for a list of canonical available +faces. + +There are many more possible keywords arguments. In the following +sections, we will examine each of them and their uses in writing submode +classes. + + +@node Paired Delimiters, Region Placement, Basic Classes, Writing Classes +@comment node-name, next, previous, up +@section Matching Paired Delimiters + +A simple pair of regular expressions does not always suffice to exactly +specify the beginning and end of submode regions correctly. For this +reason, there are several other possible keyword/argument pairs which +influence the matching process. + +Many submode regions are marked by paired delimiters. For example, the +tags used by Mason (@pxref{Mason}) include @samp{<%init>...</%init>} and +@samp{<%args>...</%args>}. It would be possible to write a separate +submode class for each type of region, but there is an easier way: the +keyword argument @code{:save-matches}. If supplied and non-nil, it +causes the regular expression @code{:back}, before being searched for, +to be formatted by replacing all strings of the form @samp{~@var{N}} +(where @var{N} is an integer) with the corresponding numbered +subexpression of the match for @code{:front}. As an example, here is an +excerpt from the @code{here-doc} submode class. @xref{Here-documents}, +for more information about this submode. + +@lisp +:front "<<\\([a-zA-Z0-9_-]+\\)" +:back "^~1$" +:save-matches 1 +@end lisp + +The regular expression for @code{:front} matches @samp{<<} followed by a +string of one or more alphanumeric characters, underscores, and dashes. +The latter string, which happens to be the name of the here-document, is +saved as the first subexpression, since it is surrounded by +@samp{\(...\)}. Then, because the value of @code{:save-matches} is +present and non-nil, the string @samp{~1} is replaced in the value of +@code{:back} by the name of the here-document, thus creating a regular +expression to match the correct ending delimiter. + + +@node Region Placement, Submode Groups, Paired Delimiters, Writing Classes +@comment node-name, next, previous, up +@section Placing Submode Regions Precisely + +Normally, a submode region begins immediately after the end of the +string matching the @code{:front} regular expression and ends +immediately before the beginning of the string matching the @code{:back} +regular expression. This can be changed with the keywords +@code{:include-front} and @code{:include-back}. If their arguments are +@code{nil}, or they do not appear, the default behavior is unchanged. +But if the argument of @code{:include-front} (respectively, +@code{:include-back}) is non-nil, the submode region will begin +(respectively, end) immediately before (respectively, after) the string +matching the @code{:front} (respectively, @code{:back}) regular +expression. In other words, these keywords specify whether or not the +delimiter strings are @emph{included} in the submode region. + +When @code{:front} and @code{:back} are regexps, the delimiter is +normally considered to be the entire matched region. This can be +changed using the @code{:front-match} and @code{:back-match} +keywords. The values of the keywords is a number specifying the +submatch. This defaults to zero (specifying the whole regexp). + +Two more keywords which affect the placement of the region +@code{:front-offset} and @code{:back-offset}, which both take integers +as arguments. The argument of @code{:front-offset} (respectively, +@code{:back-offset}) gives the distance in characters from the beginning +(respectively, ending) location specified so far, to the actual point +where the submode region begins (respectively, ends). For example, if +@code{:include-front} is nil or unsupplied and @code{:front-offset} is +2, the submode region will begin two characters after the end of the +match for @code{:front}, and if @code{:include-back} is non-nil and +@code{:back-offset} is -1, the region will end one character before the +end of the match for @code{:back}. + +In addition to integers, the arguments of @code{:front-offset} and +@code{:back-offset} can be functions which are invoked to move the point +from the position specified by the matches and inclusions to the correct +beginning or end of the submode region, or lists whose elements are +either functions or numbers and whose effects are applied in sequence. +To help disentangle these options, here is another excerpt from the +@code{here-doc} submode class: + +@lisp +:front "<<\\([a-zA-Z0-9_-]+\\)" +:front-offset (end-of-line 1) +:back "^~1$" +:save-matches 1 +@end lisp + +Here the value of @code{:front-offset} is the list @code{(end-of-line +1)}, meaning that from the end of the match for @code{:front}, go to the +end of the line, and then one more character forward (thus to the +beginning of the next line), and begin the submode region there. This +coincides with the normal behavior of here-documents: they begin on the +following line and go until the ending flag. + +If the @code{:back} should not be able to start a new submode region, +set the @code{:end-not-begin} keyword to non-nil. + +@node Submode Groups, Calculated Submodes, Region Placement, Writing Classes +@comment node-name, next, previous, up +@section Defining Groups of Submodes + +Sometimes more than one submode class is required to accurately reflect +the behavior of a single type of syntax. For example, Mason has three +very different types of Perl regions: blocks bounded by matched tags +such as @samp{<%perl>...</%perl>}, inline output expressions bounded by +@samp{<%...%>}, and single lines of code which simply begin with a +@samp{%} character. In cases like these, it is possible to specify an +``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}. +@end defun + +Technically, an group class is specified with a @code{:classes} keyword +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. + + +@node Calculated Submodes, Calculated Faces, Submode Groups, Writing Classes +@comment node-name, next, previous, up +@section Calculating the Correct Submode + +In most cases, the author of a submode class will know in advance what +major mode to use, such as @code{text-mode} or @code{c++-mode}. If +there are multiple possible modes that the user might desire, then +@code{mmm-major-mode-preferences} should be used (@pxref{Preferred +Modes}). The function @code{mmm-set-major-mode-preferences} can be +used, with a third argument, to ensure than the mode is present. + +In some cases, however, the author has no way of knowing in advance even +what language the submode region will be in. The @code{here-doc} class +is one of these. In such cases, instead of the @code{:submode} keyword, +the @code{:match-submode} keyword must be used. Its argument should be +a function, probably written by the author of the submode class, which +calculates what major mode each region should use. + +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 +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 +not available---it should @code{(signal 'mmm-no-matching-submode nil)}. + +Since here-documents can contain code in any language, the +@code{here-doc} submode class uses @code{:match-submode} rather than +@code{:submode}. The function it uses is @code{mmm-here-doc-get-mode}, +defined in @file{mmm-sample.el}, which inspects the name of the +here-document for flags indicating the proper mode. For example, this +code should probably be in @code{perl-mode} (or @code{cperl-mode}): + +@example +print <<PERL; +s/foo/bar/g; +PERL +@end example + +This function is also a good example of proper elisp hygiene: when +writing accessory functions for a submode class, they should usually be +prefixed with @samp{mmm-} followed by the name of the submode class, to +avoid namespace conflicts. + + +@node Calculated Faces, Insertion Commands, Calculated Submodes, Writing Classes +@comment node-name, next, previous, up +@section Calculating the Correct Highlight Face + +As explained in @ref{Basic Classes}, the keyword @code{:face} should be +used to specify which of the standard submode faces (@pxref{Region +Coloring}) a submode region should be highlighted with under high +decoration. However, sometimes the function of a region can depend on +the form of the delimiters as well. In this case, a more flexible +alternative to @code{:face} is @code{:match-face}. Its value can be a +function, which is called with one argument---the form of the front +delimiter, as with @code{:match-submode}---and should return the face to +use. A more common value for @code{:match-face} is an association list, +a list of pairs @code{(@var{delim} . @var{face})}, each specifying that +if the delimiter is @var{delim}, the corresponding region should be +highlighted with @var{face}. For example, here is an excerpt from the +@code{embperl} submode class: + +@lisp +:submode perl +:front "\\[\\([-\\+!\\*\\$]\\)" +:back "~1\\]" +:save-matches 1 +:match-face (("[+" . mmm-output-submode-face) + ("[-" . mmm-code-submode-face) + ("[!" . mmm-init-submode-face) + ("[*" . mmm-code-submode-face) + ("[$" . mmm-special-submode-face)) +@end lisp + +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. + + +@node Insertion Commands, Other Hooks, Calculated Faces, Writing Classes +@comment node-name, next, previous, up +@section Specifying Insertion Commands + +As described in @ref{Insertion}, submode classes can specify key +sequences which automatically insert submode regions, with delimiters +already in place. This is done by the keyword argument @code{:insert}. +Its value should be a list, each element of which specifies a single +insertion key sequence. As an example, consider the following insertion +key sequence specifier, from the @code{embperl} submode class: + +@lisp +(?p embperl "Region Type (Character): " + @@ "[" str @@ " " _ " " @@ str "]" @@) +@end lisp + +As you can see, the specifier is a list. The first element of the list +is the character @samp{p}. (The question mark tells Emacs that this is +a character object, not a one-character symbol.) In general, the first +element can be any key, including both characters such as @samp{?p} and +function keys such as @samp{return}. It can also be a dotted pair in +which the first element is a modifier symbol such as @code{meta}, and +the second is a character or function key. The use of any other +modifier than meta is discouraged, as `mmm-insert-modifiers' is +sometimes set to \(control), and other modifiers are not very portable. +The second element is a symbol identifying this key sequence. The third +element is a prompt string which is used to ask the user for input when +this key sequence is invoked. If it is nil, the user is not prompted. + +The rest of the list specifies the actual text to be inserted, where the +submode region and delimiters should be, and where the point should end +up. (Actually, this string is simply passed to @code{skeleton-insert}; +see the documentation string of that function for more details on the +permissible elements of such a skeleton.) Strings and variable names +are inserted and interpolated. The value entered by the user when +prompted, if any, is available in the variable @code{str}. The final +location of the point (or the text around which the region is to be +wrapped) is marked with a single underscore @samp{_}. Finally, the +@@-signs mark the delimiters and submode regions. There should be four +@@-signs: one at the beginning of the front delimiter, one at the +beginning of the submode region, one at the end of the submode region, +and one at the end of the back delimiter. + +The above key sequence, bound by default to @kbd{C-c % p}, always +prompts the user for the type of region to insert. It can also be +convenient to have separate key sequences for each type of region to be +inserted, such as @kbd{C-c % +} for @samp{[+...+]} regions, @kbd{C-c % +-} for @samp{[-...-]} regions, and so on. So that the whole skeleton +doesn't have to be written out half a dozen times, there is a shortcut +syntax, as follows: + +@lisp +(?+ embperl+ ?p . "+") +@end lisp + +If the key sequence specification is a dotted list with four elements, +as this example is, it means to use the skeleton defined for the key +sequence given as the third element (@code{?p}), but to pass it the +fourth (dotted) element (@code{"+"}) as the `str' variable; the user is +not prompted. + + +@node Other Hooks, Delimiter Forms, Insertion Commands, Writing Classes +@comment node-name, next, previous, up +@section Other Hooks into the Scanning Process + +Sometimes, even the flexibility allowed by all the keyword arguments +discussed so far is insufficient to correctly match submode regions. +There are several other keyword arguments which accept custom functions +to be invoked at various points in the MMM-ification process. + +First of all, the arguments of @code{:front} and @code{:back}, in +addition to regular expressions, can be themselves functions. Such +functions should ``act like'' a regular expression search: they should +start searching at point, take one argument as a limit for the search, +and return its result by setting the match data (presumably by calling +some regexp matching function). + +This is rarely necessary, however, because often all that is needed is a +simple regexp search, followed by some sort of verification. The +keyword arguments @code{:front-verify} and @code{:back-verify}, if +supplied, may be functions which are invoked after a match is found for +@code{:front} or @code{:back}, respectively, and should inspect the +match data (such as with @code{match-string}) and return non-nil if a +submode region should be begun at this match, nil if this match should +be ignored and the search continue after it. + +The keyword argument @code{:creation-hook}, if supplied, should be a +function that is invoked whenever a submode region of this class is +created, with point at the beginning of the new region. This can be +used, for example, to set local variables appropriately. + +Finally, the entire MMM-ification process has a ``back door'' which +allows class authors to take control of the entire thing. If the +keyword argument @code{:handler} is supplied, it overrides any other +processing and is called, and passed all other class keyword arguments, +instead of @code{mmm-ify} to create submode regions. If you need to +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 +@comment node-name, next, previous, up +@section Controlling the Form of the Delimiters + +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. + +You can customize this with the keyword argument @code{:front-form} +(respectively, @code{:back-form}). If it is a string, it is used +verbatim for the front (respectively, back) form. If it is a function, +that function is called and should inspect the match data and return the +regular expression to use as the form. + +In addition, the form itself can be set to a function, by giving a +one-element list containing only that function as the argument to +@code{:front-form} or @code{:back-form}. Such a function should take +1-2 arguments. The first argument is the overlay to match the delimiter +for. If the second is non-nil, it means to insert the delimiter and +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 +@comment node-name, next, previous, up +@section Miscellaneous Other Keyword Arguments + +You can specify whether delimiter searches should be case-sensitive with +the keyword argument @code{:case-fold-search}. It defaults to @code{t}, +meaning that case should be ignored. See the documentation for the +variable @code{case-fold-search}. + +@node Indices, , Writing Classes, Top +@comment node-name, next, previous, up +@chapter Indices + +@menu +* Concept Index:: Index of MMM Mode Concepts. +* Function Index:: Index of functions and variables. +* Keystroke Index:: Index of key bindings in MMM Mode. +@end menu + +@node Concept Index, Function Index, Indices, Indices +@comment node-name, next, previous, up +@section Concept Index + +@printindex cp + + +@node Function Index, Keystroke Index, Concept Index, Indices +@comment node-name, next, previous, up +@section Function and Variable Index + +@printindex fn + + +@node Keystroke Index, , Function Index, Indices +@comment node-name, next, previous, up +@section Keystroke Index + +@printindex ky + + +@bye + +@c Local Variables: +@c mode: texinfo +@c mode: font-lock +@c mode: outline-minor +@c End: diff --git a/mmm/version.texi b/mmm/version.texi new file mode 100644 index 00000000..b62e6859 --- /dev/null +++ b/mmm/version.texi @@ -0,0 +1,3 @@ +@set UPDATED 18 February 2001 +@set EDITION 0.4.7 +@set VERSION 0.4.7 |