pax_global_header00006660000000000000000000000064145014440650014515gustar00rootroot0000000000000052 comment=96906747e862449b722b6e2c741b61871894ac3a mmm-mode-0.5.10/000077500000000000000000000000001450144406500133105ustar00rootroot00000000000000mmm-mode-0.5.10/.elpaignore000066400000000000000000000001451450144406500154360ustar00rootroot00000000000000.elpaignore .github .gitignore AUTHORS ChangeLog Checklist INSTALL Makefile NEWS TODO mmm.texi tests mmm-mode-0.5.10/.github/000077500000000000000000000000001450144406500146505ustar00rootroot00000000000000mmm-mode-0.5.10/.github/workflows/000077500000000000000000000000001450144406500167055ustar00rootroot00000000000000mmm-mode-0.5.10/.github/workflows/test.yml000066400000000000000000000017101450144406500204060ustar00rootroot00000000000000name: CI on: workflow_dispatch: pull_request: push: paths-ignore: - 'AUTHORS' - 'ChangeLog' - 'Checklist' - 'COPYING' - '.elpaignore' - 'FAQ' - 'NEWS' - 'README' - 'README.Mason' - 'TODO' jobs: build: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} strategy: matrix: emacs_version: - 25.1 - 25.2 - 25.3 - 26.1 - 26.2 - 26.3 - 27.1 - 27.2 - 28.1 - 28.2 experimental: [false] include: - emacs_version: snapshot experimental: true steps: - uses: purcell/setup-emacs@master with: version: ${{ matrix.emacs_version }} - uses: actions/checkout@v3 - name: Compile and Build Docs run: make all docs -j2 shell: bash -ev {0} - name: Run tests run: make check shell: bash -ev {0} mmm-mode-0.5.10/.gitignore000066400000000000000000000001101450144406500152700ustar00rootroot00000000000000mmm.info* *.elc *.tar.gz mmm-mode-pkg.el mmm-mode-autoloads.el mmm.html mmm-mode-0.5.10/AUTHORS000066400000000000000000000007161450144406500143640ustar00rootroot00000000000000MMM Mode was originally designed and written by Michael Shulman . It was inspired by mmm.el for XEmacs by Gongquan Chen . Recent contributors have included: bishop Joe Kelsey Alan Shutko Michael Alan Dorman Brian P Templeton Yann Dirson Marcus Harnisch and others... mmm-mode-0.5.10/COPYING000066400000000000000000000431101450144406500143420ustar00rootroot00000000000000 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. Copyright (C) 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. , 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. mmm-mode-0.5.10/ChangeLog000066400000000000000000001036351450144406500150720ustar00rootroot00000000000000NOTE: This file is not kept up-to-date anymore. 2004-11-18 Alan Shutko * 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 * 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 * 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 * mmm-sample.el (html-js): Support JS version in language attribute. 2004-06-01 Alan Shutko * 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 * mmm-vars.el (mmm-save-local-variables): Add semantic stuff and c-syntactic-eol. 2003-03-25 Michael A. Shulman * mmm-mode.spec: Added file for building SRPMs, from bishop * autogen.sh: Added file for building from CVS 2003-03-22 Michael A. Shulman * 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 * 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 * mmm-region.el (mmm-clear-overlays): Fixed bug so turning mmm mode off now restores primary mode correctly. 2003-03-03 Michael A. Shulman * 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 * 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 * 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 * 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 * .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 * 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 . 2001-05-15 Michael Abraham Shulman * mmm-auto.el: Added cweb to autoloaded classes. 2001-05-14 Michael Abraham Shulman * mmm-region.el: Passed arguments to `signal'. * mmm-vars.el: Defined new submode placement error conditions. 2001-05-14 Alan Shutko * 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 * configure.in, mmm-mode.el, mmm-vars.el, version.texi: Released 0.4.7 2001-02-18 Alan Shutko * 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 * mmm-mason.el (mmm-mason-end-line,mmm-mason-start-line): Use bolp and eolp. 2001-02-03 Michael Abraham Shulman * 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 * mmm.texinfo: Added direntry for automated info installation. 2001-01-26 Alan Shutko * 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 * 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 * 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 * 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 * mmm-auto.el: Added ePerl and JSP to autoload. 2001-01-11 Michael Abraham Shulman * 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 * 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 * mmm-region.el (mmm-update-mode-info): Hacked so `font-lock-keywords-alist' works. 2001-01-05 Michael Abraham Shulman * mmm.texinfo: Added set-background example for XEmacs. Added info-dir-entry. 2000-09-29 Michael Abraham Shulman * mmm-class.el (mmm-apply-class): Rearranged parameters so faces actually work. 2000-09-18 Michael Abraham Shulman * configure.in, mmm-vars.el, version.texi: Released 0.4.6 2000-09-17 Michael Abraham Shulman * FAQ: Added Q about name capitalization. 2000-09-16 Michael Abraham Shulman * mmm-compat.el (mmm-keywords-used): Added `:private'. 2000-09-12 Michael Abraham Shulman * FAQ: Added file 2000-09-12 Michael Abraham Shulman * 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 * mmm.texinfo: Set MASON_VERSION. * mmm-cmds.el (mmm-display-insertion-key): Prevented (nthcdr -1 ...); breaks in XEmacs. 2000-08-29 Michael Abraham Shulman * 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 * 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 * 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 * 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 * mmm-vars.el (mmm-never-modes): Added `forms-mode'. 2000-08-02 Michael Abraham Shulman * 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 * 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 * 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 * configure.in: Changed output name from `mmm' to `mmm-mode'. 2000-07-24 Michael Abraham Shulman * mmm-sample.el: Updated file-variables class to handle prefixes. 2000-07-23 Michael Abraham Shulman * mmm-sample.el: Wrote File Variables submode class for the new syntax. 2000-07-21 Michael Abraham Shulman * 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 * 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 * 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 * README.Mason: Added comment about `mmm-global-mode'. 2000-07-12 Michael Abraham Shulman * 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 * 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 * 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 * 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 * 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 * 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 * 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 * mmm-vars.el (mmm-save-local-variable): Added comment-line-start-skip for Fortran. 2000-06-13 Michael Abraham Shulman * mmm.texinfo: Added comment about (require 'mmm-mason). 2000-06-08 Michael Abraham Shulman * 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 * .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 * mmm-auto.el: Pre-added major mode hook to text-mode-hook. 2000-05-19 Michael Abraham Shulman * mmm-vars.el (mmm-version): changed to 0.3.8. 2000-05-18 Michael Abraham Shulman * 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 * 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 * mmm-mason.el: Added dependencies on mmm-compat and mmm-vars. 2000-04-30 Michael Abraham Shulman * 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 * 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 * All: Started using RCS. 2000-04-27 Michael Abraham Shulman * mmm-sample.el (mmm-javascript-mode): Created customization variable to select mode to use for javascript regions. 2000-03-26 Michael Abraham Shulman * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * Version 0.3.6c released. * mmm-mode.el: Added comment about putting autohandlers and dhandlers in html-mode. 1999------ Michael Abraham Shulman * Version 0.3.6b released. * mmm-mode.el: Added comment about `psgml-mode' thanks to Michael Alan Dorman. 1999------ Michael Abraham Shulman * Version 0.3.6a released. * mmm-mode.el: Loaded CL at compile-time to prevent execution of macro arguments. 1999------ Michael Abraham Shulman * 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 * Version 0.3.5a released. * mmm-mode.el (mmm-ify-by-all): no longer re-fontifies buffers with no submodes. 1999------ Michael Abraham Shulman * 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 * 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 * 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 * 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 * 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 * 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 * Version 0.2.2a released. * mmm-mode.el: Fixed bug. 1999-11-18 Michael Abraham Shulman * 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 * 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 * 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 , so I have continued his version-numbering. 1999-01-12 Gongquan Chen * Version 0.11 released. * mmm.el: Fixed doc-strings and style. Thanks to comments from Jari Aalto 1999-01-11 Gongquan Chen * Version 0.10 released. * mmm.el: Initial release of mmm.el on comp.emacs.xemacs mmm-mode-0.5.10/Checklist000066400000000000000000000015411450144406500151450ustar00rootroot00000000000000-*-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'. mmm-mode-0.5.10/FAQ000066400000000000000000000177011450144406500136500ustar00rootroot00000000000000-*-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 <, or check out the MMM Mode web site, , 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. mmm-mode-0.5.10/Makefile000066400000000000000000000023461450144406500147550ustar00rootroot00000000000000# Using srcdir, builddir, and VPATH enables separate build dir with # $ make -f $srcdir srcdir := $(dir $(MAKEFILE_LIST)) VPATH = $(srcdir) builddir = . EMACS ?= emacs MAKEINFO = makeinfo MAKEINFOFLAGS = ELFILES = mmm-auto.el mmm-class.el mmm-cmds.el mmm-compat.el mmm-cweb.el \ mmm-defaults.el mmm-erb.el mmm-mason.el mmm-mode.el mmm-myghty.el \ mmm-noweb.el mmm-region.el mmm-rpm.el mmm-sample.el mmm-univ.el \ mmm-utils.el mmm-vars.el ELCFILES = $(ELFILES:.el=.elc) TESTS = highlighting.el html-erb.el all: mmm.info $(ELCFILES) mmm.info: mmm.texi $(MAKEINFO) $(MAKEINFOFLAGS) -o $@ $^ mmm.html: mmm.texi $(MAKEINFO) --html $(MAKEINFOFLAGS) -o $@ $^ docs: html info html: mmm.html info: mmm.info %.elc: %.el $(EMACS) --batch -Q -L $(builddir) -L $(srcdir) \ --eval '(setq byte-compile-dest-file-function (lambda (_) "$@"))' \ -f batch-byte-compile '$<' check: all $(EMACS) --batch -Q -L $(builddir) -L $(srcdir) -L $(srcdir)/tests \ $(addprefix -l ,$(TESTS)) -f ert-run-tests-batch-and-exit clean-lisp: $(RM) -f $(ELCFILES) clean-info: $(RM) -f mmm.info clean-html: $(RM) -rf mmm.html clean: clean-lisp clean-info clean-html .PHONY: check clean clean-html clean-info clean-lisp docs html info mmm-mode-0.5.10/NEWS000066400000000000000000000271571450144406500140230ustar00rootroot00000000000000MMM Mode NEWS -- history of user-visible changes. -*-outline-*- Copyright (C) 2003, 2004, 2013-2022 Free Software Foundation, Inc. See the file COPYING for copying conditions. Please submit bug reports at https://github.com/dgutov/mmm-mode/issues * Changes in MMM Mode 0.5.10 Functions mmm-add-find-file-hooks and mmm-add-find-file-hook have been removed (GH#137). * Changes in MMM Mode 0.5.9 Made the tests work in batch mode. Switched from Automake to plain Makefile. Now requires at least GNU Emacs 25.1. Info documentation can be generated by the GNU ELPA packager. New here document class for shell. The new class handles indented here documents, which are incompatible with the mmm classes shared with Perl. * Changes in MMM Mode 0.5.8 Support for Emacs 27. Fixes for nesting submodes. * 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 , 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 <', rather than `C-c % ' as in previous versions. Key sequences of the form `C-c % ' 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-' 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. mmm-mode-0.5.10/README000066400000000000000000000060201450144406500141660ustar00rootroot00000000000000 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 Makefile has a target to build the MMM Mode info manual, so if you're installing manually you might want to do that too. Put the mmm.info file somewhere on your Info-path and use install-info to generate or update the dir file. 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! mmm-mode-0.5.10/README.Mason000066400000000000000000000122631450144406500152500ustar00rootroot00000000000000-*-text-*- Using MMM Mode for Mason: An Overview ===================================== Since many users of MMM Mode use it for Mason , 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; 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 <% $m->call_next %> in which case the actual components contain no doctype declaration, , , or , 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 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. mmm-mode-0.5.10/TODO000066400000000000000000000052201450144406500137770ustar00rootroot00000000000000Hey 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? mmm-mode-0.5.10/mmm-auto.el000066400000000000000000000152071450144406500153730ustar00rootroot00000000000000;;; mmm-auto.el --- loading and enabling MMM Mode automatically ;; Copyright (C) 2000-2004, 2012, 2013, 2018, 2022 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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) (sh-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)))) (defun mmm-autoload-class-private-p (autoload-class-entry) "Return t if AUTOLOAD-CLASS-ENTRY is marked as private. AUTOLOAD-CLASS-ENTRY shall be an entry of the variable `mmm-autoloaded-classes'." (nth 2 autoload-class-entry)) ;;}}} ;;{{{ 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) ;;}}} (provide 'mmm-auto) ;;; mmm-auto.el ends here mmm-mode-0.5.10/mmm-class.el000066400000000000000000000311361450144406500155270ustar00rootroot00000000000000;;; mmm-class.el --- MMM submode class variables and functions ;; Copyright (C) 2000-2004, 2011-2015, 2018 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 mmm-mode-0.5.10/mmm-cmds.el000066400000000000000000000376531450144406500153620ustar00rootroot00000000000000;;; mmm-cmds.el --- MMM Mode interactive commands and keymap ;; Copyright (C) 2000-2003, 2011-2013, 2018 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 #'mmm-autoload-class-private-p 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>... 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 mmm-mode-0.5.10/mmm-compat.el000066400000000000000000000104201450144406500156760ustar00rootroot00000000000000;;; mmm-compat.el --- MMM Hacks for compatibility with other Emacsen ;; Copyright (C) 2000, 2003, 2011, 2013 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 mmm-mode-0.5.10/mmm-cweb.el000066400000000000000000000052641450144406500153450ustar00rootroot00000000000000;;; mmm-cweb.el --- MMM submode class for CWeb programs ;; Copyright (C) 2001, 2002, 2013 Free Software Foundation, Inc. ;; Author: Alan Shutko ;;{{{ 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 mmm-mode-0.5.10/mmm-defaults.el000066400000000000000000000040131450144406500162230ustar00rootroot00000000000000;;; mmm-defaults.el --- Friendly defaults for MMM Mode ;; Copyright (C) 2013 Free Software Foundation, Inc. ;; Author: Dmitry Gutov ;;{{{ 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 mmm-mode-0.5.10/mmm-erb.el000066400000000000000000000227721450144406500152000ustar00rootroot00000000000000;;; mmm-erb.el --- ERB templates editing support ;; Copyright (C) 2012, 2013, 2018 Free Software Foundation, Inc. ;; Author: Dmitry Gutov ;;{{{ 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 "\\\\|}" "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 mmm-mode-0.5.10/mmm-mason.el000066400000000000000000000124171450144406500155400ustar00rootroot00000000000000;;; mmm-mason.el --- MMM submode class for Mason components ;; Copyright (C) 2000-2003, 2013, 2018 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 "" :insert ((?t mason-<%text> nil @ "<%text>" @ "\n" _ "\n" @ "" @))) (mason-doc :submode text-mode :face mmm-comment-submode-face :front "<%doc>" :back "" :face nil :insert ((?d mason-<%doc> nil @ "<%doc>" @ "\n" _ "\n" @ "" @))) (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 "" :save-matches 1 :match-name "~1" :save-name 1 :insert ((?, mason-<%TAG> "Perl section: " @ "<%" str ">" @ ";\n" _ "\n" @ "" @) (?< 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 "" :save-matches 1 :insert ((?. mason-pseudo-<%TAG> "Pseudo-perl section: " @ "<%" str ">" @ "\n" _ "\n" @ "" @) (?> mason-pseudo-<%TAG> ?, . nil) (?a mason-<%args> ?. . "args") (?f mason-<%flags> ?. . "flags") (?r mason-<%attr> ?. . "attr"))) (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-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 :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 mmm-mode-0.5.10/mmm-mode.el000066400000000000000000000264571450144406500153600ustar00rootroot00000000000000;;; mmm-mode.el --- Allow Multiple Major Modes in a buffer ;; Copyright (C) 1999-2004, 2012-2015, 2018, 2020 Free Software Foundation, Inc. ;; Emacs Lisp Archive Entry ;; Package: mmm-mode ;; Author: Michael Abraham Shulman ;; Maintainer: Dmitry Gutov ;; URL: https://github.com/purcell/mmm-mode ;; Keywords: convenience, faces, languages, tools ;; Version: 0.5.10 ;; Package-Requires: ((emacs "25.1") (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} 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 mmm-mode-0.5.10/mmm-myghty.el000066400000000000000000000140061450144406500157400ustar00rootroot00000000000000;;; 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 ;; 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 "" :insert ((?t myghty-<%text> nil @ "<%text>" @ "\n" _ "\n" @ "" @))) (myghty-doc :submode text-mode :face mmm-comment-submode-face :front "<%doc>" :back "" :face nil :insert ((?d myghty-<%doc> nil @ "<%doc>" @ "\n" _ "\n" @ "" @))) (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 "" :save-matches 1 :match-name "~1" :save-name 1 :insert ((?, myghty-<%TAG> "Python section: " @ "<%" str ">" @ ";\n" _ "\n" @ "" @) (?< 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 "" :save-matches 1 :insert ((?. myghty-pseudo-<%TAG> "Pseudo-python section: " @ "<%" str ">" @ "\n" _ "\n" @ "" @) (?> 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 mmm-mode-0.5.10/mmm-noweb.el000066400000000000000000000331361450144406500155360ustar00rootroot00000000000000;;; mmm-noweb.el --- MMM submode class for Noweb programs ;; ;; Copyright 2003, 2004 Joe Kelsey ;; 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 ;; ;;{{{ 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 mmm-mode-0.5.10/mmm-region.el000066400000000000000000001114561450144406500157110ustar00rootroot00000000000000;;; mmm-region.el --- Manipulating and behavior of MMM submode regions ;; Copyright (C) 2000-2003, 2010-2015, 2018, 2020 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 or nesting." (sort (copy-sequence overlays) (lambda (x y) (let ((prio-x (overlay-get x 'priority)) (prio-y (overlay-get y 'priority))) (if (or prio-x prio-y) (> (or prio-x 0) (or prio-y 0)) (> (overlay-start x) (overlay-start y))))))) ;;}}} ;;{{{ 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) (font-lock-set-defaults) ;; These can't be in the local variables list, because we ;; replace their actual values, but we want to use their ;; original values elsewhere. (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) (font-lock-flush 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) start stop))) (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 start stop) "Fontify REGIONS, each like (BEG END), in mode MODE. START and STOP are the boundaries of the area to fontify." (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 (max beg start) (min end stop) 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)) ((bound-and-true-p 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 mmm-mode-0.5.10/mmm-rpm.el000066400000000000000000000052001450144406500152110ustar00rootroot00000000000000;;; mmm-rpm.el --- MMM submode class for RPM spec files ;; Copyright (C) 2000 by Marcus Harnisch ;; Author: Marcus Harnisch ;;{{{ 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 and Steve ;; Sanbeg (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 mmm-mode-0.5.10/mmm-sample.el000066400000000000000000000347331450144406500157110ustar00rootroot00000000000000;;; mmm-sample.el --- Sample MMM submode classes ;; Copyright (C) 2000-2004, 2012-2015, 2018, 2022 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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) ;;{{{ 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 "" :back ""))) ;;}}} ;;{{{ JavaScript in HTML ;; We use two classes here, both for code in a ") (js-script :submode js-mode :face mmm-code-submode-face :front "]*>[ \t]*\n?" :back "[ \t]*" :insert ((?j js-tag nil @ "" @))))) ;;}}} ;;{{{ CSS in HTML (mmm-add-group 'html-css '((css-cdata :submode css :face mmm-code-submode-face :front "]*>[ \t\n]*\\(//\\)?[ \t\n]*") (css :submode css :face mmm-code-submode-face :front "]*>[ \t]*\n?" :back "[ \t]*" :insert ((?c css-tag nil @ "" @))))) ;;}}} ;;{{{ 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-get-lang-mode (string regex group) "Find a suitable submode for STRING. If REGEX matches STRING, The matching is based on the match GROUP. The following ways to find a matching submode are tried in order: * Search `mmm-here-doc-mode-alist' for a mode. * Try the whole name, stopping at `mode' if present. * Try each word by itself (preference list) * Try each word with -mode tacked on * Try each pair of words with -mode tacked on (w1 w2 w3) -> (w1w2-mode w2w3-mode w3-mode)" (string-match regex string) (setq string (match-string group 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))))) (defun mmm-here-doc-get-mode (string) "Find a submode for STRING. First match of [a-zA-Z_-]+ is used as the submode marker." (mmm-get-lang-mode string "\\([a-zA-Z_-]+\\)" 1)) (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" @)) ))) (defun mmm-sh-here-doc-get-mode (front-string) "Find the mode for a shell here-doc starting with FRONT-STRING. The matching is based on the word used as the here-document delimiter, the word following <<. Use `mmm-get-lang-mode' to find the submode." (mmm-get-lang-mode front-string "<<-?\\(['\"]?\\)\\([-a-zA-Z0-9_]+\\)\\1" 2)) ;; HEREDOC for shell scripts following the POSIX definition. It is ;; defined in two private classes that are then grouped into the class ;; sh-here-doc ;; Define some regex-parts that are reused a lot. ;; START is the '<<' sequence (let ((start '(sequence (or line-start (not "<")) "<<")) ;; DELIM is supposed to be a WORD, which is a complicated definition. ;; It may be quoted with ', ", or ` (delim '(sequence (group-n 2 (optional (any ?' ?\" ?`))) (group-n 1 (char "_a-zA-Z0-9") (one-or-more (char "-" "_a-zA-Z0-9"))) (backref 2))) (common-props '(:front-offset (end-of-line 1) :save-matches t :delimiter-mode nil :match-submode mmm-sh-here-doc-get-mode))) (mmm-add-group 'sh-here-doc `((sh-here-doc-unindented :front ,(rx-to-string `(sequence ,start ,delim)) :back ,(rx line-start "~1" line-end) ,@common-props :insert ((?d here-doc "Here-document Name: " @ "<<" str _ "\n" @ "\n" @ str "\n" @))) (sh-here-doc-indented :front ,(rx-to-string `(sequence ,start "-" ,delim)) :back ,(rx line-start (zero-or-more "\t") "~1" line-end) ,@common-props :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 for writing and ;; contributing this submode class. (mmm-add-classes '((sgml-dtd :submode dtd-mode :face mmm-declaration-submode-face :delimiter-mode nil :front "[]*\\[" :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 @ "" @)) ) (html-php-code :submode php-mode :face mmm-code-submode-face :front "<\\?\\(php\\)?" :back "\\(\\?>\\|\\'\\)" :insert ((?p php-section nil @ "" @) (?b php-block nil @ "" @)) ))) ;;}}} ;; NOT YET UPDATED ;;{{{ HTML in PL/SQL;-COM- ;-COM- ;-COM-;; This one is the most complex example. In PL/SQL, HTML is generally ;-COM-;; output as a (single quote delimited) string inside a call to htp.p or ;-COM-;; its brethren. The problem is that there may be strings outside of ;-COM-;; htp.p calls that should not be HTML, so we need to only look inside ;-COM-;; these calls. The situation is complicated by PL/SQL's rule that two ;-COM-;; sequential single quotes in a string mean to put a single quote ;-COM-;; inside the string. ;-COM- ;-COM-;; These functions have not been thoroughly tested, and always search ;-COM-;; the entire buffer, ignoring START and END. ;-COM- ;-COM-(defun mmm-html-in-plsql (start end) ;-COM- (save-match-data ;-COM- (let ((case-fold-search t)) ;-COM- (and (re-search-forward "htp.p\\(\\|rn\\|rint\\)1?(" nil t) ;-COM- (mmm-html-in-plsql-in-htp ;-COM- ;; Find the end of the procedure call ;-COM- (save-excursion (forward-char -1) (forward-sexp) (point)) ;-COM- start end))))) ;-COM- ;-COM-(defun mmm-html-in-plsql-in-htp (htp-end start end) ;-COM- (let (beg end) ;-COM- (or (and (re-search-forward "'" htp-end 'limit) ;-COM- (setf beg (match-end 0)) ;-COM- ;; Find an odd number of 's to end the string. ;-COM- (do ((lgth 0 (length (match-string 0)))) ;-COM- ((oddp lgth) t) ;-COM- (re-search-forward "'+" nil t)) ;-COM- (setf end (1- (match-end 0))) ;-COM- (cons (cons beg end) ;-COM- (mmm-html-in-plsql-in-htp htp-end start end))) ;-COM- ;; No more strings in the procedure call; look for another. ;-COM- (and (eql (point) htp-end) ;-COM- (mmm-html-in-plsql start end))))) ;-COM- ;-COM-(add-to-list 'mmm-classes-alist ;-COM- '(htp-p (:function html-mode mmm-html-in-plsql))) ;-COM- ;;}}} (provide 'mmm-sample) ;;; mmm-sample.el ends here mmm-mode-0.5.10/mmm-univ.el000066400000000000000000000036141450144406500154030ustar00rootroot00000000000000;;; mmm-univ.el --- The "Universal" Submode Class ;; Copyright (C) 2000, 2001, 2013 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 mmm-mode-0.5.10/mmm-utils.el000066400000000000000000000125151450144406500155620ustar00rootroot00000000000000;;; mmm-utils.el --- Coding Utilities for MMM Mode ;; Copyright (C) 2000-2003, 2011-2013, 2020 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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." (declare (indent 1) (debug t)) `(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 mmm-mode-0.5.10/mmm-vars.el000066400000000000000000001241601450144406500153750ustar00rootroot00000000000000;;; mmm-vars.el --- Variables for MMM Mode ;; Copyright (C) 2000-2004, 2011-2015, 2018-2020 Free Software Foundation, Inc. ;; Author: Michael Abraham Shulman ;;{{{ 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 js-mode typescript-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) (nxml-prolog-end region (nxml-mode)) 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-cpp-expr-functions-key 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-enum-clause-introduction-re c-expr-kwds c-file-offsets c-file-style c-found-types 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-make-top-level-key ;; c-make-top-level-kwds c-noise-macro-with-parens-name-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-pack-key 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 c-type-decl-suffix-ws-ids-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)) ,@(mapcar (lambda (var) (list var nil '(typescript-mode))) '(typescript--quick-match-re typescript--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) (syntax-ppss-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--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-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-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---hook', if it exists. If SUFFIX is nil or unsupplied, run `mmm--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.10" "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 mmm-mode-0.5.10/mmm.texi000066400000000000000000002463731450144406500150100ustar00rootroot00000000000000\input texinfo @c %**start of header @documentencoding UTF-8 @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 @ifnottex @node Top @top MMM Mode MMM Mode is a minor mode for Emacs which allows Multiple Major Modes to coexist in a single buffer. @end ifnottex @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 @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 , 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 @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 @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 @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 @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 @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 @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 @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>...} 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 @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>...}, @samp{<%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 @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 @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 @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 @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 @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>-<-; -!- ->- @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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; @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 <% $m->call_next %> @end example in which case the actual components contain no doctype declaration, @code{}, @code{}, or @code{}, 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{} tag, thus alleviating its confusion. @node File Variables @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 @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 < Test Page END_HTML @end example The @code{here-doc} submode class supports the general case of here-documents while the @code{sh-here-doc} class has more specialized support for shell scripts. They can both guess the correct submode to use based on the @dfn{delimiter} (@code{END_HTML} in the example) used. For instance, it would put the above example in @code{html-mode}, noticing the string @samp{HTML} in the delimiter of the here-document. Generally speaking any language mode can be found if the language name is one of the words in delimiter, but be aware that the first word that matches will be used. The @code{mmm-major-mode-preferences} list is checked for any language mode preferences, as described in @ref{Preferred Modes}. 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 @section Javascript in HTML The submode class @code{html-js} allows for embedding Javascript code in HTML documents. It recognizes both this syntax: @example @end example and this syntax: @example @end example The mode used for Javascript regions is controlled by the user; @xref{Preferred Modes}. @node Embedded CSS @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 @end example It uses @code{css-mode} if present, @code{c++-mode} otherwise. This can be customized: @xref{Preferred Modes}. @node Embperl @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 @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 @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 @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 and Steve Sanbeg (@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 for contributing this submode class. @node Noweb @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. <> @ %def myfile.cc @ \section{[[myfile.cc]]} This is [[myfile.cc]]. MMM noweb-mode understands code quotes in documentation. <>= // This section is indented separately from previous. @ @ \section{A Perl Chunk} We need a Perl chunk. <>= #!/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. <>= // 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 for contributing this class. @node Writing Classes @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 @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 "]*>" :back ""))) @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{"]*>"}. 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{} 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 @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>...} and @samp{<%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 @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 @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>...}, 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 @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 <} and @code{