diff options
author | Alexander Zangerl <az@debian.org> | 2018-07-26 07:37:44 +0900 |
---|---|---|
committer | Alexander Zangerl <az@debian.org> | 2018-07-26 07:37:44 +0900 |
commit | f0f45902392df78582b78177e6e596521561bf5d (patch) | |
tree | 59b6b253f6cf49c4aa873b65fcc608534cec6818 |
Import mmm-mode_0.5.7.orig.tar.gz
[dgit import orig mmm-mode_0.5.7.orig.tar.gz]
-rw-r--r-- | .gitignore | 16 | ||||
-rw-r--r-- | AUTHORS | 16 | ||||
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | ChangeLog | 1071 | ||||
-rw-r--r-- | Checklist | 24 | ||||
-rw-r--r-- | FAQ | 192 | ||||
-rw-r--r-- | INSTALL | 182 | ||||
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | NEWS | 328 | ||||
-rw-r--r-- | README | 110 | ||||
-rw-r--r-- | README.Mason | 122 | ||||
-rw-r--r-- | TODO | 61 | ||||
-rw-r--r-- | acinclude.m4 | 165 | ||||
-rwxr-xr-x | autogen.sh | 28 | ||||
-rw-r--r-- | configure.in | 36 | ||||
-rwxr-xr-x | elisp-comp | 55 | ||||
-rwxr-xr-x | install-sh | 251 | ||||
-rwxr-xr-x | mdate-sh | 92 | ||||
-rwxr-xr-x | missing | 336 | ||||
-rwxr-xr-x | mkinstalldirs | 38 | ||||
-rw-r--r-- | mmm-auto.el | 178 | ||||
-rw-r--r-- | mmm-class.el | 335 | ||||
-rw-r--r-- | mmm-cmds.el | 443 | ||||
-rw-r--r-- | mmm-compat.el | 130 | ||||
-rw-r--r-- | mmm-cweb.el | 100 | ||||
-rw-r--r-- | mmm-defaults.el | 62 | ||||
-rw-r--r-- | mmm-erb.el | 243 | ||||
-rw-r--r-- | mmm-mason.el | 175 | ||||
-rw-r--r-- | mmm-mode.el | 309 | ||||
-rw-r--r-- | mmm-mode.spec | 40 | ||||
-rw-r--r-- | mmm-myghty.el | 187 | ||||
-rw-r--r-- | mmm-noweb.el | 421 | ||||
-rw-r--r-- | mmm-region.el | 923 | ||||
-rw-r--r-- | mmm-rpm.el | 80 | ||||
-rw-r--r-- | mmm-sample.el | 384 | ||||
-rw-r--r-- | mmm-univ.el | 64 | ||||
-rw-r--r-- | mmm-utils.el | 157 | ||||
-rw-r--r-- | mmm-vars.el | 1133 | ||||
-rw-r--r-- | mmm.texinfo | 2108 | ||||
-rw-r--r-- | tests/highlighting.el | 112 | ||||
-rw-r--r-- | tests/html-erb.el | 103 | ||||
-rw-r--r-- | texinfo.tex | 5484 |
42 files changed, 16650 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44d1bb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +autom4te.cache +aclocal.m4 +configure +config.log +config.status +Makefile +Makefile.in +elc-stamp +mmm.info* +*.elc +*.tar.gz +script +stamp-vti +version.texi +mmm-mode-pkg.el +mmm-mode-autoloads.el @@ -0,0 +1,16 @@ +MMM Mode was originally designed and written by Michael Shulman +<viritrilbia@gmail.com>. + +It was inspired by mmm.el for XEmacs by Gongquan Chen <chen@posc.org>. + +Recent contributors have included: + +bishop <bishop@platypus.bc.ca> +Joe Kelsey <joe@zircon.seattle.wa.us> +Alan Shutko <ats@acm.org> +Michael Alan Dorman <mdorman@users.sourceforge.net> +Brian P Templeton <plovre@users.sourceforge.net> +Yann Dirson <ydirson@fr.alcove.com> +Marcus Harnisch + +and others... @@ -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/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b507d79 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1071 @@ +NOTE: This file is not kept up-to-date anymore. + +2004-11-18 Alan Shutko <ats@acm.org> + + * mmm-myghty.el: New mode from Ben Bangert. + + * mmm-vars.el (mmm-major-mode-preferences): Added Python prefs, + also from Ben. + + * mmm-auto.el (mmm-autoloaded-classes): Merged Ben Bangert's + Myghty class. + +2004-06-16 Alan Shutko <ats@acm.org> + + * version.texi: Release 0.4.8. + + * mmm-vars.el: Release 0.4.8. + + * mmm-mode.el: Release 0.4.8. + + * mmm-noweb.el (mmm-syntax-region-list) + (mmm-syntax-other-regions, mmm-word-other-regions) + (mmm-space-other-regions, mmm-undo-syntax-other-regions): Added + from Joe's email. They're here right now, until a better place + can be found. + + * configure.in: Incr version for release. + +2004-06-10 Alan Shutko <ats@acm.org> + + * mmm-class.el (mmm-ify): Change defaults for front-delim and + back-delim to nil. 0 was breaking the no-delimiter case in + mmm-match-region. + +2004-06-02 Alan Shutko <ats@acm.org> + + * mmm-sample.el (html-js): Support JS version in language attribute. + +2004-06-01 Alan Shutko <ats@acm.org> + + * mmm-vars.el (mmm-save-local-variables): Updated cc-mode local + variables. + + * Makefile.am (lisp_LISP): Removed mmm-php.el, since it doesn't + appear to be in CVS. + + * missing: Updated for automake 1.7.9. + +2003-10-18 Alan Shutko <ats@acm.org> + + * mmm-vars.el (mmm-save-local-variables): Add semantic stuff and + c-syntactic-eol. + +2003-03-25 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-mode.spec: Added file for building SRPMs, from bishop + + * autogen.sh: Added file for building from CVS + +2003-03-22 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-sample.el (html-php): Added new submode class. + (eperl): Corrected, added comment detection. + + * mmm-cmds.el (mmm-insert-by-key): Added undo collapsing. + +2003-03-09 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-set-mode-line): Added support for "buffer mode" + display name. + + * mmm-cmds.el (mmm-insert-by-key): Match and calculate names, and + store front and back positions for delimiter overlays. + + * mmm-mason.el: Added match-name parameter. + + * mmm-sample.el: Added delimiter-mode and match-name parameters. + + * mmm-region.el: Restructured current-overlay functions. + (mmm-make-region, mmm-make-overlay, mmm-get-face): Create + delimiter overlays with modes and faces, add display-name and name + parameters, and handle evaporation intelligently. + (mmm-front-start, mmm-back-end, etc.): Use delimiter overlays. + (mmm-update-current-submode): Delete overlays whose front + delimiter has evaporated. + + * mmm-class.el (mmm-ify, mmm-match-region): Added matching for + region names. + + * mmm-vars.el (mmm-delimiter-mode, mmm-delimiter-face): Added. + +2003-03-08 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-region.el (mmm-clear-overlays): Fixed bug so turning mmm + mode off now restores primary mode correctly. + +2003-03-03 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-noweb.el (mmm-noweb-bind-keys): Implemented a "local to + submode class" keymap binding. + + * mmm-vars.el (mmm-set-mode-line): Used correct name for variable. + +2003-03-02 Michael A. Shulman <viritrilbia@gmail.com> + + * mmm-mode.el (mmm-mode): Removed ancient docstring, which had + references to long-deprecated and removed functions. The info + file is now the official user reference. + + * mmm-region.el (mmm-update-submode-region): Run hooks specified + by the region being entered, or the dominant if not. + + * mmm-vars.el (mmm-primary-mode-entry-hook): Added variable. + + * mmm-vars.el (mmm-subregion-invalid-placement): Renamed from + mmm-subregion-crosses-parents. + (mmm-primary-mode-display-name): Added variable. + (mmm-set-mode-line): Added function to allow display of specified + names outside regions. + + * mmm-region.el (mmm-valid-submode-region): Corrected algorithm, + improved documentation, renamed error. + +2003-02-05 Joe Kelsey <joe@zircon.seattle.wa.us> + + * mmm-vars.el (mmm-add-to-group): New function mmm-add-to-group + adds new private classes to an existing group. + + * mmm.texinfo (Noweb): Add documentation about noweb mode. + + * mmm-auto.el (mmm-autoloaded-classes): Add noweb to + autoloaded classes. + + * mmm-noweb.el: Modified chunk naming to give noweb-chunks + different names so that they will be indented independently. + + * mmm-sample.el: Make html-js look for language= or type= + attributes because you may have other script types. + +2003-01-30 Joe Kelsey <joe@zircon.seattle.wa.us> + + * Makefile.am: Add mmm-cweb.el, mmm-php.el and mmm-noweb.el + + * mmm-noweb.el: Add support for noweb. + + * mmm-class.el (mmm-ify, mmm-make-region): Add support for setting + the NAME property on regions. + + * mmm-cmds.el (mmm-insert-by-key): Add support for setting the + NAME property on inserts. + +2002-11-11 Alan Shutko <ats@acm.org> + + * .cvsignore: Add semantic.cache. + + * mmm-vars.el (mmm-save-local-variables): Update C variables to + save, based on Emacs CVS. + + * mmm-cweb.el (cweb): Tweaked indentation. Add cweb to the + +2001-05-16 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-mode.el (mmm-mode-on): Make style variables buffer-local. + Continue on all MMM errors. + + * mmm-vars.el (mmm-save-local-variables): Added all c-modes + indentation style variables. + + * mmm-auto.el, mmm-sample.el: + Added `sgml-dtd' submode class from Yann Dirson <ydirson@fr.alcove.com>. + +2001-05-15 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-auto.el: Added cweb to autoloaded classes. + +2001-05-14 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-region.el: Passed arguments to `signal'. + + * mmm-vars.el: Defined new submode placement error conditions. + +2001-05-14 Alan Shutko <ats@acm.org> + + * mmm-cweb.el: New file. + + * mmm-region.el (mmm-valid-submode-region): New function. + (mmm-make-region): Allow nested submodes and put the priority in + the overlay. + +2001-02-23 Michael Abraham Shulman <viritrilbia@gmail.com> + + * configure.in, mmm-mode.el, mmm-vars.el, version.texi: Released 0.4.7 + +2001-02-18 Alan Shutko <ats@acm.org> + + * mmm-vars.el (mmm-classes-alist): Document new keywords. + + * mmm.texinfo (Region Placement): Document the front-match, + back-match and end-not-begin keywords. + + * mmm-class.el (mmm-match-region, mmm-ify): Add front-match & + back-match keywords to specify which submatch to treat as the + delimiter. Add end-not-begin key. + (mmm-match->point): Add front-match and back-match args. + +2001-02-12 Alan Shutko <ats@acm.org> + + * mmm-mason.el (mmm-mason-end-line,mmm-mason-start-line): Use bolp + and eolp. + +2001-02-03 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-mode.el, mmm-region.el, mmm-vars.el: + Added `mmm-primary-mode' variable so that `major-mode' can be saved. + +2001-01-27 Alan Shutko <ats@acm.org> + + * mmm.texinfo: Added direntry for automated info installation. + +2001-01-26 Alan Shutko <ats@acm.org> + + * configure.in: Use elisp macros from w3 to check for emacs and + lisp dir. + + * aclocal.m4: Pulled elisp-related checks from the W3 library, so + --with-emacs= will work. + +2001-01-15 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-cmds.el (mmm-insert-by-key): + Use match-face and major-mode-preferences. + + * mmm-sample.el (mmm-here-doc-get-mode): + Try each word individually first. + + * mmm-utils.el (mmm-format-matches): + Removed reference to `count' variable. + + * mmm-sample.el, mmm-univ.el, mmm-utils.el: + Allowed language names for preference lookup as "mode names". + + * mmm-vars.el (mmm-set-major-mode-preferences): Added function. + +2001-01-14 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-class.el, mmm-utils.el (mmm-format-matches): + Changed to allow accessing any subexp, not + limited by a numerical value of save-matches. + +2001-01-13 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-sample.el, mmm-vars.el: Modified CSS to use preferred mode. + + * mmm-vars.el (mmm-save-local-variables): + Added syntax and indentation variables for + cc-mode and variants. + + * mmm-vars.el (mmm-major-mode-preferences): + Added check for `jde-mode' for Java code. + +2001-01-12 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-auto.el: Added ePerl and JSP to autoload. + +2001-01-11 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-sample.el: Added ePerl submode class. + + * mmm-mason.el, mmm-sample.el: + Modified classes to use preferred mode list. + + * mmm-vars.el, mmm-region.el: + Added alist to keep track of user-preferred major modes. + + * mmm-mason.el, mmm-rpm.el, mmm-sample.el: + Added flags telling which faces to use for which regions. + + * mmm-class.el, mmm-region.el, mmm-vars.el: + Added multiple faces and optional levels of decoration. + +2001-01-09 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-save-local-variables): + Added `parse-sexp-ignore-comments', which + seems to fix indentation in php-mode. + +2001-01-08 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-region.el (mmm-update-mode-info): + Hacked so `font-lock-keywords-alist' works. + +2001-01-05 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm.texinfo: Added set-background example for XEmacs. + Added info-dir-entry. + +2000-09-29 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-class.el (mmm-apply-class): + Rearranged parameters so faces actually work. + +2000-09-18 Michael Abraham Shulman <viritrilbia@gmail.com> + + * configure.in, mmm-vars.el, version.texi: Released 0.4.6 + +2000-09-17 Michael Abraham Shulman <viritrilbia@gmail.com> + + * FAQ: Added Q about name capitalization. + +2000-09-16 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-compat.el (mmm-keywords-used): Added `:private'. + +2000-09-12 Michael Abraham Shulman <viritrilbia@gmail.com> + + * FAQ: Added file + +2000-09-12 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Checklist: Added comment about adding files to the distribution. + + * README: Added comment about installing with multiple emacsen. + + * Makefile.am: Added FAQ + + * mmm-mode.el: Created Emacs Lisp Archive Entry + +2000-09-05 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm.texinfo: Set MASON_VERSION. + + * mmm-cmds.el (mmm-display-insertion-key): + Prevented (nthcdr -1 ...); breaks in XEmacs. + +2000-08-29 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-save-local-variables): Added abbrev-mode variables. + + * mmm-region.el (mmm-update-mode-info): + Tested against `mmm-set-file-name-for-modes'. + + * mmm-vars.el (mmm-set-file-name-for-modes): + Changed to a list for finer control. + +2000-08-24 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-region.el (mmm-make-region): + Explicitly set keyword defaults in &rest parameter. + + * mmm-class.el (mmm-ify): + Explicitly set defaults for keywords in &rest parameter. + +2000-08-23 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-region.el, mmm-vars.el (mmm-set-buffer-file-name-p): + Added to control file name setting. + + * mmm-vars.el (mmm-save-local-variables): + Added `mode-popup-menu' for XEmacs. + + * mmm-region.el (mmm-update-mode-info): + Added some tests for XEmacs 20 to prevent + errors and unwanted prompts. + Cleared modified flag before killing leftover temporary buffers. + +2000-08-21 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm.texinfo: + Added comments on RPM Spec, File Variables, and Here-documents. + + * mmm-auto.el: Autoloaded `rpm'. + + * mmm-auto.el: Autoloaded `rpm-sh' submode class from mmm-rpm.el. + + * mmm-rpm.el: Added file (contributed by Marcus Harnisch). + +2000-08-17 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-never-modes): Added `forms-mode'. + +2000-08-02 Michael Abraham Shulman <viritrilbia@gmail.com> + + * configure.in, mmm-vars.el, version.texi: Released 0.4.5. + + * mmm-compat.el (mmm-set-font-lock-defaults): Made into a macro. + + * mmm-auto.el: Autoloaded `mmm-ensure-fboundp'. + + * mmm-region.el (mmm-update-mode-info): + Used compatibility wrapper for font-lock defaults. + + * mmm-compat.el (mmm-set-font-lock-defaults): + Added compatibility wrapper function. + +2000-08-01 Michael Abraham Shulman <viritrilbia@gmail.com> + + * README.Mason, mmm.texinfo: + Added comments about `sgml-parent-document'. + + * mmm-utils.el (mmm-ensure-fboundp): Created function. + + * mmm-sample.el (mmm-here-doc-get-mode): + Extended to recognize names like TEXT_EOF. + +2000-07-29 Michael Abraham Shulman <viritrilbia@gmail.com> + + * configure.in, mmm-vars.el, version.texi: Released 0.4.4. + + * mmm-class.el (mmm-get-class-spec): + Implemented autoloaded submode classes. + + * mmm-vars.el (mmm-add-group): Made subclasses of a group private. + + * mmm-auto.el: Added autoloading of submode classes. + + * mmm-cmds.el (mmm-ify-by-class): + Added completion on autoloaded classes. Excluded + private classes from completion. + + * mmm-vars.el (mmm-classes-alist): + Updated docstring for new offset values and + include- flags. + + * mmm-sample.el (here-doc): Updated to use new front-offset values. + + * mmm-class.el (mmm-ify, mmm-match-region, mmm-match->point): + Added new values for front- and back-offset. + + * mmm-region.el (mmm-make-region): + Made sure overlays get the delimiter and sticky + properties even if they aren't passed explicitly. + +2000-07-26 Michael Abraham Shulman <viritrilbia@gmail.com> + + * configure.in: Changed output name from `mmm' to `mmm-mode'. + +2000-07-24 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-sample.el: Updated file-variables class to handle prefixes. + +2000-07-23 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-sample.el: Wrote File Variables submode class for the new syntax. + +2000-07-21 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-cmds.el (mmm-ify-by-class): + Added completion on all defined classes. + + * mmm-sample.el (mmm-here-doc-get-mode): + Signaled non-fboundp here-document names. + + * mmm-univ.el (mmm-univ-get-mode): Signaled error on non-fboundp modes. + + * mmm-class.el (mmm-match-region, mmm-ify): + Caught errors from :match-submode. + + * mmm-vars.el: Added `mmm-no-matching-submode' error signal. + + * mmm-sample.el: + Allowed here-documents in any mode with :match-submode. + Added insertion syntax to here-docs, javascript, and embperl. + +2000-07-14 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm.texinfo, version.texi: + Added MASON_VERSION variable to keep track of that. + + * mmm.texinfo: Wrote about changing key bindings and local variables. + Copied info from documentation of `mmm-classes-alist'. + +2000-07-13 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-run-major-mode-hook): + Added `ignore-errors' around each call. + + * mmm-vars.el (mmm-save-local-variables): + Changed `defcustom' to `defvar'. + + * mmm.texinfo: + Wrote about global classes, highlight, mode line, and hooks. + + * mmm-univ.el: Limited matches to letter/dash strings that are fboundp. + +2000-07-12 Michael Abraham Shulman <viritrilbia@gmail.com> + + * README.Mason: Added comment about `mmm-global-mode'. + +2000-07-12 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * configure.in, mmm-vars.el: Released 0.4.3. + + * mmm-univ.el: Changed %[...]% to [%...%] which looks much nicer. + + * mmm.texinfo: Wrote more about Mason. + + * mmm-mason.el: Moved commentary code to README.Mason. + + * Makefile.am: Added README.Mason to EXTRA_DIST. + + * README.Mason: Created file. + +2000-07-11 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-region.el (mmm-update-mode-info): + Used `mmm-make-temp-buffer'. Put font-lock + property directly rather than setting the variable first. + + * mmm-mode.el (mmm-mode-off): Reset font-lock variables. + + * mmm-compat.el (mmm-make-temp-buffer): + Added as workaround for make-indirect-buffer. + + * mmm-region.el: + (mmm-enable-font-lock, mmm-update-font-lock-buffer, mmm-update-mode-info): + Conditioned font-lock usage on mmm-font-lock-available-p. + + * mmm-compat.el (mmm-font-lock-available-p): Added flag. + + * mmm-region.el (mmm-update-mode-info): + Killed any lingering temporary buffers. + + * mmm-cmds.el (mmm-insert-by-key): + Made inserted regions beg- and end-sticky. + + * mmm-compat.el (mmm-keywords-used): Added :classes. + +2000-06-30 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * configure.in, mmm-vars.el: Released 0.4.2a. + + * mmm-region.el: Reordered Inspection and Creation for byte compiler. + + * mmm-mode.el: Moved mmm-mode variable to mmm-vars.el. + + * mmm-auto.el: Added some autoloads. + + * Makefile.am: Added mmm-univ.el. + + * configure.in, mmm-vars.el: Released 0.4.2. + + * mmm-auto.el (mmm-mode-on-maybe): + Conditioned font-lock updating on mmm-mode. + + * mmm-region.el: + Removed use-local-map advice; no longer necessary (thank goodness!) + + * mmm-region.el, mmm-auto.el: Fixed font-lock woes (hopefully). + + * mmm-class.el: Allowed dynamically specified submodes. + + * mmm-utils.el, mmm-mode.el, mmm-cmds.el: + Fixed font-lock woes (hopefully). + + * mmm.texinfo: Added Embperl. + + * mmm-vars.el (mmm-global-classes): + Added variable controlling global classes. + + * mmm-univ.el: Created file defining `universal' submode. + + * mmm-sample.el: Added Embperl. + + * mmm-utils.el: Added def-edebug-specs. + +2000-06-29 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-region.el (mmm-fontify-region-list): + Saved local variables before moving. + + * mmm-auto.el (mmm-check-changed-buffers): Checked for live buffer. + + * mmm-utils.el (mmm-valid-buffer): + Checked against noninteractive and hidden buffers. + + * mmm-auto.el (mmm-check-changed-buffers): + Added check against minibuffers. + + * mmm-vars.el (mmm-never-modes): Added `eshell-mode'. + +2000-06-28 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * NEWS, configure.in, mmm-vars.el: Released 0.4.1. + + * mmm-region.el (mmm-overlays-in): Added DELIM parameter. + (mmm-submode-changes-in): Added strict flags calling overlays-in. + +2000-06-27 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * configure.in, mmm-vars.el: Released 0.4.0. + + * NEWS, TODO, mmm-auto.el, mmm-region.el, mmm-vars.el, mmm.texinfo: + Changed mmm-global-mode to use post-command-hook method rather than + stack-walk method. + + * mmm-region.el: + Fixed bug saving variables when creating regions; need to set them first. + + * mmm-region.el: Added creation-hook, fixed mode-name problem. + + * mmm-class.el: Added mmm-[get,set]-class-parameters and creation-hook. + + * mmm-auto.el, mmm-region.el, mmm-vars.el: + Fixed bug where font-lock-mode was set to `t' globally, causing + global-font-lock-mode to turn it off. + +2000-06-26 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-region.el: + Rewrote local variable functions, added new ones, changed updating, + fontification, and region creation functions to handle this. + + * mmm-mode.el: + Added setting and clearing local variables with mode on and off. + + * mmm-vars.el (mmm-save-local-variables): + Added extra parameters for saving type and modes, and updated documentation. + Created several variables to save buffer- and region- locals. + (mmm-temp-buffer-name): Created variable and changed references. + +2000-06-23 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-vars.el (mmm-save-local-variable): + Added comment-line-start-skip for Fortran. + +2000-06-13 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm.texinfo: Added comment about (require 'mmm-mason). + +2000-06-08 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * configure.in, mmm-vars.el: Released 0.3.10 + + * mmm-region.el (mmm-overlays-in): + Added checks for point-min and point-max for XEmacs. + (use-local-map): Added the advice back in. + + * configure.in, mmm-vars.el: Released 0.3.9. + + * mmm-region.el (use-local-map): + Conditioned advice definition on not XEmacs. + +2000-05-28 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * .cvsignore: + Added info file and auxiliary compilation and texinfo files. + + * .cvsignore: Added configure auxiliary files. + + * .cvsignore: Ignored Makefile.in, Makefile, and configure. + + * COPYING, INSTALL, install-sh, mdate-sh, missing, mkinstalldirs, texinfo.tex: + Added files required by automake. + + * mmm.texinfo, elisp-comp, TODO, README, NEWS, ChangeLog, AUTHORS: + Added to CVS (formerly not under RCS). + +2000-05-24 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-auto.el: Pre-added major mode hook to text-mode-hook. + +2000-05-19 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-vars.el (mmm-version): changed to 0.3.8. + +2000-05-18 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-region.el: + Moved `require's back to top level for byte-compiling. Added dummy + definition of `mmm-real-use-local-map' to shut up byte compiler. + + * mmm-mode.el, mmm-cmds.el, mmm-class.el: + Moved `require's back to top level for byte-compiling. + + * mmm-auto.el: `require'd mmm-vars at top level for byte-compiling. + + * Makefile.am: + Added all the elisp files to EXTRA_DIST, since Automake doesn't see + them as sources for the distribution. + +2000-05-10 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-mason.el: Fixed bug: # is not allowed in symbols. + + * mmm-mason.el: + Changed insertion key of <%doc> to `d' and added insertion of %# + comment lines with insertion keys `#' and `3'. + + * mmm-mason.el: + Distinguished between Perl sections and pseudo-Perl sections. The one + inserts ; at the beginning for indentation hack, the other doesn't + because the Mason syntax doesn't allow it and indentation is generally + unnecessary anyway. + + * mmm-cmds.el: + Fixed "sub"-insertion specs like <%perl> under <%TAG> not to insert + the interactor string. + +2000-05-03 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-mason.el: Added dependencies on mmm-compat and mmm-vars. + +2000-04-30 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * configure.in, Makefile.am: New file. + + * mmm-sample.el, mmm-mode.el, mmm-region.el, mmm-auto.el, mmm-class.el, mmm-cmds.el, mmm-mason.el: + Changed (progn (require ...)) to (when t (require ...)) because the + first is still "top level" for the byte compiler. + + * mmm-region.el: + Required font-lock and mmm-auto at top level for byte compilation. + Moved local maps to come before updating hooks for byte compilation. + + * mmm-utils.el: Loaded CL at top level for byte-compile. + +2000-04-29 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-mode.el, mmm-region.el, mmm-sample.el, mmm-auto.el, mmm-class.el, mmm-cmds.el, mmm-mason.el: + Put all `require's not needed at compile-time into `progn's so the + byte-compiler doesn't load them (not at top level). Only `mmm-compat' + and `mmm-utils' need to be loaded at compile-time, since they define + macros. + +2000-04-27 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * All: Started using RCS. + +2000-04-27 Michael Abraham Shulman <mas@kurukshetra.cjb.net> + + * mmm-sample.el (mmm-javascript-mode): Created customization + variable to select mode to use for javascript regions. + +2000-03-26 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-cmds.el (mmm-get-insertion-spec): Insertion keys now have + symbolic names, although they have no definition. + (mmm-insertion-help): Command added to give help on insertion + keys, the way C-h does for command keys. + + * mmm-vars.el (mmm-get-all-classes): Reversed order, so + interactive classes take precedence (for insertion, mainly) over + `mmm-classes' which overrides mode/ext classes. + +2000-03-24 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-vars.el (mmm-command-modifiers, mmm-insert-modifiers): + Switched defaults to be the way I think it should be. Users can + switch back with `mmm-use-old-command-keys'. + + * README: Created file giving information on inital installation. + + * Makefile: Created makefile to compile elisp files and make info + file from texinfo file. + + * mmm-region.el: Gave up on conditional stickiness, since it + doesn't work in XEmacs and even FSF Emacs has been being flaky + with overlay after-change functions. Detecting ends in global + `after-change-functions' will work better anyway. + + * mmm-cmds.el: Renamed from `mmm-inter.el'. + (mmm-end-current-region): Added command, with key binding. + + * mmm-vars.el (mmm-classes-alist): Documentation updated for + unified submode classes. + + * mmm-class.el (mmm-ify): BEG and END arguments removed; just use + FRONT and BACK. + + * mmm-utils.el (mmm-format-matches): Ignores non-string arguments. + + * mmm-class.el (mmm-apply-class): Faces supplied for grouping + classes now override those on included classes. Parents will do + the same thing. + + * mmm-inter.el: Bound `mmm-parse-block' to C-c % 5 as well. + (mmm-reparse-current-region): Added command, with key binding. + + * mmm-insert.el: Deleted file, merging contents (insert by + keystrokes) into `mmm-inter.el'. Auto-detection insert will + probably go elsewhere. + + * mmm-inter.el (mmm-clear-current-region): Uses `mmm-overlay-at' + with `all' inclusion type. + + * mmm-region.el (mmm-overlays-at): Added `all' inclusion type. + + * mmm-class.el (mmm-apply-class, etc.): Submode classes have been + unified--no more 'regexp, 'region, 'group, etc. + +2000-03-23 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-inter.el (mmm-parse-buffer, mmm-parse-region, mmm-parse-block): + Added "Operating...done" messages. + + * mmm-region.el (mmm-make-region): Allowed caller to add extra + keyword arguments to be stored as overlay properties, anticipating + new future submode classes. + + * mmm-update.el (use-local-map): Advised to keep track of changed + local maps. + + * mmm-region.el (mmm-overlays-at): Added inclusion of boundary + points based on endpoint stickiness. + (mmm-match-front, mmm-match-back): Front and back overlay + properties can now be functions rather than regexps, in + anticipation of new future submode classes. + +2000-03-22 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-utils.el (mmm-valid-buffer): Renamed and added checking for + "never" modes. + + * mmm-vars.el (mmm-never-modes): Added, to prevent "temporary + shell-mode buffers" and other unnecessariness. + + * mmm-region.el (mmm-overlays-in): Fixed strictness so it doesn't + try to match delimiters of non-mmm overlays. + + * mmm-update.el (mmm-local-maps-alist): Keep track of changed + local maps by buffer and major mode. + (mmm-update-submode-region): Update mode info for major mode. + + * mmm-sample.el: Created file, removing code from `mmm-mode.el'. + + * mmm-auto.el: Created file, removing code from `mmm-mode.el'. + + * mason.el: Created file, removing code from `mmm-mode.el'. + + * mmm-insert.el: Created file, removing code from `mmm-mode.el'. + +2000-03-20 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-update.el: Created file, removing code from `mmm-mode.el'. + + * mmm-inter.el: Created file, removing code from `mmm-mode.el'. + + * mmm-class.el: Created file, removing code from `mmm-mode.el'. + + * mmm-mode.el (mason): Removed highlight for %doc regions. + + * mmm-region.el: Created file, removing code from `mmm-mode.el'. + + * mmm-utils.el: Created file, removing code from `mmm-mode.el'. + + * mmm-compat.el: Created file, removing code from `mmm-mode.el'. + + * mmm-vars.el: Created file, removing code from `mmm-mode.el'. + + * TODO: Created TODO file, removing comments from `mmm-mode.el'. + + * ChangeLog: Created ChangeLog file and (more or less) ported + existing Change Log to official format. + +2000-03-19 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-mode.el (mmm-global-mode): usurps and extends the role of + `mmm-add-find-file-hook'. Other modes can piggyback on our hack by + using `mmm-major-mode-hook'. + + Added :insert class parameters. Classes can now define skeletons + to insert submode regions with delimiters based on a keypress. + + Added `mmm-insert-modifiers' and `mmm-command-modifiers' to + configure which keys do what. + +2000-03-18 Michael Abraham Shulman <viritrilbia@gmail.com> + + * mmm-mode.el: Did a bunch of reorganizing. MMM-ification methods + are now submode classes, and what used to be called submode + classes are now just a type called :group. User interface is + mostly unchanged however. Replaced some gratuitous keywords with + normal symbols. + + Added bells and whistles to :regexp class type, allowing custom + "plugin" functions to verify matches and get the delimiter forms, + the latter of which aren't used yet, but will be soon. Mason + class(es) are now all regexps with a plugin or two. Function class + type is not (yet?) ported to the new interface, holding back + eval-elisp and htp.p with it. + + Changed a couple of `eval-and-compile's to `eval-when-compile'. + + Added special "non-submode" regions, where the major mode holds + sway, but no submodes allowed (until parents are implemented). + Added %doc in text-mode and %text as a non-submode to Mason, and + added %flags, %attr, %method, and %shared tags for Mason classes. + These will be new in Mason version 0.82. + +2000-03-14 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.7a released. + + * mmm-mode.el: Put `turn-on-font-lock-if-enabled' back in for FSF + Emacs. Don't know why I thought I could take it out. + +2000------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.7 released. + + * mmm-mode.el: Set insertion types of markers added to history to + coincide with sticky ends of overlays. It's not perfect, but it's + better. + + Renamed mode and submode hook variables to start with `mmm-'. + + Added "class hooks" run whenever a class is first used in a + buffer. + + Changes for XEmacs compatibility: + - Loaded XEmacs overlay emulation package. + - Renamed some overlay properties when in XEmacs + - Removed `global-font-lock-mode' dependencies. + - Added extra parameter to `regexp-opt' in Mason class. + + Removed "Disclaimers" comment section; I think we have enough + testing that it should work on most systems. + + Reversed order of Change Log so newer changes come first. + + Changed the default submode highlight to a more neutral gray. + + Renamed various "start" and "end" parameters to be more uniform. + + (mmm-ify-by-region): now checks if the region is in bounds. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.6c released. + + * mmm-mode.el: Added comment about putting autohandlers and + dhandlers in html-mode. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.6b released. + + * mmm-mode.el: Added comment about `psgml-mode' thanks to Michael + Alan Dorman. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.6a released. + + * mmm-mode.el: Loaded CL at compile-time to prevent execution of + macro arguments. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.6 released. + + * mmm-mode.el: Changes for Emacs 19 compatibility. + - Set keyword variables to themselves. + - Added hacks for absence of custom.el and regexp-opt. + - Added user variable to control use of Perl mode vs CPerl mode. + Thanks to Eric A. Zarko for suggestions and testing. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.5a released. + + * mmm-mode.el (mmm-ify-by-all): no longer re-fontifies buffers + with no submodes. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.5 released. + + * mmm-mode.el (mmm-fontify-region): now locally binds + `font-lock-beginning-of-syntax-function' to + `mmm-beginning-of-syntax' since `font-lock-fontify-block' binds it + to nil for some reason. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.4 released. + + * mmm-mode.el (mmm-ify-by-class): now fontifies the buffer + afterward, like the other interactive MMM-ification functions. + Updated a couple doc-strings and prompts. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.3 released. + + * mmm-mode.el (mmm-regexp-to-regions, mmm-mason-inline): Changed + recursion to iteration, since for long files the recursion runs + afoul of `max-lisp-eval-depth'. + (mason): Commented on workaround for Mason CPerl mess-ups. + Submode overlays now evaporate if they have zero width. + (mmm-parse-region): now has a key binding and doesn't refontify + the entire buffer. + +1999------ Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.2 released. + + * mmm-mode.el (mmm-mode-on, mmm-mode-off): are now interactive. + Fixed bug in Mason class: %def, %text, and %doc are now ignored as + they should be. + +1999-11-21 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.1 released. + + * mmm-mode.el (mmm-ify-by-class) now adds to history rather than + `mmm-classes'. + Fixed :class keyword so it works correctly. + (mmm-add-mode-ext-class): Classes associated with major modes or + filenames now do The Right Thing when the major mode is changed. + However, `mmm-mode-ext-classes-alist' cannot be directly modified. + (mmm-mode): Updated documentation to cover 0.3.x changes. + +1999-11-21 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.3.0 released. + + * mmm-mode.el (mmm-ify-by-class): Added interactive prompt. + (mmm-version): Function added to display version interactively. + Fixed and updated customization definitions. + (mmm-mode-ext-classes-alist): added, allowing the automatic + association of certain major-modes and/or file extensions with + submode classes. + Allowed submode lists to contain :class keyword, so one class can + invoke another one, if they share submode methods. + +1999-11-19 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.2.2a released. + + * mmm-mode.el: Fixed bug. + +1999-11-18 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.2.2 released. + + * mmm-mode.el (mmm-mason-inline): Replaces the regexps "<% " and + "%>" for HTML::Mason submode class. Inline perl regions don't have + to begin with a space, but the regexp "<%" matches "<%perl>" as + well, which it shouldn't. + Added `save-match-data' calls in all searching functions. + Removed unnecessary auxiliary functions. + +1999-11-16 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.2.1 released. + + * mmm-mode.el: Fixed font-lock absence, with-temp-message absence, + mmm-ifying temp buffer. + +1999-11-15 Michael Abraham Shulman <viritrilbia@gmail.com> + + * Version 0.2.0 released to HTML::Mason mailing list. + + * Comment: Although nearly 100% of the code for mmm-mode was + written by me, the original inspiration came from mmm.el for + XEmacs by Gongquan Chen <chen@posc.org>, so I have continued his + version-numbering. + +1999-01-12 Gongquan Chen <chen@posc.org> + + * Version 0.11 released. + + * mmm.el: Fixed doc-strings and style. Thanks to comments from + Jari Aalto <jaalto@tre.tele.nokia.fi> + +1999-01-11 Gongquan Chen <chen@posc.org> + + * Version 0.10 released. + + * mmm.el: Initial release of mmm.el on comp.emacs.xemacs diff --git a/Checklist b/Checklist new file mode 100644 index 0000000..449b98b --- /dev/null +++ b/Checklist @@ -0,0 +1,24 @@ +-*-text-*- + Checklist for New MMM Mode Releases + +0. Test all new code, under all Emacsen if possible. Check that the + package builds and installs. + +1. Check everything into Git. + +2. Update the NEWS and TODO files and any other commentary files and + check them into Git. + +3. Update version numbers and dates in `mmm-mode.el', `configure.in', + and `mmm-vars.el'. Check them in with comment "Released x.x.x". + +4. Make a Git snapshot (`C-x v s') of the MMM Mode directory. This is + the point at which a release becomes official. + +5. Run `make dist' and upload the tarball. Upload to SourceForge. + + Adding Files + +To add a file to the distribution, edit `Makefile.am' and add it to +lisp_LISP (if an .el file) or EXTRA_DIST (otherwise). If necessary, +add autoloads for functions or submode classes to `mmm-auto.el'. @@ -0,0 +1,192 @@ +-*-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: + + (setq mmm-submode-decoration-level 0) + +You may want to try using MMM Mode for a while with the background +highlight, however, or merely changing it to a different color. There +are two reasons it's there by default: + +1. MMM Mode isn't as smart as you might hope it would be about + 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). You can get even + more help by setting the above variable to 2, in which case regions + will get a background color according to their function. + + +* I typed `<%' (or other delimiter) but I'm still in the wrong mode. + +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). + +With a recent update, you can set `mmm-parse-when-idle' to t, to allow +MMM Mode to reparse the buffer when it's modified and Emacs is idle. +This comes at a certain performance cost. + + +* Why is the first character of the end delimiter in the submode region? + +It isn't. When your cursor looks like it is over that character, it +is actually *before* that character and therefore inside the submode +region. You can check that the offending character does not have the +background highlight--that is, if you haven't set the decoration level +to 0. For example, in the following text (where -!- represents the +cursor position) + + print <<END_TEXT; + here is some text + -!-END_TEXT + +The 'E' at the beginning of the END_TEXT line is not actually part of +the submode region. But with the cursor as indicated (that is, the +box is blinking over the `E' which follows the actual cursor +position), Emacs is in text-mode. + + +* Why won't MMM Mode work with `foo-mode'? + +Foo-mode probably has extra variables or states that need to be set +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 file an issue, 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. + +If you're having a problem with syntax highlighting, debugging is +complicated by the fact that font-lock swallows errors. To trigger the +error, evaluate the following in the problem buffer (with `M-:'): + + (font-lock-fontify-region (point-min) (point-max)) + +(1) To get a stack backtrace of an error, set the emacs variable + `debug-on-error' to non-nil (type `M-x toggle-debug-on-error 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 23 / XEmacs 20 / XEmacs 21 / etc...)? + +MMM Mode was designed for FSF Emacs and works best in versions 23 and 24. +But don't let that stop you from trying it under other variants of +emacs. If you encounter problems, feel free to ask the mailing list, +but success is not guaranteed. + +XEmacs 21 has problems with font-lock: for example, often apostrophes in +a different submode region can cause code to be incorrectly font-locked +as a string. + +Versions of FSF Emacs < 23 and XEmacs < 21 are not supported. + + +* 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 +$ ./configure --with-xemacs=/path/to/xemacs +$ 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. + + +* I want to install the Git version, but there's no `configure' script. + +The `configure' script which is included in the official distributions +is not present in Git, because it is automatically generated by GNU +Automake/Autoconf from files like `Makefile.am' and `configure.in'. +To build the Git version the same way as the official distributions, +you must first run `autogen.sh': + +$ cd mmm-mode +$ ./autogen.sh + +and then you can continue as usual: + +$ ./configure +$ make +$ make install + +Note that autogen.sh requires aclocal, automake, and autoconf, which +may or may not be installed on your system, since they are considered +developer tools rather than end-user tools. If you can't or don't +want to install them, however, you can still use the Git version of +MMM Mode by manually copying all the `.el' files into a directory in +your `load-path'. Optionally, you may also byte-compile them manually +(this is what `make' normally does). Byte-compiling gives some speed +improvement, but if you experience problems, the stack traces are +sometimes more informative if you are using the source files only. + +The Info files `mmm.info-*' are also not included in Git, since they +are generated from `mmm.texinfo' by the program `makeinfo'. If you +want to install the Info documentation from Git, you will have to run +this manually as well, and copy the resulting info files into the +appropriate location for your system. + +The Git version is, of course, even less guaranteed to be bug-free +than the official distributions. But please report any problems you +have with it, so they can be fixed for the next release. + + +* You haven't answered my question; how can I get more help? + +Create an issue at <https://github.com/purcell/mmm-mode/issues>, or +check out the MMM Mode web site, <http://mmm-mode.sourceforge.net>, +there is a link to the subscription page for the MMM Mode mailing list. + +When asking a question or reporting a problem, be sure to give the +versions of emacs and MMM Mode you are using, and any other relevant +information. @@ -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/Makefile.am b/Makefile.am new file mode 100644 index 0000000..942c467 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in + +## The MMM Mode distribution is `flat', so we have no SUBDIRS macro. + +lisp_LISP = mmm-compat.el mmm-vars.el mmm-utils.el mmm-auto.el \ + mmm-region.el mmm-class.el mmm-cmds.el mmm-mode.el \ + mmm-sample.el mmm-mason.el mmm-univ.el mmm-rpm.el mmm-cweb.el \ + mmm-noweb.el mmm-myghty.el mmm-erb.el mmm-defaults.el + +info_TEXINFOS = mmm.texinfo + +# This is a hack IMO. Automake should recognize lisp files as +# "sources" and include them in the distribution, but it doesn't. +EXTRA_DIST = $(lisp_LISP) README.Mason FAQ + +# See also `elisp-comp' for another hack. @@ -0,0 +1,328 @@ +MMM Mode NEWS -- history of user-visible changes. -*-outline-*- +Copyright (C) 2003, 2004, 2013-2015 Free Software Foundation, Inc. +See the file COPYING for copying conditions. + +Please submit bug reports at https://github.com/purcell/mmm-mode/issues + +* Changes in MMM Mode 0.5.7 +Fixes for mmm-indent-line-narrowed. + +* Changes in MMM Mode 0.5.6 +Emacs 25 compatibility fix when cl is not loaded. + +* Changes in MMM Mode 0.5.5 + +Introduced mode transition hooks, like mmm-x-enter-hook and mmm-y-exit-hook. + +New function mmm-indent-line-narrowed, to use as mmm-indent-line-function. + +`cl-lib' is a new dependency, replacing `cl'. It comes bundled with +recent versions of Emacs, and for older ones it can be installed from +GNU ELPA. + + +* Changes in MMM Mode 0.5.4 + +Fixes for indentation, SMIE support, and minor bugs. + + +* Changes in MMM Mode 0.5.2 + +Introduced `mmm-after-syntax-propertize-functions'. A primary major +mode can set it to adjust `syntax-table' text properties in submode +regions. + +New file `mmm-defaults.el'. A user can simply require it and have +basic setup for ERB, EJS and PHP files (for the last one, `php-mode' +has to be installed separately). + +`mmm-add-classes' is autoloaded. + +`mmm-beginning-of-syntax' was removed. + +Assorted highlighting and syntax detection improvements. + + +* Changes in MMM Mode 0.5.1 + +Some minor documentation updates and bugfixes. + + +* Changes in MMM Mode 0.5.0 + +** Compatibility with recent Emacsen + +Updated to work with Emacs 23 and 24. Removed some compatibility code +for older versions. Added new local variables used in the latest js-mode +and cc-engine modes. + +** New submode classes + +New submode classes for ERB and EJS templates, both in mmm-erb.el. It +also includes a smart indentation algorithm, supporting them together +with script and style tag subregions in HTML code. + +** Parsing when idle + +Setting `mmm-parse-when-idle' will make MMM Mode re-parse modified +buffers when Emacs is idle. This can lead to visible pauses, though, +depending on the size of the buffer and the number of subregions. + +** Support submode-specific syntax functions + +Relevant for Emacs 24: we define a composite syntax-propertize-function +that delegates syntax recognition to respective submode functions. + +For users, this means regular expressions in js-mode and string +interpolations and percent literals in ruby-mode. + +** Indentation + +More consistent indentation behavior, the default implementation +delegates to the submode at the end of the indentation. + +The major mode can provide its own implementation by setting +mmm-indent-line-function, to handle specific mode combinations better. + + +* Changes in MMM Mode 0.4.8 + +** Delimiter Regions + +The delimiters which mark off submode regions now have their own +overlays. They can be highlighted if you so desire using appropriate +class arguments and/or the variable mmm-delimiter-face. They are also +in an appropriate major mode, or non-mode as the case may be. + +** Nested Submodes + +Nested submodes are now vaguely supported. + +** RPM Spec File + +An RPM spec file, contributed by <bishop@platypus.bc.ca>, is now +included for people who wish to build their own SRPM to install from. + +** New Submode Classes + +Many thanks to Joe Kelsey for writing a very intelligent class for +editing Noweb files, and to Alan Shutko for one for CWeb files. We +also have a mode for SGML DTD definitions from Yann Dirson. + +** Numerous bugfixes and small improvements + + +* Changes in MMM Mode 0.4.7 + +** 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. @@ -0,0 +1,110 @@ + + MMM Mode for Emacs + ================== + +OVERVIEW + + MMM Mode is a minor mode for Emacs that allows Multiple Major Modes + to coexist in one buffer. It is well-suited to editing: + + * Preprocessed code, such as server-side Ruby, Perl or PHP embedded in HTML + * Code generating code, such as HTML output by CGI scripts + * Embedded code, such as Javascript in HTML + * Literate programming: code interspersed with documentation, e.g. Noweb + +INSTALLATION + + Use any of the following options: + + 1. Users of package.el (a.k.a. ELPA) can easily install MMM Mode from + the ELPA package repository at https://elpa.gnu.org/ -- this is the + preferred and best-supported installation mechanism. + + 2. 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. + + 3. MMM Mode has a standard GNU configure-driven installation. + (See the file INSTALL for generic instructions, most of which don't apply.) + To install in the standard locations, unpack the archive, `cd' to + the mmm-mode-X.X.X directory created, and run these commands: + + make maintainer-clean # optional step + ./autogen.sh + ./configure + make + make install + + 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; + usually the latter is preferable, except possibly for autoloads. + First the package needs to be loaded, with either + + (require 'mmm-mode) + + or instead, to save time during emacs startup, + + (require 'mmm-auto) + + Then you will probably want to set something like this: + + (setq mmm-global-mode 'maybe) + (mmm-add-mode-ext-class 'html-mode "\\.php\\'" 'html-php) + + The first line tells MMM Mode to load itself whenever you open an + appropriate file, and the second is an example which says to notice + PHP regions in html-mode files having a `.php' extension. Both + lines are necessary. + + You will, of course, want to change and duplicate the second line + according to your needs. either of the first two parameters can be + `nil', meaning not to consider that criterion. For example, if all + your html files, regardless of extension, are Mason components, you + will want something like: + + (mmm-add-mode-ext-class 'html-mode nil 'mason) + + whereas if all your files with a `.nw' extension, regardless of + primary mode (some may be LaTeX, others HTML, say) are Noweb, you + will prefer + + (mmm-add-mode-ext-class nil "\\.nw\\'" 'noweb) + + See the info file for more extensive documentation, and for other + configuration options. + +DOCUMENTATION + + For further information, see (in order) the accompanying info file, + 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 + https://github.com/purcell/mmm-mode + +FEEDBACK + + Bug reports, suggestions and questions can be submitted at + https://github.com/purcell/mmm-mode/issues. + + Thanks for using MMM Mode! diff --git a/README.Mason b/README.Mason new file mode 100644 index 0000000..062435c --- /dev/null +++ b/README.Mason @@ -0,0 +1,122 @@ +-*-text-*- + Using MMM Mode for Mason: An Overview + ===================================== + + Since many users of MMM Mode use it for Mason <www.masonhq.com>, and + since the Mason submode class is the most complex one supplied, a + few comments regarding its usage are in order. Even if you don't + use Mason, this file may be of interest to you as an example of MMM + usage and possible problems. + +INSTALLATION AND LOADING + + For general installation and information, see the README file and + the texinfo documentation. The submode class for Mason components + is called `mason' and is automatically loaded from `mmm-mason.el' + the first time it is used. + +MODES AND EXTENSIONS + + If you want to have mason submodes automatically in all Mason files, + you can use `mmm-mode-ext-classes-alist'; the details depend on what + you call your Mason components and what major mode you use. Some + example elements of `mmm-mode-ext-classes-alist' follow, with + comments on the corresponding naming scheme. + + (html-mode "\\.html\\'" mason) ;; Any .html file in html-mode + (hm--html-mode nil mason) ;; Any buffer in hm--html-mode + (sgml-mode nil mason) ;; Any buffer in sgml-mode + (nil "\\.\\(mason\\|html\\)\\'" mason) ;; All .mason and .html files + (nil "\\.m[dc]\\'" mason) ;; All .md and .mc files + (nil "\\`/var/www/mason/" mason) ;; Any file in the directory + (nil nil mason) ;; All buffers. + + In order for any of these to work, you must set `mmm-global-mode' to + a non-nil value, such as `t' or `maybe' (the two of which mean + different things; see the documentation). This can be done with a + line in .emacs such as the following: + + (setq mmm-global-mode 'maybe) + + If you use an extension for your Mason files that emacs does not + automatically place in your preferred HTML Mode (be it html-mode, + sgml-html-mode, hm--html-mode, or whatever), you will probably want + to associate that extension with your HTML Mode (this is a feature + of emacs, not MMM Mode). An example is shown below. + + (add-to-list 'auto-mode-alist '("\\.mason\\'" . html-mode)) + + This also goes for "special" Mason files such as autohandlers and + dhandlers. The code below tells emacs to use html-mode for files + named `autohandler' and `dhandler'. + + (add-to-list 'auto-mode-alist '("\\(auto\\|d\\)handler\\'" . html-mode)) + + An alternate solution is to change the names of your autohandlers + and dhandlers so that emacs recognizes them as HTML automatically. + Similar code can be used to recognize all files in a given directory + as HTML and/or Mason. + +CPERL PROBLEMS + + There are 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. + + <%perl>; + print $var; + </%perl> + + 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. + +PSGML PROBLEMS + + Some people have reported problems using PSGML with Mason. Adding + the following line to a .emacs file should suffice to turn PSGML off + and cause emacs to use a simpler HTML mode: + + (autoload 'html-mode "sgml-mode" "HTML Mode" t) + + Earlier versions of PSGML may require instead the following fix: + + (delete '("\\.html$" . sgml-html-mode) auto-mode-alist) + (delete '("\\.shtml$" . sgml-html-mode) auto-mode-alist) + + Other users report using PSGML with Mason and MMM Mode without + difficulty. If you don't have problems and want to use PSGML, you + may need to replace `html-mode' in the suggested code with + `sgml-html-mode'. (Depending on your version of PSGML, this may not + be necessary.) Similarly, if you are using XEmacs and want to use + the alternate HTML mode `hm--html-mode', replace `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 + + <body> + <% $m->call_next %> + </body> + + in which case the actual components contain no doctype declaration, + <html>, <head>, or <body>, confusing PSGML. One solution I've found + is to use the variable `sgml-parent-document' in such incomplete + components; try, for example, these lines at the end of a component. + + %# Local Variables: + %# sgml-parent-document: ("autohandler" "body" nil ("body")) + %# sgml-doctype: "/top/level/autohandler" + %# End: + + This tells PSGML that the current file is a sub-document of the file + `autohandler' and is included inside a <body> tag, thus alleviating + its confusion, and also instructs it where to find the doctype + declaration (assuming your top-level autohandler has one). This + alleviates most problems for me. I admit to not understanding PSGML + internals very well, so YMMV. @@ -0,0 +1,61 @@ +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. + +Support for: ASP + +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? + +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. + +Port or generalize the relevant bits from ERB indentation code to similar +packages for other languages. + +Make re-parsing the buffer into regions incremental: take the position +of the most early change, see the submodes nesting there, and resume +parsing with that data. Shouldn't be too hard, conceptually. Maybe +even ignore the nesting, backtrack to a position where there are no +overlays, and re-parse from there (see mmm-parse-apply as a starting +point). Remember to handle delimiter inclusion and offsets as best +possible. + +Thus, make re-parsing automatic (from syntax-propertize-function, +probably), making manual control unnecessary. + +Remove XEmacs stuff? diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..e02262f --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,165 @@ +dnl +dnl Execute arbitrary emacs lisp +dnl +AC_DEFUN(AC_EMACS_LISP, [ +elisp="$2" +if test -z "$3"; then + AC_MSG_CHECKING(for $1) +fi +AC_CACHE_VAL(EMACS_cv_SYS_$1,[ + OUTPUT=./conftest-$$ + echo ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x) (prin1-to-string x)) nil \"${OUTPUT}\"))" >& AC_FD_CC 2>&1 + ${EMACS} -batch -eval "(let ((x ${elisp})) (write-region (if (stringp x) (princ x 'ignore) (prin1-to-string x)) nil \"${OUTPUT}\"nil 5))" >& AC_FD_CC 2>&1 + retval=`cat ${OUTPUT}` + echo "=> ${retval}" >& AC_FD_CC 2>&1 + rm -f ${OUTPUT} + EMACS_cv_SYS_$1=$retval +]) +$1=${EMACS_cv_SYS_$1} +if test -z "$3"; then + AC_MSG_RESULT($$1) +fi +]) + +AC_DEFUN(AC_XEMACS_P, [ + AC_MSG_CHECKING([if $EMACS is really XEmacs]) + AC_EMACS_LISP(xemacsp,(if (string-match \"XEmacs\" emacs-version) \"yes\" \"no\") ,"noecho") + XEMACS=${EMACS_cv_SYS_xemacsp} + EMACS_FLAVOR=emacs + if test "$XEMACS" = "yes"; then + EMACS_FLAVOR=xemacs + fi + AC_MSG_RESULT($XEMACS) + AC_SUBST(XEMACS) + AC_SUBST(EMACS_FLAVOR) +]) + +AC_DEFUN(AC_PATH_LISPDIR, [ + AC_XEMACS_P + if test "$prefix" = "NONE"; then + AC_MSG_CHECKING([prefix for your Emacs]) + AC_EMACS_LISP(prefix,(expand-file-name \"..\" invocation-directory),"noecho") + prefix=${EMACS_cv_SYS_prefix} + AC_MSG_RESULT($prefix) + fi + AC_ARG_WITH(lispdir, --with-lispdir Where to install lisp files, lispdir=${withval}) + AC_MSG_CHECKING([where .elc files should go]) + if test -z "$lispdir"; then + dnl Set default value + theprefix=$prefix + if test "x$theprefix" = "xNONE"; then + theprefix=$ac_default_prefix + fi + lispdir="\$(datadir)/${EMACS_FLAVOR}/site-lisp" + for thedir in share lib; do + potential= + if test -d ${theprefix}/${thedir}/${EMACS_FLAVOR}/site-lisp; then + lispdir="\$(prefix)/${thedir}/${EMACS_FLAVOR}/site-lisp" + break + fi + done + fi + AC_MSG_RESULT($lispdir) + AC_SUBST(lispdir) +]) + +dnl +dnl Determine the emacs version we are running. +dnl Automatically substitutes @EMACS_VERSION@ with this number. +dnl +AC_DEFUN(AC_EMACS_VERSION, [ +AC_MSG_CHECKING(for emacs version) +AC_EMACS_LISP(version,(and (boundp 'emacs-major-version) (format \"%d.%d\" emacs-major-version emacs-minor-version)),"noecho") + +EMACS_VERSION=${EMACS_cv_SYS_version} +AC_SUBST(EMACS_VERSION) +AC_MSG_RESULT(${EMACS_VERSION}) +]) + +dnl +dnl Determine whether the specified version of Emacs supports packages +dnl or not. Currently, only XEmacs 20.3 does, but this is a general +dnl check. +dnl +AC_DEFUN(AC_EMACS_PACKAGES, [ +AC_ARG_WITH(package-dir, --with-package-dir Configure as a XEmacs package in directory, [ EMACS_PACKAGE_DIR="${withval}"]) +if test -n "$EMACS_PACKAGE_DIR"; then + if test "$prefix" != "NONE"; then + AC_MSG_ERROR([--with-package-dir and --prefix are mutually exclusive]) + fi + dnl Massage everything to use $(prefix) correctly. + prefix=$EMACS_PACKAGE_DIR + datadir='$(prefix)/etc/w3' + infodir='$(prefix)/info' + lispdir='$(prefix)/lisp/w3' +fi +AC_SUBST(EMACS_PACKAGE_DIR) +]) + +dnl +dnl Check whether a function exists in a library +dnl All '_' characters in the first argument are converted to '-' +dnl +AC_DEFUN(AC_EMACS_CHECK_LIB, [ +if test -z "$3"; then + AC_MSG_CHECKING(for $2 in $1) +fi +library=`echo $1 | tr _ -` +AC_EMACS_LISP($1,(progn (fmakunbound '$2) (condition-case nil (progn (require '$library) (fboundp '$2)) (error (prog1 nil (message \"$library not found\"))))),"noecho") +if test "${EMACS_cv_SYS_$1}" = "nil"; then + EMACS_cv_SYS_$1=no +fi +if test "${EMACS_cv_SYS_$1}" = "t"; then + EMACS_cv_SYS_$1=yes +fi +HAVE_$1=${EMACS_cv_SYS_$1} +AC_SUBST(HAVE_$1) +if test -z "$3"; then + AC_MSG_RESULT($HAVE_$1) +fi +]) + +dnl +dnl Check whether a variable exists in a library +dnl All '_' characters in the first argument are converted to '-' +dnl +AC_DEFUN(AC_EMACS_CHECK_VAR, [ +AC_MSG_CHECKING(for $2 in $1) +library=`echo $1 | tr _ -` +AC_EMACS_LISP($1,(progn (makunbound '$2) (condition-case nil (progn (require '$library) (boundp '$2)) (error nil))),"noecho") +if test "${EMACS_cv_SYS_$1}" = "nil"; then + EMACS_cv_SYS_$1=no +fi +HAVE_$1=${EMACS_cv_SYS_$1} +AC_SUBST(HAVE_$1) +AC_MSG_RESULT($HAVE_$1) +]) + +dnl +dnl Perform sanity checking and try to locate the custom and widget packages +dnl +AC_DEFUN(AC_CHECK_CUSTOM, [ +AC_MSG_CHECKING(for acceptable custom library) +AC_CACHE_VAL(EMACS_cv_ACCEPTABLE_CUSTOM,[ +AC_EMACS_CHECK_LIB(widget,widget-convert-text,"noecho") +AC_EMACS_CHECK_LIB(wid_edit,widget-convert-text,"noecho") +if test "${HAVE_widget}" = "yes"; then + EMACS_cv_ACCEPTABLE_CUSTOM=yes +else + if test "${HAVE_wid_edit}" != "no"; then + EMACS_cv_ACCEPTABLE_CUSTOM=yes + else + EMACS_cv_ACCEPTABLE_CUSTOM=no + fi +fi +if test "${EMACS_cv_ACCEPTABLE_CUSTOM}" = "yes"; then + AC_EMACS_LISP(widget_dir,(file-name-directory (locate-library \"widget\")),"noecho") + EMACS_cv_ACCEPTABLE_CUSTOM=$EMACS_cv_SYS_widget_dir +fi +]) + AC_ARG_WITH(custom, --with-custom Specify where to find the custom package, [ EMACS_cv_ACCEPTABLE_CUSTOM=`( cd $withval && pwd || echo "$withval" ) 2> /dev/null` ]) + CUSTOM=${EMACS_cv_ACCEPTABLE_CUSTOM} + AC_SUBST(CUSTOM) + AC_MSG_RESULT("${CUSTOM}") +]) + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..4258e25 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +notfound= +if ! type aclocal >/dev/null 2>/dev/null; then + notfound=aclocal +elif ! type automake >/dev/null 2>/dev/null; then + notfound=automake +elif ! type autoconf >/dev/null 2>/dev/null; then + notfound=autoconf +fi +if test -n "$notfound"; then + echo OOPS: I can\'t find $notfound in your path! + echo You need aclocal, automake, and autoconf to generate configure. + echo Otherwise, you can install manually, see the README file. + exit; +fi + +echo -n Running aclocal to generate aclocal.m4... +aclocal +echo done. + +echo -n Running automake to generate Makefile.in... +automake +echo done. + +echo -n Running autoconf to generate configure... +autoconf +echo done diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..c30f8f0 --- /dev/null +++ b/configure.in @@ -0,0 +1,36 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT() + +AM_INIT_AUTOMAKE(mmm-mode, 0.5.7) + +dnl +dnl Apparently, if you run a shell window in Emacs, it sets the EMACS +dnl environment variable to 't'. Lets undo the damage. +dnl +if test "${EMACS}" = "t"; then + EMACS="" +fi + +AC_ARG_WITH(xemacs, --with-xemacs Use XEmacs to build, [ if test "${withval}" = "yes"; then EMACS=xemacs; else EMACS=${withval}; fi ]) +AC_ARG_WITH(emacs, --with-emacs Use Emacs to build, [ if test "${withval}" = "yes"; then EMACS=emacs; else EMACS=${withval}; fi ]) + +AC_CHECK_PROG(EMACS, xemacs, xemacs, emacs) + +AM_PATH_LISPDIR + +AC_EMACS_VERSION + + +dnl Checks for programs. + +dnl Checks for libraries. + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. + +dnl Checks for library functions. + +AC_SUBST(EMACS) + +AC_OUTPUT(Makefile) diff --git a/elisp-comp b/elisp-comp new file mode 100755 index 0000000..76f5d60 --- /dev/null +++ b/elisp-comp @@ -0,0 +1,55 @@ +#!/bin/sh +# Copyright (C) 1995 Free Software Foundation, Inc. +# François Pinard <pinard@iro.umontreal.ca>, 1995. +# +# 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, 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. + +# This script byte-compiles all `.el' files which are part of its +# arguments, using GNU Emacs, and put the resulting `.elc' files into +# the current directory, so disregarding the original directories used +# in `.el' arguments. +# +# This script manages in such a way that all Emacs LISP files to +# be compiled are made visible between themselves, in the event +# they require or load-library one another. + +# This script was modified by Michael Abraham Shulman +# <mas@kurukshetra.cjb.net> not to create a temporary directory, so +# that elisp files not given on the command line at the same time, +# the way Automake *actually* uses this script, can load each other. + +if test $# = 0; then + echo 1>&2 "No files given to $0" + exit 1 +else + if test -z "$EMACS" || test "$EMACS" = "t"; then + # Value of "t" means we are running in a shell under Emacs. + # Just assume Emacs is called "emacs". + EMACS=emacs + fi + +# tempdir=elc.$$ +# mkdir $tempdir +# cp $* $tempdir +# cd $tempdir + +# echo "elisp-comp called on $*" + echo "(setq load-path (cons nil load-path))" > script + $EMACS -q -batch -l script -f batch-byte-compile $* +# mv *.elc .. + +# cd .. +# rm -fr $tempdir +fi diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mdate-sh b/mdate-sh new file mode 100755 index 0000000..37171f2 --- /dev/null +++ b/mdate-sh @@ -0,0 +1,92 @@ +#!/bin/sh +# Get modification time of a file or directory and pretty-print it. +# Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. +# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995 +# +# 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, 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. + +# Prevent date giving response in another language. +LANG=C +export LANG +LC_ALL=C +export LC_ALL +LC_TIME=C +export LC_TIME + +# Get the extended ls output of the file or directory. +# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. +if ls -L /dev/null 1>/dev/null 2>&1; then + set - x`ls -L -l -d $1` +else + set - x`ls -l -d $1` +fi +# The month is at least the fourth argument +# (3 shifts here, the next inside the loop). +shift +shift +shift + +# Find the month. Next argument is day, followed by the year or time. +month= +until test $month +do + shift + case $1 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; + esac +done + +day=$2 + +# Here we have to deal with the problem that the ls output gives either +# the time of day or the year. +case $3 in + *:*) set `date`; eval year=\$$# + case $2 in + Jan) nummonthtod=1;; + Feb) nummonthtod=2;; + Mar) nummonthtod=3;; + Apr) nummonthtod=4;; + May) nummonthtod=5;; + Jun) nummonthtod=6;; + Jul) nummonthtod=7;; + Aug) nummonthtod=8;; + Sep) nummonthtod=9;; + Oct) nummonthtod=10;; + Nov) nummonthtod=11;; + Dec) nummonthtod=12;; + esac + # For the first six month of the year the time notation can also + # be used for files modified in the last year. + if (expr $nummonth \> $nummonthtod) > /dev/null; + then + year=`expr $year - 1` + fi;; + *) year=$3;; +esac + +# The result. +echo $day $month $year @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# 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, 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..5e17cd3 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,38 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/mmm-auto.el b/mmm-auto.el new file mode 100644 index 0000000..30d46b7 --- /dev/null +++ b/mmm-auto.el @@ -0,0 +1,178 @@ +;;; mmm-auto.el --- loading and enabling MMM Mode automatically + +;; Copyright (C) 2000-2004, 2012, 2013, 2018 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 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.) + +;; FIXME: There's now after-change-major-mode-hook which should DTRT. + +;; 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 'mmm-vars) + +;;{{{ Autoload Submode Classes + +(defvar mmm-autoloaded-classes + '((mason "mmm-mason" nil) + (myghty "mmm-myghty" nil) + (html-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) + (cweb "mmm-cweb" nil) + (sgml-dtd "mmm-sample" nil) + (noweb "mmm-noweb" nil) + (html-php "mmm-sample" nil) + ) + "Alist of submode classes autoloaded from files. +Elements look like \(CLASS FILE PRIVATE) where CLASS is a submode +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) + (with-current-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 `mmm-global-mode' is non-nil and there are classes +to apply, or always if `mmm-global-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 diff --git a/mmm-class.el b/mmm-class.el new file mode 100644 index 0000000..d745519 --- /dev/null +++ b/mmm-class.el @@ -0,0 +1,335 @@ +;;; mmm-class.el --- MMM submode class variables and functions + +;; Copyright (C) 2000-2004, 2011-2015, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains variable and function definitions for +;; manipulating and applying MMM submode classes. See `mmm-vars.el' +;; for variables that list classes. + +;;; Code: + +(require 'cl-lib) +(require 'mmm-vars) +(require 'mmm-region) + +;;; CLASS SPECIFICATIONS +;;{{{ 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 + +(cl-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))) + (mmm-run-class-hook class) + ;; Hack in case class hook sets mmm-buffer-mode-display-name etc. + (mmm-set-mode-line))) + +(cl-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. + (cl-pushnew (cl-second err) invalid-classes :test #'equal)))) + (when invalid-classes + (signal 'mmm-invalid-submode-class invalid-classes)))) + +;;}}} +;;{{{ Apply All Classes + +;; FIXME: This should be called by syntax-propertize-function, +;; not vice versa. +(cl-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-submode-region) + ;; Try to continue supporting XEmacs for a while. + (when (fboundp 'syntax-propertize) + (syntax-ppss-flush-cache start) + (syntax-propertize stop)) + (mmm-refontify-maybe start stop)) + +;;}}} + +;;; BUFFER SCANNING +;;{{{ Scan for Regions + +(cl-defun mmm-ify + (&rest all &key classes handler + ;; Many args are marked as "unused" below, but that's only + ;; because they're used via `all'. + submode _match-submode + (start (point-min)) (stop (point-max)) + front back _save-matches (case-fold-search t) + (beg-sticky (not (number-or-marker-p front))) + (end-sticky (not (number-or-marker-p back))) + _include-front _include-back + (front-offset 0) (back-offset 0) + (front-delim nil) (back-delim nil) + (delimiter-mode mmm-delimiter-mode) + front-face back-face + _front-verify _back-verify + _front-form _back-form + creation-hook + face _match-face + _save-name _match-name + ;; FIXME: Since those args's arent' used directly (only passed down + ;; via `all'), these default values aren't obeyed! + (_front-match 0) (_back-match 0) + _end-not-begin + ;insert private + &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-delim front-delim :back-delim back-delim + :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) + (cl-loop for (beg end front-pos back-pos matched-front matched-back + matched-submode matched-face matched-name + invalid-resume ok-resume) = + (apply #'mmm-match-region :start (point) all) + while beg + if end ; match-submode, if present, succeeded. + do + (condition-case nil + (progn + (mmm-make-region + (or matched-submode submode) beg end + :face (or matched-face face) + :front front-pos :back back-pos + :evaporation 'front + :match-front matched-front :match-back matched-back + :beg-sticky beg-sticky :end-sticky end-sticky + :name matched-name + :delimiter-mode delimiter-mode + :front-face front-face :back-face back-face + :creation-hook creation-hook + ) + (goto-char ok-resume)) + ;; If our region is invalid, go back to the end of the + ;; front match and continue on. + (mmm-error (goto-char invalid-resume))) + ;; If match-submode was unable to find a match, go back to + ;; the end of the front match and continue on. + else do (goto-char invalid-resume) + ))))) + +;;}}} +;;{{{ Match Regions + +(cl-defun mmm-match-region + (&key start stop front back front-verify back-verify + front-delim back-delim + include-front include-back front-offset back-offset + front-form back-form save-matches match-submode match-face + front-match back-match end-not-begin + save-name match-name + &allow-other-keys) + "Find the first valid region between point and STOP. +Return \(BEG END FRONT-POS BACK-POS FRONT-FORM BACK-FORM SUBMODE FACE +NAME INVALID-RESUME OK-RESUME) specifying the region. See +`mmm-match-and-verify' for the valid values of FRONT and BACK +\(markers, regexps, or functions). A nil value for END means that +MATCH-SUBMODE failed to find a valid submode. INVALID-RESUME is the +point at which the search should continue if the region is invalid, +and OK-RESUME if the region is valid." + (when (mmm-match-and-verify front start stop front-verify) + (let ((beg (mmm-match->point include-front front-offset front-match)) + (front-pos (if front-delim + (mmm-match->point t front-delim front-match) + nil)) + (invalid-resume (match-end front-match)) + (front-form (mmm-get-form front-form))) + (let ((submode (if match-submode + (condition-case nil + (mmm-save-all + (funcall match-submode front-form)) + (mmm-no-matching-submode + (cl-return-from + mmm-match-region + (cl-values beg nil nil nil nil nil nil nil nil + invalid-resume nil)))) + nil)) + (name (cond ((functionp match-name) + (mmm-save-all (funcall match-name front-form))) + ((stringp match-name) + (if save-name + (mmm-format-matches match-name) + match-name)))) + (face (cond ((functionp match-face) + (mmm-save-all + (funcall match-face front-form))) + (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 back-match)) + (back-pos (if back-delim + (mmm-match->point nil back-delim back-match) + nil)) + (back-form (mmm-get-form back-form)) + (ok-resume (if end-not-begin + (match-end back-match) + end))) + (cl-values beg end front-pos back-pos front-form back-form + submode face name + invalid-resume ok-resume))))))) + +(defun mmm-match->point (beginp offset match) + "Find a point of starting or stopping from the match data. If +BEGINP, start at \(match-beginning MATCH), else \(match-end MATCH), +and move OFFSET. Handles all values of OFFSET--see `mmm-classes-alist'." + (save-excursion + (goto-char (if beginp + (match-beginning match) + (match-end 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) + (cl-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 diff --git a/mmm-cmds.el b/mmm-cmds.el new file mode 100644 index 0000000..3de5166 --- /dev/null +++ b/mmm-cmds.el @@ -0,0 +1,443 @@ +;;; mmm-cmds.el --- MMM Mode interactive commands and keymap + +;; Copyright (C) 2000-2003, 2011-2013, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains the interactive commands for MMM Mode. + +;;; Code: + +(require 'cl-lib) +(require 'font-lock) +(require 'mmm-compat) +(require 'mmm-vars) +(require 'mmm-class) + +;; APPLYING CLASSES +;;{{{ 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: " + (cl-remove-duplicates + (mapcar (lambda (spec) (list (symbol-name (car spec)))) + (append + (cl-remove-if (lambda (spec) (plist-get (cdr spec) :private)) + mmm-classes-alist) + (cl-remove-if #'caddr mmm-autoloaded-classes))) + :test #'equal) + 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)) + +;;}}} + +;; EDITING WITH REGIONS +;;{{{ 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...") + (cl-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))))) + +;;}}} +;;{{{ Reparse Current Region + +(defun mmm-reparse-current-region () + "Clear and reparse the area of the current submode region. +Use this command if a submode region's boundaries have become wrong." + (interactive) + (let ((ovl (mmm-overlay-at (point) 'all))) + (when ovl + (let ((beg (save-excursion + (goto-char (mmm-front-start ovl)) + (forward-line -1) + (point))) + (end (save-excursion + (goto-char (mmm-back-end ovl)) + (forward-line 1) + (point)))) + (mmm-parse-region beg end))))) + +;;}}} +;;{{{ Clear Submode Regions + +;; See also `mmm-clear-history' which is interactive. + +(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)) + +;;}}} +;;{{{ End Current Region + +(cl-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 "") + (cl-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)))))) + +;;}}} +;;{{{ Narrow to Region + +(defun mmm-narrow-to-submode-region (&optional pos) + "Narrow to the submode region at point." + (interactive) + ;; Probably don't use mmm-current-overlay here, because this is + ;; sometimes called from inside messy functions. + (let ((ovl (mmm-overlay-at pos))) + (when ovl + (narrow-to-region (overlay-start ovl) (overlay-end ovl))))) + +;; The inverse command is `widen', usually on `C-x n w' + +;;}}} + +;; INSERTING REGIONS +;;{{{ Insert regions by keystroke + +;; This is the "default" binding in the MMM Mode keymap. Keys defined +;; 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 (cl-subsetp mmm-insert-modifiers mods) + (mmm-insert-by-key + (append (cl-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." + (cl-multiple-value-bind (class skel str) (mmm-get-insertion-spec key) + (when skel + (let ((after-change-functions nil) + (old-undo buffer-undo-list) undo) + ;; XEmacs' skeleton doesn't manage positions by itself, so we + ;; have to do it. + (if mmm-xemacs (setq skeleton-positions nil)) + (skeleton-proxy-new skel str arg) + (cl-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)) + (match-face (plist-get class :match-face)) + (match-name (plist-get class :match-name)) + (front-form (regexp-quote (buffer-substring front beg))) + (back-form (regexp-quote (buffer-substring end back))) + submode face name) + (setq submode + (mmm-modename->function + (if match-submode + (mmm-save-all (funcall match-submode front-form)) + (plist-get class :submode)))) + (setq face + (cond ((functionp match-face) + (mmm-save-all + (funcall match-face front-form))) + (match-face + (cdr (assoc front-form match-face))) + (t + (plist-get class :face)))) + (setq name + (cond ((plist-get class :skel-name) + ;; Optimize the name to the user-supplied str + ;; if we are so instructed. + str) + ;; Call it if it is a function + ((functionp match-name) + (mmm-save-all (funcall match-name front-form))) + ;; Now we know it's a string, does it need to + ;; be formatted? + ((plist-get class :save-name) + ;; Yes. Haven't done a match before, so + ;; match the front regexp against the given + ;; form to format the string + (string-match (plist-get class :front) + front-form) + (mmm-format-matches match-name front-form)) + (t + ;; No, just use it as-is + match-name))) + (mmm-make-region + submode beg end + :face face + :name name + :front front :back back + :match-front front-form :match-back back-form + :evaporation 'front +;;; :beg-sticky (plist-get class :beg-sticky) +;;; :end-sticky (plist-get class :end-sticky) + :beg-sticky t :end-sticky t + :creation-hook (plist-get class :creation-hook)) + (mmm-enable-font-lock submode))) + ;; Now get rid of intermediate undo boundaries, so that the entire + ;; insertion can be undone as one action. This should really be + ;; skeleton's job, but it doesn't do it. + (setq undo buffer-undo-list) + (while (not (eq (cdr undo) old-undo)) + (when (eq (cadr undo) nil) + (setcdr undo (cddr undo))) + (setq undo (cdr undo))))))) + +(defun mmm-get-insertion-spec (key &optional classlist) + "Get the insertion info for KEY from all classes in CLASSLIST. +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." + (cl-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)) + +;;}}} +;;{{{ 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." + (cl-remove-duplicates + (cl-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-(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 diff --git a/mmm-compat.el b/mmm-compat.el new file mode 100644 index 0000000..c594575 --- /dev/null +++ b/mmm-compat.el @@ -0,0 +1,130 @@ +;;; mmm-compat.el --- MMM Hacks for compatibility with other Emacsen + +;; Copyright (C) 2000, 2003, 2011, 2013 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file provides a number of hacks that are necessary for MMM +;; Mode to function in different Emacsen. MMM Mode is designed for +;; FSF Emacs, but these hacks usually enable it to work +;; almost perfectly in XEmacs 21. + +;;; Code: + +;;{{{ Emacsen Detection + +(defvar mmm-xemacs (featurep 'xemacs) + "Whether we are running XEmacs.") + +;;}}} +;;{{{ Regexp-Opt (XEmacs) + +;; As of XEmacs' xemacs-base package version 1.82, +;; the regexp-opt API is compatible with GNU Emacs. +(defalias 'mmm-regexp-opt 'regexp-opt) + +;;}}} +;;{{{ 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 with name based on NAME including the text of BUFFER. +This text should not be modified." + (if (fboundp 'make-indirect-buffer) + `(make-indirect-buffer ,buffer (generate-new-buffer-name ,name)) + `(save-excursion + (set-buffer (generate-new-buffer ,name)) + (insert-buffer ,buffer) + (current-buffer)))) + +;;}}} +;;{{{ Emacs < 26 requires namespaced CL functions + +(if (>= emacs-major-version 26) + (defalias 'mmm-mapcan 'mapcan) + (require 'cl-lib) + (defalias 'mmm-mapcan 'cl-mapcan)) + +;;}}} + +(provide 'mmm-compat) + +;;; mmm-compat.el ends here diff --git a/mmm-cweb.el b/mmm-cweb.el new file mode 100644 index 0000000..ef399db --- /dev/null +++ b/mmm-cweb.el @@ -0,0 +1,100 @@ +;;; mmm-cweb.el --- MMM submode class for CWeb programs + +;; Copyright (C) 2001, 2002, 2013 Free Software Foundation, Inc. + +;; Author: Alan Shutko <ats@acm.org> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains the definition of an MMM Mode submode class for +;; editing CWeb programs. + +;;; Code: + +(require 'mmm-compat) +(require 'mmm-vars) +(require 'mmm-auto) + +(defvar mmm-cweb-section-tags + '("@ " "@*")) + +(defvar mmm-cweb-section-regexp + (concat "^" (mmm-regexp-opt mmm-cweb-section-tags t))) + +(defvar mmm-cweb-c-part-tags + '("@c" "@>=" "@>+=" "@p")) + +(defvar mmm-cweb-c-part-regexp + (concat (mmm-regexp-opt mmm-cweb-c-part-tags t))) + +(defun mmm-cweb-in-limbo (pos) + "Check to see if POS is in limbo, ie before any cweb sections." + (save-match-data + (save-excursion + (goto-char pos) + (not (re-search-backward mmm-cweb-section-regexp nil t))))) + +(defun mmm-cweb-verify-brief-c () + "Verify function for cweb-brief-c class. +Checks whether the match is in limbo." + (not (mmm-cweb-in-limbo (match-beginning 0)))) + +(mmm-add-group + 'cweb + `( + (cweb-c-part + :submode c-mode + :front ,mmm-cweb-c-part-regexp + :back ,mmm-cweb-section-regexp) + (cweb-label + :submode tex-mode + :front "@<" + :back "@>" + :face mmm-comment-submode-face + :insert ((?l cweb-label nil @ "@<" @ "@>"))) + (cweb-brief-c + :submode c-mode + :front "[^\\|]\\(|\\)[^|]" + :front-match 1 + :front-verify mmm-cweb-verify-brief-c +; :front-offset -1 + :back "[^\\|]\\(|\\)" + :back-match 1 +; :back-offset 1 + :end-not-begin t + :insert ((?| cweb-c-in-tex nil "|" @ "|"))) + (cweb-comment + :submode tex-mode + :front "/[*]" + :back "[*]/" + :face mmm-comment-submode-face) +)) + +;; (add-to-list 'mmm-mode-ext-classes-alist +;; '(plain-tex-mode "\\.w\\'" cweb)) +;; (add-to-list 'mmm-mode-ext-classes-alist +;; '(latex-mode "\\.w\\'" cweb)) +;; (add-to-list 'auto-mode-alist '("\\.w\\'" . tex-mode)) + +(provide 'mmm-cweb) + +;;; mmm-cweb.el ends here diff --git a/mmm-defaults.el b/mmm-defaults.el new file mode 100644 index 0000000..f4f3eec --- /dev/null +++ b/mmm-defaults.el @@ -0,0 +1,62 @@ +;;; mmm-defaults.el --- Friendly defaults for MMM Mode + +;; Copyright (C) 2013 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov <dgutov@yandex.ru> + +;;{{{ 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: + +;; To enable multiple mode support in ERB, EJS and PHP files, just add the +;; following line to your init file: +;; +;; (require 'mmm-defaults) +;; +;; Note that for PHP you still need to have php-mode (installed separately). +;; +;; TODO: Add more file types and classes here. Mention this file in README. + +;;; Code: + +(require 'mmm-auto) + +(setq mmm-global-mode 'auto) + +;;; ERB and EJS + +(mmm-add-mode-ext-class 'html-erb-mode "\\.erb\\'" 'erb) +(mmm-add-mode-ext-class 'html-erb-mode "\\.ejs\\'" 'ejs) +(mmm-add-mode-ext-class 'html-erb-mode nil 'html-js) +(mmm-add-mode-ext-class 'html-erb-mode nil 'html-css) + +(add-to-list 'auto-mode-alist '("\\.html\\.erb\\'" . html-erb-mode)) +(add-to-list 'auto-mode-alist '("/[^.]+\\.erb\\'" . html-erb-mode)) +(add-to-list 'auto-mode-alist '("\\.jst\\.ejs\\'" . html-erb-mode)) + +;;; PHP + +(mmm-add-mode-ext-class 'html-mode nil 'html-js) +(mmm-add-mode-ext-class 'html-mode nil 'html-css) +(mmm-add-mode-ext-class 'html-mode "\\.php\\'" 'html-php) +(add-to-list 'auto-mode-alist '("\\.html\\.php\\'" . html-mode)) +(add-to-list 'auto-mode-alist '("/[^.]+\\.php\\'" . html-mode)) + +(provide 'mmm-defaults) + +;;; mmm-defaults.el ends here diff --git a/mmm-erb.el b/mmm-erb.el new file mode 100644 index 0000000..b3a5e04 --- /dev/null +++ b/mmm-erb.el @@ -0,0 +1,243 @@ +;;; mmm-erb.el --- ERB templates editing support + +;; Copyright (C) 2012, 2013, 2018 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov <dgutov@yandex.ru> + +;;{{{ 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 definitions of ERB and EJS submode classes, and well as +;; support functions for proper indentation. + +;; Usage: + +;; (require 'mmm-auto) + +;; (setq mmm-global-mode 'auto) + +;; (mmm-add-mode-ext-class 'html-erb-mode "\\.html\\.erb\\'" 'erb) +;; (mmm-add-mode-ext-class 'html-erb-mode "\\.jst\\.ejs\\'" 'ejs) +;; (mmm-add-mode-ext-class 'html-erb-mode nil 'html-js) +;; (mmm-add-mode-ext-class 'html-erb-mode nil 'html-css) + +;; (add-to-list 'auto-mode-alist '("\\.html\\.erb\\'" . html-erb-mode)) +;; (add-to-list 'auto-mode-alist '("\\.jst\\.ejs\\'" . html-erb-mode)) + +;; Optional settings: + +;; (setq mmm-submode-decoration-level 2 +;; mmm-parse-when-idle t) + +;; nXML as primary mode (supports only JS and CSS subregions): + +;; (mmm-add-mode-ext-class 'nxml-web-mode nil 'html-js) +;; (mmm-add-mode-ext-class 'nxml-web-mode nil 'html-css) + +;; (add-to-list 'auto-mode-alist '("\\.xhtml\\'" . nxml-web-mode)) + +;;; Code: + +(require 'sgml-mode) +(require 'cl-lib) +(require 'mmm-vars) +(require 'mmm-region) + +(mmm-add-classes + '((erb :submode ruby-mode :front "<%[#=]?" :back "-?%>" + :match-face (("<%#" . mmm-comment-submode-face) + ("<%=" . mmm-output-submode-face) + ("<%" . mmm-code-submode-face)) + :insert ((?% erb-code nil @ "<%" @ " " _ " " @ "%>" @) + (?# erb-comment nil @ "<%#" @ " " _ " " @ "%>" @) + (?= erb-expression nil @ "<%=" @ " " _ " " @ "%>" @)) + :creation-hook mmm-erb-mark-as-special) + (ejs :submode js-mode :front "<%[#=]?" :back "-?%>" + :match-face (("<%#" . mmm-comment-submode-face) + ("<%=" . mmm-output-submode-face) + ("<%" . mmm-code-submode-face)) + :insert ((?% ejs-code nil @ "<%" @ " " _ " " @ "%>" @) + (?# ejs-comment nil @ "<%#" @ " " _ " " @ "%>" @) + (?= ejs-expression nil @ "<%=" @ " " _ " " @ "%>" @)) + :creation-hook mmm-erb-mark-as-special))) + +(defun mmm-erb-mark-as-special () + "Hook function to run in ERB and EJS tag regions." + (overlay-put mmm-current-overlay 'mmm-special-tag t)) + +;;;###autoload +(define-derived-mode html-erb-mode html-mode "ERB-HTML" + (setq sgml-unclosed-tags nil) ; Simplifies indentation logic. + (set (make-local-variable 'mmm-indent-line-function) #'mmm-erb-indent-line) + (add-hook 'mmm-after-syntax-propertize-functions + #'html-erb-after-syntax-propertize nil t)) + +(defun html-erb-after-syntax-propertize (overlay _mode beg end) + (when overlay + (with-silent-modifications + (funcall + (syntax-propertize-rules ("<\\|>" (0 "."))) + beg end)))) + +(defun mmm-erb-indent-line () + "Indent the current line intelligently." + (interactive) + (let ((offset (- (current-column) (current-indentation)))) + (back-to-indentation) + (mmm-update-submode-region) + (if (and mmm-current-overlay mmm-current-submode + (< (overlay-start mmm-current-overlay) (point-at-bol))) + ;; Region starts before the current line (and contains indentation). + ;; If it starts on the current line, then either first part of the line + ;; is in primary mode, or we're on the first line of a script or style + ;; tag contents. In the latter case, better to also indent it according + ;; to the primary mode (as text): `js-indent-line' ignores narrowing, + ;; gets confused by the angle bracket on the previous line and thus + ;; breaks our "top level" heuristic. + (mmm-erb-indent-line-submode) + (mmm-erb-indent-line-primary)) + (when (> offset 0) (forward-char offset)))) + +(defun mmm-erb-indent-line-submode () + "Indent line within a submode." + (let (added-whitespace) + (if (<= (overlay-end mmm-current-overlay) + (save-excursion (back-to-indentation) (point))) + ;; We're at a closing tag. + (mmm-erb-indent-to-region-start) + (save-restriction + (save-excursion + (goto-char (overlay-start mmm-current-overlay)) + (when (not (looking-at "^\\|\\s-*$")) + ;; Submode region has text on the same line as the opening tag, + ;; pad it with whitespace to make the following lines line up. + (setq added-whitespace (current-column)) + (insert-char ?\s added-whitespace))) + (narrow-to-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay)) + (funcall (mmm-erb-orig-indent-function mmm-current-submode)) + (when added-whitespace + ;; Remove the padding. + (save-excursion + (goto-char (overlay-start mmm-current-overlay)) + (delete-char added-whitespace)))) + ;; If submode indent function moved us to bol, + ;; we're on the top level, indent according to the primary mode. + (when (zerop (current-indentation)) + (mmm-erb-indent-to-region-start + (mmm-erb-indent-offset mmm-primary-mode)))))) + +(defun mmm-erb-indent-to-region-start (&optional additional-offset) + "Indent line to match start of region, possibly adding ADDITIONAL-OFFSET." + (indent-line-to + (save-excursion + (goto-char (1- (overlay-start mmm-current-overlay))) + (+ (current-indentation) + (or additional-offset 0))))) + +(defun mmm-erb-indent-line-primary () + "Indent line in primary mode." + (let* ((here (point)) + ;; Go before previous line's tag. + (start (progn (forward-line -1) + (back-to-indentation) + (let ((lcon (sgml-lexical-context))) + (when (eq (car lcon) 'tag) + ;; Tag spreads several lines. + (goto-char (cdr lcon)) + (back-to-indentation))) + (point))) + (regions (mmm-regions-in start here)) + (n 0)) + ;; Collect indent modifier depending on type of tags. + (cl-loop for region in regions + for type = (mmm-erb-scan-region region) + when type do + (if (eq type 'close) + (when (cl-plusp n) (cl-decf n)) + (cl-incf n (if (eq type 'close) 0 1)))) + (let ((eol (progn (goto-char here) (end-of-line 1) (point)))) + ;; Look for "else" and "end" instructions to adjust modifier. + ;; If a block start instruction comes first, abort. + (cl-loop for region in (mmm-regions-in here eol) + for type = (mmm-erb-scan-region region) + until (eq type 'open) + when (memq type '(middle close)) do (cl-decf n))) + (goto-char here) + (funcall (mmm-erb-orig-indent-function mmm-primary-mode)) + (let* ((indent (current-indentation)) + (indent-step (mmm-erb-indent-offset mmm-primary-mode))) + (indent-line-to (+ indent (if n (* indent-step n) 0)))))) + +(defun mmm-erb-scan-region (region) + (when region ; Can be nil if a line is empty, for example. + (cl-destructuring-bind (submode beg end ovl) region + (let ((scan-fn (plist-get '(ruby-mode mmm-erb-scan-erb + js-mode mmm-erb-scan-ejs) + submode))) + (and scan-fn + (overlay-get ovl 'mmm-special-tag) + (save-excursion + (goto-char beg) + (skip-syntax-forward "-") + (funcall scan-fn end))))))) + +(defconst mmm-erb-ruby-close-re "\\<end\\>\\|}" + "Regexp to match the end of a Ruby block.") + +(defun mmm-erb-scan-erb (limit) + (cond ((looking-at "\\(?:if\\|unless\\|for\\|while\\)\\b") 'open) + ((looking-at "\\(?:else\\|elsif\\)\\b") 'middle) + ((looking-at mmm-erb-ruby-close-re) 'close) + ((and (re-search-forward (concat "\\(?: +do +\\| *{ *\\)" + "\\(?:|[A-Za-z0-9_, ]*|\\)? *") + limit t) + (let ((pt (point))) + (not (when (< pt limit) + (goto-char limit) + (skip-syntax-backward "-") + (looking-back mmm-erb-ruby-close-re pt))))) + 'open))) + +(defun mmm-erb-scan-ejs (limit) + (cond ((looking-at "\\(?:if\\|for\\|while\\)\\b") 'open) + ((looking-at "} *else\\b") 'middle) + ((looking-at "}") 'close) + ((re-search-forward " *{ *" limit t) 'open))) + +(defun mmm-erb-orig-indent-function (mode) + (get mode 'mmm-indent-line-function)) + +(defvar mmm-erb-offset-var-alist + '((html-erb-mode . sgml-basic-offset) + (nxml-web-mode . nxml-child-indent))) + +(defun mmm-erb-indent-offset (mode) + (let ((name (cdr (assoc mode mmm-erb-offset-var-alist)))) + (when name (symbol-value name)))) + +;;;###autoload +(define-derived-mode nxml-web-mode nxml-mode "nXML-Web" + (set (make-local-variable 'mmm-indent-line-function) #'mmm-erb-indent-line)) + +(provide 'mmm-erb) + +;;; mmm-erb.el ends here diff --git a/mmm-mason.el b/mmm-mason.el new file mode 100644 index 0000000..240ddfc --- /dev/null +++ b/mmm-mason.el @@ -0,0 +1,175 @@ +;;; mmm-mason.el --- MMM submode class for Mason components + +;; Copyright (C) 2000-2003, 2013, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains the definition of an MMM Mode submode class for +;; editing 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 + :match-name "~1" + :save-name 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))) + +;;}}} +;;{{{ Set Mode Line + +(defun mmm-mason-set-mode-line () + (setq mmm-buffer-mode-display-name "Mason")) +(add-hook 'mmm-mason-class-hook #'mmm-mason-set-mode-line) + +;;}}} + +(provide 'mmm-mason) + +;;; mmm-mason.el ends here diff --git a/mmm-mode.el b/mmm-mode.el new file mode 100644 index 0000000..cca89b8 --- /dev/null +++ b/mmm-mode.el @@ -0,0 +1,309 @@ +;;; mmm-mode.el --- Allow Multiple Major Modes in a buffer + +;; Copyright (C) 1999-2004, 2012-2015, 2018 Free Software Foundation, Inc. + +;; Emacs Lisp Archive Entry +;; Package: mmm-mode +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> +;; Maintainer: Dmitry Gutov <dgutov@yandex.ru> +;; URL: https://github.com/purcell/mmm-mode +;; Keywords: convenience, faces, languages, tools +;; Version: 0.5.7 +;; Package-Requires: ((cl-lib "0.2")) + +;;{{{ 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 +;; `cl-mapl', `cl-loop' and `cl-destructuring-bind', I try not to use `cl-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 `cl-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. + +;;}}} + +;;; Code: + +(require 'cl-lib) +;; 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 \"primary\" major mode that controls +most of the buffer, and a number of \"submodes\" that each hold sway +over certain regions. The submode regions are usually highlighted by +a background color for ease of recognition. While the point is in a +submode region, the following changes \(are supposed to) occur: + +1. The local keymap and the syntax table are that of the submode. +2. The mode line changes to show what submode region is active. +3. The major mode menu and mouse popup menu are that of the submode. +4. Some local variables of the submode shadow the default mode's. +5. Font-lock fontifies correctly for the submode. +6. Indentation function dispatches to the appropriate submode. +7. User-specified hooks run when the point enters or exits a submode. + +The user may specify a number of hooks which may run when the point +transitions between submodes, or between the primary mode and a +submode. When a major mode is entered, the hook mmm-x-enter-hook is +run, where x is the name of the major mode. When a major mode is +left, the hook mmm-y-exit-hook is run, where y is the name of the +major mode. Users may also specify hooks with names of the form +mmm-x-y-hook which are run when the point leaves a mode named x, +and enters a mode named y. + +For further information, including installation and configuration +instructions, see the Info file mmm.info which is included with the +distribution of MMM Mode. Many of MMM's configuration variables are +available through M-x customize-group RET mmm." + (interactive "P") + (if (if arg (> (prefix-numeric-value arg) 0) (not mmm-mode)) + (mmm-mode-on) + (mmm-mode-off))) + +(add-to-list 'minor-mode-alist (list 'mmm-mode mmm-mode-string)) + +;;}}} +;;{{{ Mode On + +(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) + (when (fboundp 'c-make-styles-buffer-local) + (c-make-styles-buffer-local t)) + (mmm-update-mode-info major-mode) + (setq mmm-region-saved-locals-for-dominant + ;; FIXME: Neither is defined in recent Emacs. + (cl-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 nil) + (mmm-add-hooks) + (mmm-fixup-skeleton) + (set (make-local-variable 'font-lock-fontify-region-function) + #'mmm-fontify-region) + (when (boundp 'syntax-begin-function) + (set (make-local-variable 'syntax-begin-function) nil)) + (set (make-local-variable 'syntax-propertize-function) + #'mmm-syntax-propertize-function) + (set (make-local-variable 'indent-line-function) mmm-indent-line-function) + (setq mmm-mode t) + (condition-case err + (mmm-apply-all) + (mmm-error + ;; Complain, but don't die, since we want files to go ahead + ;; and be opened anyway, and the mode to go ahead and be + ;; turned on. Should we delete all previously made submode + ;; regions when we find an invalid one? + (message "%s" (error-message-string err)))) + (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)) + (mmm-update-font-lock-buffer) + (mmm-refontify-maybe) + (setq mmm-mode nil) + ;; Restore the mode line + (setq mmm-primary-mode-display-name nil + mmm-buffer-mode-display-name nil) + (mmm-set-mode-line))) + +;;}}} +;;{{{ Mode Keymap + +(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 &optional keymap) + (define-key (or keymap 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) + +(mmm-define-key ?z 'mmm-narrow-to-submode-region) + +;; This one is exact, since C-h is (usually) already used for help. +(define-key mmm-mode-prefix-map [?h] 'mmm-insertion-help) + +;; 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 diff --git a/mmm-mode.spec b/mmm-mode.spec new file mode 100644 index 0000000..15005fe --- /dev/null +++ b/mmm-mode.spec @@ -0,0 +1,40 @@ +Summary: Emacs - Edit different parts of a file in different major modes +Name: mmm-mode +Version: 0.4.7 +Release: 1 +URL: http://unc.dl.sourceforge.net/sourceforge/mmm-mode +Source0: ${URL}/%{name}-%{version}.tar.gz +License: GPL; Michael Abraham Shulman <viritrilbia@gmail.com> +Group: Applications/Editors +BuildRoot: %{_tmppath}/%{name}-%(id -u -n) +BuildArch: noarch +Requires: emacs + +%description +MMM Mode is an add-on package for emacs that enables the user to edit +different parts of a file in different major modes. It is well suited +for editing embedded code and code-generating code. + +%prep +%setup -q +%configure + +%build +%__make + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc AUTHORS ChangeLog FAQ INSTALL NEWS README README.Mason TODO +%{_infodir}/mmm.info* +%{_datadir}/emacs/site-lisp/*.el* + +%changelog +* Sat Mar 22 2003 <bishop@flotsam.platypus.bc.ca> +- Initial build. diff --git a/mmm-myghty.el b/mmm-myghty.el new file mode 100644 index 0000000..d893a2f --- /dev/null +++ b/mmm-myghty.el @@ -0,0 +1,187 @@ +;;; mmm-myghty.el --- MMM submode class for Myghty components + +;; Copyright (C) 2000, 2004, 2013, 2018 Free Software Foundation, Inc. + +;; Author: Ben Bangert +;; Original Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net> + +;; Based on mmm-mason.el, trivial changes by Ben Bangert + +;;{{{ 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: + +;; I went to the hard (sarcasm) effort of applying two global +;; search/replaces, and adding a few keywords for additional +;; blocks that Myghty introduced. Many thanks to Michael for writing +;; the mmm-mason without which I would never have found the time +;; to patch up for Myghty. + +;;; Code: + +(require 'mmm-compat) +(require 'mmm-vars) +(require 'mmm-auto) + +;;{{{ Python Tags + +(defvar mmm-myghty-python-tags + '("python" "init" "cleanup" "once" "filter" "shared" "global" + "threadlocal" "requestlocal" + "python_init" "python_cleanup" "python_once" "python_filter")) + +(defvar mmm-myghty-pseudo-python-tags + '("args" "python_args" "attr" "flags")) + +(defvar mmm-myghty-non-python-tags + '("doc" "python_doc" "text" "python_text" "def" "python_def" "method")) + +(defvar mmm-myghty-python-tags-regexp + (concat "<%" (mmm-regexp-opt mmm-myghty-python-tags t) ">") + "Matches tags beginning Myghty sections containing Python code. +Saves the name of the tag matched.") + +(defvar mmm-myghty-pseudo-python-tags-regexp + (concat "<%" (mmm-regexp-opt mmm-myghty-pseudo-python-tags t) ">") + "Match tags beginning Myghty sections that look like Python but aren't. +Saves the name of the tag matched.") + +(defvar mmm-myghty-tag-names-regexp + (regexp-opt (append mmm-myghty-python-tags mmm-myghty-non-python-tags) t) + "Matches any Myghty tag name after the \"<%\". Used to verify that a +\"<%\" sequence starts an inline section.") + +(defun mmm-myghty-verify-inline () + (not (looking-at mmm-myghty-tag-names-regexp))) + +;;}}} +;;{{{ Add Classes + +(mmm-add-group + 'myghty + `((myghty-text + :submode nil + :front "<%text>" + :back "</%text>" + :insert ((?t myghty-<%text> nil @ "<%text>" @ "\n" + _ "\n" @ "</%text>" @))) + (myghty-doc + :submode text-mode + :face mmm-comment-submode-face + :front "<%doc>" + :back "</%doc>" + :face nil + :insert ((?d myghty-<%doc> nil @ "<%doc>" @ "\n" + _ "\n" @ "</%doc>" @))) + (myghty-python + :submode python + :match-face (("<%python>" . mmm-code-submode-face) + ("<%init>" . mmm-init-submode-face) + ("<%cleanup>" . mmm-cleanup-submode-face) + ("<%once>" . mmm-init-submode-face) + ("<%global>" . mmm-init-submode-face) + ("<%filter>" . mmm-special-submode-face) + ("<%shared>" . mmm-init-submode-face) + ("<%threadlocal>" . mmm-init-submode-face) + ("<%requestlocal>" . mmm-init-submode-face)) + :front ,mmm-myghty-python-tags-regexp + :back "</%~1>" + :save-matches 1 + :match-name "~1" + :save-name 1 + :insert ((?, myghty-<%TAG> "Python section: " @ "<%" str ">" @ + ";\n" _ "\n" @ "</%" str ">" @) + (?< myghty-<%TAG> ?, . nil) + (?p myghty-<%python> ?, . "python") + (?i myghty-<%init> ?, . "init") + (?c myghty-<%cleanup> ?, . "cleanup") + (?o myghty-<%once> ?, . "once") + (?g myghty-<%global> ?, . "global") + (?t myghty-<%threadlocal> ?, . "threadlocal") + (?e myghty-<%requestlocal> ?, . "requestlocal") + (?l myghty-<%filter> ?, . "filter") + (?s myghty-<%shared> ?, . "shared"))) + (myghty-pseudo-python + :submode python + :face mmm-declaration-submode-face + :front ,mmm-myghty-pseudo-python-tags-regexp + :back "</%~1>" + :save-matches 1 + :insert ((?. myghty-pseudo-<%TAG> "Pseudo-python section: " @ "<%" str ">" @ + "\n" _ "\n" @ "</%" str ">" @) + (?> myghty-pseudo-<%TAG> ?, . nil) + (?a myghty-<%args> ?. . "args") + (?f myghty-<%flags> ?. . "flags") + (?r myghty-<%attr> ?. . "attr"))) + (myghty-inline + :submode python + :face mmm-output-submode-face + :front "<%" + :front-verify mmm-myghty-verify-inline + :back "%>" + :insert ((?% myghty-<%-%> nil @ "<%" @ " " _ " " @ "%>" @) + (?5 myghty-<%-%> ?% . nil))) + (myghty-call + :submode python + :face mmm-special-submode-face + :front "<&" + :back "&>" + :insert ((?& myghty-<&-&> nil @ "<&" @ " " _ " " @ "&>" @) + (?7 myghty-<&-&> ?% . nil))) + (myghty-one-line-comment + :submode text-mode + :face mmm-comment-submode-face + :front "^%#" + :back "\n" + :insert ((?# myghty-%-comment nil (mmm-myghty-start-line) + @ "%" @ "# " _ @ '(mmm-myghty-end-line) "\n" @) + (?3 myghty-%-comment ?# . nil))) + (myghty-one-line + :submode python + :face mmm-code-submode-face + :front "^%" + :back "\n" + :insert ((return myghty-%-line nil (mmm-myghty-start-line) + @ "%" @ " " _ @ '(mmm-myghty-end-line) "\n" @))))) + +;;}}} +;;{{{ One-line Sections + +(defun mmm-myghty-start-line () + (if (bolp) + "" + "\n")) + +(defun mmm-myghty-end-line () + (if (eolp) + (delete-char 1))) + +;;}}} +;;{{{ Set Mode Line + +(defun mmm-myghty-set-mode-line () + (setq mmm-buffer-mode-display-name "Myghty")) +(add-hook 'mmm-myghty-class-hook #'mmm-myghty-set-mode-line) + +;;}}} + +(provide 'mmm-myghty) + +;;; mmm-myghty.el ends here diff --git a/mmm-noweb.el b/mmm-noweb.el new file mode 100644 index 0000000..feea5fb --- /dev/null +++ b/mmm-noweb.el @@ -0,0 +1,421 @@ +;;; mmm-noweb.el --- MMM submode class for Noweb programs +;; +;; Copyright 2003, 2004 Joe Kelsey <joe@zircon.seattle.wa.us> +;; Copyright 2018 Free Software Foundation, Inc. +;; +;; The filling, completion and chunk motion commands either taken +;; directly from or inspired by code in: +;; noweb-mode.el - edit noweb files with GNU Emacs +;; Copyright 1995 by Thorsten.Ohl @ Physik.TH-Darmstadt.de +;; with a little help from Norman Ramsey <norman@bellcore.com> +;; + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains the definition of an MMM Mode submode class for +;; editing Noweb programs. +;; +;; FIXME: The more advanced features don't work: `mmm-name-at' and +;; `mmm-syntax-region' are undefined. Need to dig around in the bug reports +;; and/or discussions, wherever the code using them was submitted. + +;;; Code: + +(require 'cl-lib) +(require 'mmm-region) +(require 'mmm-vars) +(require 'mmm-mode) + +;;{{{ Variables + +(defvar mmm-noweb-code-mode 'fundamental-mode + "*Major mode for editing code chunks. +This is set to FUNDAMENTAL-MODE by default, but you might want to change +this in the Local Variables section of your file to something more +appropriate, like C-MODE, FORTRAN-MODE, or even INDENTED-TEXT-MODE." + ;; FIXME: Any of CC Mode modes aren't really appropriate: + ;; https://github.com/purcell/mmm-mode/issues/57 + ) + +(defvar mmm-noweb-quote-mode nil + "*Major mode for quoted code chunks within documentation chunks. +If nil, defaults to `mmm-noweb-code-mode', which see.") + +(defvar mmm-noweb-quote-string "quote" + "*String used to form quoted code submode region names. +See `mmm-noweb-quote'.") + +(defvar mmm-noweb-quote-number 0 + "*Starting value appended to `mmm-noweb-quote-string'. +See `mmm-noweb-quote'.") + +(defvar mmm-noweb-narrowing nil + "*Narrow the region to the current pair of chunks.") + +;;}}} +;;{{{ Support for mmm submode stuff + +(defun mmm-noweb-chunk (_form) + "Return the noweb code mode chosen by the user. +If the next 100 characters of the buffer contain a string of the form +\"-*- MODE -*-\", then return MODE as the chosen mode, otherwise +return the value of `mmm-noweb-code-mode'." + ;; Look for -*- mode -*- in the first two lines. + ;; 120 chars = 40 chars for #! + 80 chars for following line... + (if (re-search-forward "-\\*-\\s +\\(\\S-+\\)\\s +-\\*-" (+ (point) 120) t) + (let* ((string (match-string-no-properties 1)) + (modestr (intern (if (string-match "mode\\'" string) + string + (concat string "-mode"))))) + (or (mmm-ensure-modename modestr) + mmm-noweb-code-mode)) + mmm-noweb-code-mode)) + +(defun mmm-noweb-quote (_form) + "Create a unique name for a quoted code region within a documentation chunk." + (or mmm-noweb-quote-mode + mmm-noweb-code-mode)) + +(defun mmm-noweb-quote-name (_form) + "Create a unique name for a quoted code region within a documentation chunk." + (setq mmm-noweb-quote-number (1+ mmm-noweb-quote-number)) + (concat mmm-noweb-quote-string "-" + (number-to-string mmm-noweb-quote-number))) + +(defun mmm-noweb-chunk-name (form) + "Get the chunk name from FRONT-FORM." + (string-match "<<\\(.*\\)>>=" form) + (match-string-no-properties 1 form)) + +;;}}} +;;{{{ mmm noweb submode group + +;; We assume that the global document mode is latex or whatever, the +;; user wants. This class controls the code chunk submodes. We use +;; match-submode to either return the value in mmm-noweb-code-mode or to +;; look at the first line of the chunk for a submode setting. We reset +;; case-fold-search because chunk names are case sensitive. The front +;; string identifies the chunk name between the <<>>. Since this is +;; done, name-match can use the same functions as save-matches for back. +;; Our insert skeleton places a new code chunk and the skel-name lets us +;; optimize the skelton naming to use the inserted string. + +(mmm-add-group + 'noweb + '((noweb-chunk + :match-submode mmm-noweb-chunk + :case-fold-search nil + :front "^<<\\(.*\\)>>=" + :match-name "~1" + :save-name 1 + :front-offset (end-of-line 1) + :back "^@\\( \\|$\\|\\( %def .*$\\)\\)" + :insert ((?c noweb-code "Code Chunk Name: " + "\n" @ "<<" str ">>=" @ "\n" _ "\n" @ "@ " @ "\n")) + :skel-name t + ) + (noweb-quote + :match-submode mmm-noweb-quote + :face mmm-special-submode-face + :front "\\[\\[" +; :name-match mmm-noweb-quote-name + :back "\\]\\]" + :insert ((?q noweb-quote nil @ "[[" @ _ @ "]]" @)) + ) + )) + +;;}}} +;;{{{ Noweb regions + +(defun mmm-noweb-regions (start stop regexp) + "Return a liat of regions of the form (NAME BEG END) that exclude +names which match REGEXP." + (let* ((remove-next nil) + (regions + (cl-maplist (lambda (pos-list) + (if (cdr pos-list) + (if remove-next + (setq remove-next nil) + (let ((name (or (mmm-name-at (car pos-list) 'beg) + (symbol-name mmm-primary-mode)))) + (if (and regexp (string-match regexp name) ) + (progn + (setq remove-next t) + nil) + (list name + (car pos-list) (cadr pos-list))))))) + (mmm-submode-changes-in start stop)))) + ;; The above loop leaves lots of nils in the list... + ;; Removing them saves us from having to do the (last x 2) + ;; trick that mmm-regions-in does. + (setq regions (delq nil regions)))) + +;;}}} +;;{{{ Filling, etc + +(defun mmm-noweb-narrow-to-doc-chunk () + "Narrow to the current doc chunk. +The current chunk includes all quoted code chunks (i.e., \[\[...\]\]). +This function is only valid when called with point in a doc chunk or +quoted code chunk." + (interactive) + (let ((name (mmm-name-at (point)))) + (if (or (null name) (string-match "^quote" name)) + (let ((prev (cond + ((= (point) (point-min)) (point)) + (t (cadar (last (mmm-noweb-regions (point-min) (point) + "^quote")))))) + (next (cond + ((= (point) (point-max)) (point)) + (t (save-excursion + (goto-char (cadr + (cadr (mmm-noweb-regions (point) + (point-max) + "^quote")))) + (forward-line -1) + (point)))))) + (narrow-to-region prev next))))) + +(defun mmm-noweb-fill-chunk (&optional justify) + "Fill the current chunk according to mode. +Run `fill-region' on documentation chunks and `indent-region' on code +chunks." + (interactive "P") + (save-restriction + (let ((name (mmm-name-at (point)))) + (if (and name (not (string-match "^quote" name))) + (if (or indent-region-function indent-line-function) + (progn + (mmm-space-other-regions) + (indent-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay) nil)) + (error "No indentation functions defined in %s!" major-mode)) + (progn + (mmm-word-other-regions) + (fill-paragraph justify))) + (mmm-undo-syntax-other-regions)))) + +(defun mmm-noweb-fill-paragraph-chunk (&optional justify) + "Fill a paragraph in the current chunk." + (interactive "P") + (save-restriction + (let ((name (mmm-name-at (point)))) + (if (and name (not (string-match "^quote" name))) + (progn + (mmm-space-other-regions) + (fill-paragraph justify)) + (progn + (mmm-word-other-regions) + (fill-paragraph justify))) + (mmm-undo-syntax-other-regions)))) + +(defun mmm-noweb-fill-named-chunk (&optional _justify) + "Fill the region containing the named chunk." + (interactive "P") + (save-restriction + (let* ((name (or (mmm-name-at) (symbol-name mmm-primary-mode))) + (list (cdr (assoc name (mmm-names-alist (point-min) (point-max)))))) + (if (or (string= name (symbol-name mmm-primary-mode)) + (string-match "^quote" name)) + (progn + (mmm-word-other-regions) + (do-auto-fill)) + (progn + (mmm-space-other-regions) + (indent-region (caar list) (cadar (last list)) nil))) + (mmm-undo-syntax-other-regions)))) + +(defun mmm-noweb-auto-fill-doc-chunk () + "Replacement for `do-auto-fill'." + (save-restriction + (mmm-noweb-narrow-to-doc-chunk) + (mmm-word-other-regions) + (do-auto-fill) + (mmm-undo-syntax-other-regions))) + +(defun mmm-noweb-auto-fill-doc-mode () + "Install the improved auto fill function, iff necessary." + (if auto-fill-function + ;; FIXME: Use add-function? + (setq auto-fill-function #'mmm-noweb-auto-fill-doc-chunk))) + +(defun mmm-noweb-auto-fill-code-mode () + "Install the default auto fill function, iff necessary." + (if auto-fill-function + ;; FIXME: Use remove-function? + (setq auto-fill-function #'do-auto-fill))) + +;;}}} +;;{{{ Functions on named chunks + +(defun mmm-noweb-complete-chunk () + "Try to complete the chunk name." + (interactive) + (let ((end (point)) + (beg (save-excursion + (if (re-search-backward "<<" + (save-excursion + (beginning-of-line) + (point)) + t) + (match-end 0) + nil)))) + (if beg + (let* ((pattern (buffer-substring beg end)) + (alist (mmm-names-alist (point-min) (point-max))) + (completion (try-completion pattern alist))) + (cond ((eq completion t)) + ((null completion) + (message "Can't find completion for \"%s\"" pattern) + (ding)) + ((not (string= pattern completion)) + (delete-region beg end) + (insert completion) + (if (not (looking-at ">>")) + (insert ">>"))) + (t + (message "Making completion list...") + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (all-completions pattern alist))) + (message "Making completion list...%s" "done")))) + (message "Not at chunk name...")))) + +(defvar mmm-noweb-chunk-history nil + "History for `mmm-noweb-goto-chunk'.") + +(defun mmm-noweb-goto-chunk () + "Goto the named chunk." + (interactive) + (widen) + (let* ((completion-ignore-case t) + (alist (mmm-names-alist (point-min) (point-max))) + (chunk (completing-read + "Chunk: " alist nil t + (mmm-name-at (point)) + mmm-noweb-chunk-history))) + (goto-char (caadr (assoc chunk alist))))) + +(defun mmm-noweb-goto-next (&optional cnt) + "Goto the continuation of the current chunk." + (interactive "p") + (widen) + (let ((name (mmm-name-at (point)))) + (if name + (let ((list (cdr (assoc name (mmm-names-alist + (overlay-end mmm-current-overlay) + (point-max)))))) + (if list + (goto-char (caar (nthcdr (1- cnt) list)))))))) + +(defun mmm-noweb-goto-previous (&optional cnt) + "Goto the continuation of the current chunk." + (interactive "p") + (widen) + (let ((name (mmm-name-at (point)))) + (if name + (let ((list (reverse + (cdr (assoc name + (mmm-names-alist (point-min) + (overlay-start + mmm-current-overlay))))))) + (if list + (goto-char (cadar (nthcdr cnt list)))))))) + +;;}}} +;;{{{ Key mappings + +(defvar mmm-noweb-map (make-sparse-keymap)) +(defvar mmm-noweb-prefix-map (make-sparse-keymap)) +(define-key mmm-noweb-map mmm-mode-prefix-key mmm-noweb-prefix-map) + +(mmm-define-key ?d 'mmm-noweb-narrow-to-doc-chunk mmm-noweb-prefix-map) +(mmm-define-key ?n 'mmm-noweb-goto-next mmm-noweb-prefix-map) +(mmm-define-key ?p 'mmm-noweb-goto-previous mmm-noweb-prefix-map) +(mmm-define-key ?q 'mmm-noweb-fill-chunk mmm-noweb-prefix-map) +;; Cannot use C-g as goto command, so use C-s. +(mmm-define-key ?s 'mmm-noweb-goto-chunk mmm-noweb-prefix-map) + +(define-key mmm-noweb-prefix-map "\t" 'mmm-noweb-complete-chunk) + +;; Don't want to add to either the mmm mode map (used in other mmm +;; buffers) or the local map (used in other major mode buffers), so we +;; make a full-buffer spanning overlay and add the map there. +(defun mmm-noweb-bind-keys () + (save-restriction + (widen) + (let ((ovl (make-overlay (point-min) (point-max) nil nil t))) + ;; 'keymap', not 'local-map' + (overlay-put ovl 'keymap mmm-noweb-map)))) + +(add-hook 'mmm-noweb-class-hook #'mmm-noweb-bind-keys) + +;; TODO: make this overlay go away if mmm is turned off + +;;}}} + +;; These functions below living here temporarily until a real place is +;; found. + +(defun mmm-syntax-region-list (syntax regions) + "Apply SYNTAX to a list of REGIONS of the form (BEG END). +If SYNTAX is not nil, set the syntax-table property of each region. +If SYNTAX is nil, remove the region syntax-table property. +See `mmm-syntax-region'." + (mapcar (lambda (reg) + (mmm-syntax-region (car reg) (cadr reg) syntax)) + regions)) + +(defun mmm-syntax-other-regions (syntax &optional name) + "Apply SYNTAX cell to other regions. +Regions are separated by name, using either `mmm-name-at' or the +optional NAME to determine the current region name." + (if (null name) + (setq name (or (mmm-name-at) + (symbol-name mmm-primary-mode)))) + (mapcar (lambda (reg) + (if (not (string= (car reg) name)) + (mmm-syntax-region-list syntax (cdr reg)))) + (mmm-names-alist (point-min) (point-max)))) + +(defun mmm-word-other-regions () + "Give all other regions word syntax." + (interactive) + (mmm-syntax-other-regions '(2 . 0)) + (setq parse-sexp-lookup-properties t)) + +(defun mmm-space-other-regions () + "Give all other regions space syntax." + (interactive) + (mmm-syntax-other-regions '(0 . 0)) + (setq parse-sexp-lookup-properties t)) + +(defun mmm-undo-syntax-other-regions () + "Remove syntax-table property from other regions." + (interactive) + (mmm-syntax-other-regions nil) + (setq parse-sexp-lookup-properties nil)) + + +(provide 'mmm-noweb) + +;;; mmm-noweb.el ends here diff --git a/mmm-region.el b/mmm-region.el new file mode 100644 index 0000000..5eab4b2 --- /dev/null +++ b/mmm-region.el @@ -0,0 +1,923 @@ +;;; mmm-region.el --- Manipulating and behavior of MMM submode regions + +;; Copyright (C) 2000-2003, 2010-2015, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file 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. + +;; See mmm-class.el for functions which scan the buffer and decide +;; where to create regions. + +;;; Code: + +(require 'cl-lib) +(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. + +(defsubst mmm-overlay-at (&optional pos type) + "Return the highest-priority MMM Mode overlay at POS. +See `mmm-included-p' for the values of TYPE." + (car (mmm-overlays-at pos type))) + +(defun mmm-overlays-at (&optional pos type) + "Return a list of the MMM overlays at POS, in decreasing priority. +See `mmm-included-p' for the values of TYPE." + (or pos (setq pos (point))) + (mmm-sort-overlays + (cl-remove-if-not + (lambda (ovl) + (and (overlay-get ovl 'mmm) + (mmm-included-p ovl pos type))) + ;; XEmacs complains about positions outside the buffer + (overlays-in (max (1- pos) (point-min)) + (min (1+ pos) (point-max)))))) + +(defun mmm-included-p (ovl pos &optional type) + "Return true if the overlay OVL contains POS. + +If OVL strictly contains POS, always return true. If OVL starts or +ends at POS, return true or false based on the value of TYPE, which +should be one of nil, `beg', `end', `none', or `all'. +* If TYPE is nil, return true for an overlay starting at POS only if + it is beg-sticky, and for one ending at POS only if it is end-sticky. +* If TYPE is `beg', return true for any overlay starting at POS but + false for any ending at POS. +* If TYPE is `end', return true for any overlay ending at POS but + false for any starting at POS. +* If TYPE is `all', return true for any overlay starting or ending at POS. +* If TYPE is `none' (or any other value), return false for any + overlay starting or ending at POS." + (let ((beg (overlay-start ovl)) + (end (overlay-end ovl))) + (cond ((and (= beg pos) (= end pos)) + ;; Do the Right Thing for zero-width overlays + (cl-case type + ((nil) (and (overlay-get ovl 'beg-sticky) + (overlay-get ovl 'end-sticky))) + ((none) nil) + (t t))) + ((= beg pos) + (cl-case type + ((nil) (overlay-get ovl 'beg-sticky)) + ((beg all) t) + (t nil))) + ((= end pos) + (cl-case type + ((nil) (overlay-get ovl 'end-sticky)) + ((end all) t) + (t nil))) + ((and (> end pos) (< beg pos)) + t)))) + +;; `mmm-overlays-in' has been retired as altogether too confusing a +;; name, when what is really meant is one of the following three: + +(defun mmm-overlays-containing (start stop) + "Return all MMM overlays containing the region START to STOP. +The overlays are returned in order of decreasing priority. No +attention is paid to stickiness." + (mmm-sort-overlays + (cl-remove-if-not + (lambda (ovl) + (and (overlay-get ovl 'mmm) + (<= (overlay-start ovl) start) + (>= (overlay-end ovl) stop))) + (overlays-in (max start (point-min)) + (min stop (point-max)))))) + +(defun mmm-overlays-contained-in (start stop) + "Return all MMM overlays entirely contained in START to STOP. +The overlays are returned in order of decreasing priority. No +attention is paid to stickiness." + (mmm-sort-overlays + (cl-remove-if-not + (lambda (ovl) + (and (overlay-get ovl 'mmm) + (>= (overlay-start ovl) start) + (<= (overlay-end ovl) stop))) + (overlays-in (max start (point-min)) + (min stop (point-max)))))) + +(defun mmm-overlays-overlapping (start stop) + "Return all MMM overlays overlapping the region START to STOP. +The overlays are returned in order of decreasing priority. No +attention is paid to stickiness." + (mmm-sort-overlays + (cl-remove-if-not + (lambda (ovl) + (overlay-get ovl 'mmm)) + (overlays-in (max start (point-min)) + (min stop (point-max)))))) + +(defun mmm-sort-overlays (overlays) + "Sort OVERLAYS in order of decreasing priority." + (sort (cl-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, or point. +Return non-nil if the current region changed. + +Also deletes overlays that ought to evaporate because their delimiters +have disappeared." + (mapc #'delete-overlay + (cl-remove-if (lambda (ovl) + (or (not (eq (overlay-get ovl 'mmm-evap) 'front)) + (overlay-buffer (overlay-get ovl 'front)))) + (mmm-overlays-at pos))) + (let ((ovl (mmm-overlay-at pos))) + (if (eq ovl mmm-current-overlay) + nil + (mmm-set-current-pair (if ovl (overlay-get ovl 'mmm-mode)) ovl) + t))) + +(defun mmm-set-current-pair (mode ovl) + "Set the current submode to MODE, the current overlay to OVL +and update the saved previous values." + (setq mmm-previous-overlay mmm-current-overlay + mmm-previous-submode mmm-current-submode) + (setq mmm-current-submode mode + mmm-current-overlay ovl)) + +(defun mmm-submode-at (&optional pos type) + "Return the submode at POS \(or point), or NIL if none. +See `mmm-included-p' for values of TYPE." + (let ((ovl (mmm-overlay-at pos type))) + (if ovl (overlay-get ovl 'mmm-mode)))) + +;;}}} +;;{{{ Delimiter Matching and Boundaries + +(defun mmm-match-front (ovl) + "Return non-nil if the front delimiter of OVL matches as it should. +Sets the match data to the front delimiter, if it is a regexp. +Otherwise, calls it as a function with point at the beginning of the +front delimiter overlay \(i.e. where the front delimiter ought to +start) and one argument being the region overlay. The function should +return non-nil if the front delimiter matches correctly, and set the +match data appropriately." + (let* ((front-ovl (overlay-get ovl 'front)) + (front (if front-ovl (overlay-get front-ovl 'match)))) + (when front + (save-excursion + (goto-char (overlay-start front-ovl)) + (if (stringp front) + ;; It's a regexp + (looking-at front) + ;; It's a function + (funcall front ovl)))))) + +(defun mmm-match-back (ovl) + "Return non-nil if the back delimiter of OVL matches as it should. +Sets the match data to the back delimiter, if it is a regexp. +Otherwise, calls it as a function with point at the beginning of the +back delimiter overlay \(i.e. where the back delimiter ought to start) +and one argument being the region overlay. The function should return +non-nil if the back delimiter matches correctly, and set the match +data appropriately." + (let* ((back-ovl (overlay-get ovl 'back)) + (back (if back-ovl (overlay-get back-ovl 'match)))) + (when back + (save-excursion + (goto-char (overlay-start back-ovl)) + (if (stringp back) + ;; It's a regexp + (looking-at back) + ;; It's a function + (funcall back ovl)))))) + +(defun mmm-front-start (ovl) + "Return the position at which the front delimiter of OVL starts." + (let ((front (overlay-get ovl 'front))) + ;; Overlays which have evaporated become "overlays in no buffer" + (if (and front (overlay-buffer front)) + (overlay-start front) + (overlay-start ovl)))) + +(defun mmm-back-end (ovl) + "Return the position at which the back delimiter of OVL ends." + (let ((back (overlay-get ovl 'back))) + ;; Overlays which have evaporated become "overlays in no buffer" + (if (and back (overlay-buffer back)) + (overlay-end back) + (overlay-end ovl)))) + +;;}}} + +;; CREATION & DELETION +;;{{{ Make Submode Regions + +(defun mmm-valid-submode-region (submode beg end) + "Check if the region between BEG and END is valid for SUBMODE. +This region must be entirely contained within zero or more existing +submode regions, none of which start or end inside it, and it must be +a valid child of the highest-priority of those regions, if any. +Signals errors, returns `t' if no error." + ;; First check if the placement is valid. Every existing region + ;; that overlaps this one must contain it in its entirety. + (let ((violators (cl-set-difference + (mmm-overlays-overlapping beg end) + (mmm-overlays-containing beg end)))) + (if violators + (signal 'mmm-subregion-invalid-placement + violators))) + ;; Now check if it is inside a valid parent + (let ((parent-mode (mmm-submode-at beg 'beg))) + (and parent-mode + ;; TODO: Actually check parents here. For present purposes, + ;; we just make sure we aren't putting a submode inside one + ;; of the same type. Actually, what we should really be + ;; doing is checking classes/names of regions, not just the + ;; submodes. + (eq submode parent-mode) + (signal 'mmm-subregion-invalid-parent + (list parent-mode)))) + t) + +(cl-defun mmm-make-region + (submode beg end &key face + front back (evaporation 'front) + delimiter-mode front-face back-face + display-name + (match-front "") (match-back "") + (beg-sticky t) (end-sticky t) + name creation-hook + ) + "Make a submode region from BEG to END of SUBMODE. + +BEG and END are buffer positions or markers with BEG <= END \(although +see EVAPORATION below). SUBMODE is a major mode function or a valid +argument to `mmm-modename->function'. FACE is a valid display face. + +FRONT and BACK specify the positions of the front and back delimiters +for this region, if any. If FRONT is a buffer position or marker, the +front delimiter runs from it to BEG. FRONT can also be a two-element +list \(FRONT-BEG FRONT-END) specifying the exact position of the front +delimiter. One must have FRONT-BEG < FRONT-END <= BEG. + +Similarly, BACK may be a buffer position or marker, in which case the +back delimiter runs from END to BACK. BACK can also be a two-element +list \(BACK-BEG BACK-END) specifying the exact position, in which case +we must have END <= BACK-BEG < BACK-END. + +EVAPORATION specifies under what conditions this submode region should +disappear. +* If `nil', the region never disappears. This can cause serious + problems when using cut-and-paste and is not recommended. +* If the value is t, the region disappears whenever it has zero + length. This is recommended for manually created regions used for + temporary editing convenience. +* If the value is `front', the region will disappear whenever the text + in its front delimiter disappears, that is, whenever the overlay + which marks its front delimiter has zero width. +The default value is `front'. However, if the parameter FRONT is nil, +then this makes no sense, so the default becomes `t'. Note that if +EVAPORATION is `t', then an error is signalled if BEG = END. + +MATCH-FRONT \(resp. MATCH-BACK) is a regexp or function to match the +correct delimiters, see `mmm-match-front' \(resp. `mmm-match-back'). +It is ignored if FRONT \(resp. BACK) is nil. At present these are not +used much. + +DELIMITER-MODE specifies the major mode to use for delimiter regions. +A `nil' value means they remain in the primary mode. + +FACE, FRONT-FACE, and BACK-FACE, are faces to use for the region, the +front delimiter, and the back delimiter, respectively, under high +decoration \(see `mmm-submode-decoration-level'). + +BEG-STICKY and END-STICKY determine whether the front and back of the +region, respectively, are sticky with respect to new insertion. The +default is yes. + +NAME is a string giving the \"name\" of this submode region. Submode +regions with the same name are considered part of the same code +fragment and formatted accordingly. + +DISPLAY-NAME is a string to display in the mode line when point is in +this submode region. If nil or not given, the name associated with +SUBMODE is used. In delimiter regions, \"--\" is shown. + +CREATION-HOOK should be a function to run after the region is created, +with point at the start of the new region." + ;; Check placement of region and delimiters + (unless (if (eq evaporation t) + (< beg end) + (<= beg end)) + (signal 'mmm-subregion-invalid-placement (list beg end))) + (when front + (unless (listp front) + (setq front (list front beg))) + (unless (and (< (car front) (cadr front)) + (<= (cadr front) beg)) + (signal 'mmm-subregion-invalid-placement front))) + (when back + (unless (listp back) + (setq back (list end back))) + (unless (and (< (car back) (cadr back)) + (<= end (car back))) + (signal 'mmm-subregion-invalid-placement back))) + (setq submode (mmm-modename->function submode)) + ;; Check embedding in existing regions + (mmm-valid-submode-region submode beg end) + (mmm-mode-on) + (when submode + (mmm-update-mode-info submode)) + (and (not front) (eq evaporation 'front) (setq evaporation t)) + (let ((region-ovl + (mmm-make-overlay submode beg end name face beg-sticky end-sticky + (or (eq evaporation t) nil) display-name))) + ;; Save evaporation type for checking later + (overlay-put region-ovl 'mmm-evap evaporation) + ;; Calculate priority to supersede anything already there. + ;; XXX: Actually, don't, in order not to hide the region highlighting. + ;; Let's try omitting the priorities and see if any problems crop up. + ;; (overlay-put region-ovl 'priority (length (mmm-overlays-at beg))) + ;; Make overlays for the delimiters, with appropriate pointers. + (when front + (let ((front-ovl + (mmm-make-overlay delimiter-mode (car front) (cadr front) + nil front-face nil nil t "--" t))) + (overlay-put region-ovl 'front front-ovl) + (overlay-put front-ovl 'region region-ovl) + (overlay-put front-ovl 'match match-front))) + (when back + (let ((back-ovl + (mmm-make-overlay delimiter-mode (car back) (cadr back) + nil back-face nil nil t "--" t))) + (overlay-put region-ovl 'back back-ovl) + (overlay-put back-ovl 'region region-ovl) + (overlay-put back-ovl 'match match-back))) + ;; Update everything and run all the hooks + (mmm-save-all + ;; Can be nil when a zero-width region is immediately evaporated + (when (overlay-start region-ovl) + (goto-char (overlay-start region-ovl))) + (mmm-set-current-pair submode region-ovl) + (mmm-set-local-variables submode region-ovl) + (mmm-run-submode-hook submode) + (when creation-hook + (funcall creation-hook))) + (mmm-update-submode-region) + region-ovl)) + +(defun mmm-make-overlay (submode beg end name face beg-sticky end-sticky evap + &optional display-name delim) + "Internal function to make submode overlays. +Does not handle delimiters. Use `mmm-make-region'." + (let ((ovl (make-overlay beg end nil (not beg-sticky) end-sticky))) + (mapc + (lambda (pair) (overlay-put ovl (car pair) (cadr pair))) + `((mmm t) ; Mark all submode overlays + (mmm-mode ,submode) + ,@(if delim '((delim t)) nil) + (mmm-local-variables + ;; Have to be careful to make new list structure here + ,(cl-list* (list 'font-lock-cache-state nil) + (list 'font-lock-cache-position (make-marker)) + (copy-tree + (cdr (assq submode mmm-region-saved-locals-defaults))))) + (name ,name) + (display-name ,display-name) + ;; Need to save these, because there's no way of accessing an + ;; overlay's official "front-advance" parameter once it's created. + (beg-sticky ,beg-sticky) + (end-sticky ,end-sticky) + ;; These have special meaning to Emacs + (,mmm-evaporate-property ,evap) + (face ,(mmm-get-face face submode delim)) + )) + ovl)) + +(defun mmm-get-face (face submode &optional delim) + (cond ((= mmm-submode-decoration-level 0) nil) + ((and (= mmm-submode-decoration-level 2) face) face) + (delim 'mmm-delimiter-face) + (submode 'mmm-default-submode-face))) + +;;}}} +;;{{{ Clear Overlays + +;; See also `mmm-clear-current-region'. + +(defun mmm-clear-overlays (&optional start stop strict) + "Clears all MMM overlays overlapping START and STOP. +If STRICT, only clear those entirely included in that region." + (mapc #'delete-overlay + (if strict + (mmm-overlays-contained-in (or start (point-min)) + (or stop (point-max))) + (mmm-overlays-overlapping (or start (point-min)) + (or stop (point-max))))) + (mmm-update-submode-region)) + +;;}}} + +;; 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 + ;; http://debbugs.gnu.org/13836 + buffer-file-truename) + (unless (and (not force) + (get mode 'mmm-local-variables) + buffer-entry + region-entry) + (let ((temp-buffer (mmm-make-temp-buffer (current-buffer) + mmm-temp-buffer-name)) + (filename (buffer-file-name)) + (mmm-in-temp-buffer t) + ;; Don't try to use jit-lock, it's automatically disabled + ;; starting with 24.4 anyway. + font-lock-support-mode) + (unwind-protect + (with-current-buffer temp-buffer + ;; Handle stupid modes that need the file name set. + (when (memq mode mmm-set-file-name-for-modes) + (setq buffer-file-name filename)) + (funcall mode) + (when (featurep 'font-lock) + (put mode 'mmm-font-lock-mode font-lock-mode) + ;; These can't be in the local variables list, because we + ;; replace their actual values, but we want to use their + ;; original values elsewhere. + (put mode 'mmm-fontify-region-function + font-lock-fontify-region-function) + (put mode 'mmm-syntax-propertize-function + (and (boundp 'syntax-propertize-function) + syntax-propertize-function)) + (put mode 'mmm-indent-line-function indent-line-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)) + (kill-buffer temp-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-submode + mmm-previous-overlay) + (let ((new-mode (or mmm-current-submode mmm-primary-mode)) + (old-mode (or mmm-previous-submode mmm-primary-mode))) + (mmm-run-constructed-hook old-mode new-mode) + (mmm-run-constructed-hook old-mode "exit") + (mmm-run-constructed-hook new-mode "enter") + (mmm-update-mode-info new-mode) + (mmm-set-local-variables new-mode mmm-current-overlay) + (mmm-enable-font-lock new-mode)) + (mmm-set-mode-line) + (dolist (func (if mmm-current-overlay + (overlay-get mmm-current-overlay 'entry-hook) + mmm-primary-mode-entry-hook)) + (ignore-errors (funcall func))))) + +(defun mmm-add-hooks () + (if (featurep 'xemacs) + (make-local-hook 'post-command-hook)) + (add-hook 'post-command-hook #'mmm-update-submode-region nil t) + (when mmm-parse-when-idle + (add-hook 'pre-command-hook #'mmm-mode-reset-timer nil t) + (add-hook 'after-change-functions #'mmm-mode-edit nil t))) + +(defun mmm-remove-hooks () + (remove-hook 'post-command-hook #'mmm-update-submode-region t) + (remove-hook 'pre-command-hook #'mmm-mode-reset-timer t) + (remove-hook 'after-change-functions #'mmm-mode-edit t)) + +;;}}} +;;{{{ 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'." + (mmm-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 (nth 2 element) t))) + (if (functionp (nth 2 element)) + (funcall (nth 2 element)) + (member mode (nth 2 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'." + (mmm-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))) + +;; FIXME: Has no callers. Used for debugging? +(defun mmm-get-saved-local (mode ovl var) + "Get the value of the local variable VAR saved for MODE and OVL, if any." + (cadr (assq var (mmm-get-saved-local-variables ovl mode)))) + +;; FIXME: It's too easy to accidentally pass nil as MODE here. +;; We probably should call this from `mmm-set-current-pair', and not +;; rely on its callers to default to the primary mode when appropriate. +;; Also, incorporate the opmimization from `mmm-fontify-region-list'. +(defun mmm-set-local-variables (mode ovl) + "Set all the local variables saved for MODE and OVL. +Looks up global, buffer and region saves. When MODE is nil, just +the region ones." + (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 ovl))) + +;; Used for debugging. +(defun mmm-diff-local-variables (mode ovl) + (let (res) + (mapc (lambda (var) + (let ((current-value (if (consp (car var)) + (funcall (caar var)) + (symbol-value (car var))))) + (unless (equal current-value (cadr var)) + (push + (message "var: %s, current: %s, saved: %s" (car var) + current-value (cadr var)) + res)))) + (mmm-get-saved-local-variables mode ovl)) + res)) + +(defun mmm-get-saved-local-variables (mode ovl) + (append (get mode 'mmm-local-variables) + (cdr (assq mode mmm-buffer-saved-locals)) + (if ovl + (overlay-get ovl 'mmm-local-variables) + mmm-region-saved-locals-for-dominant))) + +(defun mmm-save-changed-local-variables (mode ovl) + "Save by-buffer and by-region variables for MODE and OVL. +Called when we move to a new submode region, with MODE and OVL 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 (not font-lock-mode) + (get mode 'mmm-font-lock-mode) + (font-lock-mode 1))) + +(defun mmm-update-font-lock-buffer () + "Turn on font lock if any mode in the buffer enables it." + (if (cl-some (lambda (mode) + (get mode 'mmm-font-lock-mode)) + (cons mmm-primary-mode + (mapcar (lambda (ovl) + (overlay-get ovl 'mmm-mode)) + (mmm-overlays-overlapping + (point-min) (point-max))))) + (font-lock-mode 1) + (font-lock-mode 0))) + +;; FIXME: Most uses of this function happen when the buffer is parsed +;; into regions manually. That should go away after +;; syntax-propertize-function does this. +(defun mmm-refontify-maybe (&optional start stop) + "Re-fontify from START to STOP, or entire buffer, if enabled." + (when font-lock-mode + (if (fboundp 'font-lock-flush) + (progn + (font-lock-flush start stop) + ;; FIXME: Do we really need to do this eagerly here? + (font-lock-ensure start stop)) + (if (or start stop) + (font-lock-fontify-region (or start (point-min)) + (or stop (point-max))) + (with-no-warnings (font-lock-fontify-buffer)))))) + +;;}}} +;;{{{ Get Submode Regions + +;; In theory, these are general functions that have nothing to do +;; with font-lock, but they aren't used anywhere else, so we might as +;; well have them close. + +(defun mmm-submode-changes-in (start stop) + "Return a list of all submode-change positions from START to STOP. +The list is sorted in order of increasing buffer position." + (let ((changes (sort (cl-remove-duplicates + (mmm-mapcan (lambda (ovl) + `(,(overlay-start ovl) + ,(overlay-end ovl))) + (mmm-overlays-overlapping start stop))) + #'<))) + (when (or (not changes) (< start (car changes))) + (push start changes)) + (let ((last (last changes))) + (when (> stop (car last)) + (setcdr last (list stop)))) + changes)) + +(defun mmm-regions-in (start stop) + "Return a list of regions of the form (MODE BEG END OVL) whose disjoint +union covers the region from START to STOP, including delimiters." + (when (> stop start) + (let ((regions + (cl-maplist (lambda (pos-list) + (when (cdr pos-list) + (let ((ovl (mmm-overlay-at (car pos-list) 'beg))) + (list (if ovl + (overlay-get ovl 'mmm-mode) + mmm-primary-mode) + (car pos-list) (cadr pos-list) + ovl)))) + (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 OVL). The disjoint union all +of the REGIONS covers START to STOP." + (let ((regions (mmm-regions-in start stop)) + alist) + (mapc (lambda (region) + (let* ((mode (car region)) + (elem (cdr region)) + (kv (assoc mode alist))) + (if kv + (push elem (cdr kv)) + (push (cons mode (list elem)) alist)))) + regions) + (mapcar (lambda (kv) + (cons (car kv) (nreverse (cdr kv)))) + alist))) + +;;}}} +;;{{{ Fontify Regions + +(defun mmm-fontify-region (start stop &optional loudly) + "Fontify from START to STOP keeping track of submodes correctly." + (let ((saved-mode mmm-current-submode) + (saved-ovl mmm-current-overlay)) + (unwind-protect + (progn + (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-submode mmm-current-overlay) + (mapc (lambda (elt) + (when (get (car elt) 'mmm-font-lock-mode) + (mmm-fontify-region-list (car elt) (cdr elt)))) + (mmm-regions-alist start stop))) + ;; `post-command-hook' contains `mmm-update-submode-region', + ;; but jit-lock runs later, so we need to restore local vars now. + (mmm-set-current-pair saved-mode saved-ovl) + (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl))) + (when loudly (message nil))) + +(defvar syntax-ppss-cache) +(defvar syntax-ppss-last) + +(defun mmm-fontify-region-list (mode regions) + "Fontify REGIONS, each like (BEG END), in mode MODE." + (save-excursion + (let ((func (get mode 'mmm-fontify-region-function)) + font-lock-extend-region-functions) + (mapc (lambda (reg) + (cl-destructuring-bind (beg end ovl) reg + (goto-char beg) + ;; 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-pair mode ovl) + (mmm-set-local-variables (unless (eq mmm-previous-submode mode) + mode) + mmm-current-overlay) + (save-restriction + (let ((font-lock-dont-widen t) + ;; FIXME: Messing with syntax-ppss-* vars should not + ;; be needed any more in Emacs≥26. + syntax-ppss-last syntax-ppss-cache) + ;; TODO: Remove this conditional when cc-mode + ;; respects submode boundaries. + (when (and ovl (not (memq mode mmm-c-derived-modes))) + (narrow-to-region beg end)) + (funcall func beg end nil))) + ;; Catch changes in font-lock cache. + (mmm-save-changed-local-variables + mmm-current-submode mmm-current-overlay))) + regions)))) + +;;}}} +;;{{{ Syntax + +(defvar mmm-after-syntax-propertize-functions nil + "List of functions to call after applying `syntax-table' text +properties to a submode region. It is passed four arguments: the +region overlay, the submode and the bounds of the region.") + +(defun mmm-syntax-propertize-function (start stop) + "Composite function that applies `syntax-table' text properties. +It iterates over all submode regions between START and STOP and +calls each respective submode's `syntax-propertize-function'." + (let ((saved-mode mmm-current-submode) + (saved-ovl mmm-current-overlay)) + (mmm-save-changed-local-variables + mmm-current-submode mmm-current-overlay) + (unwind-protect + (mapc (lambda (elt) + (let* ((mode (car elt)) + (func (get mode 'mmm-syntax-propertize-function)) + (beg (cadr elt)) (end (nth 2 elt)) + (ovl (nth 3 elt)) + ;; FIXME: Messing with syntax-ppss-* vars should not + ;; be needed any more in Emacs≥26. + syntax-ppss-cache + syntax-ppss-last) + (goto-char beg) + (mmm-set-current-pair mode ovl) + (mmm-set-local-variables mode mmm-current-overlay) + (save-restriction + (when mmm-current-overlay + (narrow-to-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay))) + (cond + (func + (funcall func beg end)) + (font-lock-syntactic-keywords + (let ((syntax-propertize-function nil)) + (font-lock-fontify-syntactic-keywords-region beg end)))) + (run-hook-with-args 'mmm-after-syntax-propertize-functions + mmm-current-overlay mode beg end)))) + (mmm-regions-in start stop)) + (mmm-set-current-pair saved-mode saved-ovl) + (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl)))) + +;;}}} +;;{{{ Indentation + +(defvar mmm-indent-line-function #'mmm-indent-line + "The function to call to indent a line. +This will be the value of `indent-line-function' for the whole +buffer. It's supposed to delegate to the appropriate submode's +indentation function. See `mmm-indent-line' as the starting point.") + +(defun mmm-indent-line-narrowed () + "An indent function which works on some modes where `mmm-indent-line' doesn't. +Works like `mmm-indent-line', but narrows the buffer before indenting to +appease modes which rely on constructs like (point-min) to indent." + (interactive) + (save-excursion + (back-to-indentation) + (mmm-update-submode-region) + (let ((indent-function (get + (if (and mmm-current-overlay + (> (overlay-end mmm-current-overlay) (point))) + mmm-current-submode + mmm-primary-mode) + 'mmm-indent-line-function))) + (if mmm-current-overlay + (save-restriction + (narrow-to-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay)) + (funcall indent-function)) + (funcall indent-function))))) + +(defun mmm-indent-line () + (interactive) + (funcall + (save-excursion + (back-to-indentation) + (mmm-update-submode-region) + (get + (if (and mmm-current-overlay + (> (overlay-end mmm-current-overlay) (point))) + mmm-current-submode + mmm-primary-mode) + 'mmm-indent-line-function)))) + +;;}}} +(provide 'mmm-region) + +;;; mmm-region.el ends here diff --git a/mmm-rpm.el b/mmm-rpm.el new file mode 100644 index 0000000..71fe923 --- /dev/null +++ b/mmm-rpm.el @@ -0,0 +1,80 @@ +;;; 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> + +;;{{{ 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 diff --git a/mmm-sample.el b/mmm-sample.el new file mode 100644 index 0000000..5ee4419 --- /dev/null +++ b/mmm-sample.el @@ -0,0 +1,384 @@ +;;; mmm-sample.el --- Sample MMM submode classes + +;; Copyright (C) 2000-2004, 2012-2015, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file contains several sample submode classes for use with MMM +;; Mode. For a more detailed, advanced example, see `mmm-mason.el'. + +;; In order to use any of classes defined here, just require `mmm-auto' and +;; add the respective (major mode -> class <- file extension) associations +;; with `mmm-add-mode-ext-class'. + +;;; Code: + +(require 'cl-lib) +(require 'mmm-auto) +(require 'mmm-vars) + +;;{{{ <Perl> in httpd.conf + +;; This is the simplest example. Many applications will need no more +;; than a simple regexp. +;; +;; Usage: (mmm-add-mode-ext-class 'apache-generic-mode nil 'httpd-conf-perl) + +(mmm-add-classes + '((httpd-conf-perl + :submode perl + :delimiter-mode nil + :front "<Perl>" + :back "</Perl>"))) + +;;}}} +;;{{{ JavaScript in HTML + +;; We use two classes here, both for code in a <script> tag, one wrapped in +;; CDATA, another not. And another class to group them together. +;; +;; Usage: (mmm-add-mode-ext-class 'html-mode nil 'html-js) + +(mmm-add-group + 'html-js + '((js-script-cdata + :submode js-mode + :face mmm-code-submode-face + :front "<script[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?" + :back "[ \t]*\\(//\\)?]]>[ \t\n]*</script>") + (js-script + :submode js-mode + :face mmm-code-submode-face + :front "<script[^>]*>[ \t]*\n?" + :back "[ \t]*</script>" + :insert ((?j js-tag nil @ "<script type=\"text/javascript\">\n" + @ "" _ "" @ "\n</script>" @))))) + +;;}}} +;;{{{ CSS in HTML + +(mmm-add-group + 'html-css + '((css-cdata + :submode css + :face mmm-code-submode-face + :front "<style[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?" + :back "[ \t]*\\(//\\)?]]>[ \t\n]*</style>") + (css + :submode css + :face mmm-code-submode-face + :front "<style[^>]*>[ \t]*\n?" + :back "[ \t]*</style>" + :insert ((?c css-tag nil @ "<style type=\"text/css\">\n" + @ "" _ "" @ "\n</style>" @))))) + +;;}}} +;;{{{ 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. + (cl-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 (cl-ldiff words (member "mode" words)) + (list "mode")) + "-"))) + ;; Try each word by itself (preference list) + (cl-some (lambda (word) + (mmm-ensure-modename (intern word))) + words) + ;; Try each word with -mode tacked on + (cl-some (lambda (word) + (mmm-ensure-modename + (intern (concat word "-mode")))) + words) + ;; Try each pair of words with -mode tacked on + (cl-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 + :delimiter-mode nil + :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-name "embperl" + :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-expr + :submode perl + :face mmm-output-submode-face + :front "<:=" + :back ":>" + :insert ((?= eperl-expr nil @ "<:=" @ " " _ " " @ ":>" @))) + (eperl-code + :submode perl + :face mmm-code-submode-face + :front "<:" + :back "_?:>" + :match-name "eperl" + :insert ((?p eperl-code nil @ "<:" @ " " _ " " @ ":>" @) + (?: eperl-code ?p . nil) + (?_ eperl-code_ nil @ "<:" @ " " _ " " @ "_:>" @))) + (eperl-comment + :submode text + :face mmm-comment-submode-face + :front ":>//" + :back "\n") + )) + +;;}}} +;;{{{ 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 + :delimiter-mode nil + ))) + +;;}}} +;;{{{ JSP Pages + +(mmm-add-group 'jsp + `((jsp-comment + :submode text-mode + :face mmm-comment-submode-face + :front "<%--" + :back "--%>" + :insert ((?- jsp-comment nil @ "<%--" @ " " _ " " @ "--%>" @)) + ) + (jsp-code + :submode java + :match-face (("<%!" . mmm-declaration-submode-face) + ("<%=" . mmm-output-submode-face) + ("<%" . mmm-code-submode-face)) + :front "<%[!=]?" + :back "%>" + :match-name "jsp" + :insert ((?% jsp-code nil @ "<%" @ " " _ " " @ "%>" @) + (?! jsp-declaration nil @ "<%!" @ " " _ " " @ "%>" @) + (?= jsp-expression nil @ "<%=" @ " " _ " " @ "%>" @)) + ) + (jsp-directive + :submode text-mode + :face mmm-special-submode-face + :front "<%@" + :back "%>" + :insert ((?@ jsp-directive nil @ "<%@" @ " " _ " " @ "%>" @)) + ))) + +;;}}} +;;{{{ SGML DTD + +;; Thanks to Yann Dirson <ydirson@fr.alcove.com> for writing and +;; contributing this submode class. + +(mmm-add-classes + '((sgml-dtd + :submode dtd-mode + :face mmm-declaration-submode-face + :delimiter-mode nil + :front "<! *doctype[^>[]*\\[" + :back "]>"))) + +;;}}} +;;{{{ PHP in HTML + +(mmm-add-group 'html-php + '((html-php-output + :submode php-mode + :face mmm-output-submode-face + :front "<\\?php *echo " + :back "\\(\\?>\\|\\'\\)" + :include-front t + :front-offset 5 + :insert ((?e php-echo nil @ "<?php" @ " echo " _ " " @ "?>" @)) + ) + (html-php-code + :submode php-mode + :face mmm-code-submode-face + :front "<\\?\\(php\\)?" + :back "\\(\\?>\\|\\'\\)" + :insert ((?p php-section nil @ "<?php" @ " " _ " " @ "?>" @) + (?b php-block nil @ "<?php" @ "\n" _ "\n" @ "?>" @)) + ))) + +;;}}} + +;; NOT YET UPDATED +;;{{{ HTML in PL/SQL;-COM- +;-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) + +;;; mmm-sample.el ends here diff --git a/mmm-univ.el b/mmm-univ.el new file mode 100644 index 0000000..3a2c86b --- /dev/null +++ b/mmm-univ.el @@ -0,0 +1,64 @@ +;;; mmm-univ.el --- The "Universal" Submode Class + +;; Copyright (C) 2000, 2001, 2013 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 diff --git a/mmm-utils.el b/mmm-utils.el new file mode 100644 index 0000000..d17ee44 --- /dev/null +++ b/mmm-utils.el @@ -0,0 +1,157 @@ +;;; mmm-utils.el --- Coding Utilities for MMM Mode + +;; Copyright (C) 2000-2003, 2011-2013 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file provides a number of macros and other coding utilities +;; for MMM Mode. + +;;; Code: + +;;{{{ 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 + mmm-in-temp-buffer) + ,@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 + (if (fboundp 'format-mode-line) + (format-mode-line (cdr pair)) + (cdr pair)) + t t string)))))) + string) + +(defun mmm-format-matches (string &optional on-string) + "Format STRING by matches from the current match data. +Strings like ~N are replaced by the Nth subexpression from the last +global match. Does nothing if STRING is not a string. + +ON-STRING, if supplied, means to use the match data from a +`string-match' on that string, rather than the global match data." + (when (stringp string) + (let ((old-data (match-data)) + subexp) + (save-match-data + (while (string-match "~\\([0-9]\\)" string) + (setq subexp (string-to-number (match-string-no-properties 1 string)) + string (replace-match + (save-match-data + (set-match-data old-data) + (match-string-no-properties subexp on-string)) + t t string)))))) + string) + +;;}}} +;;{{{ 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 values 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 values 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))))) + +;;}}} +;;{{{ Markers + +;; Mostly for remembering interactively made regions +(defun mmm-make-marker (pos beg-p sticky-p) + "Make, and return, a marker at POS that is or isn't sticky. +BEG-P represents whether the marker delimits the beginning of a +region \(or the end of it). STICKY-P is whether it should be sticky, +i.e. whether text inserted at the marker should be inside the region." + (let ((mkr (set-marker (make-marker) pos))) + (set-marker-insertion-type mkr (if beg-p (not sticky-p) sticky-p)) + mkr)) + +;;}}} + +(provide 'mmm-utils) + +;;; mmm-utils.el ends here diff --git a/mmm-vars.el b/mmm-vars.el new file mode 100644 index 0000000..b567bb0 --- /dev/null +++ b/mmm-vars.el @@ -0,0 +1,1133 @@ +;;; mmm-vars.el --- Variables for MMM Mode + +;; Copyright (C) 2000-2004, 2011-2015, 2018 Free Software Foundation, Inc. + +;; Author: Michael Abraham Shulman <viritrilbia@gmail.com> + +;;{{{ GPL + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;}}} + +;;; Commentary: + +;; This file 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) +(require 'mmm-utils) +(require 'cl-lib) + +;; MISCELLANEOUS +;;{{{ Shut up the Byte Compiler + +;; Otherwise it complains about undefined variables. +(defvar mmm-current-submode) +(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) +(defvar mmm-current-overlay) +(declare-function mmm-apply-all "mmm-class") +(declare-function mmm-set-class-parameter "mmm-class" (class param value)) +(declare-function mmm-get-class-parameter "mmm-class" (class param)) + +;;}}} +;;{{{ Error Conditions + +;; Most of these should be caught internally and never seen by the +;; user, except when the user is creating submode regions manually. + +;; Signalled when we try to put a submode region inside one where it +;; isn't meant to go. +(put 'mmm-subregion-invalid-parent + 'error-conditions + '(mmm-subregion-invalid-parent mmm-error error)) +(put 'mmm-subregion-invalid-parent + 'error-message + "Invalid submode region parent") + +;; Signalled when we try to put a submode region overlapping others in +;; an invalid way. +(put 'mmm-subregion-invalid-placement + 'error-conditions + '(mmm-subregion-invalid-placement mmm-error error)) +(put 'mmm-subregion-invalid-placement + 'error-message + "Submode region placement invalid") + +;; Signalled when we try to apply a submode class that doesn't exist. +(put 'mmm-invalid-submode-class + 'error-conditions + '(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. This error should *always* be caught internally +;; and never seen by the user. +(put 'mmm-no-matching-submode + 'error-conditions + '(mmm-no-matching-submode mmm-error error)) +(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 + php-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 buffer) + font-lock-set-defaults + font-lock-major-mode + 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 + font-lock-syntactic-face-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) + semantic-bovinate-toplevel-override + semantic-toplevel-bovine-table + ;; Indentation style control variables. + ;; These have to be localized in Emacs: see `mmm-mode-on'. + ,@(mapcar + (lambda (var) (list var nil mmm-c-derived-modes)) + '(c++-template-syntax-table + c-<-op-cont-regexp + c->-op-cont-regexp + c-after-brace-list-key + c-after-suffixed-type-decl-key + c-after-suffixed-type-maybe-decl-key + c-any-class-key + c-asm-stmt-kwds + c-assignment-op-regexp + c-backslash-column + c-basic-offset + c-before-context-fontification-functions + c-bitfield-kwds + c-block-comment-prefix + c-block-decls-with-vars + c-block-prefix-charset + c-block-stmt-1-2-key + c-block-stmt-1-key + c-block-stmt-1-kwds + c-block-stmt-2-key + c-block-stmt-2-kwds + c-brace-list-key + c-case-kwds-regexp + c-cast-parens + c-class-key + c-class-kwds + c-cleanup-list + c-colon-type-list-re + c-comment-only-line-offset + c-comment-prefix-regexp + c-comment-start-regexp + c-cpp-defined-fns + c-current-comment-prefix + c-decl-block-key + c-decl-hangon-key + c-decl-prefix-or-start-re + c-decl-prefix-re + c-decl-spec-kwds + c-decl-start-kwds + c-decl-start-re + c-doc-comment-start-regexp + c-expr-kwds + c-file-offsets + c-file-style + c-not-primitive-type-keywords-regexp + c-hanging-braces-alist + c-hanging-colons-alist + c-hanging-comment-ender-p + c-hanging-comment-starter-p + c-hanging-semi\&comma-criteria + c-identifier-key + c-identifier-last-sym-match + c-identifier-start + c-identifier-syntax-modifications + c-identifier-syntax-table + c-in-comment-lc-prefix + c-indent-comment-alist + c-indent-comments-syntactically-p + c-indentation-style + c-inexpr-block-kwds + c-inexpr-class-kwds + c-keywords + c-keywords-obarray + c-keywords-regexp + c-known-type-key + c-label-kwds + c-label-kwds-regexp + c-label-minimum-indentation + c-lambda-kwds + c-literal-start-regexp + c-macro-with-semi-re + c-nonlabel-token-key + c-nonlabel-token-2-key + c-nonsymbol-chars + c-nonsymbol-token-regexp + c-not-decl-init-keywords + c-offsets-alist + c-opt-<>-arglist-start + c-opt-<>-arglist-start-in-paren + c-opt-<>-sexp-key + c-opt-access-key + c-opt-asm-stmt-key + c-opt-bitfield-key + c-opt-block-decls-with-vars-key + c-opt-block-stmt-key + c-opt-cpp-prefix + c-opt-cpp-start + c-opt-decl-spec-key + c-opt-friend-key + c-opt-identifier-concat-key + c-opt-inexpr-block-key + c-opt-inexpr-brace-list-key + c-opt-inexpr-class-key + c-opt-lambda-key + c-opt-method-key + c-opt-postfix-decl-spec-key + c-opt-type-component-key + c-opt-type-concat-key + c-opt-type-modifier-key + c-opt-type-suffix-key + c-other-decl-block-key + c-other-decl-block-kwds + c-other-decl-kwds + c-overloadable-operators-regexp + c-paragraph-separate + c-paragraph-start + c-paren-stmt-key + c-primary-expr-regexp + c-primitive-type-key + c-primitive-type-kwds + c-protection-kwds + c-postfix-decl-spec-key + c-recognize-<>-arglists + c-recognize-knr-p + c-recognize-paren-inits + c-recognize-typeless-decls + c-regular-keywords-regexp + c-simple-stmt-key + c-simple-stmt-kwds + c-special-brace-lists + c-specifier-key + c-specifier-kwds + c-stmt-delim-chars + c-stmt-delim-chars-with-comma + c-symbol-char-key + c-symbol-key + c-symbol-start + c-syntactic-eol + c-syntactic-ws-end + c-syntactic-ws-start + c-type-decl-prefix-key + c-type-decl-suffix-key + c-type-prefix-key + c-typeof-key + c-prefix-spec-kwds-re + c-typedef-key + c-typedef-decl-key + comment-end + comment-start + comment-start-skip)) + ,@(mapcar + (lambda (var) (list var nil '(js-mode))) + '(js--quick-match-re + js--quick-match-re-func)) + ;; Skeleton insertion + skeleton-transformation + ;; Abbrev mode + abbrev-mode + local-abbrev-table + ;; And finally the syntax table and local map. + ((syntax-table . set-syntax-table) buffer) + ((current-local-map . use-local-map) buffer) + paragraph-separate + paragraph-start + (whitespace-active-style buffer) + (whitespace-display-table buffer) + (whitespace-display-table-was-local buffer) + (whitespace-font-lock buffer) + (whitespace-font-lock-mode buffer) + (whitespace-font-lock-keywords buffer) + (whitespace-mode buffer) + (whitespace-point--used buffer) + (whitespace-point buffer) + (whitespace-bob-marker buffer) + forward-sexp-function + smie-rules-function + smie-grammar + smie-forward-token-function + smie-backward-token-function + ) + "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 respectively. +* None (0) means to use no coloring at all. +* Low (1) means to use `mmm-default-submode-face' for all submode + regions \(except for \"non-submode\" regions, i.e. those that are of + the primary mode) and `mmm-delimiter-face' for region delimiters. +* High (2) means to use different faces for different types of submode + regions and delimiters, such as initialization code, expressions that + are output, declarations, and so on, as specified by the submode + class. The default faces are still used for regions that do not + specify a face." + :group 'mmm-faces + :type '(choice (const :tag "None" 0) + (const :tag "Low" 1) + (const :tag "High" 2))) + +(defface mmm-init-submode-face '((((background light)) (:background "Pink")) + (((background dark)) (:background "MediumOrchid")) + (t (:background "Pink"))) + "Face used for submodes containing initialization code." + :group 'mmm-faces) + +(defface mmm-cleanup-submode-face '((((background light)) (:background "Wheat")) + (((background dark)) (:background "peru")) + (t (:background "Wheat"))) + "Face used for submodes containing cleanup code." + :group 'mmm-faces) + +(defface mmm-declaration-submode-face '((((background light)) (:background "Aquamarine")) + (((background dark)) (:background "DarkTurquoise")) + (t (:background "Aquamarine"))) + "Face used for submodes containing declarations." + :group 'mmm-faces) + +(defface mmm-comment-submode-face '((((background light)) (:background "SkyBlue")) + (((background dark)) (:background "SteelBlue")) + (t (:background "SkyBlue"))) + "Face used for submodes containing comments and documentation." + :group 'mmm-faces) + +(defface mmm-output-submode-face '((((background light)) (:background "Plum")) + (((background dark)) (:background "MediumVioletRed")) + (t (:background "Plum"))) + "Face used for submodes containing expression that are output." + :group 'mmm-faces) + +(defface mmm-special-submode-face '((((background light)) (:background "MediumSpringGreen")) + (((background dark)) (:background "ForestGreen")) + (t (:background "MediumSpringGreen"))) + "Face used for special submodes not fitting any other category." + :group 'mmm-faces) + +(defface mmm-code-submode-face '((((background light)) (:background "LightGray")) + (((background dark)) (:background "DimGray")) + (t (:background "LightGray"))) + "Face used for submodes containing ordinary code." + :group 'mmm-faces) + +(defface mmm-default-submode-face '((((background light)) (:background "gray85")) + (((background dark)) (:background "gray20")) + (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) + +(defface mmm-delimiter-face nil + "Face used to mark submode delimiters." + :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 mode-line display when point is in a submode region. + +~M is replaced by the name of the primary major mode \(which may be +replaced by a combined-mode function, see the info documentation). + +~m is replaced by the submode region overlay's `display-name' +property, if it has one. Otherwise it is replaced by the mode name of +the submode region. + +If `mmm-primary-mode-display-name' is non-nil, then this variable is +used even when point is not in a submode region \(i.e. it is in a +primary mode region), with ~m being replaced by the value of that +variable." + :group 'mmm + :type 'string) + +(defvar mmm-primary-mode-display-name nil + "If non-nil, displayed as the primary mode name in the mode line. +See also `mmm-buffer-mode-display-name'.") +(make-variable-buffer-local 'mmm-primary-mode-display-name) + +(defvar mmm-buffer-mode-display-name nil + "If non-nil, displayed in the mode line instead of the primary mode +name, which is then shown next to it as if it were a submode when in a +primary mode region, i.e. outside all submode regions.") +(make-variable-buffer-local 'mmm-buffer-mode-display-name) + +(defun mmm-set-mode-line () + "Set the mode line display correctly for the current submode, +according to `mmm-submode-mode-line-format'." + (let ((primary (or mmm-primary-mode-display-name + (get mmm-primary-mode 'mmm-mode-name))) + (submode (and mmm-current-overlay + (or (overlay-get mmm-current-overlay 'display-name) + (get mmm-current-submode 'mmm-mode-name))))) + (if mmm-buffer-mode-display-name + (setq mode-name + (mmm-format-string mmm-submode-mode-line-format + `(("~M" . ,mmm-buffer-mode-display-name) + ("~m" . ,(or submode primary))))) + (if submode + (setq mode-name + (mmm-format-string mmm-submode-mode-line-format + `(("~M" . ,primary) + ("~m" . ,submode)))) + (setq mode-name primary)))) + (force-mode-line-update)) + +;;}}} +;;{{{ Submode Classes + +(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) + (python python-mode python-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) + "Add major mode MODE as acceptable for LANGUAGE. +This sets the value of `mmm-major-mode-preferences'. If DEFAULT +is non-nil, MODE is added at the front of the list of modes for +LANGUAGE. Otherwise, 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 (cl-remove-if-not + #'fboundp + (cdr (assq mode mmm-major-mode-preferences)))))) + +;;}}} +;;{{{ Delimiter Regions + +(defcustom mmm-delimiter-mode 'fundamental-mode + "Major mode used by default for delimiter regions. +Classes are encouraged to override this by providing a delimiter-mode +parameter-- see `mmm-classes-alist'." + :group 'mmm + :type 'function) + +;;}}} +;;{{{ Key Bindings + +(defcustom mmm-mode-prefix-key [(control ?c) ?%] + "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 this hooks are run, point is guaranteed to be at the start of +the newly created submode region. + +Finally, a hook named mmm-<class>-class-hook is run whenever a buffer +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))) + +(defvar mmm-primary-mode-entry-hook nil + "Hook run when point moves into a region of the primary mode. +Each submode region can have an `entry-hook' property which is run +when they are entered, but since primary mode regions have no overlay +to store properties, this is a buffer-local variable. + +N.B. This variable is not a standard Emacs hook. Unlike Emacs' +\"local hooks\" it has *no* global value, only a local one. Its value +should always be a list of functions \(possibly empty) and never a +single function. It may be used with `add-hook', however.") +(make-variable-buffer-local 'mmm-primary-mode-entry-hook) + +;;}}} +;;{{{ Major Mode Hook + +(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-hook'. However, `find-file-hook' 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 + +;; There's a point to be made that this variable should default to +;; `maybe' (i.e. not nil and not t), because that's what practically +;; everyone wants. I subscribe, however, to the view that simply +;; *loading* a lisp extension should not change the (user-visible) +;; behavior of Emacs, until it is configured or turned on in some +;; way, which dictates that the default for this must be nil. +(defcustom mmm-global-mode nil + "Specify in which buffers to turn on MMM Mode automatically. + +- 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) + +;; These are not traditional editing modes, so mmm makes no sense, and +;; can mess things up seriously if it doesn't know not to try. +(defcustom mmm-never-modes + '( + help-mode + 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 the temporary buffers MMM creates have a +file name. In these modes, this file name is the same as that of the +parent buffer. In general, this has been found to cause more problems +than it solves, but some modes require it.") + +;;}}} +;;{{{ Idle Parsing + +(defcustom mmm-parse-when-idle nil + "Non-nil to automatically reparse the buffer when it has some + modifications and Emacs has been idle for `mmm-idle-timer-delay'." + :type 'boolean + :group 'mmm) + +(defcustom mmm-idle-timer-delay 0.2 + "Delay in secs before re-parsing after user makes changes." + :type 'number + :group 'mmm) +(make-variable-buffer-local 'mmm-idle-timer-delay) + +(defvar mmm-mode-parse-timer nil "Private variable.") +(make-variable-buffer-local 'mmm-mode-parse-timer) +(defvar mmm-mode-buffer-dirty nil "Private variable.") +(make-variable-buffer-local 'mmm-mode-buffer-dirty) + +(defun mmm-mode-edit (_beg _end _len) + (setq mmm-mode-buffer-dirty t) + (mmm-mode-reset-timer)) + +(defun mmm-mode-reset-timer () + (when mmm-mode-parse-timer + (cancel-timer mmm-mode-parse-timer)) + (setq mmm-mode-parse-timer + (run-with-idle-timer mmm-idle-timer-delay nil + #'mmm-mode-idle-reparse (current-buffer)))) + +(defun mmm-mode-idle-reparse (buffer) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (when mmm-mode-buffer-dirty + (mmm-apply-all) + (setq mmm-mode-buffer-dirty nil) + (setq mmm-mode-parse-timer nil))))) + +;;}}} + +;; 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 + +;; Notes: +;; 1. :parent could be an all-class argument. Same with :keymap. +;; 2. :match-submode really does have to be distinct from :submode, +;; because 'functionp' isn't enough to distinguish which is meant. +(defvar mmm-classes-alist nil + "Alist containing all defined mmm submode classes. +A submode class is a named recipe for parsing a document into submode +regions, and sometimes for inserting new ones while editing. + +Each element of this alist looks like \(CLASS . ARGS) where CLASS is a +symbol naming the submode class and ARGS is a list of keyword +arguments, called a \"class specifier\". There are a large number of +accepted keyword arguments in the class specifier. + +The argument CLASSES, if supplied, must be a list of other submode +class names, or class specifiers, representing other classes to call +recursively. The FACE arguments of these classes are overridden by +the FACE argument of this class. If the argument CLASSES is supplied, +all other arguments to this class are ignored. That is, \"grouping\" +classes can do nothing but group other classes. + +The argument HANDLER, if supplied, also overrides any other processing. +It must be a function, and all the arguments are passed to it as +keywords, and it must do everything. See `mmm-ify' for what sorts of +things it must do. This back-door interface should be cleaned up. + +The optional argument FACE gives the display face of the submode +regions under high decoration (see `mmm-submode-decoration-level'). +It must be a valid face. The standard faces used for submode regions +are `mmm-*-submode-face' where * is one of `init', `cleanup', +`declaration', `comment', `output', `special', or `code'. A more +flexible alternative is the argument MATCH-FACE. MATCH-FACE can be a +function, which is called with one argument, the form of the front +delimiter \(found from FRONT-FORM, below), and should return the face +to use. It can also be an alist, with each element of the form +\(DELIM . FACE). + +If neither CLASSES nor HANDLER are supplied, either SUBMODE or +MATCH-SUBMODE must be. SUBMODE specifies the submode to use for the +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 FRONT-MATCH'th match \(or the beginning thereof, if INCLUDE-FRONT +is non-nil), plus FRONT-OFFSET, becomes the beginning of the submode +region. If FRONT is a function, that function is called instead, and +must act somewhat like a search, in that it should start at point, +take one argument as a search bound, and set the match data. A +similar pattern is followed for BACK \(the search starts at the +beginning of the submode region), save that the beginning of its +BACK-MATCH'th match \(or the end, if INCLUDE-BACK is non-nil) becomes +the end of the submode region, plus BACK-OFFSET. + +If SAVE-MATCHES is non-nil, then BACK, if it is a regexp, is formatted +by replacing strings of the form \"~N\" by the corresponding value of +\(match-string n) after matching FRONT. + +FRONT-MATCH and BACK-MATCH default to zero. They specify which +sub-match of the FRONT and BACK regexps to treat as the delimiter. +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. + +FRONT-DELIM \(resp. BACK-DELIM), if supplied, can take values like +those of FRONT-OFFSET \(resp. BACK-OFFSET), specifying the offset from +the start \(resp. end) of the match for FRONT \(resp. BACK) to use as +the starting \(resp. ending) point for the front \(resp. back) +delimiter. If nil, it means not to make a region for the respective +delimiter at all. + +DELIMITER-MODE, if supplied, specifies what submode to use for the +delimiter regions, if any. If `nil', the primary mode is used. If +not supplied, `mmm-delimiter-mode' is used. + +FRONT-FACE and BACK-FACE specify faces to use for displaying the +delimiter regions, under high decoration. + +FRONT-FORM and BACK-FORM, if given, must supply a regexp used to match +the *actual* delimiter. If they are strings, they are used as-is. If +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. + +MATCH-NAME, if supplied, specifies how to determine the \"name\" for +each submode region. It must be a string or a function. If it is a +function, it is passed the value of FRONT-FORM and must return the +name to use. If it is a string, it is used as-is unless SAVE-NAME has +a non-nil value, in which case, the string is interpreted the same as +BACK when SAVE-MATCHES is non-nil. If MATCH-NAME is not specified, +the regions are unnamed. Regions with the same name are considered +part of the same chunk of code, and formatted as such, while unnamed +regions are not grouped with any others. + +As a special optimization for insertion, if SKEL-NAME is non-nil, the +insertion code will use the user-prompted string value as the region +name, instead of going through the normal matching procedure. + +PRIVATE, if supplied and non-nil, means that this class is a private +or internal class, usually one invoked by another class via :classes, +and is not for the user to see.") + +;;;###autoload +(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 \"grouping class\" named GROUP which calls them all. +The CLASSES are all made private, i.e. non-user-visible." + (mmm-add-classes (mapcar (lambda (class) + (append class + '(:private t))) + classes)) + (add-to-list 'mmm-classes-alist + (list group :classes (mapcar #'cl-first classes)))) + +(defun mmm-add-to-group (group classes) + "Add CLASSES to the \"grouping class\" named GROUP. +The CLASSES are all made private, i.e. non-user-visible." + (mmm-add-classes (mapcar (lambda (class) + (append class + '(:private t))) + classes)) + (mmm-set-class-parameter group :classes + (append (mmm-get-class-parameter group :classes) + (mapcar #'cl-first classes)))) + +;;}}} +;;{{{ Version Number + +(defconst mmm-version "0.5.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-buffer" + "Name for temporary buffers created by MMM Mode. +Using non-special name, so that font-lock-mode will be enabled +automatically when appropriate, and will set all related vars.") + +(defvar mmm-in-temp-buffer nil + "Bound to t when working in the temp buffer.") + +;;}}} +;;{{{ 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 #'cl-third + (cl-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) + (cl-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.texinfo b/mmm.texinfo new file mode 100644 index 0000000..7bd1d24 --- /dev/null +++ b/mmm.texinfo @@ -0,0 +1,2108 @@ +\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 + +@ifinfo + +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 +@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. + +@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. +* Noweb:: Noweb literate programs. + +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. +* Region Names:: Naming regions for syntax grouping. +* Other Hooks:: Running code at arbitrary points. +* Delimiters:: Controlling delimiter overlays. +* 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 is useful whenever one +file contains text in two or more programming languages, or that +should be in two or more different modes. For example: + +@itemize @bullet +@item +CGI scripts written in any language, from Perl to PL/SQL, may want to +output verbatim HTML, and the writer of such scripts may want to use +Emacs' html-mode or sgml-mode to edit this HTML code, while remaining +in the appropriate programming language mode for the rest of the +file. @xref{Here-documents}, for example. + +@item +There are now many ``content delivery systems'' which turn the CGI +script idea around and simply add extra commands to an HTML file, +often in some programming language, which are interpreted on the +server. @xref{Mason}, @xref{Embperl}, @xref{ePerl}, @xref{JSP}. + +@item +HTML itself can also contain embedded languages such as Javascript and +CSS styles, for which Emacs has different major modes. +@xref{Javascript}, and @xref{Embedded CSS}, for example. + +@item +The idea of ``literate programming'' requires the same file to contain +documentation (written as text, html, latex, etc.) and code (in an +appropriate programming language). @xref{Noweb}, for example. + +@item +Emacs allows files of any type to contain `local variables', which can +include Emacs Lisp code to be evaluated. @xref{File Variables, , , +emacs, The Emacs Manual}. It may be easier to edit this code in Emacs +Lisp mode than in whatever mode is used for the rest of the file. +@xref{File Variables}. + +@item +There are many more possible uses for MMM Mode. RPM spec files can +contain shell scripts (@pxref{RPM}). Email or newsgroup messages may +contain sample code. And so on. We encourage you to experiment. +@end itemize + +@menu +* Basic Concepts:: A simple explanation of how it works. +* 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. @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{html-js}, or @code{java}, while @var{mode} +should be the name of a major mode such as @code{perl-mode}, +@code{cperl-mode}, @code{javascript-mode}, or @code{c++-mode}. + +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. +* Noweb:: Noweb literate programs. +@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. + +Some people have reported problems using PSGML with Mason. Adding the +following line to a @file{.emacs} file should suffice to turn PSGML off +and cause emacs to use a simpler HTML mode: + +@lisp +(autoload 'html-mode "sgml-mode" "HTML Mode" t) +@end lisp + +Earlier versions of PSGML may require instead the following fix: + +@lisp +(delete '("\\.html$" . sgml-html-mode) auto-mode-alist) +(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, you may +need to replace @code{html-mode} in the suggested code with +@code{sgml-html-mode}. (Depending on your version of PSGML, this may +not be necessary.) Similarly, if you are using XEmacs and want to use +the alternate HTML mode @code{hm--html-mode}, replace @code{html-mode} +with that symbol. + +One problem that crops up when using PSGML with Mason is that even +ignoring the special tags and Perl code (which, as I've said, haven't +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, Noweb, 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 Noweb, , RPM, Supplied Classes +@comment node-name, next, previous, up +@section Noweb literate programming + +@file{mmm-noweb.el} contains the definition of an MMM Mode submode +class for editing Noweb documents. Most Noweb documents use \LaTeX +for the documentation chunks. Code chunks in Noweb are +document-specific, and the mode may be set with a local variable +setting in the document. The variable @var{mmm-noweb-code-mode} +controls the global code chunk mode. Since Noweb files may have many +languages in their code chunks, this mode also allows setting the mode +by specifying a mode in the first line or two of a code chunk, using +the normal Emacs first-line mode setting syntax. Note that this +first-line mode setting only matches a single word for the mode name, +and does not support the variable name setting of the generalized +first file line syntax. + +@verbatim +% -*- mode: latex; mmm-noweb-code-mode: c++; -*- +% First chunk delimiter! +@ +\noweboptions{smallcode} + +\title{Sample Noweb File} +\author{Joe Kelsey\\ +\nwanchorto{mailto:bozo@bozo.bozo}{\tt bozo@bozo.bozo}} +\maketitle + +@ +\section{Introduction} +Normal noweb documentation for the required [[*]] chunk. +<<*>>= +// C++ mode here! +// We might list the program here, or simply included chunks. +<<myfile.cc>> +@ %def myfile.cc + +@ +\section{[[myfile.cc]]} +This is [[myfile.cc]]. MMM noweb-mode understands code quotes in +documentation. +<<myfile.cc>>= +// This section is indented separately from previous. +@ + +@ +\section{A Perl Chunk} +We need a Perl chunk. +<<myfile.pl>>= +#!/usr/bin/perl +# -*- perl -*- +# Each differently named chunk is flowed separately. +@ + +\section{Finish [[myfile.cc]]} +When we resume a previously defined chunk, they are indented together. +<<myfile.cc>>= +// Pick up where we left off... +@ + +@end verbatim + +The quoted code chunks inside documentation chunks are given the mode +found in the variable @var{mmm-noweb-quote-mode}, if set, or the value +in @var{mmm-noweb-code-mode} otherwise. Also, each quoted chunk is +set to have a unique name to prevent them from being indented as a +unit. + +Suggested setup code: +@lisp +(mmm-add-mode-ext-class 'latex-mode "\\.nw\\'" 'noweb) +(add-to-list 'auto-mode-alist '("\\.nw\\'" . latex-mode)) +@end lisp + +In mmm-noweb buffers, each differently-named code chunk has a +different @code{:name}, allowing all chunks with the same name to get +indented together. + +This mode also supplies special paragraph filling operations for use +in documentation areas of the buffer. From a primary-mode +(@code{latex-mode, , emacs}) region, pressing @kbd{C-c % C-q} will mark all +submode regions with word syntax (@code{mmm-word-other-regions}), fill +the current paragraph (@code{(fill-paragraph justify)}), and remove the +syntax markings (@code{mmm-undo-syntax-other-regions}). + +Thanks to Joe Kelsey <joe@@zircon.seattle.wa.us> for contributing this +class. + + +@node Writing Classes, Indices, Supplied Classes, Top +@comment node-name, next, previous, up +@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. +* Region Names:: Naming regions for syntax grouping. +* Other Hooks:: Running code at arbitrary points. +* Delimiters:: Controlling delimiter overlays. +* 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 of lists, +similar to what might be passed to @code{mmm-add-classes}, are added +just as by that function. Furthermore, another class named +@var{group} is added, which encompasses all the classes in +@var{classes}. +@end defun + +Technically, an group class is specified with a @code{:classes} keyword +argument, and the subsidiary classes are given a non-nil @code{:private} +keyword argument to make them invisible. But in general, all you should +ever need to know is how to invoke the function above. + +@defun mmm-add-to-group @var{group} @var{classes} +Adds a list of classes to an already existing group. This can be +used, for instance, to add a new quoting definition to @var{html-js} +using this example to add the quote characters ``%=%'': + +@lisp +(mmm-add-to-group 'html-js '((js-html + :submode javascript + :face mmm-code-submode-face + :front "%=%" + :back "%=%" + :end-not-begin t))) +@end lisp +@end defun + + +@node Calculated Submodes, Calculated Faces, Submode Groups, Writing Classes +@comment node-name, next, previous, up +@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{Delimiters}). The function should then return a symbol +that would be a valid argument to @code{:submode}: either the name of a +mode, or that of a language to look up a preferred mode. If it detects +an invalid match---for example, the user has specified a mode which is +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. Note that +@var{mmm-submode-decoration-level} must be set to 2 (high decoration) +for different faces to be displayed. + + +@node Insertion Commands, Region Names, 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 Region Names, Other Hooks, Insertion Commands, Writing Classes +@comment node-name, next, previous, up +@section Giving Names to Submode Regions for Grouping + +Submode regions can be given ``names'' which are used for grouping. +Names are always strings and are compared as strings. Regions with +the same name are considered part of the same chunk of code. This is +used by the syntax and fontification functions. Unnamed regions are +not grouped with any others. + +By default, regions are nameless, but with the @code{:match-name} +keyword argument a name can be supplied. This argument must be a +string or a function. If it is a function, it is passed a string +representing the front delimiter found, and must return the name to +use. If it is a string, it is used as-is for the name, unless +@code{:save-name} has a non-nil value, in which case expressions such +as @samp{~1} are substituted with the corresponding matched +subexpression from @code{:front}. This is the same as how +@code{:back} is interpreted when @code{:save-matches} is non-nil. + +As a special optimization for region insertion (@pxref{Insertion +Commands}), the argument @code{:skel-name} can be set to a non-nil +value, in which case the insertion code will use the user-prompted +string value as the region name, instead of going through the normal +matching procedure. + + +@node Other Hooks, Delimiters, Region Names, Writing Classes +@comment node-name, next, previous, up +@section Other Hooks into the Scanning Process + +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 Delimiters, Misc Keywords, Other Hooks, Writing Classes +@comment node-name, next, previous, up +@section Controlling the Delimiter Regions and Forms + +MMM also makes overlays for the delimiter regions, to keep track of +their position and form. Normally, the front delimiter overlay starts +at the beginning of the match for @code{:front} and ends at the +beginning of the submode region overlay, while the back delimiter +overlay starts at the end of the submode region overlay and ends at +the end of the match for @code{:back}. You can supply offsets from +these positions using the keyword arguments @code{:front-delim} and +@code{:back-delim}, which take values of the same sort as +@code{:front-offset} and @code{:back-offset}. + +In addition, the delimiter regions can be in a major mode of their +own. There are usually only two meaningful modes to use: the primary +mode or a non-mode like fundamental-mode. These correspond to the +following two situations: + +@itemize +@item +If the delimiter syntax which specifies the submode regions is +something @emph{added to} the syntax of the primary mode by a +pre-interpreter, then the delimiter regions should be in a non-mode. +This is the case, for example, with all server-side HTML script +extensions, such as @xref{Mason}, @xref{Embperl}, and @xref{ePerl}. +It is also the case for literate programming such as @xref{Noweb}. +This is the default behavior. The non-mode used is controlled by the +variable @code{mmm-delimiter-mode}, which defaults to +fundamental-mode. + +@item +If, on the other hand, the delimiter syntax and inclusion of different +modes is an @emph{intrinsic part} of the primary mode, then the +delimiter regions should remain in the primary mode. This is the +case, for example, with @xref{Embedded CSS}, and @xref{Javascript}, +since the @code{<style>} and @code{<script>} tags are perfectly valid +HTML. In this case, you should give the keyword parameter +@code{:delimiter-mode} with a value of @code{nil}, meaning to use the +primary mode. +@end itemize + +The keyword parameter @code{:delimiter-mode} can be given any major +mode as an argument, but the above two situations should cover the +vast majority of cases. + +The delimiter regions can also be highlighted, if you wish. The +keyword parameters @code{:front-face} and @code{:back-face} may be +faces specifying how to highlight these regions under high +decoration. Under low decoration, the value of the variable +@code{mmm-delimiter-face} is used (by default, nothing), and of course +under no decoration there is no coloring. + +Finally, for each submode region overlay, MMM Mode stores the ``form'' +of the front and back delimiters, which are regular expressions that +match the delimiters. At present these are not used for much, but in +the future they may be used to help with automatic updating of regions +as you type. Normally, the form stored is the result of evaluating +the expression @code{(regexp-quote (match-string 0))} after each match +is found. + +You can customize this with the keyword argument @code{:front-form} +(respectively, @code{:back-form}). If it is a string, it is used +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, , Delimiters, 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/tests/highlighting.el b/tests/highlighting.el new file mode 100644 index 0000000..5ce2269 --- /dev/null +++ b/tests/highlighting.el @@ -0,0 +1,112 @@ +;; Copyright (C) 2013-2014 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'ert-x) + +(defvar foo-mode-keywords + `((,(concat "\\b" + (regexp-opt '("foo" "bar") t) + "\\b") + . font-lock-keyword-face))) + +(define-derived-mode foo1-mode fundamental-mode "" + (setq font-lock-defaults '(foo-mode-keywords t t))) + +(ert-deftest mmm-font-lock-without-font-lock-syntax-table () + (ert-with-test-buffer nil + (let (mmm-mode-ext-classes-alist + mmm-parse-when-idle) + (insert "foo // foo_bar") + (fundamental-mode) + (mmm-mode-on) + (mmm-ify-by-regexp 'foo1-mode "// " 0 "\\'" 0 nil) + (font-lock-fontify-region (point-min) (point-max)) + (beginning-of-buffer) + (should-not (get-text-property (point) 'face)) + (search-forward "fo" nil nil 2) + (should (eq (get-text-property (point) 'face) font-lock-keyword-face)) + (search-forward "ba") + (should (eq (get-text-property (point) 'face) font-lock-keyword-face))))) + +(define-derived-mode foo2-mode fundamental-mode "" + (setq font-lock-defaults '(foo-mode-keywords t t ((?_ . "w"))))) + +(ert-deftest mmm-font-lock-with-font-lock-syntax-table () + (ert-with-test-buffer nil + (let (mmm-mode-ext-classes-alist + mmm-parse-when-idle) + (insert "foo // foo_bar") + (fundamental-mode) + (mmm-mode-on) + (mmm-ify-by-regexp 'foo2-mode "// " 0 "\\'" 0 nil) + (font-lock-fontify-region (point-min) (point-max)) + (should-not (next-single-property-change (point-min) 'face))))) + +(define-derived-mode foo3-mode fundamental-mode "" + (setq font-lock-defaults '(foo-mode-keywords nil t ((?_ . "w"))))) + +(ert-deftest mmm-syntax-propertize-function-preserves-current-syntax-table () + (ert-with-test-buffer nil + (let (mmm-mode-ext-classes-alist + mmm-parse-when-idle) + (insert "foo_and_bar\n\nfoo") + (foo3-mode) + (mmm-mode-on) + (syntax-ppss-flush-cache (point-min)) + ;; It locally changes `syntax-table' to `font-lock-syntax-table' + ;; and calls `syntax-ppss' inside that before fontifying. + (font-lock-fontify-region (point-min) (point-max)) + (let ((pt (next-single-property-change (point-min) 'face))) + (should pt) + (goto-char pt) + (should (looking-at "foo\\'")))))) + +(ert-deftest mmm-fontify-region-list-ignores-outside-for-syntactic-ff-tion () + (ert-with-test-buffer nil + (let (mmm-mode-ext-classes-alist + mmm-parse-when-idle) + (insert "unpaired '!\n") + (insert "js>>\n") + (insert "var woo = js;\n") + (foo1-mode) + (mmm-mode-on) + (syntax-ppss-flush-cache (point-min)) + (mmm-ify-by-regexp 'js-mode "js>>\n" 0 "\\'" 0 nil) + (font-lock-fontify-region (point-min) (point-max)) + (search-backward "var") + (should (eq 'font-lock-keyword-face + (get-text-property (point) 'face)))))) + +(ert-deftest mmm-fontify-region-list-carries-string-after-subregion () + (ert-with-test-buffer nil + (let (mmm-mode-ext-classes-alist + mmm-parse-when-idle) + (insert "<p class=\"foo <% 1 + 2 %> bar tee\"</p>") + (html-mode) + (mmm-mode-on) + (syntax-ppss-flush-cache (point-min)) + (mmm-ify-by-regexp 'js-mode "<%" 0 "%>" 0 nil) + (font-lock-fontify-region (point-min) (point-max)) + (search-backward "1") + (should (null (get-text-property (point) 'face))) + (search-forward "bar") + (should (eq 'font-lock-string-face + (get-text-property (point) 'face)))))) diff --git a/tests/html-erb.el b/tests/html-erb.el new file mode 100644 index 0000000..fe34c86 --- /dev/null +++ b/tests/html-erb.el @@ -0,0 +1,103 @@ +;; Copyright (C) 2013 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'ert) +(require 'ert-x) +(require 'mmm-erb) + +(defvar mmm-erb-text + "<%= foo do %> + <div class=\"clear\"/> + <% end %>") + +(defconst mmm-erb-edge-emacs (string-lessp "24.3.50" emacs-version)) + +(defun mmm-erb-current-overlay-string () + (buffer-substring-no-properties + (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay))) + +(defmacro mmm-erb-deftest (name &rest body) + (let ((expected-result (and (eq (car body) :expected-result) + (nth 1 body)))) + (when expected-result + (setq body (nthcdr 2 body))) + `(ert-deftest ,(intern (format "mmm-erb-%s" name)) () + :expected-result ,(or expected-result :passed) + (ert-with-test-buffer nil + (let ((buffer-file-name "foo.html.erb") + (mmm-global-mode 'maybe) + mmm-parse-when-idle + mmm-mode-ext-classes-alist) + (mmm-add-mode-ext-class 'html-erb-mode "\\.html\\.erb\\'" 'erb) + (html-erb-mode) + (mmm-mode-on-maybe) + (should mmm-mode) + ,@body))))) + +(put 'mmm-erb-deftest 'lisp-indent-function 'defun) + +(mmm-erb-deftest parses-buffer + (insert mmm-erb-text) + (mmm-apply-all) + (should (not mmm-current-overlay)) + (search-backward "foo") + (should (mmm-update-current-submode)) + (should (string= " foo do " (mmm-erb-current-overlay-string))) + (search-forward "end") + (should (mmm-update-current-submode)) + (should (string= " end " (mmm-erb-current-overlay-string)))) + +(defun mmm-erb-assert-string-syntax () + (goto-char (point-min)) + (search-forward "\"") + (should (nth 3 (syntax-ppss))) + (search-forward "\"") + (should (not (nth 3 (syntax-ppss))))) + +(defun mmm-erb-assert-non-string-syntax () + (goto-char (point-min)) + (search-forward "\"") + (should (not (nth 3 (syntax-ppss)))) + (search-forward "\"") + (should (not (nth 3 (syntax-ppss))))) + +(mmm-erb-deftest attribute-values-are-strings + (insert mmm-erb-text) + (mmm-apply-all) + (mmm-erb-assert-string-syntax)) + +(mmm-erb-deftest quotes-outside-tags-dont-make-strings + :expected-result (if mmm-erb-edge-emacs :passed :failed) + (insert "<% foo do %><p>\"foo bar\"</p><% end %>") + (mmm-apply-all) + (mmm-erb-assert-non-string-syntax)) + +(mmm-erb-deftest gt-inside-subregion-doesnt-change-nesting + (insert "<% if 2 > 1 %><div class=\"foo\"/><% end %>") + (mmm-apply-all) + (mmm-erb-assert-string-syntax)) + +(mmm-erb-deftest lt-inside-subregion-doesnt-change-nesting + :expected-result (if mmm-erb-edge-emacs :passed :failed) + (insert "<% if 2 < 1 %><p>\"foo bar\"</p><% end %>") + (mmm-apply-all) + (mmm-erb-assert-non-string-syntax)) diff --git a/texinfo.tex b/texinfo.tex new file mode 100644 index 0000000..aa52853 --- /dev/null +++ b/texinfo.tex @@ -0,0 +1,5484 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{1999-01-05}% +% +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98 +% Free Software Foundation, Inc. +% +% This texinfo.tex 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 texinfo.tex 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 this texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +% In other words, you are welcome to use, share and improve this program. +% You are forbidden to forbid anyone else to use, share and improve +% what you give them. Help stamp out software-hoarding! +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% ftp://ftp.gnu.org/pub/gnu/texinfo.tex +% /home/gd/gnu/doc/texinfo.tex on the GNU machines. +% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) +% ftp://tug.org/tex/texinfo.tex +% ftp://ctan.org/macros/texinfo/texinfo.tex +% (and all CTAN mirrors, finger ctan@ctan.org for a list). +% The texinfo.tex in the texinfo distribution itself could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. +% Please include a precise test case in each bug report, +% including a complete document with which we can reproduce the problem. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For simple +% manuals, however, you can get away with: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever, to process the dvi file. +% The extra runs of TeX get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% We never want plain's outer \+ definition in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortContents\undefined \gdef\putwordShortContents{Short Contents}\fi +\ifx\putwordTableofContents\undefined\gdef\putwordTableofContents{Table of Contents}\fi + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\ifx\eTeXversion\undefined +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\else +\def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\fi + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment; press RETURN to continue} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Press RETURN to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 +} + + +% @page forces the start of a new page +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1@end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +{ + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} +} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we \let\value to this in \indexdummies). Ones +% whose names contain - or _ still won't work, but we can't do anything +% about that. The command has to be fully expandable, since the result +% winds up in the index file. This means that if the variable's value +% contains other Texinfo commands, it's almost certain it will fail +% (although perhaps we could fix that with sufficient work to do a +% one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{fonts,} +% Font-change commands. + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\ninettsl\ttslshape{10}{900} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\itshape{9}{1000} +\setfont\indsl\slshape{9}{1000} +\let\indtt=\ninett +\let\indttsl=\ninettsl +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic +\let\cite=\smartslanted + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp#1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @url, @env, @command quotes seem unnecessary, so use \code. +\let\url=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional second argument +% specifying the text to display. First (mandatory) arg is the url. +% Perhaps eventually put in a hypertex \special here. +% +\def\uref#1{\urefxxx #1,,\finish} +\def\urefxxx#1,#2,#3\finish{% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% + \else + \code{#1}% + \fi +} + +% rms does not like the angle brackets --karl, 17may97. +% So now @email is just like @uref. +%\def\email#1{\angleleft{\tt #1}\angleright} +\let\email=\uref + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym downcases the argument and prints in smallcaps. +\def\acronym#1{{\smallcaps \lowercase{#1}}} + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +% Contains a kludge to get @end[description] to work. +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +% @table, @ftable, @vtable. +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the part of the @columnfraction before the decimal point, which +% is presumably either 0 or the empty string (but we don't check, we +% just throw it away). #2 is the decimal part, which we use as the +% percent of \hsize for this column. +\def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + +% @multitable ... @end multitable definitions: +% +\def\multitable{\parsearg\dotable} +\def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% The \closeout helps reduce unnecessary open files; the limit on the +% Acorn RISC OS is a mere 16 files. +\def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\ { }% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +% Need these in case \tex is in effect and \{ is a \delimiter again. +% But can't use \lbracecmd and \rbracecmd because texindex assumes +% braces and backslashes are used only as delimiters. +\let\{ = \mylbrace +\let\} = \myrbrace +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\uref##1{\realbackslash uref {##1}}% +\def\url##1{\realbackslash url {##1}}% +\def\env##1{\realbackslash env {##1}}% +\def\command##1{\realbackslash command {##1}}% +\def\option##1{\realbackslash option {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\acronym##1{\realbackslash acronym {##1}}% +% +% Handle some cases of @value -- where the variable name does not +% contain - or _, and the value does not contain any +% (non-fully-expandable) commands. +\let\value = \expandablevalue +% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\url=\indexdummyfont +\let\uref=\indexdummyfont +\let\env=\indexdummyfont +\let\command=\indexdummyfont +\let\option=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other + @gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% For \ifx comparisons. +\def\emptymacro{\empty} + +% Most index entries go through here, but \dosubind is the general case. +% +\def\doind#1#2{\dosubind{#1}{#2}\empty} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% \empty if called from \doind, as we usually are. The main exception +% is with defuns, which call us directly. +% +\def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If third (subentry) arg is present, add it to the index string. + \ifx\thirdarg\emptymacro \else + \toks0 = {#3}% + \edef\temp{\temp{\the\toks0}}% + \fi + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak +}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage = \vbox{% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case, we must prevent the second \partialpage from + % simply overwriting the first, causing us to lose the page. + % This will preserve it until a real output routine can ship it + % out. Generally, \partialpage will be empty when this runs and + % this will be a no-op. + \unvbox\partialpage + % + % Unvbox the main output page. + \unvbox255 + \kern-\topskip \kern\baselineskip + }}% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \advance\vsize by \ht\partialpage + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + +% @chapter, @appendix, @unnumbered. +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% +\temp +\donoderef +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 +\message{\putwordAppendix\space \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% +\temp +\appendixnoderef +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +% @top is like @unnumbered. +\outer\def\top{\parsearg\unnumberedyyy} + +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of <toks register>. (We also do this for +% the toc entries.) +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% +\temp +\unnumbnoderef +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +} + +% Sections. +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{% +\plainsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsections. +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{% +\plainsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsubsections. +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc,} +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. We supply {\folio} at the end of the +% argument, which will end up as the last argument to the \...entry macro. +% +% We open the .toc file here instead of at @setfilename or any other +% given time so that @contents can be put in the document anywhere. +% +\newif\iftocfileopened +\def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Finish up the main text and prepare to read what we've written +% to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund <tege@matematik.su.se> + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTableofContents}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% Define the \E... control sequence only if we are inside the particular +% environment, so the error checking in \end will work. +% +% To end an @example-like environment, we first end the paragraph (via +% \afterenvbreak's vertical glue), and then the group. That way we keep +% the zero \parskip that the environments set -- \parskip glue will be +% inserted at the beginning of the next paragraph in the document, after +% the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup} + +% @lisp: indented, narrowed, typewriter font. +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @example: Same as @lisp. +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + +% @small... is usually equivalent to the non-small (@smallbook +% redefines). We must call \example (or whatever) last in the +% definition, since it reads the return following the @example (or +% whatever) command. +% +% This actually allows (for example) @end display inside an +% @smalldisplay. Too bad, but makeinfo will catch the error anyway. +% +\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} +\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} +\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. +% Originally contributed by Pavel@xerox. +\def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \indexfonts + \lisp +} + +% @display: same as @lisp except keep current font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% @smalldisplay (when @smallbook): @display plus smaller fonts. +% +\def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \indexfonts \rm + \display +} + +% @format: same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @smallformat (when @smallbook): @format plus smaller fonts. +% +\def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \indexfonts \rm + \format +} + +% @flushleft (same as @format). +% +\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + +% @flushright. +% +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble +} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\noindent +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 +\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% +\def\defmethparsebody#1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +% @deftypemethod has an extra argument that nothing else does. Sigh. +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% #5 is the method's return type. +% +\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}} + +% @defmethod, and so on + +% @defop CATEGORY CLASS OPERATION ARG... + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @deftypemethod CLASS RETURN-TYPE METHOD ARG... +% +\def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @defmethod == @defop Method +% +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} +% +% #1 is the class name, #2 the method name, #3 the args. +\def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{#1}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup +} +\else +\def\scanmacro#1{% +\begingroup \newlinechar`\^^M +\let\xeatspaces\eatspaces\scantokens{#1}\endgroup} +\fi + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% Utility routines. +% Thisdoes \let #1 = #2, except with \csnames. +\def\cslet#1#2{% +\expandafter\expandafter +\expandafter\let +\expandafter\expandafter +\csname#1\endcsname +\csname#2\endcsname} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=12\catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + +\def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \expandafter\ifx \csname macsave.\the\macname\endcsname \relax + \cslet{macsave.\the\macname}{\the\macname}% + \else + \message{Warning: redefining \the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\def\unmacro{\parsearg\unmacroxxx} +\def\unmacroxxx#1{% + \expandafter\ifx \csname macsave.\the\macname\endcsname \relax + \errmessage{Macro \the\macname\ not defined.}% + \else + \cslet{#1}{macsave.#1}% + \expandafter\let \csname macsave.\the\macname\endcsname \undefined + \fi +} + +% This makes use of the obscure feature that if the last token of a +% <parameter list> is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname} + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname} + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + + +\message{cross references,} +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's job is to define \lastnode. +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +% The sectioning commands (@chapter, etc.) call these. +\def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi +} +\def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi +} +\def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi +} + + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\def\anchor#1{\setref{#1}{Ynothing}} + + +% \setref{NAME}{SNT} defines a cross-reference point NAME, namely +% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have +% to set \indexdummies so commands such as @code in a section title +% aren't expanded. It would be nicer not to expand the titles in the +% first place, but there's so many layers that that is hard to do. +% +\def\setref#1#2{{% + \indexdummies + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2} +}} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \normalturnoffactive so that punctuation chars such as underscore +% and backslash work in node names. (\turnoffactive doesn't do \.) +\def\dosetq#1#2{% + {\let\folio=0 + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% +} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +% +\def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname +} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +% +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://ftp.tug.org/tex/epsf.tex.} +% +% Only complain once about lack of epsf.tex. +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + % If the image is by itself, center it. + \ifvmode + \nobreak\medskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + \epsfbox{#1.eps}% + \fi +} + + +\message{paper sizes,} +% And other related parameters. + +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. We +% call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = \hsize + \divide\emergencystretch by 45 + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; 3) voffset; +% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can +% set \parskip and call \setleading for \baselineskip. +% +\def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% +}} + +% Use @smallbook to reset parameters for 7x9.5 (or so) format. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 +}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 +} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\def\pagesizes{\parsearg\pagesizesxxx} +\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% +}} + +% Set default to letter. +% +\letterpaper + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +% These look ok in all fonts, so just make them not special. The @rm below +% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d" +@c time-stamp-end: "}" +@c End: |