diff options
Diffstat (limited to 'ocaml-binary-annot/emacs')
| -rw-r--r-- | ocaml-binary-annot/emacs/.cvsignore | 1 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/COPYING | 340 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/Makefile | 76 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/README | 206 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/README.itz | 177 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-compat.el | 41 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-emacs.el | 43 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-font-old.el | 141 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-font.el | 114 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-help.el | 855 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-hilit.el | 67 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-types.el | 765 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml-xemacs.el | 53 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/caml.el | 1932 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/camldebug.el | 793 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/inf-caml.el | 363 | ||||
| -rw-r--r-- | ocaml-binary-annot/emacs/ocamltags.in | 142 |
17 files changed, 6109 insertions, 0 deletions
diff --git a/ocaml-binary-annot/emacs/.cvsignore b/ocaml-binary-annot/emacs/.cvsignore new file mode 100644 index 0000000000..ea6381f91b --- /dev/null +++ b/ocaml-binary-annot/emacs/.cvsignore @@ -0,0 +1 @@ +ocamltags diff --git a/ocaml-binary-annot/emacs/COPYING b/ocaml-binary-annot/emacs/COPYING new file mode 100644 index 0000000000..5b6e7c66c2 --- /dev/null +++ b/ocaml-binary-annot/emacs/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ocaml-binary-annot/emacs/Makefile b/ocaml-binary-annot/emacs/Makefile new file mode 100644 index 0000000000..9519b396a5 --- /dev/null +++ b/ocaml-binary-annot/emacs/Makefile @@ -0,0 +1,76 @@ +######################################################################### +# # +# Objective Caml # +# # +# Xavier Leroy, projet Cristal, INRIA Rocquencourt # +# # +# Copyright 1997 Institut National de Recherche en Informatique et # +# en Automatique. All rights reserved. This file is distributed # +# under the terms of the GNU General Public License. # +# # +######################################################################### + +# $Id$ + +include ../config/Makefile + +# Files to install +FILES= caml-font.el caml-hilit.el caml.el camldebug.el \ + inf-caml.el caml-compat.el caml-help.el caml-types.el \ + caml-xemacs.el caml-emacs.el + +# Where to install. If empty, automatically determined. +#EMACSDIR= + +# Name of Emacs executable +EMACS=emacs + +# Where to install ocamltags script +SCRIPTDIR = $(BINDIR) + +# Command for byte-compiling the files +COMPILECMD=(progn \ + (setq load-path (cons "." load-path)) \ + (byte-compile-file "caml-xemacs.el") \ + (byte-compile-file "caml-emacs.el") \ + (byte-compile-file "caml.el") \ + (byte-compile-file "inf-caml.el") \ + (byte-compile-file "caml-help.el") \ + (byte-compile-file "caml-types.el") \ + (byte-compile-file "camldebug.el")) + +install: + @if test "$(EMACSDIR)" = ""; then \ + set xxx `($(EMACS) --batch --eval "(mapcar 'print load-path)") \ + 2>/dev/null | \ + sed -n -e '/\/site-lisp/s/"//gp'`; \ + if test "$$2" = ""; then \ + echo "Cannot determine Emacs site-lisp directory"; \ + exit 2; \ + fi; \ + $(MAKE) EMACSDIR="$$2" simple-install; \ + else \ + $(MAKE) simple-install; \ + fi + +# install the .el files, but do not compile them. +install-el: + $(MAKE) NOCOMPILE=true install + +simple-install: + @echo "Installing in $(EMACSDIR)..." + if test -d $(EMACSDIR); then : ; else mkdir -p $(EMACSDIR); fi + cp $(FILES) $(EMACSDIR) + if [ -z "$(NOCOMPILE)" ]; then \ + cd $(EMACSDIR); $(EMACS) --batch --eval '$(COMPILECMD)'; \ + fi + +ocamltags: ocamltags.in + sed -e 's:@EMACS@:$(EMACS):' ocamltags.in >ocamltags + chmod a+x ocamltags + +install-ocamltags: ocamltags + cp ocamltags $(SCRIPTDIR)/ocamltags + +clean: + rm -f ocamltags *~ #*# diff --git a/ocaml-binary-annot/emacs/README b/ocaml-binary-annot/emacs/README new file mode 100644 index 0000000000..7ddb362b4e --- /dev/null +++ b/ocaml-binary-annot/emacs/README @@ -0,0 +1,206 @@ + O'Caml emacs mode, snapshot of $Date$ + +The files in this archive define a caml-mode for emacs, for editing +Objective Caml and Objective Label programs, as well as an +inferior-caml-mode, to run a toplevel. + +Caml-mode supports indentation, compilation and error retrieving, +sending phrases to the toplevel. Moreover support for hilit, +font-lock and imenu was added. + +This package is based on the original caml-mode for caml-light by +Xavier Leroy, extended with indentation by Ian Zimmerman. For details +see README.itz, which is the README from Ian Zimmerman's package. + +To use it, just put the .el files in your path, and add the following +three lines in your .emacs. + + (setq auto-mode-alist + (cons '("\\.ml[iylp]?$" . caml-mode) auto-mode-alist)) + (autoload 'caml-mode "caml" "Major mode for editing Caml code." t) + (autoload 'run-caml "inf-caml" "Run an inferior Caml process." t) + +I added camldebug.el from the original distribution, since there will +soon be a debugger for Objective Caml, but I do not know enough about +it. + +To install the mode itself, edit the Makefile and do + + % make install + +To install ocamltags, do + + % make install-ocamltags + +To use highlighting capabilities, add ONE of the following two lines +to your .emacs. The second one works better on recent versions of +emacs. + + (if window-system (require 'caml-hilit)) + (if window-system (require 'caml-font)) + +caml.el and inf-caml.el can be used collectively, but it might be a +good idea to copy caml-hilit.el or caml-font.el to you own directory, +and edit it to your taste and colors. + +Main key bindings: + +TAB indent current line +M-C-q indent phrase +M-C-h mark phrase +C-c C-a switch between interface and implementation +C-c C-c compile (usually make) +C-x` goto next error (also mouse button 2 in the compilation log) + +Once you have started caml by M-x run-caml: + +M-C-x send phrase to inferior caml process +C-c C-r send region to inferior caml process +C-c C-s show inferior caml process +C-c` goto error in expression sent by M-C-x + +For other bindings, see C-h b. + +Changes log: +----------- +Version 3.10.1: +--------------- +* use caml-font.el from Olivier Andrieu + old version is left as caml-font-old.el for compatibility + +Version 3.07: +------------- +* support for showing type information <Damien Doligez> + +Version 3.05: +------------- +* improved interaction with inferior caml mode + +* access help from the source + +* fixes in indentation code + +Version 3.03: +------------- +* process ;; properly + +Version 3.00: +------------- +* adapt to new label syntax + +* intelligent indentation of parenthesis + +Version 2.02: +------------- +* improved ocamltags <ITZ and JG> + +* added support for multibyte characters in emacs 20 + +Version 2.01+: +-------------- +* corrected a bug in caml-font.el <Adam P. Jenkins> + +* corrected abbreviations and added ocamltags script <Ian T Zimmerman> + +Version 2.01: +------------ +* code for interactive errors added by ITZ + +Version 2.00: +------------ +* changed the algorithm to skip comments + +* adapted for the new object syntax + +Version 1.07: +------------ +* next-error bug fix by John Malecki + +* camldebug.el modified by Xavier Leroy + +Version 1.06: +------------ +* new keywords in O'Caml 1.06 + +* compatibility with GNU Emacs 20 + +* changed from caml-imenu-disable to caml-imenu-enable (off by default) + +Version 1.05: +------------ +* a few indentation bugs corrected. let, val ... are now indented + correctly even when you write them at the beginning of a line. + +* added a Caml menu, and Imenu support. Imenu menu can be disabled + by setting the variable caml-imenu-disable to t. + Xemacs support for the Menu, but no Imenu. + +* key bindings closer to lisp-mode. + +* O'Labl compatibility (":" is part of words) may be switched off by + setting caml-olabl-disable to t. + +* camldebug.el was updated by Xavier Leroy. + +Version 1.03b: +------------- +* many bugs corrected. + +* (partial) compatibility with Caml-Light added. + (setq caml-quote-char "`") + (setq inferior-caml-program "camllight") + Literals will be correctly understood and highlighted. However, + indentation rules are still Objective Caml's: this just happens to + work well in most cases, but is only intended for occasional use. + +* as many people asked for it, application is now indented. This seems + to work well: this time differences in indentation between the + compiler's source and this mode are really exceptionnal. On the + other hand, you may think that some special cases are strange. No + miracle. + +* nicer behaviour when sending a phrase/region to the inferior caml + process. + +Version 1.03: +------------ +* support of Objective Caml and Objective Label. + +* an indentation very close to mine, which happens to be the same as + Xavier's, since the sources of the Objective Caml compiler do not + change if you indent them in this mode. + +* highlighting. + +Some remarks about the style supported: +-------------------------------------- + +Since Objective Caml's syntax is very liberal (more than 100 +shift-reduce conflicts with yacc), automatic indentation is far from +easy. Moreover, you expect the indentation to be not purely syntactic, +but also semantic: reflecting the meaning of your program. + +This mode tries to be intelligent. For instance some operators are +indented differently in the middle and at the end of a line (thanks to +Ian Zimmerman). Also, we do not indent after if .. then .. else, when +else is on the same line, to reflect that this idiom is equivalent to +a return instruction in a more imperative language, or after the in of +let .. in, since you may see that as an assignment. + +However, you may want to use a different indentation style. This is +made partly possible by a number of variables at the beginning of +caml.el. Try to set them. However this only changes the size of +indentations, not really the look of your program. This is enough to +disable the two idioms above, but to do anything more you will have to +edit the code... Enjoy! + +This mode does not force you to put ;; in your program. This means +that we had to use a heuristic to decide where a phrase starts and +stops, to speed up the code. A phrase starts when any of the keywords +let, type, class, module, functor, exception, val, external, appears +at the beginning of a line. Using the first column for such keywords +in other cases may confuse the phrase selection function. + +Comments and bug reports to + + Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> diff --git a/ocaml-binary-annot/emacs/README.itz b/ocaml-binary-annot/emacs/README.itz new file mode 100644 index 0000000000..8e1366f478 --- /dev/null +++ b/ocaml-binary-annot/emacs/README.itz @@ -0,0 +1,177 @@ +DESCRIPTION: + +This directory contains files to help editing Caml code, running a +Caml toplevel, and running the Caml debugger under the Gnu Emacs editor. + +AUTHORS: + +Ian T Zimmerman <itz@rahul.net> added indentation to caml mode, beefed +up camldebug to work much like gud/gdb. + +Xavier Leroy (Xavier.Leroy@inria.fr), Jerome Vouillon (Jerome.Vouillon@ens.fr). +camldebug.el is derived from FSF code. + +CONTENTS: + + caml.el A major mode for editing Caml code in Gnu Emacs + inf-caml.el To run a Caml toplevel under Emacs, with input and + output in an Emacs buffer. + camldebug.el To run the Caml debugger under Emacs. + + +NOTE FOR EMACS 18 USERS: + +This package will no longer work with Emacs 18.x. Sorry. You really +should consider upgrading to Emacs 19. + +USAGE: + +Add the following lines to your .emacs file: + +(setq auto-mode-alist (cons '("\\.ml[iylp]?" . caml-mode) auto-mode-alist)) +(autoload 'caml-mode "caml" "Major mode for editing Caml code." t) +(autoload 'run-caml "inf-caml" "Run an inferior Caml process." t) +(autoload 'camldebug "camldebug" "Run the Caml debugger." t) + +The Caml major mode is triggered by visiting a file with extension .ml, +.mli, .mly. .mll or .mlp, or manually by M-x caml-mode. It gives you the +correct syntax table for the Caml language. For a brief description of +the indentation capabilities, see below under NEWS. + +The Caml mode also allows you to run batch Caml compilations from +Emacs (using M-x compile) and browse the errors (C-x `). Typing C-x ` +sets the point at the beginning of the erroneous program fragment, and +the mark at the end. Under Emacs 19, the program fragment is +temporarily highlighted. + +M-x run-caml starts a Caml toplevel with input and output in an Emacs +buffer named *inferior-caml*. This gives you the full power of Emacs +to edit the input to the Caml toplevel. This mode is based on comint +so you get all the usual comint features, including command history. + +After M-x run-caml, typing C-c C-e or M-C-x in a buffer in Caml mode +sends the current phrase (containing the point) to the Caml toplevel, +and evaluates it. + +M-x camldebug FILE starts the Caml debugger camldebug on the executable +FILE, with input and output in an Emacs buffer named *camldebug-FILE*. +For a brief description of the commands available in this buffer, see +NEWS below. + +NEWS: + +Ok, so this is the really important part of this file :-) I took the +original package from the contrib subdirectory of the caml-light +distribution, and hacked on it. First, I added real syntax dependent +indentation to caml mode. Like Xavier has said, it was hard (and I +knew it would be), but I refused to believe it was impossible, partly +because I knew of a Standard ML mode with indentation (written by +Matthew Morley). + +Indentation works pretty much like in other programming modes. C-j at +the end of a line starts a new line properly indented. M-C-\ indents +the current region (this may take a while :-)). I incorporated a +slightly different TAB function, one that I use in other modes: if TAB +is pressed while the point is not in line indentation, the line is +indented to the column where point is (instead of just inserting a TAB +character - you can always to that with C-q C-i). This way, you can +indent a line any time, regardless of where the point lies, by hitting +TAB twice in succession. If you don't like this behaviour (but you +should), it's quite easy to add to your startup code like this: + +(defun caml-old-style-indent () + (if (caml-in-indentation) + (caml-indent-command) + (insert "\t"))) + +(add-hook 'caml-mode-hook + (function (lambda () + (define-key 'caml-mode-map "\t" + caml-old-style-indent)))) + +You can customize the appearance of your caml code by twiddling the +variables listed at the start of caml.el. Good luck. :-) + +Other news in caml mode are the various caml-insert-*-form commands. I +believe they are self-explanatory - just do a C-h m in a caml buffer +to see what you've got. + +The ohter major news is that I changed camldebug mode considerably. I +took many clues from the gud "Grand Unified Debugger" mode distributed +with modern versions of Emacs. The main benefit here is that you can +do debugger commands _from your caml source buffer_. Commands with the +C-c prefix in the debugger buffer have counterparts which do the same +thing (well, a similar thing) in the source buffer, with the C-x C-a +prefix. + +I made the existing debugger commands smarter in that they now attempt +to guess the correct parameter to the underlying camldebug command. A +numeric argument will always override that guess. For example, the +guess for C-c C-b (camldebug-break) is to set a breakpoint at the +current event (which was the only behaviour provided with the old +camldebug.el). But C-u 1 C-c C-b will now send "break 1" to the +camldebug process, setting a break at code address 1. + +This also allowed me to add many more commands for which the +underlying camldebug commands require a parameter. The best way to +learn about them is to do C-h m in the camldebug buffer, and then C-h +f for the commands you'll see listed. + +Finally, I added command completion. To use it, you'll have to apply +the provided patch to the debugger itself +(contrib/debugger/command_line_interpreter.ml), and recompile it +(you'll get one warning from the compiler; it is safe to ignore +it). Then hitting TAB in the following situation, for example: + +(cdb) pri_ + +will complete the "pri" to "print". + +CAVEATS: + +I don't use X and haven't tested this stuff under the X mode of +emacs. It is entirely possible (though not very probable) that I +introduced some undesirable interaction between X (fontification, +highlighting,...) and caml mode. I will welcome reports of such +problems (see REPORTING below), but I won't be able to do much about +them unless you also provide a patch. + +I don't know if the informational messages produced by camldebug are +internationalized. If they are, the debugger mode won't work unless +you set the language to English. The mode uses the messages to +synchronize with camldebug, and looks for fixed Emacs regular +expressions that match them. This may be fixed (if necessary) in a +future release. + +BUGS: + +In the debugger buffer, it's possible to overflow your mental stack by +asking for help on help on help on help on help on help on help on +help... + +THANKS: + +Xavier Leroy <Xavier.Leroy@inria.fr> for Caml-light. Used together with the +Emacs interface, it is about the most pleasant programming environment +I've known on any platform. + +Eric Raymond <esr@thyrsus.com> for gud, which camldebug mode apes. + +Barry Warsaw <bwarsaw@cen.com> for elp, without which I wouldn't have +been able to get the indentation code to perform acceptably. + +Gareth Rees <Gareth.Rees@cl.cam.ac.uk> for suggestions how to speed up +Emacs regular expression search, even if I didn't use them in the end. + +Bill Dubuque <wgd@martigny.ai.mit.edu> for alerting me to the +necessity of guarding against C-g inside Emacs code which modifies +syntax tables. + +REPORTING: + +Bug reports (preferably with patches), suggestions, donations etc. to: + +Ian T Zimmerman +-------------------------------------------+ +Box 13445 I With so many executioners available, I +Berkeley CA 94712 USA I suicide is a really foolish thing to do. I +mailto:itz@rahul.net +-------------------------------------------+ diff --git a/ocaml-binary-annot/emacs/caml-compat.el b/ocaml-binary-annot/emacs/caml-compat.el new file mode 100644 index 0000000000..8ba7a99c7e --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-compat.el @@ -0,0 +1,41 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +;(* *) +;(* Copyright 1998 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;; function definitions for old versions of emacs + +;; indent-line-to + +(if (not (fboundp 'indent-line-to)) + (defun indent-line-to (column) + "Indent current line to COLUMN. + +This function removes or adds spaces and tabs at beginning of line +only if necessary. It leaves point at end of indentation." + (if (= (current-indentation) column) + (back-to-indentation) + (beginning-of-line 1) + (delete-horizontal-space) + (indent-to column)))) + +;; buffer-substring-no-properties + +(cond + ((fboundp 'buffer-substring-no-properties)) + ((fboundp 'buffer-substring-without-properties) + (defalias 'buffer-substring-no-properties + 'buffer-substring-without-properties)) + (t + (defalias 'buffer-substring-no-properties 'buffer-substring))) + +(provide 'caml-compat) diff --git a/ocaml-binary-annot/emacs/caml-emacs.el b/ocaml-binary-annot/emacs/caml-emacs.el new file mode 100644 index 0000000000..d034ff304a --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-emacs.el @@ -0,0 +1,43 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Didier Remy, projet Cristal, INRIA Rocquencourt *) +;(* *) +;(* Copyright 2003 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;; for caml-help.el +(defalias 'caml-info-other-window 'info-other-window) + +;; for caml-types.el + +(defalias 'caml-line-beginning-position 'line-beginning-position) + +(defalias 'caml-read-event 'read-event) +(defalias 'caml-window-edges 'window-edges) +(defun caml-mouse-vertical-position () + (cddr (mouse-position))) +(defalias 'caml-ignore-event-p 'integer-or-marker-p) +(defalias 'caml-mouse-movement-p 'mouse-movement-p) +(defalias 'caml-sit-for 'sit-for) + +(defmacro caml-track-mouse (&rest body) (cons 'track-mouse body)) + +(defun caml-event-window (e) (posn-window (event-start e))) +(defun caml-event-point-start (e) (posn-point (event-start e))) +(defun caml-event-point-end (e) (posn-point (event-end e))) + +(defun caml-release-event-p (original event) + (and (equal (event-basic-type original) (event-basic-type event)) + (let ((modifiers (event-modifiers event))) + (or (member 'drag modifiers) + (member 'click modifiers))))) + + +(provide 'caml-emacs) diff --git a/ocaml-binary-annot/emacs/caml-font-old.el b/ocaml-binary-annot/emacs/caml-font-old.el new file mode 100644 index 0000000000..8faa542f05 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-font-old.el @@ -0,0 +1,141 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Jacques Garrigue and Ian T Zimmerman *) +;(* *) +;(* Copyright 1997 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;; useful colors + +(cond + ((x-display-color-p) + (require 'font-lock) + (cond + ((not (boundp 'font-lock-type-face)) + ; make the necessary faces + (make-face 'Firebrick) + (set-face-foreground 'Firebrick "Firebrick") + (make-face 'RosyBrown) + (set-face-foreground 'RosyBrown "RosyBrown") + (make-face 'Purple) + (set-face-foreground 'Purple "Purple") + (make-face 'MidnightBlue) + (set-face-foreground 'MidnightBlue "MidnightBlue") + (make-face 'DarkGoldenRod) + (set-face-foreground 'DarkGoldenRod "DarkGoldenRod") + (make-face 'DarkOliveGreen) + (set-face-foreground 'DarkOliveGreen "DarkOliveGreen4") + (make-face 'CadetBlue) + (set-face-foreground 'CadetBlue "CadetBlue") + ; assign them as standard faces + (setq font-lock-comment-face 'Firebrick) + (setq font-lock-string-face 'RosyBrown) + (setq font-lock-keyword-face 'Purple) + (setq font-lock-function-name-face 'MidnightBlue) + (setq font-lock-variable-name-face 'DarkGoldenRod) + (setq font-lock-type-face 'DarkOliveGreen) + (setq font-lock-reference-face 'CadetBlue))) + ; extra faces for documention + (make-face 'Stop) + (set-face-foreground 'Stop "White") + (set-face-background 'Stop "Red") + (make-face 'Doc) + (set-face-foreground 'Doc "Red") + (setq font-lock-stop-face 'Stop) + (setq font-lock-doccomment-face 'Doc) +)) + +; The same definition is in caml.el: +; we don't know in which order they will be loaded. +(defvar caml-quote-char "'" + "*Quote for character constants. \"'\" for Objective Caml, \"`\" for Caml-Light.") + +(defconst caml-font-lock-keywords + (list +;stop special comments + '("\\(^\\|[^\"]\\)\\((\\*\\*/\\*\\*)\\)" + 2 font-lock-stop-face) +;doccomments + '("\\(^\\|[^\"]\\)\\((\\*\\*[^*]*\\([^)*][^*]*\\*+\\)*)\\)" + 2 font-lock-doccomment-face) +;comments + '("\\(^\\|[^\"]\\)\\((\\*[^*]*\\*+\\([^)*][^*]*\\*+\\)*)\\)" + 2 font-lock-comment-face) +;character literals + (cons (concat caml-quote-char "\\(\\\\\\([ntbr" caml-quote-char "\\]\\|" + "[0-9][0-9][0-9]\\)\\|.\\)" caml-quote-char + "\\|\"[^\"\\]*\\(\\\\\\(.\\|\n\\)[^\"\\]*\\)*\"") + 'font-lock-string-face) +;modules and constructors + '("`?\\<[A-Z][A-Za-z0-9_']*\\>" . font-lock-function-name-face) +;definition + (cons (concat + "\\<\\(a\\(nd\\|s\\)\\|c\\(onstraint\\|lass\\)" + "\\|ex\\(ception\\|ternal\\)\\|fun\\(ct\\(ion\\|or\\)\\)?" + "\\|in\\(herit\\|itializer\\)?\\|let" + "\\|m\\(ethod\\|utable\\|odule\\)" + "\\|of\\|p\\(arser\\|rivate\\)\\|rec\\|type" + "\\|v\\(al\\|irtual\\)\\)\\>") + 'font-lock-type-face) +;blocking + '("\\<\\(begin\\|end\\|object\\|s\\(ig\\|truct\\)\\)\\>" + . font-lock-keyword-face) +;control + (cons (concat + "\\<\\(do\\(ne\\|wnto\\)?\\|else\\|for\\|i\\(f\\|gnore\\)" + "\\|lazy\\|match\\|new\\|or\\|t\\(hen\\|o\\|ry\\)" + "\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\)\\>" + "\\|\|\\|->\\|&\\|#") + 'font-lock-reference-face) + '("\\<raise\\>" . font-lock-comment-face) +;labels (and open) + '("\\(\\([~?]\\|\\<\\)[a-z][a-zA-Z0-9_']*:\\)[^:=]" 1 + font-lock-variable-name-face) + '("\\<\\(assert\\|open\\|include\\)\\>\\|[~?][ (]*[a-z][a-zA-Z0-9_']*" + . font-lock-variable-name-face))) + +(defconst inferior-caml-font-lock-keywords + (append + (list +;inferior + '("^[#-]" . font-lock-comment-face)) + caml-font-lock-keywords)) + +;; font-lock commands are similar for caml-mode and inferior-caml-mode +(defun caml-mode-font-hook () + (cond + ((fboundp 'global-font-lock-mode) + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '(caml-font-lock-keywords nil nil ((?' . "w") (?_ . "w"))))) + (t + (setq font-lock-keywords caml-font-lock-keywords))) + (make-local-variable 'font-lock-keywords-only) + (setq font-lock-keywords-only t) + (font-lock-mode 1)) + +(add-hook 'caml-mode-hook 'caml-mode-font-hook) + +(defun inferior-caml-mode-font-hook () + (cond + ((fboundp 'global-font-lock-mode) + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '(inferior-caml-font-lock-keywords + nil nil ((?' . "w") (?_ . "w"))))) + (t + (setq font-lock-keywords inferior-caml-font-lock-keywords))) + (make-local-variable 'font-lock-keywords-only) + (setq font-lock-keywords-only t) + (font-lock-mode 1)) + +(add-hook 'inferior-caml-mode-hooks 'inferior-caml-mode-font-hook) + +(provide 'caml-font) diff --git a/ocaml-binary-annot/emacs/caml-font.el b/ocaml-binary-annot/emacs/caml-font.el new file mode 100644 index 0000000000..f287ffa045 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-font.el @@ -0,0 +1,114 @@ +;; caml-font: font-lock support for OCaml files +;; +;; rewrite and clean-up. +;; Changes: +;; - fontify strings and comments using syntactic font lock +;; - define a `font-lock-syntactic-face-function' to fontify ocamldoc comments +;; - fontify infix operators like mod, land, lsl, etc. +;; - fontify line number directives +;; - fontify "failwith" and "invalid_arg" like "raise" +;; - fontify '\x..' character constants +;; - use the regexp-opt function to build regexps (more readable) +;; - use backquote and comma in sexp (more readable) +;; - drop the `caml-quote-char' variable (I don't use caml-light :)) +;; - stop doing weird things with faces + + +(require 'font-lock) + +(defvar caml-font-stop-face + (progn + (make-face 'caml-font-stop-face) + (set-face-foreground 'caml-font-stop-face "White") + (set-face-background 'caml-font-stop-face "Red") + 'caml-font-stop-face)) + +(defvar caml-font-doccomment-face + (progn + (make-face 'caml-font-doccomment-face) + (set-face-foreground 'caml-font-doccomment-face "Red") + 'caml-font-doccomment-face)) + +(unless (facep 'font-lock-preprocessor-face) + (defvar font-lock-preprocessor-face + (copy-face 'font-lock-builtin-face + 'font-lock-preprocessor-face))) + +(defconst caml-font-lock-keywords + `( +;character literals + ("'\\(.\\|\\\\\\([ntbr\"'\\\\]\\|[0-9]\\{3\\}\\|x[0-9A-Fa-f]\\{2\\}\\)\\)'" + . font-lock-string-face) +;modules and constructors + ("`?\\<[A-Z][A-Za-z0-9_']*\\>" . font-lock-function-name-face) +;definition + (,(regexp-opt '("and" "as" "constraint" "class" + "exception" "external" "fun" "function" "functor" + "in" "inherit" "initializer" "let" + "method" "mutable" "module" "of" "private" "rec" + "type" "val" "virtual") + 'words) + . font-lock-type-face) +;blocking + (,(regexp-opt '("begin" "end" "object" "sig" "struct") 'words) + . font-lock-keyword-face) +;linenums + ("# *[0-9]+" . font-lock-preprocessor-face) +;infix operators + (,(regexp-opt '("asr" "land" "lor" "lsl" "lsr" "lxor" "mod") 'words) + . font-lock-builtin-face) +;control + (,(concat "[|#&]\\|->\\|" + (regexp-opt '("do" "done" "dowto" "else" "for" "if" "ignore" + "lazy" "match" "new" "or" "then" "to" "try" + "when" "while" "with") + 'words)) + . font-lock-constant-face) + ("\\<raise\\|failwith\\|invalid_arg\\>" + . font-lock-comment-face) +;labels (and open) + ("\\(\\([~?]\\|\\<\\)[a-z][a-zA-Z0-9_']*:\\)[^:=]" + 1 font-lock-variable-name-face) + ("\\<\\(assert\\|open\\|include\\)\\>\\|[~?][ (]*[a-z][a-zA-Z0-9_']*" + . font-lock-variable-name-face))) + + +(defun caml-font-syntactic-face (s) + (let ((in-string (nth 3 s)) + (in-comment (nth 4 s)) + (start (nth 8 s))) + (cond + (in-string 'font-lock-string-face) + (in-comment + (save-excursion + (goto-char start) + (cond + ((looking-at "(\\*\\*/\\*\\*)") 'caml-font-stop-face) + ((looking-at "(\\*\\*[^*]") 'caml-font-doccomment-face) + (t 'font-lock-comment-face))))))) + + +;; font-lock commands are similar for caml-mode and inferior-caml-mode +(defun caml-font-set-font-lock () + (setq font-lock-defaults + '(caml-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-face-function . caml-font-syntactic-face))) + (font-lock-mode 1)) +(add-hook 'caml-mode-hook 'caml-font-set-font-lock) + + + +(defconst inferior-caml-font-lock-keywords + `(("^[#-]" . font-lock-comment-face) + ,@caml-font-lock-keywords)) + +(defun inferior-caml-set-font-lock () + (setq font-lock-defaults + '(inferior-caml-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-face-function . caml-font-syntactic-face))) + (font-lock-mode 1)) +(add-hook 'inferior-caml-mode-hooks 'inferior-caml-set-font-lock) + +(provide 'caml-font) diff --git a/ocaml-binary-annot/emacs/caml-help.el b/ocaml-binary-annot/emacs/caml-help.el new file mode 100644 index 0000000000..59d8a3b0c5 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-help.el @@ -0,0 +1,855 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Didier Remy, projet Cristal, INRIA Rocquencourt *) +;(* *) +;(* Copyright 2001 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;; caml-info.el --- contextual completion and help to caml-mode + +;; Didier Remy, November 2001. + +;; This provides two functions completion and help +;; look for caml-complete and caml-help + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This is a preliminary version. +;; +;; Possible improvements? +;; - dump some databaes: Info, Lib, ... +;; - accept a search path for local libraries instead of current dir +;; (then distinguish between different modules lying in different +;; directories) +;; - improve the construction for info files. +;; +;; Abstract over +;; - the viewing method and the database, so that the documentation for +;; and identifier could be search in +;; * info / html / man / mli's sources +;; * viewed in emacs or using an external previewer. +;; +;; Take all identifiers (labels, Constructors, exceptions, etc.) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +(eval-and-compile + (if (and (boundp 'running-xemacs) running-xemacs) + (require 'caml-xemacs) + (require 'caml-emacs))) + +;; Loading or building databases. +;; + +;; variables to be customized + +(defvar ocaml-lib-path 'lazy + "Path list for ocaml lib sources (mli files) + +'lazy means ask ocaml to find it for your at first use.") +(defun ocaml-lib-path () + "Computes if necessary and returns the path for ocaml libs" + (if (listp ocaml-lib-path) nil + (setq ocaml-lib-path + (split-string + (shell-command-to-string + (or + (and (boundp 'inferior-caml-program) + (string-match "\\([^ ]*/ocaml\\)\\( \\|$\\)" + inferior-caml-program) + (let ((file + (concat (match-string 1 inferior-caml-program) + "c"))) + (and (file-executable-p file) + (concat file " -where")))) + "ocamlc -where"))))) + ocaml-lib-path) + + + +;; General purpose auxiliary functions + +(defun ocaml-capitalize (s) + (concat (capitalize (substring s 0 1)) (substring s 1))) + +(defun ocaml-uncapitalize (s) + (if (> (length s) 0) + (concat (downcase (substring s 0 1)) (substring s 1)) + s)) + +(defun iter (f l) (while (consp l) (apply f (list (car l))) (setq l (cdr l)))) + +(defun ocaml-find-files (path filter &optional depth split) + (let* ((path-string + (if (stringp path) + (if (file-directory-p path) path nil) + (mapconcat '(lambda (d) (if (file-directory-p d) d)) + path " "))) + (command + (and path-string + (concat "find " path-string + " '(' " filter " ')' " + (if depth (concat " -maxdepth " (int-to-string depth))) + (if split nil " -printf '%\p '") + ))) + (files + (and command (shell-command-to-string command)))) + (if (and split (stringp files)) (split-string files "\n") files) + )) + +;; Specialized auxiliary functions + + +;; Global table of modules contents of modules loaded lazily. + +(defvar ocaml-module-alist 'lazy + "A-list of modules with how and where to find help information. + 'delay means non computed yet") + +(defun ocaml-add-mli-modules (modules tag &optional path) + (let ((files + (ocaml-find-files (or path (ocaml-lib-path)) + "-type f -name '*.mli'" 1 t))) + (while (consp files) + (if (string-match "\\([^/]*\\).mli" (car files)) + (let* ((module (ocaml-capitalize (match-string 1 (car files)))) + (dir (file-name-directory (car files))) + (dirp (member dir (ocaml-lib-path)))) + (if (and (consp dirp) (string-equal dir (car dirp))) + (setq dir (car dirp))) + (if (assoc module modules) nil + (setq modules + (cons (cons module (cons (cons tag dir) 'lazy)) modules)) + ))) + (setq files (cdr files))) + modules)) + +(defun ocaml-add-path (dir &optional path) + "Extend ocaml-module-alist with modules of DIR relative to PATH" + (interactive "D") + (let* ((old (ocaml-lib-path)) + (new + (if (file-name-absolute-p dir) dir + (concat + (or (find-if '(lambda (p) (file-directory-p (concat p "/" dir))) + (cons default-directory old)) + (error "Directory not found")) + "/" dir)))) + (setq ocaml-lib-path (cons (car old) (cons new (cdr old)))) + (setq ocaml-module-alist + (ocaml-add-mli-modules (ocaml-module-alist) 'lib new)))) + +(defun ocaml-module-alist () + "Call by need value of variable ocaml-module-alist" + (if (listp ocaml-module-alist) + nil + ;; build list of mli files + (setq ocaml-module-alist (ocaml-add-mli-modules nil 'lib)) + ;; dumping information ? TODO + ) + ocaml-module-alist) + +(defun ocaml-get-or-make-module (module &optional tag) + (let ((info (assoc module (ocaml-module-alist)))) + (if info nil + (setq info (cons module (cons (cons 'local default-directory) 'lazy))) + (setq ocaml-module-alist (cons info ocaml-module-alist)) + ) + info)) + +;; Symbols of module are lazily computed + +(defun ocaml-module-filename (module) + (let ((module (ocaml-uncapitalize module)) (name)) + (if (file-exists-p (setq name (concat module ".mli"))) nil + (let ((tmp (ocaml-lib-path))) + (while (consp tmp) + (setq name (concat (car tmp) "/" module ".mli")) + (if (file-exists-p name) (setq tmp nil) + (setq name nil))))) + name)) + +(defun ocaml-module-symbols (module-info) + (let* ((module (car module-info)) + (tail (and module-info (cdr module-info))) + (tag (caar tail)) + (dir (cdar tail)) + (file) + (alist)) + (if (listp (cdr tail)) + (cdr tail) + (if (equal tag 'info) + (setq dir (car ocaml-lib-path)) ; XXX to be fixed + ) + (setq file (concat dir "/" (ocaml-uncapitalize module) ".mli")) + (message file) + (save-window-excursion + (set-buffer (get-buffer-create "*caml-help*")) + (if (and file (file-exists-p file)) + (progn + (message "Scanning module %s" file) + (insert-file-contents file)) + (message "Module %s not found" module)) + (while (re-search-forward + "\\([ \t]*val\\|let\\|exception\\|external\\| [|]\\) \\([a-zA-Z_0-9'][a-zA-Z_0-9']*\\)\\|^ *[{]* \\([a-z_][A-Za-z_0-9]*\\) : [^;\n][^;\n]*;" + (point-max) 'move) + (pop-to-buffer (current-buffer)) + (setq alist (cons (or (match-string 2) (match-string 3)) alist))) + (erase-buffer) + ) + (setcdr tail alist) + alist) + )) + +;; Local list of visible modules. + +(defvar ocaml-visible-modules 'lazy + "A-list of open modules, local to every file.") +(make-variable-buffer-local 'ocaml-visible-modules) +(defun ocaml-visible-modules () + (if (listp ocaml-visible-modules) nil + (progn + (setq ocaml-visible-modules + (list (ocaml-get-or-make-module "Pervasives"))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "^ *open *\\([A-Z][a-zA-Z'_0-9]*\\)" + (point-max) t) + (let ((module (match-string 1))) + (if (assoc module ocaml-visible-modules) nil + (setq ocaml-visible-modules + (cons (ocaml-get-or-make-module module) + ocaml-visible-modules))))) + ))) + ocaml-visible-modules) + +(defun ocaml-open-module (arg) + "*Make module of name ARG visible whe ARG is a string. +When call interactively, make completion over known modules." + (interactive "P") + (if (not (stringp arg)) + (let ((modules (ocaml-module-alist))) + (setq arg + (completing-read "Open module: " modules)))) + (if (and (stringp arg) (not (equal arg ""))) + (progn + (if (assoc arg (ocaml-visible-modules)) + (ocaml-close-module arg)) + (setq ocaml-visible-modules + (cons (ocaml-get-or-make-module arg) (ocaml-visible-modules))) + )) + (message "%S" (mapcar 'car (ocaml-visible-modules)))) + +(defun ocaml-close-module (arg) + "*Close module of name ARG when ARG is a string. +When call interactively, make completion over visible modules. +Otherwise if ARG is true, close all modules and reset to default. " + (interactive "P") + (if (= (prefix-numeric-value arg) 4) + (setq ocaml-visible-modules 'lazy) + (let* ((modules (ocaml-visible-modules))) + (if (null modules) (error "No visible module to close")) + (unless (stringp arg) + (setq arg + (completing-read + (concat "Close module [" (caar modules) "] : ") + modules)) + (if (equal arg "") (setq arg (caar modules)))) + (setq ocaml-visible-modules + (remove-if '(lambda (m) (equal (car m) arg)) + ocaml-visible-modules)) + )) + (message "%S" (mapcar 'car (ocaml-visible-modules)))) + + +;; Look for identifiers around point + +(defun ocaml-qualified-identifier (&optional show) + "Search for a qualified identifier (Path. entry) around point. + +Entry may be nil. +Currently, the path may only be nil or a single Module. +For paths is of the form Module.Path', it returns Module +and always nil for entry. + +If defined Module and Entry are represented by a region in the buffer, +and are nil otherwise. + +For debugging purposes, it returns the string Module.entry if called +with an optional non-nil argument. +" + (save-excursion + (let ((module) (entry)) + (if (looking-at "[ \n]") (skip-chars-backward " ")) + (if (re-search-backward + "\\([^A-Za-z0-9_.']\\|\\`\\)\\([A-Za-z0-9_']*[.]\\)*[A-Za-z0-9_']*\\=" + (- (point) 100) t) + (progn + (or (looking-at "\\`[A-Za-z)-9_.]") (forward-char 1)) + (if (looking-at "\\<\\([A-Za-z_][A-Za-z0-9_']*\\)[.]") + (progn + (setq module (cons (match-beginning 1) (match-end 1))) + (goto-char (match-end 0)))) + (if (looking-at "\\<\\([A-Za-z_][A-Za-z0-9_']*\\)\\>") + (setq entry (cons (match-beginning 1) (match-end 1)))))) + (if show + (concat + (and module (buffer-substring (car module) (cdr module))) + "." + (and entry (buffer-substring (car entry) (cdr entry)))) + (cons module entry)) + ))) + +;; completion around point + +(defun ocaml-completion (pattern module) + (let ((list + (or + (and module + (list + (or (assoc module (ocaml-module-alist)) + (error "Unknown module %s" module)))) + (ocaml-visible-modules)))) + (message "Completion from %s" (mapconcat 'car list " ")) + (if (null pattern) + (apply 'append (mapcar 'ocaml-module-symbols list)) + (let ((pat (concat "^" (regexp-quote pattern))) (res)) + (iter + '(lambda (l) + (iter '(lambda (x) + (if (string-match pat (car l)) + (if (member x res) nil (setq res (cons x res))))) + (ocaml-module-symbols l))) + list) + res) + ))) + +(defun caml-complete (arg) + "Does completion for OCaml identifiers qualified. + +It attemps to recognize an qualified identifier Module . entry +around point using function \\[ocaml-qualified-identifier]. + +If Module is defined, it does completion for identifier in Module. + +If Module is undefined, it does completion in visible modules. +Then, if completion fails, it does completion among all modules +where identifier is defined." + (interactive "p") + (let* ((module-entry (ocaml-qualified-identifier)) (entry) + (module) + (beg) (end) (pattern)) + (if (car module-entry) + (progn + (setq module + (buffer-substring (caar module-entry) (cdar module-entry))) + (or (assoc module (ocaml-module-alist)) + (and (setq module + (completing-read "Module: " (ocaml-module-alist) + nil nil module)) + (save-excursion + (goto-char (caar module-entry)) + (delete-region (caar module-entry) (cdar module-entry)) + (insert module) t) + (setq module-entry (ocaml-qualified-identifier)) + (car module-entry) + (progn (setq entry (cdr module-entry)) t)) + (error "Unknown module %s" module)))) + (if (consp (cdr module-entry)) + (progn + (setq beg (cadr module-entry)) + (setq end (cddr module-entry))) + (if (and module + (save-excursion + (goto-char (cdar module-entry)) + (looking-at " *[.]"))) + (progn + (setq beg (match-end 0)) + (setq end beg)))) + (if (not (and beg end)) + (error "Did not find anything to complete around point") + + (setq pattern (buffer-substring beg end)) + (let* ((all-completions (ocaml-completion pattern module)) + (completion + (try-completion pattern (mapcar 'list all-completions)))) + (cond ((eq completion t)) + + ((null completion) + (let* + ((modules (ocaml-find-module pattern)) + (visible (intersection modules (ocaml-visible-modules))) + (hist) + (module + (cond + ((null modules) + nil) + ((equal (length modules) 1) + (caar modules)) + ((equal (length visible) 1) + (caar visible)) + (t + (setq hist (mapcar 'car modules)) + (completing-read "Module: " modules nil t + "" (cons hist 0))) + ))) + (if (null module) + (error "Can't find completion for \"%s\"" pattern) + (message "Completion found in module %s" module) + (if (and (consp module-entry) (consp (cdr module-entry))) + (delete-region (caar module-entry) end) + (delete-region beg end)) + (insert module "." pattern)))) + + ((not (string-equal pattern completion)) + (delete-region beg end) + (goto-char beg) + (insert completion)) + + (t + (with-output-to-temp-buffer "*Completions*" + (display-completion-list all-completions)) + )) + )))) + + +;; Info files (only in ocamldoc style) + + +(defvar ocaml-info-prefix "ocaml-lib" + "Prefix of ocaml info files describing library modules. +Suffix .info will be added to info files. +Additional suffix .gz may be added if info files are compressed. +") +;; + +(defun ocaml-hevea-info-add-entries (entries dir name) + (let* + ((filter + (concat "-type f -regex '.*/" name + "\\(.info\\|\\)\\(-[0-9]*\\|\\)\\([.]gz\\|\\)'" + )) + (section-regexp + "\\* \\(Section [1-9][0-9--]*\\)::[ \t][ \t]*Module *\\([A-Z][A-Za-z_0-9]*\\)") + (files (ocaml-find-files dir filter)) + (command)) + ;; scanning info files + (if (or (null files) + (not (stringp files)) + (string-match files "^ *$")) + (message "No info file found: %s." (mapconcat 'identity files " ")) + (message "Scanning info files %s." files) + (save-window-excursion + (set-buffer (get-buffer-create "*caml-help*")) + (setq command + (concat "zcat -f " files + " | grep -e '" section-regexp "'")) + (message "Scanning files with: %s" command) + (or (shell-command command (current-buffer)) + (error "Error while scanning")) + (goto-char (point-min)) + (while (re-search-forward section-regexp (point-max) t) + (let* ((module (match-string 2)) + (section (match-string 1))) + ;; (message "%s %s" module section) + (if (assoc module entries) nil + (setq entries + (cons (cons module (concat "(" name ")" section)) + entries)) + ))) + (let ((buf (get-buffer "*caml-help*"))) + (if buf (kill-buffer buf))))) + entries)) + +(defun ocaml-hevea-info () + "The default way to create an info data base from the value +of \\[Info-default-directory-list] and the base name \\[ocaml-info-name] +of files to look for. + +This uses info files produced by HeVeA. +" + (let ((collect) (seen)) + (iter '(lambda (d) + (if (member d seen) nil + (setq collect + (ocaml-hevea-info-add-entries + collect d ocaml-info-prefix)) + (setq done (cons d seen)))) + Info-directory-list) + collect)) + +(defun ocaml-ocamldoc-info-add-entries (entries dir name) + (let* + ((module-regexp "^Node: \\([A-Z][A-Za-z_0-9]*\\)[^ ]") + (command + (concat + "find " dir " -type f -regex '.*/" name + "\\(.info\\|\\)\\([.]gz\\|\\)' -print0" + " | xargs -0 zcat -f | grep '" module-regexp "'"))) + (message "Scanning info files in %s" dir) + (save-window-excursion + (set-buffer (get-buffer-create "*caml-help*")) + (or (shell-command command (current-buffer)) + (error "Could not run:%s" command)) + (goto-char (point-min)) + (while (re-search-forward module-regexp (point-max) t) + (if (equal (char-after (match-end 1)) 127) + (let* ((module (match-string 1))) + (if (assoc module entries) nil + (setq entries + (cons (cons module (concat "(" name ")" module)) + entries)) + )))) + ; (kill-buffer (current-buffer)) + ) + entries)) + +(defun ocaml-ocamldoc-info () + "The default way to create an info data base from the value +of \\[Info-default-directory-list] and the base name \\[ocaml-info-name] +of files to look for. + +This uses info files produced by ocamldoc." + (require 'info) + (let ((collect) (seen)) + (iter '(lambda (d) + (if (member d seen) nil + (setq collect + (ocaml-ocamldoc-info-add-entries collect d + ocaml-info-prefix)) + (setq done (cons d seen)))) + Info-directory-list) + collect)) + +;; Continuing + +(defvar ocaml-info-alist 'ocaml-ocamldoc-info + "A-list binding module names to info entries: + + nil means do not use info. + + A function to build the list lazily (at the first call). The result of +the function call will be assign permanently to this variable for future +uses. We provide two default functions \\[ocaml-info-default-function] +(info produced by HeVeA is the default) and \\[ocaml-info-default-function] +(info produced by ocamldoc). + + Otherwise, this value should be an alist binding module names to info +entries of the form to \"(entry)section\" be taken by the \\[info] +command. An entry may be an info module or a complete file name." +) + +(defun ocaml-info-alist () + "Call by need value of variable ocaml-info-alist" + (cond + ((listp ocaml-info-alist)) + ((functionp ocaml-info-alist) + (setq ocaml-info-alist (apply ocaml-info-alist nil))) + (t + (error "wrong type for ocaml-info-alist"))) + ocaml-info-alist) + +;; help around point + +(defun ocaml-find-module (symbol &optional module-list) + (let ((list (or module-list (ocaml-module-alist))) + (collect)) + (while (consp list) + (if (member symbol (ocaml-module-symbols (car list))) + (setq collect (cons (car list) collect))) + (setq list (cdr list))) + (nreverse collect) + )) + +(defun ocaml-buffer-substring (region) + (and region (buffer-substring-no-properties (car region) (cdr region)))) + +;; Help function. + + +(defun ocaml-goto-help (&optional module entry same-window) + "Searches info manual for MODULE and ENTRY in MODULE. +If unspecified, MODULE and ENTRY are inferred from the position in the +current buffer using \\[ocaml-qualified-identifier]." + (interactive) + (let ((window (selected-window)) + (info-section (assoc module (ocaml-info-alist)))) + (if info-section + (caml-info-other-window (cdr info-section)) + (ocaml-visible-modules) + (let* ((module-info + (or (assoc module (ocaml-module-alist)) + (and (file-exists-p + (concat (ocaml-uncapitalize module) ".mli")) + (ocaml-get-or-make-module module)))) + (location (cdr (cadr module-info)))) + (cond + (location + (let ((file (concat location (ocaml-uncapitalize module) ".mli"))) + (if (window-live-p same-window) + (progn (select-window same-window) + (view-mode-exit view-return-to-alist view-exit-action)) + ;; (view-buffer (find-file-noselect file) 'view)) + ) + (view-file-other-window file) + (bury-buffer (current-buffer)))) + (info-section (error "Aborted")) + (t (error "No help for module %s" module)))) + ) + (if (stringp entry) + (let ((here (point)) + (regex (regexp-quote entry)) + (case-fold-search nil)) + (goto-char (point-min)) + (if (or (re-search-forward + (concat "\\(val\\|exception\\|type\\|external\\|[|{;]\\) +" + regex) + ;; (concat "\\(val\\|exception\\|external\\) +\\(" + ;; regex "\\|( *" regex " *)\\)") + (point-max) t) + (re-search-forward + (concat "type [^{]*{[^}]*" regex " :") + ;; (concat "\\(type\\|[|{;]\\) +" regex) + (point-max) t) + (progn + (if (window-live-p window) (select-window window)) + (error "Entry %s not found in module %s" + entry module)) + ;; (search-forward entry (point-max) t) + ) + (ocaml-help-show -1) + (progn + (message "Help for entry %s not found in module %s" + entry module) + (goto-char here))) + )) + (ocaml-link-activate (cdr info-section)) + (if (window-live-p window) (select-window window)) + )) + +(defun caml-help (arg) + "Find documentation for OCaml qualified identifiers. + +It attemps to recognize an qualified identifier of the form +``Module . entry'' around point using function `ocaml-qualified-identifier'. + +If Module is undetermined it is temptatively guessed from the identifier name +and according to visible modules. If this is still unsucessful, the user is +then prompted for a Module name. + +The documentation for Module is first seach in the info manual if available, +then in the ``module.mli'' source file. The entry is then searched in the +documentation. + +Visible modules are computed only once, at the first call. +Modules can be made visible explicitly with `ocaml-open-module' and +hidden with `ocaml-close-module'. + +Prefix arg 0 forces recompilation of visible modules (and their content) +from the file content. + +Prefix arg 4 prompts for Module and identifier instead of guessing values +from the possition of point in the current buffer. +" + (interactive "p") + (delete-overlay ocaml-help-ovl) + (let ((module) (entry) (module-entry)) + (cond + ((= arg 4) + (or (and + (setq module + (completing-read "Module: " (ocaml-module-alist) + nil t "" (cons 'hist 0))) + (not (string-equal module ""))) + (error "Quit")) + (let ((symbols + (mapcar 'list + (ocaml-module-symbols + (assoc module (ocaml-module-alist)))))) + (setq entry + (completing-read (format "Value: %s." module) symbols nil t))) + (if (string-equal entry "") (setq entry nil)) + ) + (t + (if (= arg 0) (setq ocaml-visible-modules 'lazy)) + (setq module-entry (ocaml-qualified-identifier)) + (setq entry (ocaml-buffer-substring (cdr module-entry))) + (setq module + (or (ocaml-buffer-substring (car module-entry)) + (let ((modules + (or (ocaml-find-module entry (ocaml-visible-modules)) + (ocaml-find-module entry))) + (hist) (default)) + (cond + ((null modules) + (error "No module found for entry %s" entry)) + ((equal (length modules) 1) + (caar modules)) + (t + (setq hist (mapcar 'car modules)) + (setq default (car hist)) + (setq module + (completing-read + (concat "Module: " + (and default (concat "[" default "] "))) + modules nil t "" (cons 'hist 0))) + (if (string-equal module "") default module)) + )))) + )) + (message "Help for %s%s%s" module (if entry "." "") (or entry "")) + (ocaml-goto-help module entry) + )) + +;; auto-links + +(defconst ocaml-link-regexp + "\\(type\\|and\\) \\('[a-z] +\\|(\\('[a-z], *\\)*'[a-z])\\|\\) *\\([a-zA-Z0-9_]*\\)\\( *$\\| =\\)") +(defconst ocaml-longident-regexp + "\\([A-Z][a-zA-Z_0]*\\)[.]\\([a-zA-Z][A-Za-z0-9_]*\\)") + +(defvar ocaml-links nil + "Local links in the current of last info node or interface file. + +The car of the list is a key that indentifies the module to prevent +recompilation when next help command is relative to the same module. +The cdr is a list of elments, each of which is an string and a pair of +buffer positions." +) +(make-variable-buffer-local 'ocaml-links) + +(defun ocaml-info-links (section) + (cdr + (if (and ocaml-links section (equal (car ocaml-links) section)) + ocaml-links + (save-excursion + (goto-char (point-min)) + (let ((regexp (concat (if (equal major-mode 'Info-mode) "^ - " "^") + ocaml-link-regexp)) + (all)) + (while (re-search-forward regexp (point-max) t) + (setq all + (cons (cons (match-string 4) + (cons (match-beginning 4) + (match-end 4))) + all))) + (setq ocaml-links (cons section all)) + ))))) + +(defvar ocaml-link-map (make-sparse-keymap)) +(define-key ocaml-link-map [mouse-2] 'ocaml-link-goto) + +(defvar ocaml-help-ovl (make-overlay 1 1)) +(make-face 'ocaml-help-face) +(set-face-doc-string 'ocaml-help-face + "face for hilighting expressions and types") +(if (not (face-differs-from-default-p 'ocaml-help-face)) + (set-face-background 'ocaml-help-face "#88FF44")) +(overlay-put ocaml-help-ovl 'face 'ocaml-help-face) + +(defun ocaml-help-show (arg) + (let ((right (point)) + (left (progn (forward-word arg) (point)))) + (goto-char right) + (move-overlay ocaml-help-ovl left right (current-buffer)) + (recenter 1) + )) + +(defun ocaml-link-goto (click) + (interactive "e") + (let* ((pos (caml-event-point-start click)) + (win (caml-event-window click)) + (buf (window-buffer win)) + (window (selected-window)) + (link)) + (setq link + (with-current-buffer buf + (buffer-substring + (previous-single-property-change (+ pos 1) 'local-map + buf (- pos 100)) + (next-single-property-change pos 'local-map + buf (+ pos 100))))) + (if (string-match (concat "^" ocaml-longident-regexp "$") link) + (ocaml-goto-help (match-string 1 link) (match-string 2 link) win) + (if (not (equal (window-buffer window) buf)) + (switch-to-buffer-other-window buf)) + (if (setq link (assoc link (cdr ocaml-links))) + (progn + (goto-char (cadr link)) + (ocaml-help-show 1))) + (if (window-live-p window) (select-window window)) + ))) + +(cond + ((and (x-display-color-p) + (not (memq 'ocaml-link-face (face-list)))) + (make-face 'ocaml-link-face) + (set-face-foreground 'ocaml-link-face "Purple"))) + + +(defun ocaml-link-activate (section) + (let ((links (ocaml-info-links section))) + (if links + (let ((regexp (concat "[^A-Za-z0-9'_]\\(" + ocaml-longident-regexp "\\|" + (mapconcat 'car links "\\|") + "\\)[^A-Za-z0-9'_]")) + (case-fold-search nil)) + (save-excursion + (goto-char (point-min)) + (let ((buffer-read-only nil) + ;; use of dynamic scoping, need not be restored! + (modified-p (buffer-modified-p))) + (unwind-protect + (save-excursion + (goto-char (point-min)) + (while (re-search-forward regexp (point-max) t) + (put-text-property (match-beginning 1) (match-end 1) + 'mouse-face 'highlight) + (put-text-property (match-beginning 1) (match-end 1) + 'local-map ocaml-link-map) + (if (x-display-color-p) + (put-text-property (match-beginning 1) (match-end 1) + 'face 'ocaml-link-face))) + ) + ;; need to restore flag if buffer was unmodified. + (unless modified-p (set-buffer-modified-p nil)) + )) + ))))) + + + +;; bindings ---now in caml.el + +; (and +; (boundp 'caml-mode-map) +; (keymapp caml-mode-map) +; (progn +; (define-key caml-mode-map [?\C-c?i] 'ocaml-add-path) +; (define-key caml-mode-map [?\C-c?]] 'ocaml-close-module) +; (define-key caml-mode-map [?\C-c?[] 'ocaml-open-module) +; (define-key caml-mode-map [?\C-c?\C-h] 'caml-help) +; (define-key caml-mode-map [?\C-c?\t] 'caml-complete) +; (let ((map (lookup-key caml-mode-map [menu-bar caml]))) +; (and +; (keymapp map) +; (progn +; (define-key map [separator-help] '("---")) +; (define-key map [open] '("Open add path" . ocaml-add-path )) +; (define-key map [close] +; '("Close module for help" . ocaml-close-module)) +; (define-key map [open] '("Open module for help" . ocaml-open-module)) +; (define-key map [help] '("Help for identifier" . caml-help)) +; (define-key map [complete] '("Complete identifier" . caml-complete)) +; ) +; )))) + + +(provide 'caml-help) diff --git a/ocaml-binary-annot/emacs/caml-hilit.el b/ocaml-binary-annot/emacs/caml-hilit.el new file mode 100644 index 0000000000..697e58173d --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-hilit.el @@ -0,0 +1,67 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Jacques Garrigue and Ian T Zimmerman *) +;(* *) +;(* Copyright 1997 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +; Highlighting patterns for hilit19 under caml-mode + +; defined also in caml.el +(defvar caml-quote-char "'" + "*Quote for character constants. \"'\" for Objective Caml, \"`\" for Caml-Light.") + +(defconst caml-mode-patterns + (list +;comments + '("\\(^\\|[^\"]\\)\\((\\*[^*]*\\*+\\([^)*][^*]*\\*+\\)*)\\)" + 2 comment) +;string + (list 'hilit-string-find (string-to-char caml-quote-char) 'string) + (list (concat caml-quote-char "\\(\\\\\\([ntbr" caml-quote-char "\\]\\|" + "[0-9][0-9][0-9]\\)\\|.\\)" caml-quote-char) + nil + 'string) +;labels + '("\\(\\([~?]\\|\\<\\)[a-z][a-zA-Z0-9_']*:\\)[^:=]" 1 brown) + '("[~?][ (]*[a-z][a-zA-Z0-9_']*" nil brown) +;modules + '("\\<\\(assert\\|open\\|include\\)\\>" nil brown) + '("`?\\<[A-Z][A-Za-z0-9_\']*\\>" nil MidnightBlue) +;definition + (list (concat + "\\<\\(a\\(nd\\|s\\)\\|c\\(onstraint\\|lass\\)" + "\\|ex\\(ception\\|ternal\\)\\|fun\\(ct\\(ion\\|or\\)\\)?" + "\\|in\\(herit\\)?\\|let\\|m\\(ethod\\|utable\\|odule\\)" + "\\|of\\|p\\(arser\\|rivate\\)\\|rec\\|type" + "\\|v\\(al\\|irtual\\)\\)\\>") + nil 'ForestGreen) +;blocking + '("\\<\\(object\\|struct\\|sig\\|begin\\|end\\)\\>" 2 include) +;control + (list (concat + "\\<\\(do\\(ne\\|wnto\\)?\\|else\\|for\\|i\\(f\\|gnore\\)" + "\\|lazy\\|match\\|new\\|or\\|t\\(hen\\|o\\|ry\\)" + "\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\)\\>" + "\\|\|\\|->\\|&\\|#") + nil 'keyword) + '(";" nil struct)) + "Hilit19 patterns used for Caml mode") + +(hilit-set-mode-patterns 'caml-mode caml-mode-patterns) +(hilit-set-mode-patterns + 'inferior-caml-mode + (append + (list +;inferior + '("^[#-]" nil firebrick)) + caml-mode-patterns)) + +(provide 'caml-hilit) diff --git a/ocaml-binary-annot/emacs/caml-types.el b/ocaml-binary-annot/emacs/caml-types.el new file mode 100644 index 0000000000..05b1a2c0a6 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-types.el @@ -0,0 +1,765 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Damien Doligez, projet Moscova, INRIA Rocquencourt *) +;(* *) +;(* Copyright 2003 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +; An emacs-lisp complement to the "-annot" option of ocamlc and ocamlopt. + +;; XEmacs compatibility + +(eval-and-compile + (if (and (boundp 'running-xemacs) running-xemacs) + (require 'caml-xemacs) + (require 'caml-emacs))) + + + +(defvar caml-types-location-re nil "Regexp to parse *.annot files. + +Annotation files *.annot may be generated with the \"-annot\" option +of ocamlc and ocamlopt. + +Their format is: + + file ::= block * + block ::= position <SP> position <LF> annotation * + position ::= filename <SP> num <SP> num <SP> num + annotation ::= keyword open-paren <LF> <SP> <SP> data <LF> close-paren <LF> + + <SP> is a space character (ASCII 0x20) + <LF> is a line-feed character (ASCII 0x0A) + num is a sequence of decimal digits + filename is a string with the lexical conventions of O'Caml + open-paren is an open parenthesis (ASCII 0x28) + close-paren is a closed parenthesis (ASCII 0x29) + data is any sequence of characters where <LF> is always followed by + at least two space characters. + +- in each block, the two positions are respectively the start and the + end of the range described by the block. +- in a position, the filename is the name of the file, the first num + is the line number, the second num is the offset of the beginning + of the line, the third num is the offset of the position itself. +- the char number within the line is the difference between the third + and second nums. + +The current list of keywords is: +type call ident" +) + +(let* ((caml-types-filename-re "\"\\(\\([^\\\"]\\|\\\\.\\)*\\)\"") + (caml-types-number-re "\\([0-9]*\\)")) + (setq caml-types-position-re + (concat caml-types-filename-re " " + caml-types-number-re " " + caml-types-number-re " " + caml-types-number-re)) + (setq caml-types-location-re + (concat "^" caml-types-position-re " " caml-types-position-re))) + +(defvar caml-types-expr-ovl (make-overlay 1 1)) +(make-face 'caml-types-expr-face) +(set-face-doc-string 'caml-types-expr-face + "face for hilighting expressions and types") +(if (not (face-differs-from-default-p 'caml-types-expr-face)) + (set-face-background 'caml-types-expr-face "#88FF44")) +(overlay-put caml-types-expr-ovl 'face 'caml-types-expr-face) + +(defvar caml-types-typed-ovl (make-overlay 1 1)) +(make-face 'caml-types-typed-face) +(set-face-doc-string 'caml-types-typed-face + "face for hilighting typed expressions") +(if (not (face-differs-from-default-p 'caml-types-typed-face)) + (set-face-background 'caml-types-typed-face "#FF8844")) +(overlay-put caml-types-typed-ovl 'face 'caml-types-typed-face) + +(defvar caml-types-scope-ovl (make-overlay 1 1)) +(make-face 'caml-types-scope-face) +(set-face-doc-string 'caml-types-scope-face + "face for hilighting variable scopes") +(if (not (face-differs-from-default-p 'caml-types-scope-face)) + (set-face-background 'caml-types-scope-face "#BBFFFF")) +(overlay-put caml-types-scope-ovl 'face 'caml-types-scope-face) + +(defvar caml-types-def-ovl (make-overlay 1 1)) +(make-face 'caml-types-def-face) +(set-face-doc-string 'caml-types-def-face + "face for hilighting binding occurrences") +(if (not (face-differs-from-default-p 'caml-types-def-face)) + (set-face-background 'caml-types-def-face "#FF4444")) +(overlay-put caml-types-def-ovl 'face 'caml-types-def-face) + +(defvar caml-types-occ-ovl (make-overlay 1 1)) +(make-face 'caml-types-occ-face) +(set-face-doc-string 'caml-types-occ-face + "face for hilighting variable occurrences") +(if (not (face-differs-from-default-p 'caml-types-occ-face)) + (set-face-background 'caml-types-occ-face "#44FF44")) +(overlay-put caml-types-occ-ovl 'face 'caml-types-occ-face) + + +(defvar caml-types-annotation-tree nil) +(defvar caml-types-annotation-date nil) +(make-variable-buffer-local 'caml-types-annotation-tree) +(make-variable-buffer-local 'caml-types-annotation-date) + +(defvar caml-types-buffer-name "*caml-types*" + "Name of buffer for diplaying caml types") +(defvar caml-types-buffer nil + "buffer for diplaying caml types") + +(defun caml-types-show-type (arg) + "Show the type of expression or pattern at point. + The smallest expression or pattern that contains point is + temporarily highlighted. Its type is highlighted in the .annot + file and the mark is set to the beginning of the type. + The type is also displayed in the mini-buffer. + + Hints on using the type display: + . If you want the type of an identifier, put point within any + occurrence of this identifier. + . If you want the result type of a function application, put point + at the first space after the function name. + . If you want the type of a list, put point on a bracket, on a + semicolon, or on the :: constructor. + . Even if type checking fails, you can still look at the types + in the file, up to where the type checker failed. + +Types are also displayed in the buffer *caml-types*, which is +displayed when the command is called with Prefix argument 4. + +See also `caml-types-explore' for exploration by mouse dragging. +See `caml-types-location-re' for annotation file format. +" + (interactive "p") + (let* ((target-buf (current-buffer)) + (target-file (file-name-nondirectory (buffer-file-name))) + (target-line (1+ (count-lines (point-min) + (caml-line-beginning-position)))) + (target-bol (caml-line-beginning-position)) + (target-cnum (point))) + (caml-types-preprocess (buffer-file-name)) + (setq caml-types-buffer (get-buffer-create caml-types-buffer-name)) + (let* ((targ-loc (vector target-file target-line target-bol target-cnum)) + (node (caml-types-find-location targ-loc "type" () + caml-types-annotation-tree))) + (cond + ((null node) + (delete-overlay caml-types-expr-ovl) + (message "Point is not within a typechecked expression or pattern.")) + (t + (let ((left (caml-types-get-pos target-buf (elt node 0))) + (right (caml-types-get-pos target-buf (elt node 1))) + (type (cdr (assoc "type" (elt node 2))))) + (move-overlay caml-types-expr-ovl left right target-buf) + (with-current-buffer caml-types-buffer + (erase-buffer) + (insert type) + (message (format "type: %s" type))) + )))) + (if (and (= arg 4) + (not (window-live-p (get-buffer-window caml-types-buffer)))) + (display-buffer caml-types-buffer)) + (unwind-protect + (caml-sit-for 60) + (delete-overlay caml-types-expr-ovl) + ))) + +(defun caml-types-show-call (arg) + "Show the kind of call at point. + The smallest function call that contains point is + temporarily highlighted. Its kind is highlighted in the .annot + file and the mark is set to the beginning of the kind. + The kind is also displayed in the mini-buffer. + +The kind is also displayed in the buffer *caml-types*, which is +displayed when the command is called with Prefix argument 4. + +See `caml-types-location-re' for annotation file format. +" + (interactive "p") + (let* ((target-buf (current-buffer)) + (target-file (file-name-nondirectory (buffer-file-name))) + (target-line (1+ (count-lines (point-min) + (caml-line-beginning-position)))) + (target-bol (caml-line-beginning-position)) + (target-cnum (point))) + (caml-types-preprocess (buffer-file-name)) + (setq caml-types-buffer (get-buffer-create caml-types-buffer-name)) + (let* ((targ-loc (vector target-file target-line target-bol target-cnum)) + (node (caml-types-find-location targ-loc "call" () + caml-types-annotation-tree))) + (cond + ((null node) + (delete-overlay caml-types-expr-ovl) + (message "Point is not within a function call.")) + (t + (let ((left (caml-types-get-pos target-buf (elt node 0))) + (right (caml-types-get-pos target-buf (elt node 1))) + (kind (cdr (assoc "call" (elt node 2))))) + (move-overlay caml-types-expr-ovl left right target-buf) + (with-current-buffer caml-types-buffer + (erase-buffer) + (insert kind) + (message (format "%s call" kind))) + )))) + (if (and (= arg 4) + (not (window-live-p (get-buffer-window caml-types-buffer)))) + (display-buffer caml-types-buffer)) + (unwind-protect + (caml-sit-for 60) + (delete-overlay caml-types-expr-ovl) + ))) + +(defun caml-types-show-ident (arg) + "Show the binding of identifier at point. + The identifier that contains point is + temporarily highlighted. Its binding is highlighted in the .annot + file and the mark is set to the beginning of the binding. + The binding is also displayed in the mini-buffer. + +The binding is also displayed in the buffer *caml-types*, which is +displayed when the command is called with Prefix argument 4. + +See `caml-types-location-re' for annotation file format. +" + (interactive "p") + (let* ((target-buf (current-buffer)) + (target-file (file-name-nondirectory (buffer-file-name))) + (target-line (1+ (count-lines (point-min) + (caml-line-beginning-position)))) + (target-bol (caml-line-beginning-position)) + (target-cnum (point))) + (caml-types-preprocess (buffer-file-name)) + (setq caml-types-buffer (get-buffer-create caml-types-buffer-name)) + (let* ((targ-loc (vector target-file target-line target-bol target-cnum)) + (node (caml-types-find-location targ-loc "ident" () + caml-types-annotation-tree))) + (cond + ((null node) + (delete-overlay caml-types-expr-ovl) + (message "Point is not within an identifier.")) + (t + (let ((left (caml-types-get-pos target-buf (elt node 0))) + (right (caml-types-get-pos target-buf (elt node 1))) + (kind (cdr (assoc "ident" (elt node 2))))) + (move-overlay caml-types-expr-ovl left right target-buf) + (let* ((loc-re (concat caml-types-position-re " " + caml-types-position-re)) + (end-re (concat caml-types-position-re " --")) + (def-re (concat "def \\([^ ]*\\) " loc-re)) + (def-end-re (concat "def \\([^ ]*\\) " end-re)) + (internal-re (concat "int_ref \\([^ ]*\\) " loc-re)) + (external-re "ext_ref \\(.*\\)")) + (cond + ((string-match def-re kind) + (let ((var-name (match-string 1 kind)) + (l-file (file-name-nondirectory (match-string 2 kind))) + (l-line (string-to-int (match-string 4 kind))) + (l-bol (string-to-int (match-string 5 kind))) + (l-cnum (string-to-int (match-string 6 kind))) + (r-file (file-name-nondirectory (match-string 7 kind))) + (r-line (string-to-int (match-string 9 kind))) + (r-bol (string-to-int (match-string 10 kind))) + (r-cnum (string-to-int (match-string 11 kind)))) + (let* ((lpos (vector l-file l-line l-bol l-cnum)) + (rpos (vector r-file r-line r-bol r-cnum)) + (left (caml-types-get-pos target-buf lpos)) + (right (caml-types-get-pos target-buf rpos))) + (message (format "local variable %s is bound here" var-name)) + (move-overlay caml-types-scope-ovl left right target-buf)))) + ((string-match def-end-re kind) + (let ((var-name (match-string 1 kind)) + (l-file (file-name-nondirectory (match-string 2 kind))) + (l-line (string-to-int (match-string 4 kind))) + (l-bol (string-to-int (match-string 5 kind))) + (l-cnum (string-to-int (match-string 6 kind)))) + (let* ((lpos (vector l-file l-line l-bol l-cnum)) + (left (caml-types-get-pos target-buf lpos)) + (right (buffer-size target-buf))) + (message (format "global variable %s is bound here" var-name)) + (move-overlay caml-types-scope-ovl left right target-buf)))) + ((string-match internal-re kind) + (let ((var-name (match-string 1 kind)) + (l-file (file-name-nondirectory (match-string 2 kind))) + (l-line (string-to-int (match-string 4 kind))) + (l-bol (string-to-int (match-string 5 kind))) + (l-cnum (string-to-int (match-string 6 kind))) + (r-file (file-name-nondirectory (match-string 7 kind))) + (r-line (string-to-int (match-string 9 kind))) + (r-bol (string-to-int (match-string 10 kind))) + (r-cnum (string-to-int (match-string 11 kind)))) + (let* ((lpos (vector l-file l-line l-bol l-cnum)) + (rpos (vector r-file r-line r-bol r-cnum)) + (left (caml-types-get-pos target-buf lpos)) + (right (caml-types-get-pos target-buf rpos))) + (move-overlay caml-types-def-ovl left right target-buf) + (message (format "%s is bound at line %d char %d" + var-name l-line (- l-cnum l-bol)))))) + ((string-match external-re kind) + (let ((fullname (match-string 1 kind))) + (with-current-buffer caml-types-buffer + (erase-buffer) + (insert fullname) + (message (format "external ident: %s" fullname))))))) + )))) + (if (and (= arg 4) + (not (window-live-p (get-buffer-window caml-types-buffer)))) + (display-buffer caml-types-buffer)) + (unwind-protect + (caml-sit-for 60) + (delete-overlay caml-types-expr-ovl) + (delete-overlay caml-types-def-ovl) + (delete-overlay caml-types-scope-ovl) + ))) + +(defun caml-types-preprocess (target-path) + (let* ((type-path (caml-types-locate-type-file target-path)) + (type-date (nth 5 (file-attributes (file-chase-links type-path)))) + (target-date (nth 5 (file-attributes target-file)))) + (unless (and caml-types-annotation-tree + type-date + caml-types-annotation-date + (not (caml-types-date< caml-types-annotation-date type-date))) + (if (and type-date target-date (caml-types-date< type-date target-date)) + (error (format "`%s' is more recent than `%s'" target-path type-path))) + (message "Reading annotation file...") + (let* ((type-buf (caml-types-find-file type-path)) + (tree (with-current-buffer type-buf + (widen) + (goto-char (point-min)) + (caml-types-build-tree + (file-name-nondirectory target-path))))) + (setq caml-types-annotation-tree tree + caml-types-annotation-date type-date) + (kill-buffer type-buf) + (message "done")) + ))) + +(defun caml-types-locate-type-file (target-path) + (let ((sibling (concat (file-name-sans-extension target-path) ".annot"))) + (if (file-exists-p sibling) + sibling + (defun parent-dir (d) (file-name-directory (directory-file-name d))) + (let ((project-dir (file-name-directory sibling)) + type-path) + (while (not (file-exists-p + (setq type-path + (expand-file-name + (file-relative-name sibling project-dir) + (expand-file-name "_build" project-dir))))) + (if (equal project-dir (parent-dir project-dir)) + (error (concat "No annotation file. " + "You should compile with option \"-annot\"."))) + (setq project-dir (parent-dir project-dir))) + type-path)))) + +(defun caml-types-date< (date1 date2) + (or (< (car date1) (car date2)) + (and (= (car date1) (car date2)) + (< (nth 1 date1) (nth 1 date2))))) + + +; we use an obarray for hash-consing the strings within each tree + +(defun caml-types-make-hash-table () + (make-vector 255 0)) + +(defun caml-types-hcons (elem table) + (symbol-name (intern elem table))) + + +(defun next-annotation () + (forward-char 1) + (if (re-search-forward "^[a-z\"]" () t) + (forward-char -1) + (goto-char (point-max))) + (looking-at "[a-z]") +) + +; tree of intervals +; each node is a vector +; [ pos-left pos-right annotation child child child... ] +; annotation is a list of: +; (kind . info) where kind = "type" "call" etc. +; and info = the contents of the annotation + +(defun caml-types-build-tree (target-file) + (let ((stack ()) + (accu ()) + (table (caml-types-make-hash-table)) + (annotation ())) + (while (re-search-forward caml-types-location-re () t) + (let ((l-file (file-name-nondirectory (match-string 1))) + (l-line (string-to-int (match-string 3))) + (l-bol (string-to-int (match-string 4))) + (l-cnum (string-to-int (match-string 5))) + (r-file (file-name-nondirectory (match-string 6))) + (r-line (string-to-int (match-string 8))) + (r-bol (string-to-int (match-string 9))) + (r-cnum (string-to-int (match-string 10)))) + (unless (caml-types-not-in-file l-file r-file target-file) + (setq annotation ()) + (while (next-annotation) + (cond ((looking-at + "^\\([a-z]+\\)(\n \\(\\([^\n)]\\|.)\\|\n[^)]\\)*\\)\n)") + (let ((kind (caml-types-hcons (match-string 1) table)) + (info (caml-types-hcons (match-string 2) table))) + (setq annotation (cons (cons kind info) annotation)))))) + (setq accu ()) + (while (and stack + (caml-types-pos-contains l-cnum r-cnum (car stack))) + (setq accu (cons (car stack) accu)) + (setq stack (cdr stack))) + (let* ((left-pos (vector l-file l-line l-bol l-cnum)) + (right-pos (vector r-file r-line r-bol r-cnum)) + (node (caml-types-make-node left-pos right-pos annotation + accu))) + (setq stack (cons node stack)))))) + (if (null stack) + (error "no annotations found for this source file") + (let* ((left-pos (elt (car (last stack)) 0)) + (right-pos (elt (car stack) 1))) + (if (null (cdr stack)) + (car stack) + (caml-types-make-node left-pos right-pos () (nreverse stack))))))) + +(defun caml-types-not-in-file (l-file r-file target-file) + (or (and (not (string= l-file target-file)) + (not (string= l-file ""))) + (and (not (string= r-file target-file)) + (not (string= r-file ""))))) + +(defun caml-types-make-node (left-pos right-pos annotation children) + (let ((result (make-vector (+ 3 (length children)) ())) + (i 3)) + (aset result 0 left-pos) + (aset result 1 right-pos) + (aset result 2 annotation) + (while children + (aset result i (car children)) + (setq children (cdr children)) + (setq i (1+ i))) + result)) + +(defun caml-types-pos-contains (l-cnum r-cnum node) + (and (<= l-cnum (elt (elt node 0) 3)) + (>= r-cnum (elt (elt node 1) 3)))) + +(defun caml-types-find-location (targ-pos kind curr node) + (if (not (caml-types-pos-inside targ-pos node)) + curr + (if (and (elt node 2) (assoc kind (elt node 2))) + (setq curr node)) + (let ((i (caml-types-search node targ-pos))) + (if (and (> i 3) + (caml-types-pos-inside targ-pos (elt node (1- i)))) + (caml-types-find-location targ-pos kind curr (elt node (1- i))) + curr)))) + +; trouve le premier fils qui commence apres la position +; ou (length node) si tous commencent avant +(defun caml-types-search (node pos) + (let ((min 3) + (max (length node)) + med) + (while (< min max) + (setq med (/ (+ min max) 2)) + (if (caml-types-pos<= (elt (elt node med) 0) pos) + (setq min (1+ med)) + (setq max med))) + min)) + +(defun caml-types-pos-inside (pos node) + (let ((left-pos (elt node 0)) + (right-pos (elt node 1))) + (and (caml-types-pos<= left-pos pos) + (caml-types-pos> right-pos pos)))) + +(defun caml-types-find-interval (buf targ-pos node) + (let ((nleft (elt node 0)) + (nright (elt node 1)) + (left ()) + (right ()) + i) + (cond + ((not (caml-types-pos-inside targ-pos node)) + (if (not (caml-types-pos<= nleft targ-pos)) + (setq right nleft)) + (if (not (caml-types-pos> nright targ-pos)) + (setq left nright))) + (t + (setq left nleft + right nright) + (setq i (caml-types-search node targ-pos)) + (if (< i (length node)) + (setq right (elt (elt node i) 0))) + (if (> i 3) + (setq left (elt (elt node (1- i)) 1))))) + (cons (if left + (caml-types-get-pos buf left) + (with-current-buffer buf (point-min))) + (if right + (caml-types-get-pos buf right) + (with-current-buffer buf (point-max)))))) + + +;; Warning: these comparison functions are not symmetric. +;; The first argument determines the format: +;; when its file component is empty, only the cnum is compared. + +(defun caml-types-pos<= (pos1 pos2) + (let ((file1 (elt pos1 0)) + (line1 (elt pos1 1)) + (bol1 (elt pos1 2)) + (cnum1 (elt pos1 3)) + (file2 (elt pos2 0)) + (line2 (elt pos2 1)) + (bol2 (elt pos2 2)) + (cnum2 (elt pos2 3))) + (if (string= file1 "") + (<= cnum1 cnum2) + (and (string= file1 file2) + (or (< line1 line2) + (and (= line1 line2) + (<= (- cnum1 bol1) (- cnum2 bol2)))))))) + +(defun caml-types-pos> (pos1 pos2) + (let ((file1 (elt pos1 0)) + (line1 (elt pos1 1)) + (bol1 (elt pos1 2)) + (cnum1 (elt pos1 3)) + (file2 (elt pos2 0)) + (line2 (elt pos2 1)) + (bol2 (elt pos2 2)) + (cnum2 (elt pos2 3))) + (if (string= file1 "") + (> cnum1 cnum2) + (and (string= file1 file2) + (or (> line1 line2) + (and (= line1 line2) + (> (- cnum1 bol1) (- cnum2 bol2)))))))) + +(defun caml-types-get-pos (buf pos) + (save-excursion + (set-buffer buf) + (goto-line (elt pos 1)) + (forward-char (- (elt pos 3) (elt pos 2))) + (point))) + +; find-file-read-only-noselect seems to be missing from emacs... +(defun caml-types-find-file (name) + (let (buf) + (cond + ((setq buf (get-file-buffer name)) + (unless (verify-visited-file-modtime buf) + (if (buffer-modified-p buf) + (find-file-noselect name) + (with-current-buffer buf (revert-buffer t t))) + )) + ((and (file-readable-p name) + (setq buf (find-file-noselect name))) + (with-current-buffer buf (toggle-read-only 1)) + ) + (t + (error (format "Can't read the annotation file `%s'" name))) + ) + buf)) + +(defun caml-types-mouse-ignore (event) + (interactive "e") + nil) + +(defun caml-types-time () + (let ((time (current-time))) + (+ (* (mod (cadr time) 1000) 1000) + (/ (cadr (cdr time)) 1000)))) + +(defun caml-types-explore (event) + "Explore type annotations by mouse dragging. + +The expression under the mouse is highlighted and its type is displayed +in the minibuffer, until the move is released, much as `caml-types-show-type'. +The function uses two overlays. + + . One overlay delimits the largest region whose all subnodes + are well-typed. + . Another overlay delimits the current node under the mouse (whose type + annotation is beeing displayed). +" + (interactive "e") + (set-buffer (window-buffer (caml-event-window event))) + (let* ((target-buf (current-buffer)) + (target-file (file-name-nondirectory (buffer-file-name))) + (target-line) (target-bol) + target-pos + Left Right limits cnum node mes type + region + (window (caml-event-window event)) + target-tree + (speed 100) + (last-time (caml-types-time)) + (original-event event) + ) + (select-window window) + (unwind-protect + (progn + (caml-types-preprocess (buffer-file-name)) + (setq target-tree caml-types-annotation-tree) + (setq caml-types-buffer (get-buffer-create caml-types-buffer-name)) + ;; (message "Drag the mouse to explore types") + (unwind-protect + (caml-track-mouse + (while event + (cond + ;; we ignore non mouse events + ((caml-ignore-event-p event)) + ;; we stop when the original button is released + ((caml-release-event-p original-event event) + (setq event nil)) + ;; we scroll when the motion is outside the window + ((and (caml-mouse-movement-p event) + (not (and (equal window (caml-event-window event)) + (integer-or-marker-p + (caml-event-point-end event))))) + (let* ((win (caml-window-edges window)) + (top (nth 1 win)) + (bottom (- (nth 3 win) 1)) + mouse + time + ) + (while (and + (caml-sit-for 0 (/ 500 speed)) + (setq time (caml-types-time)) + (> (- time last-time) (/ 500 speed)) + (setq mouse (caml-mouse-vertical-position)) + (or (< mouse top) (>= mouse bottom)) + ) + (setq last-time time) + (cond + ((< mouse top) + (setq speed (- top mouse)) + (condition-case nil + (scroll-down 1) + (error (message "Beginning of buffer!")))) + ((>= mouse bottom) + (setq speed (+ 1 (- mouse bottom))) + (condition-case nil + (scroll-up 1) + (error (message "End of buffer!")))) + ) + (setq speed (* speed speed)) + ))) + ;; main action, when the motion is inside the window + ;; or on orginal button down event + ((or (caml-mouse-movement-p event) + (equal original-event event)) + (setq cnum (caml-event-point-end event)) + (if (and region + (<= (car region) cnum) (< cnum (cdr region))) + ;; mouse remains in outer region + nil + ;; otherwise, reset the outer region + (setq region + (caml-types-typed-make-overlay + target-buf (caml-event-point-start event)))) + (if + (and limits + (>= cnum (car limits)) (< cnum (cdr limits))) + ;; inner region is unchanged + nil + ;; recompute the inner region and type annotation + (setq target-bol + (save-excursion + (goto-char cnum) (caml-line-beginning-position)) + target-line (1+ (count-lines (point-min) + target-bol)) + target-pos + (vector target-file target-line target-bol cnum)) + (save-excursion + (setq node (caml-types-find-location "type" + target-pos () target-tree)) + (set-buffer caml-types-buffer) + (erase-buffer) + (cond + (node + (setq Left + (caml-types-get-pos target-buf (elt node 0)) + Right + (caml-types-get-pos target-buf (elt node 1))) + (move-overlay + caml-types-expr-ovl Left Right target-buf) + (setq limits + (caml-types-find-interval target-buf + target-pos node) + type (elt node 2)) + ) + (t + (delete-overlay caml-types-expr-ovl) + (setq type "*no type information*") + (setq limits + (caml-types-find-interval + target-buf target-pos target-tree)) + )) + (setq mes (format "type: %s" type)) + (insert type) + )) + (message mes) + ) + ) + ;; we read next event, unless it is nil, and loop back. + (if event (setq event (caml-read-event))) + ) + ) + ;; delete overlays at end of exploration + (delete-overlay caml-types-expr-ovl) + (delete-overlay caml-types-typed-ovl) + )) + ;; When an error occurs, the mouse release event has not been read. + ;; We could wait for mouse release to prevent execution of + ;; a binding of mouse release, such as cut or paste. + ;; In most common cases, next event will be the mouse release. + ;; However, it could also be a key stroke before mouse release. + ;; Emacs does not allow to test whether mouse is up or down. + ;; Not sure it is robust to loop for mouse release after an error + ;; occured, as is done for exploration. + ;; So far, we just ignore next event. (Next line also be uncommenting.) + (if event (caml-read-event)) + ))) + +(defun caml-types-typed-make-overlay (target-buf pos) + (interactive "p") + (let ((start pos) (end pos) len node left right) + (setq len (length caml-types-annotation-tree)) + (while (> len 3) + (setq len (- len 1)) + (setq node (aref caml-types-annotation-tree len)) + (if (and (equal target-buf (current-buffer)) + (setq left (caml-types-get-pos target-buf (elt node 0)) + right (caml-types-get-pos target-buf (elt node 1))) + (<= left pos) (> right pos) + ) + (setq start (min start left) + end (max end right)) + )) + (move-overlay caml-types-typed-ovl + (max (point-min) (- start 1)) + (min (point-max) (+ end 1)) target-buf) + (cons start end))) + +(defun caml-types-version () + "internal version number of caml-types.el" + (interactive) + (message "4") +) + +(provide 'caml-types) diff --git a/ocaml-binary-annot/emacs/caml-xemacs.el b/ocaml-binary-annot/emacs/caml-xemacs.el new file mode 100644 index 0000000000..fe141c5ce2 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml-xemacs.el @@ -0,0 +1,53 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Didier Remy, projet Cristal, INRIA Rocquencourt *) +;(* *) +;(* Copyright 2003 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +(require 'overlay) + +;; for caml-help.el +(defun caml-info-other-window (arg) + (save-excursion (info arg)) + (view-buffer-other-window "*info*")) + +;; for caml-types.el +(defun caml-line-beginning-position () + (save-excursion (beginning-of-line) (point))) + +(defalias 'caml-read-event 'next-event) +(defalias 'caml-window-edges 'window-pixel-edges) +(defun caml-mouse-vertical-position () + (let ((e (mouse-position-as-motion-event))) + (and e (event-y-pixel e)))) +(defalias 'caml-mouse-movement-p 'motion-event-p) +(defun caml-event-window (e) + (and (mouse-event-p e) (event-window e))) +(defun caml-event-point-start (e) (event-closest-point e)) +(defun caml-event-point-end (e) (event-closest-point e)) +(defun caml-ignore-event-p (e) + (if (and (key-press-event-p e) (equal (key-binding e) 'keyboard-quit)) + (keyboard-quit)) + (not (mouse-event-p e))) + + +(defun caml-sit-for (sec &optional mili) + (sit-for (+ sec (if mili (* 0.001 mili) 0)))) + + + +(defmacro caml-track-mouse (&rest body) (cons 'progn body)) + +(defun caml-release-event-p (original event) + (and (button-release-event-p event) + (equal (event-button original) (event-button event)))) + +(provide 'caml-xemacs) diff --git a/ocaml-binary-annot/emacs/caml.el b/ocaml-binary-annot/emacs/caml.el new file mode 100644 index 0000000000..4f03b5a582 --- /dev/null +++ b/ocaml-binary-annot/emacs/caml.el @@ -0,0 +1,1932 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Jacques Garrigue and Ian T Zimmerman *) +;(* *) +;(* Copyright 1997 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;;; caml.el --- O'Caml code editing commands for Emacs + +;; Xavier Leroy, july 1993. + +;;indentation code is Copyright (C) 1996 by Ian T Zimmerman <itz@rahul.net> +;;copying: covered by the current FSF General Public License. + +;; indentation code adapted for Objective Caml by Jacques Garrigue, +;; july 1997. <garrigue@kurims.kyoto-u.ac.jp> + +;;user customizable variables +(defvar caml-quote-char "'" + "*Quote for character constants. \"'\" for Objective Caml, \"`\" for Caml-Light.") + +(defvar caml-imenu-enable nil + "*Enable Imenu support.") + +(defvar caml-mode-indentation 2 + "*Used for \\[caml-unindent-command].") + +(defvar caml-lookback-limit 5000 + "*How far to look back for syntax things in caml mode.") + +(defvar caml-max-indent-priority 8 + "*Bounds priority of operators permitted to affect caml indentation. + +Priorities are assigned to `interesting' caml operators as follows: + + all keywords 0 to 7 8 + type, val, ... + 0 7 + :: ^ 6 + @ 5 + := <- 4 + if 3 + fun, let, match ... 2 + module 1 + opening keywords 0.") + +(defvar caml-apply-extra-indent 2 + "*How many spaces to add to indentation for an application in caml mode.") +(make-variable-buffer-local 'caml-apply-extra-indent) + +(defvar caml-begin-indent 2 + "*How many spaces to indent from a begin keyword in caml mode.") +(make-variable-buffer-local 'caml-begin-indent) + +(defvar caml-class-indent 2 + "*How many spaces to indent from a class keyword in caml mode.") +(make-variable-buffer-local 'caml-class-indent) + +(defvar caml-exception-indent 2 + "*How many spaces to indent from a exception keyword in caml mode.") +(make-variable-buffer-local 'caml-exception-indent) + +(defvar caml-for-indent 2 + "*How many spaces to indent from a for keyword in caml mode.") +(make-variable-buffer-local 'caml-for-indent) + +(defvar caml-fun-indent 2 + "*How many spaces to indent from a fun keyword in caml mode.") +(make-variable-buffer-local 'caml-fun-indent) + +(defvar caml-function-indent 4 + "*How many spaces to indent from a function keyword in caml mode.") +(make-variable-buffer-local 'caml-function-indent) + +(defvar caml-if-indent 2 + "*How many spaces to indent from a if keyword in caml mode.") +(make-variable-buffer-local 'caml-if-indent) + +(defvar caml-if-else-indent 0 + "*How many spaces to indent from an if .. else line in caml mode.") +(make-variable-buffer-local 'caml-if-else-indent) + +(defvar caml-inherit-indent 2 + "*How many spaces to indent from a inherit keyword in caml mode.") +(make-variable-buffer-local 'caml-inherit-indent) + +(defvar caml-initializer-indent 2 + "*How many spaces to indent from a initializer keyword in caml mode.") +(make-variable-buffer-local 'caml-initializer-indent) + +(defvar caml-include-indent 2 + "*How many spaces to indent from a include keyword in caml mode.") +(make-variable-buffer-local 'caml-include-indent) + +(defvar caml-let-indent 2 + "*How many spaces to indent from a let keyword in caml mode.") +(make-variable-buffer-local 'caml-let-indent) + +(defvar caml-let-in-indent 0 + "*How many spaces to indent from a let .. in keyword in caml mode.") +(make-variable-buffer-local 'caml-let-in-indent) + +(defvar caml-match-indent 2 + "*How many spaces to indent from a match keyword in caml mode.") +(make-variable-buffer-local 'caml-match-indent) + +(defvar caml-method-indent 2 + "*How many spaces to indent from a method keyword in caml mode.") +(make-variable-buffer-local 'caml-method-indent) + +(defvar caml-module-indent 2 + "*How many spaces to indent from a module keyword in caml mode.") +(make-variable-buffer-local 'caml-module-indent) + +(defvar caml-object-indent 2 + "*How many spaces to indent from a object keyword in caml mode.") +(make-variable-buffer-local 'caml-object-indent) + +(defvar caml-of-indent 2 + "*How many spaces to indent from a of keyword in caml mode.") +(make-variable-buffer-local 'caml-of-indent) + +(defvar caml-parser-indent 4 + "*How many spaces to indent from a parser keyword in caml mode.") +(make-variable-buffer-local 'caml-parser-indent) + +(defvar caml-sig-indent 2 + "*How many spaces to indent from a sig keyword in caml mode.") +(make-variable-buffer-local 'caml-sig-indent) + +(defvar caml-struct-indent 2 + "*How many spaces to indent from a struct keyword in caml mode.") +(make-variable-buffer-local 'caml-struct-indent) + +(defvar caml-try-indent 2 + "*How many spaces to indent from a try keyword in caml mode.") +(make-variable-buffer-local 'caml-try-indent) + +(defvar caml-type-indent 4 + "*How many spaces to indent from a type keyword in caml mode.") +(make-variable-buffer-local 'caml-type-indent) + +(defvar caml-val-indent 2 + "*How many spaces to indent from a val keyword in caml mode.") +(make-variable-buffer-local 'caml-val-indent) + +(defvar caml-while-indent 2 + "*How many spaces to indent from a while keyword in caml mode.") +(make-variable-buffer-local 'caml-while-indent) + +(defvar caml-::-indent 2 + "*How many spaces to indent from a :: operator in caml mode.") +(make-variable-buffer-local 'caml-::-indent) + +(defvar caml-@-indent 2 + "*How many spaces to indent from a @ operator in caml mode.") +(make-variable-buffer-local 'caml-@-indent) + +(defvar caml-:=-indent 2 + "*How many spaces to indent from a := operator in caml mode.") +(make-variable-buffer-local 'caml-:=-indent) + +(defvar caml-<--indent 2 + "*How many spaces to indent from a <- operator in caml mode.") +(make-variable-buffer-local 'caml-<--indent) + +(defvar caml-->-indent 2 + "*How many spaces to indent from a -> operator in caml mode.") +(make-variable-buffer-local 'caml-->-indent) + +(defvar caml-lb-indent 2 + "*How many spaces to indent from a \[ operator in caml mode.") +(make-variable-buffer-local 'caml-lb-indent) + +(defvar caml-lc-indent 2 + "*How many spaces to indent from a \{ operator in caml mode.") +(make-variable-buffer-local 'caml-lc-indent) + +(defvar caml-lp-indent 1 + "*How many spaces to indent from a \( operator in caml mode.") +(make-variable-buffer-local 'caml-lp-indent) + +(defvar caml-and-extra-indent nil + "*Extra indent for caml lines starting with the and keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-and-extra-indent) + +(defvar caml-do-extra-indent nil + "*Extra indent for caml lines starting with the do keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-do-extra-indent) + +(defvar caml-done-extra-indent nil + "*Extra indent for caml lines starting with the done keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-done-extra-indent) + +(defvar caml-else-extra-indent nil + "*Extra indent for caml lines starting with the else keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-else-extra-indent) + +(defvar caml-end-extra-indent nil + "*Extra indent for caml lines starting with the end keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-end-extra-indent) + +(defvar caml-in-extra-indent nil + "*Extra indent for caml lines starting with the in keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-in-extra-indent) + +(defvar caml-then-extra-indent nil + "*Extra indent for caml lines starting with the then keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-then-extra-indent) + +(defvar caml-to-extra-indent -1 + "*Extra indent for caml lines starting with the to keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-to-extra-indent) + +(defvar caml-with-extra-indent nil + "*Extra indent for caml lines starting with the with keyword. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-with-extra-indent) + +(defvar caml-comment-indent 3 + "*Indent inside comments.") +(make-variable-buffer-local 'caml-comment-indent) + +(defvar caml-|-extra-indent -2 + "*Extra indent for caml lines starting with the | operator. +Usually negative. nil is align on master.") +(make-variable-buffer-local 'caml-|-extra-indent) + +(defvar caml-rb-extra-indent -2 + "*Extra indent for caml lines statring with ]. +Usually negative. nil is align on master.") + +(defvar caml-rc-extra-indent -2 + "*Extra indent for caml lines starting with }. +Usually negative. nil is align on master.") + +(defvar caml-rp-extra-indent -1 + "*Extra indent for caml lines starting with ). +Usually negative. nil is align on master.") + +(defvar caml-electric-indent t + "*Non-nil means electrically indent lines starting with |, ] or }. + +Many people find eletric keys irritating, so you can disable them if +you are one.") + +(defvar caml-electric-close-vector t + "*Non-nil means electrically insert a | before a vector-closing ]. + +Many people find eletric keys irritating, so you can disable them if +you are one. You should probably have this on, though, if you also +have caml-electric-indent on, which see.") + +;;code +(if (or (not (fboundp 'indent-line-to)) + (not (fboundp 'buffer-substring-no-properties))) + (require 'caml-compat)) + +(defvar caml-shell-active nil + "Non nil when a subshell is running.") + +(defvar running-xemacs (string-match "XEmacs" emacs-version) + "Non-nil if we are running in the XEmacs environment.") + +(defvar caml-mode-map nil + "Keymap used in Caml mode.") +(if caml-mode-map + () + (setq caml-mode-map (make-sparse-keymap)) + (define-key caml-mode-map "|" 'caml-electric-pipe) + (define-key caml-mode-map "}" 'caml-electric-pipe) + (define-key caml-mode-map "]" 'caml-electric-rb) + (define-key caml-mode-map "\t" 'caml-indent-command) + (define-key caml-mode-map [backtab] 'caml-unindent-command) + +;itz 04-21-96 instead of defining a new function, use defadvice +;that way we get out effect even when we do \C-x` in compilation buffer +; (define-key caml-mode-map "\C-x`" 'caml-next-error) + + (if running-xemacs + (define-key caml-mode-map 'backspace 'backward-delete-char-untabify) + (define-key caml-mode-map "\177" 'backward-delete-char-untabify)) + + ;; caml-types + (define-key caml-mode-map [?\C-c?\C-t] 'caml-types-show-type) ; "type" + (define-key caml-mode-map [?\C-c?\C-f] 'caml-types-show-call) ; "function" + (define-key caml-mode-map [?\C-c?\C-l] 'caml-types-show-ident) ; "let" + ;; must be a mouse-down event. Can be any button and any prefix + (define-key caml-mode-map [?\C-c down-mouse-1] 'caml-types-explore) + ;; caml-help + (define-key caml-mode-map [?\C-c?i] 'ocaml-add-path) + (define-key caml-mode-map [?\C-c?]] 'ocaml-close-module) + (define-key caml-mode-map [?\C-c?[] 'ocaml-open-module) + (define-key caml-mode-map [?\C-c?\C-h] 'caml-help) + (define-key caml-mode-map [?\C-c?\t] 'caml-complete) + ;; others + (define-key caml-mode-map "\C-cb" 'caml-insert-begin-form) + (define-key caml-mode-map "\C-cf" 'caml-insert-for-form) + (define-key caml-mode-map "\C-ci" 'caml-insert-if-form) + (define-key caml-mode-map "\C-cl" 'caml-insert-let-form) + (define-key caml-mode-map "\C-cm" 'caml-insert-match-form) + (define-key caml-mode-map "\C-ct" 'caml-insert-try-form) + (define-key caml-mode-map "\C-cw" 'caml-insert-while-form) + (define-key caml-mode-map "\C-c`" 'caml-goto-phrase-error) + (define-key caml-mode-map "\C-c\C-a" 'caml-find-alternate-file) + (define-key caml-mode-map "\C-c\C-c" 'compile) + (define-key caml-mode-map "\C-c\C-e" 'caml-eval-phrase) + (define-key caml-mode-map "\C-c\C-\[" 'caml-backward-to-less-indent) + (define-key caml-mode-map "\C-c\C-\]" 'caml-forward-to-less-indent) + (define-key caml-mode-map "\C-c\C-q" 'caml-indent-phrase) + (define-key caml-mode-map "\C-c\C-r" 'caml-eval-region) + (define-key caml-mode-map "\C-c\C-s" 'caml-show-subshell) + (define-key caml-mode-map "\M-\C-h" 'caml-mark-phrase) + (define-key caml-mode-map "\M-\C-q" 'caml-indent-phrase) + (define-key caml-mode-map "\M-\C-x" 'caml-eval-phrase) + + (if running-xemacs nil ; if not running xemacs + (let ((map (make-sparse-keymap "Caml")) + (forms (make-sparse-keymap "Forms"))) + (define-key caml-mode-map "\C-c\C-d" 'caml-show-imenu) + (define-key caml-mode-map [menu-bar] (make-sparse-keymap)) + (define-key caml-mode-map [menu-bar caml] (cons "Caml" map)) + ;; caml-help + + (define-key map [open] '("Open add path" . ocaml-add-path )) + (define-key map [close] + '("Close module for help" . ocaml-close-module)) + (define-key map [open] '("Open module for help" . ocaml-open-module)) + (define-key map [help] '("Help for identifier" . caml-help)) + (define-key map [complete] '("Complete identifier" . caml-complete)) + (define-key map [separator-help] '("---")) + + ;; caml-types + (define-key map [show-type] + '("Show type at point" . caml-types-show-type )) + (define-key map [separator-types] '("---")) + + ;; others + (define-key map [camldebug] '("Call debugger..." . camldebug)) + (define-key map [run-caml] '("Start subshell..." . run-caml)) + (define-key map [compile] '("Compile..." . compile)) + (define-key map [switch-view] + '("Switch view" . caml-find-alternate-file)) + (define-key map [separator-format] '("--")) + (define-key map [forms] (cons "Forms" forms)) + (define-key map [show-imenu] '("Show index" . caml-show-imenu)) + (put 'caml-show-imenu 'menu-enable '(not caml-imenu-shown)) + (define-key map [show-subshell] '("Show subshell" . caml-show-subshell)) + (put 'caml-show-subshell 'menu-enable 'caml-shell-active) + (define-key map [eval-phrase] '("Eval phrase" . caml-eval-phrase)) + (put 'caml-eval-phrase 'menu-enable 'caml-shell-active) + (define-key map [indent-phrase] '("Indent phrase" . caml-indent-phrase)) + (define-key forms [while] + '("while .. do .. done" . caml-insert-while-form)) + (define-key forms [try] '("try .. with .." . caml-insert-try-form)) + (define-key forms [match] '("match .. with .." . caml-insert-match-form)) + (define-key forms [let] '("let .. in .." . caml-insert-let-form)) + (define-key forms [if] '("if .. then .. else .." . caml-insert-if-form)) + (define-key forms [begin] '("for .. do .. done" . caml-insert-for-form)) + (define-key forms [begin] '("begin .. end" . caml-insert-begin-form))))) + +(defvar caml-mode-xemacs-menu + (if running-xemacs + '("Caml" + [ "Indent phrase" caml-indent-phrase :keys "C-M-q" ] + [ "Eval phrase" caml-eval-phrase + :active caml-shell-active :keys "C-M-x" ] + [ "Show subshell" caml-show-subshell caml-shell-active ] + ("Forms" + [ "while .. do .. done" caml-insert-while-form t] + [ "try .. with .." caml-insert-try-form t ] + [ "match .. with .." caml-insert-match-form t ] + [ "let .. in .." caml-insert-let-form t ] + [ "if .. then .. else .." caml-insert-if-form t ] + [ "for .. do .. done" caml-insert-for-form t ] + [ "begin .. end" caml-insert-begin-form t ]) + "---" + [ "Switch view" caml-find-alternate-file t ] + [ "Compile..." compile t ] + [ "Start subshell..." run-caml t ] + "---" + [ "Show type at point" caml-types-show-type t ] + "---" + [ "Complete identifier" caml-complete t ] + [ "Help for identifier" caml-help t ] + [ "Add path for documentation" ocaml-add-path t ] + [ "Open module for documentation" ocaml-open t ] + [ "Close module for documentation" ocaml-close t ] + )) + "Menu to add to the menubar when running Xemacs") + +(defvar caml-mode-syntax-table nil + "Syntax table in use in Caml mode buffers.") +(if caml-mode-syntax-table + () + (setq caml-mode-syntax-table (make-syntax-table)) + ; backslash is an escape sequence + (modify-syntax-entry ?\\ "\\" caml-mode-syntax-table) + ; ( is first character of comment start + (modify-syntax-entry ?\( "()1n" caml-mode-syntax-table) + ; * is second character of comment start, + ; and first character of comment end + (modify-syntax-entry ?* ". 23n" caml-mode-syntax-table) + ; ) is last character of comment end + (modify-syntax-entry ?\) ")(4" caml-mode-syntax-table) + ; backquote was a string-like delimiter (for character literals) + ; (modify-syntax-entry ?` "\"" caml-mode-syntax-table) + ; quote and underscore are part of words + (modify-syntax-entry ?' "w" caml-mode-syntax-table) + (modify-syntax-entry ?_ "w" caml-mode-syntax-table) + ; ISO-latin accented letters and EUC kanjis are part of words + (let ((i 160)) + (while (< i 256) + (modify-syntax-entry i "w" caml-mode-syntax-table) + (setq i (1+ i))))) + +(defvar caml-mode-abbrev-table nil + "Abbrev table used for Caml mode buffers.") +(if caml-mode-abbrev-table nil + (setq caml-mode-abbrev-table (make-abbrev-table)) + (define-abbrev caml-mode-abbrev-table "and" "and" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "do" "do" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "done" "done" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "else" "else" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "end" "end" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "in" "in" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "then" "then" 'caml-abbrev-hook) + (define-abbrev caml-mode-abbrev-table "with" "with" 'caml-abbrev-hook)) + +;; Other internal variables + +(defvar caml-last-noncomment-pos nil + "Caches last buffer position determined not inside a caml comment.") +(make-variable-buffer-local 'caml-last-noncomment-pos) + +;;last-noncomment-pos can be a simple position, because we nil it +;;anyway whenever buffer changes upstream. last-comment-start and -end +;;have to be markers, because we preserve them when the changes' end +;;doesn't overlap with the comment's start. + +(defvar caml-last-comment-start nil + "A marker caching last determined caml comment start.") +(make-variable-buffer-local 'caml-last-comment-start) + +(defvar caml-last-comment-end nil + "A marker caching last determined caml comment end.") +(make-variable-buffer-local 'caml-last-comment-end) + +(make-variable-buffer-local 'before-change-function) + +(defvar caml-imenu-shown nil + "True if we have computed definition list.") +(make-variable-buffer-local 'caml-imenu-shown) + +(defconst caml-imenu-search-regexp + (concat "\\<in\\>\\|" + "^[ \t]*\\(let\\|class\\|type\\|m\\(odule\\|ethod\\)" + "\\|functor\\|and\\|val\\)[ \t]+" + "\\(\\('[a-zA-Z0-9]+\\|([^)]+)" + "\\|mutable\\|private\\|rec\\|type\\)[ \t]+\\)?" + "\\([a-zA-Z][a-zA-Z0-9_']*\\)")) + +;;; The major mode +(eval-when-compile + (if (and (boundp 'running-xemacs) running-xemacs) nil + (require 'imenu))) + +;; +(defvar caml-mode-hook nil + "Hook for caml-mode") + +(defun caml-mode () + "Major mode for editing Caml code. + +\\{caml-mode-map}" + + (interactive) + (kill-all-local-variables) + (setq major-mode 'caml-mode) + (setq mode-name "caml") + (use-local-map caml-mode-map) + (set-syntax-table caml-mode-syntax-table) + (setq local-abbrev-table caml-mode-abbrev-table) + (make-local-variable 'paragraph-start) + (setq paragraph-start (concat "^$\\|" page-delimiter)) + (make-local-variable 'paragraph-separate) + (setq paragraph-separate paragraph-start) + (make-local-variable 'paragraph-ignore-fill-prefix) + (setq paragraph-ignore-fill-prefix t) + (make-local-variable 'require-final-newline) + (setq require-final-newline t) + (make-local-variable 'comment-start) + (setq comment-start "(*") + (make-local-variable 'comment-end) + (setq comment-end "*)") + (make-local-variable 'comment-column) + (setq comment-column 40) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "(\\*+ *") + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments nil) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'caml-indent-command) + ;itz Fri Sep 25 13:23:49 PDT 1998 + (make-local-variable 'add-log-current-defun-function) + (setq add-log-current-defun-function 'caml-current-defun) + ;itz 03-25-96 + (setq before-change-function 'caml-before-change-function) + (setq caml-last-noncomment-pos nil) + (setq caml-last-comment-start (make-marker)) + (setq caml-last-comment-end (make-marker)) + ;garrigue 27-11-96 + (setq case-fold-search nil) + ;garrigue july 97 + (if running-xemacs ; from Xemacs lisp mode + (if (and (featurep 'menubar) + current-menubar) + (progn + ;; make a local copy of the menubar, so our modes don't + ;; change the global menubar + (set-buffer-menubar current-menubar) + (add-submenu nil caml-mode-xemacs-menu))) + ;imenu support (not for Xemacs) + (make-local-variable 'imenu-create-index-function) + (setq imenu-create-index-function 'caml-create-index-function) + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression caml-imenu-search-regexp) + (if (and caml-imenu-enable (< (buffer-size) 10000)) + (caml-show-imenu))) + (run-hooks 'caml-mode-hook)) + +(defun caml-set-compile-command () + "Hook to set compile-command locally, unless there is a Makefile or + a _build directory or a _tags file in the current directory." + (interactive) + (unless (or (null buffer-file-name) + (file-exists-p "makefile") + (file-exists-p "Makefile") + (file-exists-p "_build") + (file-exists-p "_tags")) + (let* ((filename (file-name-nondirectory buffer-file-name)) + (basename (file-name-sans-extension filename)) + (command nil)) + (cond + ((string-match ".*\\.mli\$" filename) + (setq command "ocamlc -c")) + ((string-match ".*\\.ml\$" filename) + (setq command "ocamlc -c") ; (concat "ocamlc -o " basename) + ) + ((string-match ".*\\.mll\$" filename) + (setq command "ocamllex")) + ((string-match ".*\\.mll\$" filename) + (setq command "ocamlyacc")) + ) + (if command + (progn + (make-local-variable 'compile-command) + (setq compile-command (concat command " " filename)))) + ))) + +(add-hook 'caml-mode-hook 'caml-set-compile-command) + +;;; Auxiliary function. Garrigue 96-11-01. + +(defun caml-find-alternate-file () + (interactive) + (let ((name (buffer-file-name))) + (if (string-match "^\\(.*\\)\\.\\(ml\\|mli\\)$" name) + (find-file + (concat + (caml-match-string 1 name) + (if (string= "ml" (caml-match-string 2 name)) ".mli" ".ml")))))) + +;;; subshell support + +(defun caml-eval-region (start end) + "Send the current region to the inferior Caml process." + (interactive"r") + (require 'inf-caml) + (inferior-caml-eval-region start end)) + +;; old version ---to be deleted later +; +; (defun caml-eval-phrase () +; "Send the current Caml phrase to the inferior Caml process." +; (interactive) +; (save-excursion +; (let ((bounds (caml-mark-phrase))) +; (inferior-caml-eval-region (car bounds) (cdr bounds))))) + +(defun caml-eval-phrase (arg &optional min max) + "Send the phrase containing the point to the CAML process. +With prefix-arg send as many phrases as its numeric value, +If an error occurs during evalutaion, stop at this phrase and +repport the error. + +Return nil if noerror and position of error if any. + +If arg's numeric value is zero or negative, evaluate the current phrase +or as many as prefix arg, ignoring evaluation errors. +This allows to jump other erroneous phrases. + +Optional arguments min max defines a region within which the phrase +should lies." + (interactive "p") + (require 'inf-caml) + (inferior-caml-eval-phrase arg min max)) + +(defun caml-eval-buffer (arg) + "Evaluate the buffer from the beginning to the phrase under the point. +With prefix arg, evaluate past the whole buffer, no stopping at +the current point." + (interactive "p") + (let ((here (point)) err) + (goto-char (point-min)) + (setq err + (caml-eval-phrase 500 (point-min) (if arg (point-max) here))) + (if err (set-mark err)) + (goto-char here))) + +(defun caml-show-subshell () + (interactive) + (require 'inf-caml) + (inferior-caml-show-subshell)) + + +;;; Imenu support +(defun caml-show-imenu () + (interactive) + (require 'imenu) + (switch-to-buffer (current-buffer)) + (imenu-add-to-menubar "Defs") + (setq caml-imenu-shown t)) + +(defun caml-prev-index-position-function () + (let (found data) + (while (and (setq found + (re-search-backward caml-imenu-search-regexp nil 'move)) + (progn (setq data (match-data)) t) + (or (caml-in-literal-p) + (caml-in-comment-p) + (if (looking-at "in") (caml-find-in-match))))) + (set-match-data data) + found)) +(defun caml-create-index-function () + (let (value-alist + type-alist + class-alist + method-alist + module-alist + and-alist + all-alist + menu-alist + (prev-pos (point-max)) + index) + (goto-char prev-pos) + (imenu-progress-message prev-pos 0 t) + ;; collect definitions + (while (caml-prev-index-position-function) + (setq index (cons (caml-match-string 5) (point))) + (imenu-progress-message prev-pos nil t) + (setq all-alist (cons index all-alist)) + (cond + ((looking-at "[ \t]*and") + (setq and-alist (cons index and-alist))) + ((looking-at "[ \t]*let") + (setq value-alist (cons index (append and-alist value-alist))) + (setq and-alist nil)) + ((looking-at "[ \t]*type") + (setq type-alist (cons index (append and-alist type-alist))) + (setq and-alist nil)) + ((looking-at "[ \t]*class") + (setq class-alist (cons index (append and-alist class-alist))) + (setq and-alist nil)) + ((looking-at "[ \t]*val") + (setq value-alist (cons index value-alist))) + ((looking-at "[ \t]*\\(module\\|functor\\)") + (setq module-alist (cons index module-alist))) + ((looking-at "[ \t]*method") + (setq method-alist (cons index method-alist))))) + ;; build menu + (mapcar + '(lambda (pair) + (if (symbol-value (cdr pair)) + (setq menu-alist + (cons + (cons (car pair) + (sort (symbol-value (cdr pair)) 'imenu--sort-by-name)) + menu-alist)))) + '(("Values" . value-alist) + ("Types" . type-alist) + ("Modules" . module-alist) + ("Methods" . method-alist) + ("Classes" . class-alist))) + (if all-alist (setq menu-alist (cons (cons "Index" all-alist) menu-alist))) + (imenu-progress-message prev-pos 100 t) + menu-alist)) + +;;; Indentation stuff + +(defun caml-in-indentation () + "Tests whether all characters between beginning of line and point +are blanks." + (save-excursion + (skip-chars-backward " \t") + (bolp))) + +;;; The command +;;; Sorry, I didn't like the previous behaviour... Garrigue 96/11/01 + +(defun caml-indent-command (&optional p) + "Indent the current line in Caml mode. + +Compute new indentation based on caml syntax. If prefixed, indent +the line all the way to where point is." + + (interactive "*p") + (cond + ((and p (> p 1)) (indent-line-to (current-column))) + ((caml-in-indentation) (indent-line-to (caml-compute-final-indent))) + (t (save-excursion + (indent-line-to + (caml-compute-final-indent)))))) + +(defun caml-unindent-command () + + "Decrease indentation by one level in Caml mode. + +Works only if the point is at the beginning of an indented line +\(i.e. all characters between beginning of line and point are +blanks\). Does nothing otherwise. The unindent size is given by the +variable caml-mode-indentation." + + (interactive "*") + (let* ((begline + (save-excursion + (beginning-of-line) + (point))) + (current-offset + (- (point) begline))) + (if (and (>= current-offset caml-mode-indentation) + (caml-in-indentation)) + (backward-delete-char-untabify caml-mode-indentation)))) + +;;; +;;; Error processing +;;; + +;; Error positions are given in bytes, not in characters +;; This function switches to monobyte mode + +(if (not (fboundp 'char-bytes)) + (defalias 'forward-byte 'forward-char) + (defun caml-char-bytes (ch) + (let ((l (char-bytes ch))) + (if (> l 1) (- l 1) l))) + (defun forward-byte (count) + (if (> count 0) + (while (> count 0) + (let ((char (char-after))) + (if (null char) + (setq count 0) + (setq count (- count (caml-char-bytes (char-after)))) + (forward-char)))) + (while (< count 0) + (let ((char (char-after))) + (if (null char) + (setq count 0) + (setq count (+ count (caml-char-bytes (char-before)))) + (backward-char)))) + ))) + +(require 'compile) + +;; In Emacs 19, the regexps in compilation-error-regexp-alist do not +;; match the error messages when the language is not English. +;; Hence we add a regexp. + +(defconst caml-error-regexp + "^[ A-\377]+ \"\\([^\"\n]+\\)\", [A-\377]+ \\([0-9]+\\)[-,:]" + "Regular expression matching the error messages produced by camlc.") + +(if (boundp 'compilation-error-regexp-alist) + (or (assoc caml-error-regexp + compilation-error-regexp-alist) + (setq compilation-error-regexp-alist + (cons (list caml-error-regexp 1 2) + compilation-error-regexp-alist)))) + +;; A regexp to extract the range info + +(defconst caml-error-chars-regexp + ".*, .*, [A-\377]+ \\([0-9]+\\)-\\([0-9]+\\):?" + "Regular expression extracting the character numbers +from an error message produced by camlc.") + +;; Wrapper around next-error. + +(defvar caml-error-overlay nil) +(defvar caml-next-error-skip-warnings-flag nil) + +(defun caml-string-to-int (x) + (if (fboundp 'string-to-number) (string-to-number x) (string-to-int x))) + +;;itz 04-21-96 somebody didn't get the documentation for next-error +;;right. When the optional argument is a number n, it should move +;;forward n errors, not reparse. + +;itz 04-21-96 instead of defining a new function, use defadvice +;that way we get our effect even when we do \C-x` in compilation buffer + +(defadvice next-error (after caml-next-error activate) + "Reads the extra positional information provided by the Caml compiler. + +Puts the point and the mark exactly around the erroneous program +fragment. The erroneous fragment is also temporarily highlighted if +possible." + + (if (eq major-mode 'caml-mode) + (let (skip bol beg end) + (save-excursion + (set-buffer + (if (boundp 'compilation-last-buffer) + compilation-last-buffer ;Emacs 19 + "*compilation*")) ;Emacs 18 + (save-excursion + (goto-char (window-point (get-buffer-window (current-buffer)))) + (if (looking-at caml-error-chars-regexp) + (setq beg + (caml-string-to-int + (buffer-substring (match-beginning 1) (match-end 1))) + end + (caml-string-to-int + (buffer-substring (match-beginning 2) (match-end 2))))) + (next-line) + (beginning-of-line) + (if (and (looking-at "Warning") + caml-next-error-skip-warnings-flag) + (setq skip 't)))) + (cond + (skip (next-error)) + (beg + (setq end (- end beg)) + (beginning-of-line) + (forward-byte beg) + (setq beg (point)) + (forward-byte end) + (setq end (point)) + (goto-char beg) + (push-mark end t) + (cond ((fboundp 'make-overlay) + (if caml-error-overlay () + (setq caml-error-overlay (make-overlay 1 1)) + (overlay-put caml-error-overlay 'face 'region)) + (unwind-protect + (progn + (move-overlay caml-error-overlay + beg end (current-buffer)) + (sit-for 60)) + (delete-overlay caml-error-overlay))))))))) + +(defun caml-next-error-skip-warnings (&rest args) + (let ((old-flag caml-next-error-skip-warnings-flag)) + (unwind-protect + (progn (setq caml-next-error-skip-warnings-flag 't) + (apply 'next-error args)) + (setq caml-next-error-skip-warnings-flag old-flag)))) + + +;; Usual match-string doesn't work properly with font-lock-mode +;; on some emacs. + +(defun caml-match-string (num &optional string) + + "Return string of text matched by last search, without properties. + +NUM specifies which parenthesized expression in the last regexp. +Value is nil if NUMth pair didn't match, or there were less than NUM +pairs. Zero means the entire text matched by the whole regexp or +whole string." + + (let* ((data (match-data)) + (begin (nth (* 2 num) data)) + (end (nth (1+ (* 2 num)) data))) + (if string (substring string begin end) + (buffer-substring-no-properties begin end)))) + +;; itz Thu Sep 24 19:02:42 PDT 1998 this is to have some level of +;; comfort when sending phrases to the toplevel and getting errors. +(defun caml-goto-phrase-error () + "Find the error location in current Caml phrase." + (interactive) + (require 'inf-caml) + (let ((bounds (save-excursion (caml-mark-phrase)))) + (inferior-caml-goto-error (car bounds) (cdr bounds)))) + +;;; Phrases + +;itz the heuristics used to see if we're `between two phrases' +;didn't seem right to me. + +(defconst caml-phrase-start-keywords + (concat "\\<\\(class\\|ex\\(ternal\\|ception\\)\\|functor" + "\\|let\\|module\\|open\\|type\\|val\\)\\>") + "Keywords starting phrases in files") + +;; a phrase starts when a toplevel keyword is at the beginning of a line +(defun caml-at-phrase-start-p () + (and (bolp) + (or (looking-at "#") + (looking-at caml-phrase-start-keywords)))) + +(defun caml-skip-comments-forward () + (skip-chars-forward " \n\t") + (while (or (looking-at comment-start-skip) (caml-in-comment-p)) + (if (= (following-char) ?\)) (forward-char) + (search-forward comment-end)) + (skip-chars-forward " \n\t"))) + +(defun caml-skip-comments-backward () + (skip-chars-backward " \n\t") + (while (and (eq (preceding-char) ?\)) (eq (char-after (- (point) 2)) ?*)) + (backward-char) + (while (caml-in-comment-p) (search-backward comment-start)) + (skip-chars-backward " \n\t"))) + +(defconst caml-phrase-sep-keywords (concat ";;\\|" caml-phrase-start-keywords)) + +(defun caml-find-phrase (&optional min-pos max-pos) + "Find the CAML phrase containing the point. +Return the position of the beginning of the phrase, and move point +to the end. +" + (interactive) + (if (not min-pos) (setq min-pos (point-min))) + (if (not max-pos) (setq max-pos (point-max))) + (let (beg end use-semi kwop) + ;(caml-skip-comments-backward) + (cond + ; shall we have special processing for semicolons? + ;((and (eq (char-before (- (point) 1)) ?\;) (eq (char-before) ?\;)) + ; (forward-char) + ; (caml-skip-comments-forward) + ; (setq beg (point)) + ; (while (and (search-forward ";;" max-pos 'move) + ; (or (caml-in-comment-p) (caml-in-literal-p))))) + (t + (caml-skip-comments-forward) + (if (caml-at-phrase-start-p) (forward-char)) + (while (and (cond + ((re-search-forward caml-phrase-sep-keywords max-pos 'move) + (goto-char (match-beginning 0)) t)) + (or (not (or (bolp) (looking-at ";;"))) + (caml-in-comment-p) + (caml-in-literal-p))) + (forward-char)) + (setq end (+ (point) (if (looking-at ";;") 2 0))) + (while (and + (setq kwop (caml-find-kwop caml-phrase-sep-keywords min-pos)) + (not (string= kwop ";;")) + (not (bolp)))) + (if (string= kwop ";;") (forward-char 2)) + (if (not kwop) (goto-char min-pos)) + (caml-skip-comments-forward) + (setq beg (point)) + (if (>= beg end) (error "no phrase before point")) + (goto-char end))) + (caml-skip-comments-forward) + beg)) + +(defun caml-mark-phrase (&optional min-pos max-pos) + "Put mark at end of this Caml phrase, point at beginning. +" + (interactive) + (let* ((beg (caml-find-phrase min-pos max-pos)) (end (point))) + (push-mark) + (goto-char beg) + (cons beg end))) + +;;itz Fri Sep 25 12:58:13 PDT 1998 support for adding change-log entries +(defun caml-current-defun () + (save-excursion + (caml-mark-phrase) + (if (not (looking-at caml-phrase-start-keywords)) nil + (re-search-forward caml-phrase-start-keywords) + (let ((done nil)) + (while (not done) + (cond + ((looking-at "\\s ") + (skip-syntax-forward " ")) + ((char-equal (following-char) ?\( ) + (forward-sexp 1)) + ((char-equal (following-char) ?') + (skip-syntax-forward "w_")) + (t (setq done t))))) + (re-search-forward "\\(\\sw\\|\\s_\\)+") + (match-string 0)))) + +(defun caml-overlap (b1 e1 b2 e2) + (<= (max b1 b2) (min e1 e2))) + +;this clears the last comment cache if necessary +(defun caml-before-change-function (begin end) + (if (and caml-last-noncomment-pos + (> caml-last-noncomment-pos begin)) + (setq caml-last-noncomment-pos nil)) + (if (and (marker-position caml-last-comment-start) + (marker-position caml-last-comment-end) + (caml-overlap begin end + caml-last-comment-start + caml-last-comment-end)) + (prog2 + (set-marker caml-last-comment-start nil) + (set-marker caml-last-comment-end nil))) + (let ((orig-function (default-value 'before-change-function))) + (if orig-function (funcall orig-function begin end)))) + +(defun caml-in-literal-p () + "Returns non-nil if point is inside a caml literal." + (let* ((start-literal (concat "[\"" caml-quote-char "]")) + (char-literal + (concat "\\([^\\]\\|\\\\\\.\\|\\\\[0-9][0-9][0-9]\\)" + caml-quote-char)) + (pos (point)) + (eol (progn (end-of-line 1) (point))) + state in-str) + (beginning-of-line 1) + (while (and (not state) + (re-search-forward start-literal eol t) + (<= (point) pos)) + (cond + ((string= (caml-match-string 0) "\"") + (setq in-str t) + (while (and in-str (not state) + (re-search-forward "\"\\|\\\\\"" eol t)) + (if (> (point) pos) (setq state t)) + (if (string= (caml-match-string 0) "\"") (setq in-str nil))) + (if in-str (setq state t))) + ((looking-at char-literal) + (if (and (>= pos (match-beginning 0)) (< pos (match-end 0))) + (setq state t) + (goto-char (match-end 0)))))) + (goto-char pos) + state)) + +(defun caml-forward-comment () + "Skip one (eventually nested) comment." + (let ((count 1) match) + (while (> count 0) + (if (not (re-search-forward "(\\*\\|\\*)" nil 'move)) + (setq count -1) + (setq match (caml-match-string 0)) + (cond + ((caml-in-literal-p) + nil) + ((string= match comment-start) + (setq count (1+ count))) + (t + (setq count (1- count)))))) + (= count 0))) + +(defun caml-backward-comment () + "Skip one (eventually nested) comment." + (let ((count 1) match) + (while (> count 0) + (if (not (re-search-backward "(\\*\\|\\*)" nil 'move)) + (setq count -1) + (setq match (caml-match-string 0)) + (cond + ((caml-in-literal-p) + nil) + ((string= match comment-start) + (setq count (1- count))) + (t + (setq count (1+ count)))))) + (= count 0))) + +(defun caml-in-comment-p () + "Returns non-nil if point is inside a caml comment. +Returns nil for the parenthesis openning a comment." + ;;we look for comments differently than literals. there are two + ;;reasons for this. first, caml has nested comments and it is not so + ;;clear that parse-partial-sexp supports them; second, if proper + ;;style is used, literals are never split across lines, so we don't + ;;have to worry about bogus phrase breaks inside literals, while we + ;;have to account for that possibility in comments. + (if caml-last-comment-start + (save-excursion + (let* ((cached-pos caml-last-noncomment-pos) + (cached-begin (marker-position caml-last-comment-start)) + (cached-end (marker-position caml-last-comment-end))) + (cond + ((and cached-begin cached-end + (< cached-begin (point)) (< (point) cached-end)) t) + ((and cached-pos (= cached-pos (point))) nil) + ((and cached-pos (> cached-pos (point)) + (< (abs (- cached-pos (point))) caml-lookback-limit)) + (let (end found (here (point))) + ; go back to somewhere sure + (goto-char cached-pos) + (while (> (point) here) + ; look for the end of a comment + (while (and (if (search-backward comment-end (1- here) 'move) + (setq end (match-end 0)) + (setq end nil)) + (caml-in-literal-p))) + (if end (setq found (caml-backward-comment)))) + (if (and found (= (point) here)) (setq end nil)) + (if (not end) + (setq caml-last-noncomment-pos here) + (set-marker caml-last-comment-start (point)) + (set-marker caml-last-comment-end end)) + end)) + (t + (let (begin found (here (point))) + ;; go back to somewhere sure (or far enough) + (goto-char + (if cached-pos cached-pos (- (point) caml-lookback-limit))) + (while (< (point) here) + ;; look for the beginning of a comment + (while (and (if (search-forward comment-start (1+ here) 'move) + (setq begin (match-beginning 0)) + (setq begin nil)) + (caml-in-literal-p))) + (if begin (setq found (caml-forward-comment)))) + (if (and found (= (point) here)) (setq begin nil)) + (if (not begin) + (setq caml-last-noncomment-pos here) + (set-marker caml-last-comment-start begin) + (set-marker caml-last-comment-end (point))) + begin))))))) + +;; Various constants and regexps + +(defconst caml-before-expr-prefix + (concat "\\<\\(asr\\|begin\\|class\\|do\\(wnto\\)?\\|else" + "\\|i\\(f\\|n\\(herit\\|itializer\\)?\\)" + "\\|f\\(or\\|un\\(ct\\(ion\\|or\\)\\)?\\)" + "\\|l\\(and\\|or\\|s[lr]\\|xor\\)\\|m\\(atch\\|od\\)" + "\\|o[fr]\\|parser\\|s\\(ig\\|truct\\)\\|t\\(hen\\|o\\|ry\\)" + "\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\)\\>\\|:begin\\>" + "\\|[=<>@^|&+-*/$%][!$%*+-./:<=>?@^|~]*\\|:[:=]\\|[[({,;]") + + "Keywords that may appear immediately before an expression. +Used to distinguish it from toplevel let construct.") + +(defconst caml-matching-kw-regexp + (concat + "\\<\\(and\\|do\\(ne\\)?\\|e\\(lse\\|nd\\)\\|in\\|t\\(hen\\|o\\)" + "\\|with\\)\\>\\|[^[|]|") + "Regexp used in caml mode for skipping back over nested blocks.") + +(defconst caml-matching-kw-alist + '(("|" . caml-find-pipe-match) + (";" . caml-find-semi-match) + ("," . caml-find-comma-match) + ("end" . caml-find-end-match) + ("done" . caml-find-done-match) + ("in" . caml-find-in-match) + ("with" . caml-find-with-match) + ("else" . caml-find-else-match) + ("then" . caml-find-then-match) + ("to" . caml-find-done-match) + ("do" . caml-find-done-match) + ("and" . caml-find-and-match)) + + "Association list used in caml mode for skipping back over nested blocks.") + +(defconst caml-kwop-regexps (make-vector 9 nil) + "Array of regexps representing caml keywords of different priorities.") + +(defun caml-in-expr-p () + (let ((pos (point)) (in-expr t)) + (caml-find-kwop + (concat caml-before-expr-prefix "\\|" + caml-matching-kw-regexp "\\|" + (aref caml-kwop-regexps caml-max-indent-priority))) + (cond + ; special case for ;; + ((and (> (point) 1) (= (preceding-char) ?\;) (= (following-char) ?\;)) + (setq in-expr nil)) + ((looking-at caml-before-expr-prefix) + (if (not (looking-at "(\\*")) (goto-char (match-end 0))) + (skip-chars-forward " \t\n") + (while (looking-at "(\\*") + (forward-char) + (caml-forward-comment) + (skip-chars-forward " \t\n")) + (if (<= pos (point)) (setq in-expr nil)))) + (goto-char pos) + in-expr)) + +(defun caml-at-sexp-close-p () + (or (char-equal ?\) (following-char)) + (char-equal ?\] (following-char)) + (char-equal ?} (following-char)))) + +(defun caml-find-kwop (kwop-regexp &optional min-pos) + "Look back for a caml keyword or operator matching KWOP-REGEXP. +Second optional argument MIN-POS bounds the search. + +Ignore occurences inside literals. If found, return a list of two +values: the actual text of the keyword or operator, and a boolean +indicating whether the keyword was one we looked for explicitly +{non-nil}, or on the other hand one of the block-terminating +keywords." + + (let ((start-literal (concat "[\"" caml-quote-char "]")) + found kwop) + (while (and (> (point) 1) (not found) + (re-search-backward kwop-regexp min-pos 'move)) + (setq kwop (caml-match-string 0)) + (cond + ((looking-at "(\\*") + (if (> (point) 1) (backward-char))) + ((caml-in-comment-p) + (search-backward "(" min-pos 'move)) + ((looking-at start-literal)) + ((caml-in-literal-p) + (re-search-backward start-literal min-pos 'move)) ;ugly hack + ((setq found t)))) + (if found + (if (not (string-match "\\`[^|[]|[^]|]?\\'" kwop)) ;arrrrgh!! + kwop + (forward-char 1) "|") nil))) + +; Association list of indentation values based on governing keywords. +; +;Each element is of the form (KEYWORD OP-TYPE PRIO INDENT). OP-TYPE is +;non-nil for operator-type nodes, which affect indentation in a +;different way from keywords: subsequent lines are indented to the +;actual occurrence of an operator, but relative to the indentation of +;the line where the governing keyword occurs. + +(defconst caml-no-indent 0) + +(defconst caml-kwop-alist + '(("begin" nil 6 caml-begin-indent) + (":begin" nil 6 caml-begin-indent) ; hack + ("class" nil 0 caml-class-indent) + ("constraint" nil 0 caml-val-indent) + ("sig" nil 1 caml-sig-indent) + ("struct" nil 1 caml-struct-indent) + ("exception" nil 0 caml-exception-indent) + ("for" nil 6 caml-for-indent) + ("fun" nil 3 caml-fun-indent) + ("function" nil 3 caml-function-indent) + ("if" nil 6 caml-if-indent) + ("if-else" nil 6 caml-if-else-indent) + ("include" nil 0 caml-include-indent) + ("inherit" nil 0 caml-inherit-indent) + ("initializer" nil 0 caml-initializer-indent) + ("let" nil 6 caml-let-indent) + ("let-in" nil 6 caml-let-in-indent) + ("match" nil 6 caml-match-indent) + ("method" nil 0 caml-method-indent) + ("module" nil 0 caml-module-indent) + ("object" nil 6 caml-object-indent) + ("of" nil 7 caml-of-indent) + ("open" nil 0 caml-no-indent) + ("parser" nil 3 caml-parser-indent) + ("try" nil 6 caml-try-indent) + ("type" nil 0 caml-type-indent) + ("val" nil 0 caml-val-indent) + ("when" nil 2 caml-if-indent) + ("while" nil 6 caml-while-indent) + ("::" t 5 caml-::-indent) + ("@" t 4 caml-@-indent) + ("^" t 4 caml-@-indent) + (":=" nil 3 caml-:=-indent) + ("<-" nil 3 caml-<--indent) + ("->" nil 2 caml-->-indent) + ("\[" t 8 caml-lb-indent) + ("{" t 8 caml-lc-indent) + ("\(" t 8 caml-lp-indent) + ("|" nil 2 caml-no-indent) + (";;" nil 0 caml-no-indent)) +; if-else and let-in are not keywords but idioms +; "|" is not in the regexps +; all these 3 values correspond to hard-coded names + +"Association list of indentation values based on governing keywords. + +Each element is of the form (KEYWORD OP-TYPE PRIO INDENT). OP-TYPE is +non-nil for operator-type nodes, which affect indentation in a +different way from keywords: subsequent lines are indented to the +actual occurrence of an operator, but relative to the indentation of +the line where the governing keyword occurs.") + +;;Originally, we had caml-kwop-regexp create these at runtime, from an +;;additional field in caml-kwop-alist. That proved way too slow, +;;although I still can't understand why. itz + +(aset caml-kwop-regexps 0 + (concat + "\\<\\(begin\\|object\\|for\\|s\\(ig\\|truct\\)\\|while\\)\\>" + "\\|:begin\\>\\|[[({]\\|;;")) +(aset caml-kwop-regexps 1 + (concat (aref caml-kwop-regexps 0) "\\|\\<\\(class\\|module\\)\\>")) +(aset caml-kwop-regexps 2 + (concat + (aref caml-kwop-regexps 1) + "\\|\\<\\(fun\\(ction\\)?\\|initializer\\|let\\|m\\(atch\\|ethod\\)" + "\\|parser\\|try\\|val\\)\\>\\|->")) +(aset caml-kwop-regexps 3 + (concat (aref caml-kwop-regexps 2) "\\|\\<if\\|when\\>")) +(aset caml-kwop-regexps 4 + (concat (aref caml-kwop-regexps 3) "\\|:=\\|<-")) +(aset caml-kwop-regexps 5 + (concat (aref caml-kwop-regexps 4) "\\|@")) +(aset caml-kwop-regexps 6 + (concat (aref caml-kwop-regexps 5) "\\|::\\|\\^")) +(aset caml-kwop-regexps 7 + (concat + (aref caml-kwop-regexps 0) + "\\|\\<\\(constraint\\|exception\\|in\\(herit\\|clude\\)" + "\\|o\\(f\\|pen\\)\\|type\\|val\\)\\>")) +(aset caml-kwop-regexps 8 + (concat (aref caml-kwop-regexps 6) + "\\|\\<\\(constraint\\|exception\\|in\\(herit\\|clude\\)" + "\\|o\\(f\\|pen\\)\\|type\\)\\>")) + +(defun caml-find-done-match () + (let ((unbalanced 1) (kwop t)) + (while (and (not (= 0 unbalanced)) kwop) + (setq kwop (caml-find-kwop "\\<\\(done\\|for\\|while\\)\\>")) + (cond + ((not kwop)) + ((string= kwop "done") (setq unbalanced (1+ unbalanced))) + (t (setq unbalanced (1- unbalanced))))) + kwop)) + +(defun caml-find-end-match () + (let ((unbalanced 1) (kwop t)) + (while (and (not (= 0 unbalanced)) kwop) + (setq kwop + (caml-find-kwop + "\\<\\(end\\|begin\\|object\\|s\\(ig\\|truct\\)\\)\\>\\|:begin\\>\\|;;")) + (cond + ((not kwop)) + ((string= kwop ";;") (setq kwop nil) (forward-line 1)) + ((string= kwop "end") (setq unbalanced (1+ unbalanced))) + ( t (setq unbalanced (1- unbalanced))))) + (if (string= kwop ":begin") "begin" + kwop))) + +(defun caml-find-in-match () + (let ((unbalanced 1) (kwop t)) + (while (and (not (= 0 unbalanced)) kwop) + (setq kwop (caml-find-kwop "\\<\\(in\\|let\\|end\\)\\>")) + (cond + ((not kwop)) + ((string= kwop "end") (caml-find-end-match)) + ((string= kwop "in") (setq unbalanced (1+ unbalanced))) + (t (setq unbalanced (1- unbalanced))))) + kwop)) + +(defun caml-find-with-match () + (let ((unbalanced 1) (kwop t)) + (while (and (not (= 0 unbalanced)) kwop) + (setq kwop + (caml-find-kwop + "\\<\\(with\\|try\\|m\\(atch\\|odule\\)\\|functor\\)\\>\\|[{}()]")) + (cond + ((not kwop)) + ((caml-at-sexp-close-p) + (caml-find-paren-match (following-char))) + ((string= kwop "with") + (setq unbalanced (1+ unbalanced))) + ((or (string= kwop "module") + (string= kwop "functor") + (string= kwop "{") + (string= kwop "(")) + (setq unbalanced 0)) + (t (setq unbalanced (1- unbalanced))))) + kwop)) + +(defun caml-find-paren-match (close) + (let ((unbalanced 1) + (regexp (cond ((= close ?\)) "[()]") + ((= close ?\]) "[][]") + ((= close ?\}) "[{}]")))) + (while (and (> unbalanced 0) + (caml-find-kwop regexp)) + (if (= close (following-char)) + (setq unbalanced (1+ unbalanced)) + (setq unbalanced (1- unbalanced)))))) + +(defun caml-find-then-match (&optional from-else) + (let ((bol (if from-else + (save-excursion + (progn (beginning-of-line) (point))))) + kwop done matching-fun) + (while (not done) + (setq kwop + (caml-find-kwop + "\\<\\(e\\(nd\\|lse\\)\\|done\\|then\\|if\\|with\\)\\>\\|[])};]")) + (cond + ((not kwop) (setq done t)) + ((caml-at-sexp-close-p) + (caml-find-paren-match (following-char))) + ((string= kwop "if") (setq done t)) + ((string= kwop "then") + (if (not from-else) (setq kwop (caml-find-then-match)))) + ((setq matching-fun (cdr-safe (assoc kwop caml-matching-kw-alist))) + (setq kwop (funcall matching-fun))))) + (if (and bol (>= (point) bol)) + "if-else" + kwop))) + +(defun caml-find-pipe-match () + (let ((done nil) (kwop) + (re (concat + "\\<\\(try\\|match\\|with\\|function\\|parser\\|type" + "\\|e\\(nd\\|lse\\)\\|done\\|then\\|in\\)\\>" + "\\|[^[|]|\\|[])}]"))) + (while (not done) + (setq kwop (caml-find-kwop re)) + (cond + ((not kwop) (setq done t)) + ((looking-at "[^[|]\\(|\\)") + (goto-char (match-beginning 1)) + (setq kwop "|") + (setq done t)) + ((caml-at-sexp-close-p) + (caml-find-paren-match (following-char))) + ((string= kwop "with") + (setq kwop (caml-find-with-match)) + (setq done t)) + ((string= kwop "parser") + (if (re-search-backward "\\<with\\>" (- (point) 5) t) + (setq kwop (caml-find-with-match))) + (setq done t)) + ((string= kwop "done") (caml-find-done-match)) + ((string= kwop "end") (caml-find-end-match)) + ((string= kwop "then") (caml-find-then-match)) + ((string= kwop "else") (caml-find-else-match)) + ((string= kwop "in") (caml-find-in-match)) + (t (setq done t)))) + kwop)) + +(defun caml-find-and-match () + (let ((done nil) (kwop)) + (while (not done) + (setq kwop (caml-find-kwop + "\\<\\(object\\|exception\\|let\\|type\\|end\\|in\\)\\>")) + (cond + ((not kwop) (setq done t)) + ((string= kwop "end") (caml-find-end-match)) + ((string= kwop "in") (caml-find-in-match)) + (t (setq done t)))) + kwop)) + +(defun caml-find-else-match () + (caml-find-then-match t)) + +(defun caml-find-semi-match () + (caml-find-kwop-skipping-blocks 2)) + +(defun caml-find-comma-match () + (caml-find-kwop-skipping-blocks 3)) + +(defun caml-find-kwop-skipping-blocks (prio) + "Look back for a caml keyword matching caml-kwop-regexps [PRIO]. + + Skip nested blocks." + + (let ((done nil) (kwop nil) (matching-fun) + (kwop-list (aref caml-kwop-regexps prio))) + (while (not done) + (setq kwop (caml-find-kwop + (concat caml-matching-kw-regexp + (cond ((> prio 3) "\\|[])},;]\\|") + ((> prio 2) "\\|[])};]\\|") + (t "\\|[])}]\\|")) + kwop-list))) + (cond + ((not kwop) (setq done t)) + ((caml-at-sexp-close-p) + (caml-find-paren-match (following-char))) + ((or (string= kwop ";;") + (and (string= kwop ";") (= (preceding-char) ?\;))) + (forward-line 1) + (setq kwop ";;") + (setq done t)) + ((and (>= prio 2) (string= kwop "|")) (setq done t)) + ((string= kwop "end") (caml-find-end-match)) + ((string= kwop "done") (caml-find-done-match)) + ((string= kwop "in") + (cond ((and (caml-find-in-match) (>= prio 2)) + (setq kwop "let-in") + (setq done t)))) + ((and (string= kwop "parser") (>= prio 2) + (re-search-backward "\\<with\\>" (- (point) 5) t)) + (setq kwop (caml-find-with-match)) + (setq done t)) + ((setq matching-fun (cdr-safe (assoc kwop caml-matching-kw-alist))) + (setq kwop (funcall matching-fun)) + (if (looking-at kwop-list) (setq done t))) + (t (let* ((kwop-info (assoc kwop caml-kwop-alist)) + (is-op (and (nth 1 kwop-info) + ; check that we are not at beginning of line + (let ((pos (point)) bti) + (back-to-indentation) + (setq bti (point)) + (goto-char pos) + (< bti pos))))) + (if (and is-op (looking-at + (concat (regexp-quote kwop) + "|?[ \t]*\\(\n\\|(\\*\\)"))) + (setq kwop-list + (aref caml-kwop-regexps (nth 2 kwop-info))) + (setq done t)))))) + kwop)) + +(defun caml-compute-basic-indent (prio) + "Compute indent of current caml line, ignoring leading keywords. + +Find the `governing node' for current line. Compute desired +indentation based on the node and the indentation alists. +Assumes point is exactly at line indentation. +Does not preserve point." + + (let* (in-expr + (kwop (cond + ((looking-at ";;") + (beginning-of-line 1)) + ((looking-at "|\\([^]|]\\|\\'\\)") + (caml-find-pipe-match)) + ((and (looking-at caml-phrase-start-keywords) + (caml-in-expr-p)) + (caml-find-end-match)) + ((and (looking-at caml-matching-kw-regexp) + (assoc (caml-match-string 0) caml-matching-kw-alist)) + (funcall (cdr-safe (assoc (caml-match-string 0) + caml-matching-kw-alist)))) + ((looking-at + (aref caml-kwop-regexps caml-max-indent-priority)) + (let* ((kwop (caml-match-string 0)) + (kwop-info (assoc kwop caml-kwop-alist)) + (prio (if kwop-info (nth 2 kwop-info) + caml-max-indent-priority))) + (if (and (looking-at (aref caml-kwop-regexps 0)) + (not (looking-at "object")) + (caml-in-expr-p)) + (setq in-expr t)) + (caml-find-kwop-skipping-blocks prio))) + (t + (if (and (= prio caml-max-indent-priority) (caml-in-expr-p)) + (setq in-expr t)) + (caml-find-kwop-skipping-blocks prio)))) + (kwop-info (assoc kwop caml-kwop-alist)) + (indent-diff + (cond + ((not kwop-info) (beginning-of-line 1) 0) + ((looking-at "[[({][|<]?[ \t]*") + (length (caml-match-string 0))) + ((nth 1 kwop-info) (symbol-value (nth 3 kwop-info))) + (t + (let ((pos (point))) + (back-to-indentation) +; (if (looking-at "\\<let\\>") (goto-char pos)) + (- (symbol-value (nth 3 kwop-info)) + (if (looking-at "|") caml-|-extra-indent 0)))))) + (extra (if in-expr caml-apply-extra-indent 0))) + (+ indent-diff extra (current-column)))) + +(defconst caml-leading-kwops-regexp + (concat + "\\<\\(and\\|do\\(ne\\)?\\|e\\(lse\\|nd\\)\\|in" + "\\|t\\(hen\\|o\\)\\|with\\)\\>\\|[]|})]") + + "Regexp matching caml keywords which need special indentation.") + +(defconst caml-leading-kwops-alist + '(("and" caml-and-extra-indent 2) + ("do" caml-do-extra-indent 0) + ("done" caml-done-extra-indent 0) + ("else" caml-else-extra-indent 3) + ("end" caml-end-extra-indent 0) + ("in" caml-in-extra-indent 2) + ("then" caml-then-extra-indent 3) + ("to" caml-to-extra-indent 0) + ("with" caml-with-extra-indent 2) + ("|" caml-|-extra-indent 2) + ("]" caml-rb-extra-indent 0) + ("}" caml-rc-extra-indent 0) + (")" caml-rp-extra-indent 0)) + + "Association list of special caml keyword indent values. + +Each member is of the form (KEYWORD EXTRA-INDENT PRIO) where +EXTRA-INDENT is the variable holding extra indentation amount for +KEYWORD (usually negative) and PRIO is upper bound on priority of +matching nodes to determine KEYWORD's final indentation.") + +(defun caml-compute-final-indent () + (save-excursion + (back-to-indentation) + (cond + ((and (bolp) (looking-at comment-start-skip)) (current-column)) + ((caml-in-comment-p) + (let ((closing (looking-at "\\*)")) + (comment-mark (looking-at "\\*"))) + (caml-backward-comment) + (looking-at comment-start-skip) + (+ (current-column) + (cond + (closing 1) + (comment-mark 1) + (t (- (match-end 0) (match-beginning 0))))))) + (t (let* ((leading (looking-at caml-leading-kwops-regexp)) + (assoc-val (if leading (assoc (caml-match-string 0) + caml-leading-kwops-alist))) + (extra (if leading (symbol-value (nth 1 assoc-val)) 0)) + (prio (if leading (nth 2 assoc-val) + caml-max-indent-priority)) + (basic (caml-compute-basic-indent prio))) + (max 0 (if extra (+ extra basic) (current-column)))))))) + + + +(defun caml-split-string () + "Called whenever a line is broken inside a caml string literal." + (insert-before-markers "\"^\"") + (backward-char 1)) + +(defadvice indent-new-comment-line (around + caml-indent-new-comment-line + activate) + + "Handle multi-line strings in caml mode." + +;this advice doesn't make sense in other modes. I wish there were a +;cleaner way to do this: I haven't found one. + + (let ((hooked (and (eq major-mode 'caml-mode) (caml-in-literal-p))) + (split-mark)) + (if (not hooked) nil + (setq split-mark (set-marker (make-marker) (point))) + (caml-split-string)) + ad-do-it + (if (not hooked) nil + (goto-char split-mark) + (set-marker split-mark nil)))) + +(defadvice newline-and-indent (around + caml-newline-and-indent + activate) + + "Handle multi-line strings in caml mode." + + (let ((hooked (and (eq major-mode 'caml-mode) (caml-in-literal-p))) + (split-mark)) + (if (not hooked) nil + (setq split-mark (set-marker (make-marker) (point))) + (caml-split-string)) + ad-do-it + (if (not hooked) nil + (goto-char split-mark) + (set-marker split-mark nil)))) + +(defun caml-electric-pipe () + "If inserting a | or } operator at beginning of line, reindent the line. + +Unfortunately there is a situation where this mechanism gets +confused. It's when | is the first character of a |] sequence. This is +a misfeature of caml syntax and cannot be fixed, however, as a +workaround, the electric ] inserts | itself if the matching [ is +followed by |." + + (interactive "*") + (let ((electric (and caml-electric-indent + (caml-in-indentation) + (not (caml-in-comment-p))))) + (self-insert-command 1) + (if electric (save-excursion (caml-indent-command))))) + +(defun caml-electric-rb () + "If inserting a ] operator at beginning of line, reindent the line. + +Also, if the matching [ is followed by a | and this ] is not preceded +by |, insert one." + + (interactive "*") + (let* ((prec (preceding-char)) + (use-pipe (and caml-electric-close-vector + (not (caml-in-comment-p)) + (not (caml-in-literal-p)) + (or (not (numberp prec)) + (not (char-equal ?| prec))))) + (electric (and caml-electric-indent + (caml-in-indentation) + (not (caml-in-comment-p))))) + (self-insert-command 1) + (if electric (save-excursion (caml-indent-command))) + (if (and use-pipe + (save-excursion + (condition-case nil + (prog2 + (backward-list 1) + (looking-at "\\[|")) + (error "")))) + (save-excursion + (backward-char 1) + (insert "|"))))) + +(defun caml-abbrev-hook () + "If inserting a leading keyword at beginning of line, reindent the line." + ;itz unfortunately we need a special case + (if (and (not (caml-in-comment-p)) (not (= last-command-char ?_))) + (let* ((bol (save-excursion (beginning-of-line) (point))) + (kw (save-excursion + (and (re-search-backward "^[ \t]*\\(\\sw+\\)\\=" bol t) + (caml-match-string 1))))) + (if kw + (let ((indent (save-excursion + (goto-char (match-beginning 1)) + (caml-indent-command) + (current-column))) + (abbrev-correct (if (= last-command-char ?\ ) 1 0))) + (indent-to (- indent + (or + (symbol-value + (nth 1 + (assoc kw caml-leading-kwops-alist))) + 0) + abbrev-correct))))))) + +; (defun caml-indent-phrase () +; (interactive "*") +; (let ((bounds (caml-mark-phrase))) +; (indent-region (car bounds) (cdr bounds) nil))) + +;;; Additional commands by Didier to report errors in toplevel mode + +(defun caml-skip-blank-forward () + (if (looking-at "[ \t\n]*\\((\\*\\([^*]\\|[^(]\\*[^)]\\)*\\*)[ \t\n]*\\)*") + (goto-char (match-end 0)))) + +;; to mark phrases, so that repeated calls will take several of them +;; knows little about Ocaml appart literals and comments, so it should work +;; with other dialects as long as ;; marks the end of phrase. + +(defun caml-indent-phrase (arg) + "Indent current phrase +with prefix arg, indent that many phrases starting with the current phrase." + (interactive "p") + (save-excursion + (let ((beg (caml-find-phrase))) + (while (progn (setq arg (- arg 1)) (> arg 0)) (caml-find-phrase)) + (indent-region beg (point) nil)))) + +(defun caml-indent-buffer () + (interactive) + (indent-region (point-min) (point-max) nil)) + +(defun caml-backward-to-less-indent (&optional n) + "Move cursor back N lines with less or same indentation." + (interactive "p") + (beginning-of-line 1) + (if (< n 0) (caml-forward-to-less-indent (- n)) + (while (> n 0) + (let ((i (current-indentation))) + (forward-line -1) + (while (or (> (current-indentation) i) + (caml-in-comment-p) + (looking-at + (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)"))) + (forward-line -1))) + (setq n (1- n)))) + (back-to-indentation)) + +(defun caml-forward-to-less-indent (&optional n) + "Move cursor back N lines with less or same indentation." + (interactive "p") + (beginning-of-line 1) + (if (< n 0) (caml-backward-to-less-indent (- n)) + (while (> n 0) + (let ((i (current-indentation))) + (forward-line 1) + (while (or (> (current-indentation) i) + (caml-in-comment-p) + (looking-at + (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)"))) + (forward-line 1))) + (setq n (1- n)))) + (back-to-indentation)) + +(defun caml-insert-begin-form () + "Inserts a nicely formatted begin-end form, leaving a mark after end." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-begin-indent c))) + (insert "begin\n\nend") + (push-mark) + (indent-line-to c) + (forward-line -1) + (indent-line-to i))) + +(defun caml-insert-for-form () + "Inserts a nicely formatted for-do-done form, leaving a mark after do(ne)." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-for-indent c))) + (insert "for do\n\ndone") + (push-mark) + (indent-line-to c) + (forward-line -1) + (indent-line-to i) + (push-mark) + (beginning-of-line 1) + (backward-char 4))) + +(defun caml-insert-if-form () + "Insert nicely formatted if-then-else form leaving mark after then, else." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-if-indent c))) + (insert "if\n\nthen\n\nelse\n") + (indent-line-to i) + (push-mark) + (forward-line -1) + (indent-line-to c) + (forward-line -1) + (indent-line-to i) + (push-mark) + (forward-line -1) + (indent-line-to c) + (forward-line -1) + (indent-line-to i))) + +(defun caml-insert-match-form () + "Insert nicely formatted match-with form leaving mark after with." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-match-indent c))) + (insert "match\n\nwith\n") + (indent-line-to i) + (push-mark) + (forward-line -1) + (indent-line-to c) + (forward-line -1) + (indent-line-to i))) + +(defun caml-insert-let-form () + "Insert nicely formatted let-in form leaving mark after in." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation))) + (insert "let in\n") + (indent-line-to c) + (push-mark) + (forward-line -1) + (forward-char (+ c 4)))) + +(defun caml-insert-try-form () + "Insert nicely formatted try-with form leaving mark after with." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-try-indent c))) + (insert "try\n\nwith\n") + (indent-line-to i) + (push-mark) + (forward-line -1) + (indent-line-to c) + (forward-line -1) + (indent-line-to i))) + +(defun caml-insert-while-form () + "Insert nicely formatted while-do-done form leaving mark after do, done." + (interactive "*") + (let ((prec (preceding-char))) + (if (and (numberp prec) (not (char-equal ?\ (char-syntax prec)))) + (insert " "))) + (let* ((c (current-indentation)) (i (+ caml-if-indent c))) + (insert "while do\n\ndone") + (push-mark) + (indent-line-to c) + (forward-line -1) + (indent-line-to i) + (push-mark) + (beginning-of-line 1) + (backward-char 4))) + +(autoload 'run-caml "inf-caml" "Run an inferior Caml process." t) + +(autoload 'caml-types-show-type "caml-types" + "Show the type of expression or pattern at point." t) +(autoload 'caml-types-explore "caml-types" + "Explore type annotations by mouse dragging." t) + +(autoload 'caml-help "caml-help" + "Show documentation for qualilifed OCaml identifier." t) +(autoload 'caml-complete "caml-help" + "Does completion for documented qualified OCaml identifier." t) +(autoload 'ocaml-open-module "caml-help" + "Add module in documentation search path." t) +(autoload 'ocaml-close-module "caml-help" + "Remove module from documentation search path." t) +(autoload 'ocaml-add-path "caml-help" + "Add search path for documentation." t) + +;;; caml.el ends here + +(provide 'caml) diff --git a/ocaml-binary-annot/emacs/camldebug.el b/ocaml-binary-annot/emacs/camldebug.el new file mode 100644 index 0000000000..d5ba599cc7 --- /dev/null +++ b/ocaml-binary-annot/emacs/camldebug.el @@ -0,0 +1,793 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Jacques Garrigue and Ian T Zimmerman *) +;(* *) +;(* Copyright 1997 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;;; Run camldebug under Emacs +;;; Derived from gdb.el. +;;; gdb.el is Copyright (C) 1988 Free Software Foundation, Inc, and is part +;;; of GNU Emacs +;;; Modified by Jerome Vouillon, 1994. +;;; Modified by Ian T. Zimmerman, 1996. +;;; Modified by Xavier Leroy, 1997. + +;; 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 1, 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. + +;;itz 04-06-96 I pondered basing this on gud. The potential advantages +;;were: automatic bugfix , keymaps and menus propagation. +;;Disadvantages: gud is not so clean itself, there is little common +;;functionality it abstracts (most of the stuff is done in the +;;debugger specific parts anyway), and, most seriously, gud sees it +;;fit to add C-x C-a bindings to the _global_ map, so there would be a +;;conflict between camldebug and gdb, for instance. While it's OK to +;;assume that a sane person doesn't use gdb and dbx at the same time, +;;it's not so OK (IMHO) for gdb and camldebug. + +;; Xavier Leroy, 21/02/97: adaptation to ocamldebug. + +(require 'comint) +(require 'shell) +(require 'caml) +(require 'derived) +(require 'thingatpt) + +;;; Variables. + +(defvar camldebug-last-frame) +(defvar camldebug-delete-prompt-marker) +(defvar camldebug-filter-accumulator nil) +(defvar camldebug-last-frame-displayed-p) +(defvar camldebug-filter-function) + +(defvar camldebug-prompt-pattern "^(ocd) *" + "A regexp to recognize the prompt for ocamldebug.") + +(defvar camldebug-overlay-event nil + "Overlay for displaying the current event.") +(defvar camldebug-overlay-under nil + "Overlay for displaying the current event.") +(defvar camldebug-event-marker nil + "Marker for displaying the current event.") + +(defvar camldebug-track-frame t + "*If non-nil, always display current frame position in another window.") + +(cond + (window-system + (make-face 'camldebug-event) + (make-face 'camldebug-underline) + (if (not (face-differs-from-default-p 'camldebug-event)) + (invert-face 'camldebug-event)) + (if (not (face-differs-from-default-p 'camldebug-underline)) + (set-face-underline-p 'camldebug-underline t)) + (setq camldebug-overlay-event (make-overlay 1 1)) + (overlay-put camldebug-overlay-event 'face 'camldebug-event) + (setq camldebug-overlay-under (make-overlay 1 1)) + (overlay-put camldebug-overlay-under 'face 'camldebug-underline)) + (t + (setq camldebug-event-marker (make-marker)) + (setq overlay-arrow-string "=>"))) + +;;; Camldebug mode. + +(define-derived-mode camldebug-mode comint-mode "Inferior CDB" + + "Major mode for interacting with an inferior Camldebug process. + +The following commands are available: + +\\{camldebug-mode-map} + +\\[camldebug-display-frame] displays in the other window +the last line referred to in the camldebug buffer. + +\\[camldebug-step], \\[camldebug-back] and \\[camldebug-next], in the camldebug window, +call camldebug to step, backstep or next and then update the other window +with the current file and position. + +If you are in a source file, you may select a point to break +at, by doing \\[camldebug-break]. + +Commands: +Many commands are inherited from comint mode. +Additionally we have: + +\\[camldebug-display-frame] display frames file in other window +\\[camldebug-step] advance one line in program +C-x SPACE sets break point at current line." + + (mapcar 'make-local-variable + '(camldebug-last-frame-displayed-p camldebug-last-frame + camldebug-delete-prompt-marker camldebug-filter-function + camldebug-filter-accumulator paragraph-start)) + (setq + camldebug-last-frame nil + camldebug-delete-prompt-marker (make-marker) + camldebug-filter-accumulator "" + camldebug-filter-function 'camldebug-marker-filter + comint-prompt-regexp camldebug-prompt-pattern + comint-dynamic-complete-functions (cons 'camldebug-complete + comint-dynamic-complete-functions) + paragraph-start comint-prompt-regexp + camldebug-last-frame-displayed-p t) + (make-local-variable 'shell-dirtrackp) + (setq shell-dirtrackp t) + (setq comint-input-sentinel 'shell-directory-tracker)) + +;;; Keymaps. + +(defun camldebug-numeric-arg (arg) + (and arg (prefix-numeric-value arg))) + +(defmacro def-camldebug (name key &optional doc args) + + "Define camldebug-NAME to be a command sending NAME ARGS and bound +to KEY, with optional doc string DOC. Certain %-escapes in ARGS are +interpreted specially if present. These are: + + %m module name of current module. + %d directory of current source file. + %c number of current character position + %e text of the caml variable surrounding point. + + The `current' source file is the file of the current buffer (if +we're in a caml buffer) or the source file current at the last break +or step (if we're in the camldebug buffer), and the `current' module +name is the filename stripped of any *.ml* suffixes (this assumes the +usual correspondence between module and file naming is observed). The +`current' position is that of the current buffer (if we're in a source +file) or the position of the last break or step (if we're in the +camldebug buffer). + +If a numeric is present, it overrides any ARGS flags and its string +representation is simply concatenated with the COMMAND." + + (let* ((fun (intern (format "camldebug-%s" name)))) + (list 'progn + (if doc + (list 'defun fun '(arg) + doc + '(interactive "P") + (list 'camldebug-call name args + '(camldebug-numeric-arg arg)))) + (list 'define-key 'camldebug-mode-map + (concat "\C-c" key) + (list 'quote fun)) + (list 'define-key 'caml-mode-map + (concat "\C-x\C-a" key) + (list 'quote fun))))) + +(def-camldebug "step" "\C-s" "Step one event forward.") +(def-camldebug "backstep" "\C-k" "Step one event backward.") +(def-camldebug "run" "\C-r" "Run the program.") +(def-camldebug "reverse" "\C-v" "Run the program in reverse.") +(def-camldebug "last" "\C-l" "Go to latest time in execution history.") +(def-camldebug "backtrace" "\C-t" "Print the call stack.") +(def-camldebug "finish" "\C-f" "Finish executing current function.") +(def-camldebug "print" "\C-p" "Print value of symbol at point." "%e") +(def-camldebug "display" "\C-d" "Display value of symbol at point." "%e") +(def-camldebug "next" "\C-n" "Step one event forward (skip functions)") +(def-camldebug "up" "<" "Go up N stack frames (numeric arg) with display") +(def-camldebug "down" ">" "Go down N stack frames (numeric arg) with display") +(def-camldebug "break" "\C-b" "Set breakpoint at current line." + "@ \"%m\" # %c") + +(defun camldebug-mouse-display (click) + "Display value of $NNN clicked on." + (interactive "e") + (let* ((start (event-start click)) + (window (car start)) + (pos (car (cdr start))) + symb) + (save-excursion + (select-window window) + (goto-char pos) + (setq symb (thing-at-point 'symbol)) + (if (string-match "^\\$[0-9]+$" symb) + (camldebug-call "display" symb))))) + +(define-key camldebug-mode-map [mouse-2] 'camldebug-mouse-display) + +(defun camldebug-kill-filter (string) + ;gob up stupid questions :-) + (setq camldebug-filter-accumulator + (concat camldebug-filter-accumulator string)) + (if (not (string-match "\\(.* \\)(y or n) " + camldebug-filter-accumulator)) nil + (setq camldebug-kill-output + (cons t (match-string 1 camldebug-filter-accumulator))) + (setq camldebug-filter-accumulator "")) + (if (string-match comint-prompt-regexp camldebug-filter-accumulator) + (let ((output (substring camldebug-filter-accumulator + (match-beginning 0)))) + (setq camldebug-kill-output + (cons nil (substring camldebug-filter-accumulator 0 + (1- (match-beginning 0))))) + (setq camldebug-filter-accumulator "") + output) + "")) + +(def-camldebug "kill" "\C-k") + +(defun camldebug-kill () + "Kill the program." + (interactive) + (let ((camldebug-kill-output)) + (save-excursion + (set-buffer current-camldebug-buffer) + (let ((proc (get-buffer-process (current-buffer))) + (camldebug-filter-function 'camldebug-kill-filter)) + (camldebug-call "kill") + (while (not (and camldebug-kill-output + (zerop (length camldebug-filter-accumulator)))) + (accept-process-output proc)))) + (if (not (car camldebug-kill-output)) + (error (cdr camldebug-kill-output)) + (sit-for 0 300) + (camldebug-call-1 (if (y-or-n-p (cdr camldebug-kill-output)) "y" "n"))))) +;;FIXME: camldebug doesn't output the Hide marker on kill + +(defun camldebug-goto-filter (string) + ;accumulate onto previous output + (setq camldebug-filter-accumulator + (concat camldebug-filter-accumulator string)) + (if (not (or (string-match (concat "\\(\n\\|\\`\\)[ \t]*\\([0-9]+\\)[ \t]+" + camldebug-goto-position + "-[0-9]+[ \t]*\\(before\\).*\n") + camldebug-filter-accumulator) + (string-match (concat "\\(\n\\|\\`\\)[ \t]*\\([0-9]+\\)[ \t]+[0-9]+-" + camldebug-goto-position + "[ \t]*\\(after\\).*\n") + camldebug-filter-accumulator))) + nil + (setq camldebug-goto-output + (match-string 2 camldebug-filter-accumulator)) + (setq camldebug-filter-accumulator + (substring camldebug-filter-accumulator (1- (match-end 0))))) + (if (not (string-match comint-prompt-regexp + camldebug-filter-accumulator)) nil + (setq camldebug-goto-output (or camldebug-goto-output 'fail)) + (setq camldebug-filter-accumulator "")) + (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator) + (setq camldebug-filter-accumulator + (match-string 1 camldebug-filter-accumulator))) + "") + +(def-camldebug "goto" "\C-g") +(defun camldebug-goto (&optional time) + + "Go to the execution time TIME. + +Without TIME, the command behaves as follows: In the camldebug buffer, +if the point at buffer end, goto time 0\; otherwise, try to obtain the +time from context around point. In a caml mode buffer, try to find the +time associated in execution history with the current point location. + +With a negative TIME, move that many lines backward in the camldebug +buffer, then try to obtain the time from context around point." + + (interactive "P") + (cond + (time + (let ((ntime (camldebug-numeric-arg time))) + (if (>= ntime 0) (camldebug-call "goto" nil ntime) + (save-selected-window + (select-window (get-buffer-window current-camldebug-buffer)) + (save-excursion + (if (re-search-backward "^Time : [0-9]+ - pc : [0-9]+ " + nil t (- 1 ntime)) + (camldebug-goto nil) + (error "I don't have %d times in my history" + (- 1 ntime)))))))) + ((eq (current-buffer) current-camldebug-buffer) + (let ((time (cond + ((eobp) 0) + ((save-excursion + (beginning-of-line 1) + (looking-at "^Time : \\([0-9]+\\) - pc : [0-9]+ ")) + (string-to-int (match-string 1))) + ((string-to-int (camldebug-format-command "%e")))))) + (camldebug-call "goto" nil time))) + (t + (let ((module (camldebug-module-name (buffer-file-name))) + (camldebug-goto-position (int-to-string (1- (point)))) + (camldebug-goto-output) (address)) + ;get a list of all events in the current module + (save-excursion + (set-buffer current-camldebug-buffer) + (let* ((proc (get-buffer-process (current-buffer))) + (camldebug-filter-function 'camldebug-goto-filter)) + (camldebug-call-1 (concat "info events " module)) + (while (not (and camldebug-goto-output + (zerop (length camldebug-filter-accumulator)))) + (accept-process-output proc)) + (setq address (if (eq camldebug-goto-output 'fail) nil + (re-search-backward + (concat "^Time : \\([0-9]+\\) - pc : " + camldebug-goto-output + " - module " + module "$") nil t) + (match-string 1))))) + (if address (camldebug-call "goto" nil (string-to-int address)) + (error "No time at %s at %s" module camldebug-goto-position)))))) + + +(defun camldebug-delete-filter (string) + (setq camldebug-filter-accumulator + (concat camldebug-filter-accumulator string)) + (if (not (string-match + (concat "\\(\n\\|\\`\\)[ \t]*\\([0-9]+\\)[ \t]+[0-9]+[ \t]*in " + (regexp-quote camldebug-delete-file) + ", character " + camldebug-delete-position "\n") + camldebug-filter-accumulator)) nil + (setq camldebug-delete-output + (match-string 2 camldebug-filter-accumulator)) + (setq camldebug-filter-accumulator + (substring camldebug-filter-accumulator (1- (match-end 0))))) + (if (not (string-match comint-prompt-regexp + camldebug-filter-accumulator)) nil + (setq camldebug-delete-output (or camldebug-delete-output 'fail)) + (setq camldebug-filter-accumulator "")) + (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator) + (setq camldebug-filter-accumulator + (match-string 1 camldebug-filter-accumulator))) + "") + + +(def-camldebug "delete" "\C-d") + +(defun camldebug-delete (&optional arg) + "Delete the breakpoint numbered ARG. + +Without ARG, the command behaves as follows: In the camldebug buffer, +try to obtain the time from context around point. In a caml mode +buffer, try to find the breakpoint associated with the current point +location. + +With a negative ARG, look for the -ARGth breakpoint pattern in the +camldebug buffer, then try to obtain the breakpoint info from context +around point." + + (interactive "P") + (cond + (arg + (let ((narg (camldebug-numeric-arg arg))) + (if (> narg 0) (camldebug-call "delete" nil narg) + (save-excursion + (set-buffer current-camldebug-buffer) + (if (re-search-backward "^Breakpoint [0-9]+ at [0-9]+ : file " + nil t (- 1 narg)) + (camldebug-delete nil) + (error "I don't have %d breakpoints in my history" + (- 1 narg))))))) + ((eq (current-buffer) current-camldebug-buffer) + (let* ((bpline "^Breakpoint \\([0-9]+\\) at [0-9]+ : file ") + (arg (cond + ((eobp) + (save-excursion (re-search-backward bpline nil t)) + (string-to-int (match-string 1))) + ((save-excursion + (beginning-of-line 1) + (looking-at bpline)) + (string-to-int (match-string 1))) + ((string-to-int (camldebug-format-command "%e")))))) + (camldebug-call "delete" nil arg))) + (t + (let ((camldebug-delete-file + (concat (camldebug-format-command "%m") ".ml")) + (camldebug-delete-position (camldebug-format-command "%c"))) + (save-excursion + (set-buffer current-camldebug-buffer) + (let ((proc (get-buffer-process (current-buffer))) + (camldebug-filter-function 'camldebug-delete-filter) + (camldebug-delete-output)) + (camldebug-call-1 "info break") + (while (not (and camldebug-delete-output + (zerop (length + camldebug-filter-accumulator)))) + (accept-process-output proc)) + (if (eq camldebug-delete-output 'fail) + (error "No breakpoint in %s at %s" + camldebug-delete-file + camldebug-delete-position) + (camldebug-call "delete" nil + (string-to-int camldebug-delete-output))))))))) + +(defun camldebug-complete-filter (string) + (setq camldebug-filter-accumulator + (concat camldebug-filter-accumulator string)) + (while (string-match "\\(\n\\|\\`\\)\\(.+\\)\n" + camldebug-filter-accumulator) + (setq camldebug-complete-list + (cons (match-string 2 camldebug-filter-accumulator) + camldebug-complete-list)) + (setq camldebug-filter-accumulator + (substring camldebug-filter-accumulator + (1- (match-end 0))))) + (if (not (string-match comint-prompt-regexp + camldebug-filter-accumulator)) nil + (setq camldebug-complete-list + (or camldebug-complete-list 'fail)) + (setq camldebug-filter-accumulator "")) + (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator) + (setq camldebug-filter-accumulator + (match-string 1 camldebug-filter-accumulator))) + "") + +(defun camldebug-complete () + + "Perform completion on the camldebug command preceding point." + + (interactive) + (let* ((end (point)) + (command (save-excursion + (beginning-of-line) + (and (looking-at comint-prompt-regexp) + (goto-char (match-end 0))) + (buffer-substring (point) end))) + (camldebug-complete-list nil) (command-word)) + + ;; Find the word break. This match will always succeed. + (string-match "\\(\\`\\| \\)\\([^ ]*\\)\\'" command) + (setq command-word (match-string 2 command)) + + ;itz 04-21-96 if we are trying to complete a word of nonzero + ;length, chop off the last character. This is a nasty hack, but it + ;works - in general, not just for this set of words: the comint + ;call below will weed out false matches - and it avoids further + ;mucking with camldebug's lexer. + (if (> (length command-word) 0) + (setq command (substring command 0 (1- (length command))))) + + (let ((camldebug-filter-function 'camldebug-complete-filter)) + (camldebug-call-1 (concat "complete " command)) + (set-marker camldebug-delete-prompt-marker nil) + (while (not (and camldebug-complete-list + (zerop (length camldebug-filter-accumulator)))) + (accept-process-output (get-buffer-process + (current-buffer))))) + (if (eq camldebug-complete-list 'fail) + (setq camldebug-complete-list nil)) + (setq camldebug-complete-list + (sort camldebug-complete-list 'string-lessp)) + (comint-dynamic-simple-complete command-word camldebug-complete-list))) + +(define-key camldebug-mode-map "\C-l" 'camldebug-refresh) +(define-key camldebug-mode-map "\t" 'comint-dynamic-complete) +(define-key camldebug-mode-map "\M-?" 'comint-dynamic-list-completions) + +(define-key caml-mode-map "\C-x " 'camldebug-break) + + +(defvar current-camldebug-buffer nil) + + +;;;###autoload +(defvar camldebug-command-name "ocamldebug" + "*Pathname for executing camldebug.") + +;;;###autoload +(defun camldebug (path) + "Run camldebug on program FILE in buffer *camldebug-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for camldebug. If you wish to change this, use +the camldebug commands `cd DIR' and `directory'." + (interactive "fRun ocamldebug on file: ") + (setq path (expand-file-name path)) + (let ((file (file-name-nondirectory path))) + (pop-to-buffer (concat "*camldebug-" file "*")) + (setq default-directory (file-name-directory path)) + (message "Current directory is %s" default-directory) + (make-comint (concat "camldebug-" file) + (substitute-in-file-name camldebug-command-name) + nil + "-emacs" "-cd" default-directory file) + (set-process-filter (get-buffer-process (current-buffer)) + 'camldebug-filter) + (set-process-sentinel (get-buffer-process (current-buffer)) + 'camldebug-sentinel) + (camldebug-mode) + (camldebug-set-buffer))) + +(defun camldebug-set-buffer () + (if (eq major-mode 'camldebug-mode) + (setq current-camldebug-buffer (current-buffer)) + (save-selected-window (pop-to-buffer current-camldebug-buffer)))) + +;;; Filter and sentinel. + +(defun camldebug-marker-filter (string) + (setq camldebug-filter-accumulator + (concat camldebug-filter-accumulator string)) + (let ((output "") (begin)) + ;; Process all the complete markers in this chunk. + (while (setq begin + (string-match + "\032\032\\(H\\|M\\(.+\\):\\(.+\\):\\(.+\\):\\(before\\|after\\)\\)\n" + camldebug-filter-accumulator)) + (setq camldebug-last-frame + (if (char-equal ?H (aref camldebug-filter-accumulator + (1+ (1+ begin)))) nil + (let ((isbefore + (string= "before" + (match-string 5 camldebug-filter-accumulator))) + (startpos (string-to-int + (match-string 3 camldebug-filter-accumulator))) + (endpos (string-to-int + (match-string 4 camldebug-filter-accumulator)))) + (list (match-string 2 camldebug-filter-accumulator) + (if isbefore startpos endpos) + isbefore + startpos + endpos + ))) + output (concat output + (substring camldebug-filter-accumulator + 0 begin)) + ;; Set the accumulator to the remaining text. + camldebug-filter-accumulator (substring + camldebug-filter-accumulator + (match-end 0)) + camldebug-last-frame-displayed-p nil)) + + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; camldebug-filter-accumulator until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + (if (string-match "\032.*\\'" camldebug-filter-accumulator) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring camldebug-filter-accumulator + 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq camldebug-filter-accumulator + (substring camldebug-filter-accumulator (match-beginning 0)))) + + (setq output (concat output camldebug-filter-accumulator) + camldebug-filter-accumulator "")) + + output)) + +(defun camldebug-filter (proc string) + (let ((output)) + (if (buffer-name (process-buffer proc)) + (let ((process-window)) + ;; it does not seem necessary to save excursion here, + ;; since set-buffer as a temporary effect. + ;; comint-output-filter explicitly avoids it. + ;; in version 23, it prevents the marker to stay at end of buffer + ;; (save-excursion + (set-buffer (process-buffer proc)) + ;; If we have been so requested, delete the debugger prompt. + (if (marker-buffer camldebug-delete-prompt-marker) + (progn + (delete-region (process-mark proc) + camldebug-delete-prompt-marker) + (set-marker camldebug-delete-prompt-marker nil))) + (setq output (funcall camldebug-filter-function string)) + ;; Don't display the specified file unless + ;; (1) point is at or after the position where output appears + ;; and (2) this buffer is on the screen. + (setq process-window (and camldebug-track-frame + (not camldebug-last-frame-displayed-p) + (>= (point) (process-mark proc)) + (get-buffer-window (current-buffer)))) + ;; Insert the text, moving the process-marker. + (comint-output-filter proc output) + ;; ) + ;; this was the end of save-excursion. + ;; if save-excursion is used (comint-next-prompt 1) would be needed + ;; to move the mark past then next prompt, but this is not as good + ;; as solution. + (if process-window + (save-selected-window + (select-window process-window) + (camldebug-display-frame))))))) + +(defun camldebug-sentinel (proc msg) + (cond ((null (buffer-name (process-buffer proc))) + ;; buffer killed + ;; Stop displaying an arrow in a source file. + (camldebug-remove-current-event) + (set-process-buffer proc nil)) + ((memq (process-status proc) '(signal exit)) + ;; Stop displaying an arrow in a source file. + (camldebug-remove-current-event) + ;; Fix the mode line. + (setq mode-line-process + (concat ": " + (symbol-name (process-status proc)))) + (let* ((obuf (current-buffer))) + ;; save-excursion isn't the right thing if + ;; process-buffer is current-buffer + (unwind-protect + (progn + ;; Write something in *compilation* and hack its mode line, + (set-buffer (process-buffer proc)) + ;; Force mode line redisplay soon + (set-buffer-modified-p (buffer-modified-p)) + (if (eobp) + (insert ?\n mode-name " " msg) + (save-excursion + (goto-char (point-max)) + (insert ?\n mode-name " " msg))) + ;; If buffer and mode line will show that the process + ;; is dead, we can delete it now. Otherwise it + ;; will stay around until M-x list-processes. + (delete-process proc)) + ;; Restore old buffer, but don't restore old point + ;; if obuf is the cdb buffer. + (set-buffer obuf)))))) + + +(defun camldebug-refresh (&optional arg) + "Fix up a possibly garbled display, and redraw the mark." + (interactive "P") + (camldebug-display-frame) + (recenter arg)) + +(defun camldebug-display-frame () + "Find, obey and delete the last filename-and-line marker from CDB. +The marker looks like \\032\\032Mfilename:startchar:endchar:beforeflag\\n. +Obeying it means displaying in another window the specified file and line." + (interactive) + (camldebug-set-buffer) + (if (not camldebug-last-frame) + (camldebug-remove-current-event) + (camldebug-display-line (nth 0 camldebug-last-frame) + (nth 3 camldebug-last-frame) + (nth 4 camldebug-last-frame) + (nth 2 camldebug-last-frame))) + (setq camldebug-last-frame-displayed-p t)) + +;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen +;; and that its character CHARACTER is visible. +;; Put the mark on this character in that buffer. + +(defun camldebug-display-line (true-file schar echar kind) + (let* ((pre-display-buffer-function nil) ; screw it, put it all in one screen + (pop-up-windows t) + (buffer (find-file-noselect true-file)) + (window (display-buffer buffer t)) + (spos) (epos) (pos)) + (save-excursion + (set-buffer buffer) + (save-restriction + (widen) + (setq spos (+ (point-min) schar)) + (setq epos (+ (point-min) echar)) + (setq pos (if kind spos epos)) + (camldebug-set-current-event spos epos (current-buffer) kind)) + (cond ((or (< pos (point-min)) (> pos (point-max))) + (widen) + (goto-char pos)))) + (set-window-point window pos))) + +;;; Events. + +(defun camldebug-remove-current-event () + (if window-system + (progn + (delete-overlay camldebug-overlay-event) + (delete-overlay camldebug-overlay-under)) + (setq overlay-arrow-position nil))) + +(defun camldebug-set-current-event (spos epos buffer before) + (if window-system + (if before + (progn + (move-overlay camldebug-overlay-event spos (1+ spos) buffer) + (move-overlay camldebug-overlay-under + (+ spos 1) epos buffer)) + (move-overlay camldebug-overlay-event (1- epos) epos buffer) + (move-overlay camldebug-overlay-under spos (- epos 1) buffer)) + (save-excursion + (set-buffer buffer) + (goto-char pos) + (beginning-of-line) + (move-marker camldebug-event-marker (point)) + (setq overlay-arrow-position camldebug-event-marker)))) + +;;; Miscellaneous. + +(defun camldebug-module-name (filename) + (substring filename (string-match "\\([^/]*\\)\\.ml$" filename) (match-end 1))) + +;;; The camldebug-call function must do the right thing whether its +;;; invoking keystroke is from the camldebug buffer itself (via +;;; major-mode binding) or a caml buffer. In the former case, we want +;;; to supply data from camldebug-last-frame. Here's how we do it: + +(defun camldebug-format-command (str) + (let* ((insource (not (eq (current-buffer) current-camldebug-buffer))) + (frame (if insource nil camldebug-last-frame)) (result)) + (while (and str (string-match "\\([^%]*\\)%\\([mdcep]\\)" str)) + (let ((key (string-to-char (substring str (match-beginning 2)))) + (cmd (substring str (match-beginning 1) (match-end 1))) + (subst)) + (setq str (substring str (match-end 2))) + (cond + ((eq key ?m) + (setq subst (camldebug-module-name + (if insource (buffer-file-name) (nth 0 frame))))) + ((eq key ?d) + (setq subst (file-name-directory + (if insource (buffer-file-name) (nth 0 frame))))) + ((eq key ?c) + (setq subst (int-to-string + (if insource (1- (point)) (nth 1 frame))))) + ((eq key ?e) + (setq subst (thing-at-point 'symbol)))) + (setq result (concat result cmd subst)))) + ;; There might be text left in STR when the loop ends. + (concat result str))) + +(defun camldebug-call (command &optional fmt arg) + "Invoke camldebug COMMAND displaying source in other window. + +Certain %-escapes in FMT are interpreted specially if present. +These are: + + %m module name of current module. + %d directory of current source file. + %c number of current character position + %e text of the caml variable surrounding point. + + The `current' source file is the file of the current buffer (if +we're in a caml buffer) or the source file current at the last break +or step (if we're in the camldebug buffer), and the `current' module +name is the filename stripped of any *.ml* suffixes (this assumes the +usual correspondence between module and file naming is observed). The +`current' position is that of the current buffer (if we're in a source +file) or the position of the last break or step (if we're in the +camldebug buffer). + +If ARG is present, it overrides any FMT flags and its string +representation is simply concatenated with the COMMAND." + + ;; Make sure debugger buffer is displayed in a window. + (camldebug-set-buffer) + (message "Command: %s" (camldebug-call-1 command fmt arg))) + +(defun camldebug-call-1 (command &optional fmt arg) + + ;; Record info on the last prompt in the buffer and its position. + (save-excursion + (set-buffer current-camldebug-buffer) + (goto-char (process-mark (get-buffer-process current-camldebug-buffer))) + (let ((pt (point))) + (beginning-of-line) + (if (looking-at comint-prompt-regexp) + (set-marker camldebug-delete-prompt-marker (point))))) + (let ((cmd (cond + (arg (concat command " " (int-to-string arg))) + (fmt (camldebug-format-command + (concat command " " fmt))) + (command)))) + (process-send-string (get-buffer-process current-camldebug-buffer) + (concat cmd "\n")) + cmd)) + + +(provide 'camldebug) diff --git a/ocaml-binary-annot/emacs/inf-caml.el b/ocaml-binary-annot/emacs/inf-caml.el new file mode 100644 index 0000000000..ba2eb0390b --- /dev/null +++ b/ocaml-binary-annot/emacs/inf-caml.el @@ -0,0 +1,363 @@ +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Xavier Leroy and Jacques Garrigue *) +;(* *) +;(* Copyright 1997 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;;; inf-caml.el --- run the Caml toplevel in an Emacs buffer + +;; Xavier Leroy, july 1993. + +;; modified by Jacques Garrigue, july 1997. + +(require 'comint) +(require 'caml) + +;; User modifiable variables + +;; Whether you want the output buffer to be diplayed when you send a phrase + +(defvar caml-display-when-eval t + "*If true, display the inferior caml buffer when evaluating expressions.") + + +;; End of User modifiable variables + + +(defvar inferior-caml-mode-map nil) +(if inferior-caml-mode-map nil + (setq inferior-caml-mode-map + (copy-keymap comint-mode-map))) + +;; Augment Caml mode, so you can process Caml code in the source files. + +(defvar inferior-caml-program "ocaml" + "*Program name for invoking an inferior Caml from Emacs.") + +(defun inferior-caml-mode () + "Major mode for interacting with an inferior Caml process. +Runs a Caml toplevel as a subprocess of Emacs, with I/O through an +Emacs buffer. A history of input phrases is maintained. Phrases can +be sent from another buffer in Caml mode. + +\\{inferior-caml-mode-map}" + (interactive) + (comint-mode) + (setq comint-prompt-regexp "^# ?") + (setq major-mode 'inferior-caml-mode) + (setq mode-name "Inferior Caml") + (make-local-variable 'paragraph-start) + (setq paragraph-start (concat "^$\\|" page-delimiter)) + (make-local-variable 'paragraph-separate) + (setq paragraph-separate paragraph-start) + (make-local-variable 'paragraph-ignore-fill-prefix) + (setq paragraph-ignore-fill-prefix t) + (make-local-variable 'require-final-newline) + (setq require-final-newline t) + (make-local-variable 'comment-start) + (setq comment-start "(*") + (make-local-variable 'comment-end) + (setq comment-end "*)") + (make-local-variable 'comment-column) + (setq comment-column 40) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "(\\*+ *") + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments nil) + (use-local-map inferior-caml-mode-map) + (run-hooks 'inferior-caml-mode-hooks)) + + +(defconst inferior-caml-buffer-subname "inferior-caml") +(defconst inferior-caml-buffer-name + (concat "*" inferior-caml-buffer-subname "*")) + +;; for compatibility with xemacs + +(defun caml-sit-for (second &optional mili redisplay) + (if (and (boundp 'running-xemacs) running-xemacs) + (sit-for (if mili (+ second (* mili 0.001)) second) redisplay) + (sit-for second mili redisplay))) + +;; To show result of evaluation at toplevel + +(defvar inferior-caml-output nil) +(defun inferior-caml-signal-output (s) + (if (string-match "[^ ]" s) (setq inferior-caml-output t))) + +(defun inferior-caml-mode-output-hook () + (set-variable 'comint-output-filter-functions + (list (function inferior-caml-signal-output)) + t)) +(add-hook 'inferior-caml-mode-hooks 'inferior-caml-mode-output-hook) + +;; To launch ocaml whenever needed + +(defun caml-run-process-if-needed (&optional cmd) + (if (comint-check-proc inferior-caml-buffer-name) nil + (if (not cmd) + (if (comint-check-proc inferior-caml-buffer-name) + (setq cmd inferior-caml-program) + (setq cmd (read-from-minibuffer "Caml toplevel to run: " + inferior-caml-program)))) + (setq inferior-caml-program cmd) + (let ((cmdlist (inferior-caml-args-to-list cmd)) + (process-connection-type nil)) + (set-buffer (apply (function make-comint) + inferior-caml-buffer-subname + (car cmdlist) nil (cdr cmdlist))) + (inferior-caml-mode) + (display-buffer inferior-caml-buffer-name) + t) + (setq caml-shell-active t) + )) + +;; patched to from original run-caml sharing code with +;; caml-run-process-when-needed + +(defun run-caml (&optional cmd) + "Run an inferior Caml process. +Input and output via buffer `*inferior-caml*'." + (interactive + (list (if (not (comint-check-proc inferior-caml-buffer-name)) + (read-from-minibuffer "Caml toplevel to run: " + inferior-caml-program)))) + (caml-run-process-if-needed cmd) + (switch-to-buffer-other-window inferior-caml-buffer-name)) + + +(defun inferior-caml-args-to-list (string) + (let ((where (string-match "[ \t]" string))) + (cond ((null where) (list string)) + ((not (= where 0)) + (cons (substring string 0 where) + (inferior-caml-args-to-list (substring string (+ 1 where) + (length string))))) + (t (let ((pos (string-match "[^ \t]" string))) + (if (null pos) + nil + (inferior-caml-args-to-list (substring string pos + (length string))))))))) + +(defun inferior-caml-show-subshell () + (interactive) + (caml-run-process-if-needed) + (display-buffer inferior-caml-buffer-name) + ; Added by Didier to move the point of inferior-caml to end of buffer + (let ((buf (current-buffer)) + (caml-buf (get-buffer inferior-caml-buffer-name)) + (count 0)) + (while + (and (< count 10) + (not (equal (buffer-name (current-buffer)) + inferior-caml-buffer-name))) + (next-multiframe-window) + (setq count (+ count 1))) + (if (equal (buffer-name (current-buffer)) + inferior-caml-buffer-name) + (end-of-buffer)) + (while + (> count 0) + (previous-multiframe-window) + (setq count (- count 1))) + ) +) + +;; patched by Didier to move cursor after evaluation + +(defun inferior-caml-eval-region (start end) + "Send the current region to the inferior Caml process." + (interactive "r") + (save-excursion (caml-run-process-if-needed)) + (save-excursion + (goto-char end) + (caml-skip-comments-backward) + (comint-send-region inferior-caml-buffer-name start (point)) + ;; normally, ";;" are part of the region + (if (and (>= (point) 2) + (prog2 (backward-char 2) (looking-at ";;"))) + (comint-send-string inferior-caml-buffer-name "\n") + (comint-send-string inferior-caml-buffer-name ";;\n")) + ;; the user may not want to see the output buffer + (if caml-display-when-eval + (display-buffer inferior-caml-buffer-name t)))) + +;; jump to errors produced by ocaml compiler + +(defun inferior-caml-goto-error (start end) + "Jump to the location of the last error as indicated by inferior toplevel." + (interactive "r") + (let ((loc (+ start + (save-excursion + (set-buffer (get-buffer inferior-caml-buffer-name)) + (re-search-backward + (concat comint-prompt-regexp + "[ \t]*Characters[ \t]+\\([0-9]+\\)-[0-9]+:$")) + (string-to-int (match-string 1)))))) + (goto-char loc))) + + +;;; orgininal inf-caml.el ended here + +;; as eval-phrase, but ignores errors. + +(defun inferior-caml-just-eval-phrase (arg &optional min max) + "Send the phrase containing the point to the CAML process. +With prefix-arg send as many phrases as its numeric value, +ignoring possible errors during evaluation. + +Optional arguments min max defines a region within which the phrase +should lies." + (interactive "p") + (let ((beg)) + (while (> arg 0) + (setq arg (- arg 1)) + (setq beg (caml-find-phrase min max)) + (caml-eval-region beg (point))) + beg)) + +(defvar caml-previous-output nil + "tells the beginning of output in the shell-output buffer, so that the +output can be retreived later, asynchronously.") + +;; enriched version of eval-phrase, to repport errors. + +(defun inferior-caml-eval-phrase (arg &optional min max) + "Send the phrase containing the point to the CAML process. +With prefix-arg send as many phrases as its numeric value, +If an error occurs during evalutaion, stop at this phrase and +repport the error. + +Return nil if noerror and position of error if any. + +If arg's numeric value is zero or negative, evaluate the current phrase +or as many as prefix arg, ignoring evaluation errors. +This allows to jump other erroneous phrases. + +Optional arguments min max defines a region within which the phrase +should lies." + (interactive "p") + (if (save-excursion (caml-run-process-if-needed)) + (progn + (setq inferior-caml-output nil) + (caml-wait-output 10 1))) + (if (< arg 1) (inferior-caml-just-eval-phrase (max 1 (- 0 arg)) min max) + (let ((proc (get-buffer-process inferior-caml-buffer-name)) + (buf (current-buffer)) + previous-output orig beg end err) + (save-window-excursion + (while (and (> arg 0) (not err)) + (setq previous-output (marker-position (process-mark proc))) + (setq caml-previous-output previous-output) + (setq inferior-caml-output nil) + (setq orig (inferior-caml-just-eval-phrase 1 min max)) + (caml-wait-output) + (switch-to-buffer inferior-caml-buffer-name nil) + (goto-char previous-output) + (cond ((re-search-forward + " *Characters \\([01-9][01-9]*\\)-\\([1-9][01-9]*\\):\n[^W]" + (point-max) t) + (setq beg (string-to-int (caml-match-string 1))) + (setq end (string-to-int (caml-match-string 2))) + (switch-to-buffer buf) + (goto-char orig) + (forward-byte end) + (setq end (point)) + (goto-char orig) + (forward-byte beg) + (setq beg (point)) + (setq err beg) + ) + ((looking-at + "Toplevel input:\n[>]\\([^\n]*\\)\n[>]\\(\\( *\\)^*\\)\n") + (let ((expr (caml-match-string 1)) + (column (- (match-end 3) (match-beginning 3))) + (width (- (match-end 2) (match-end 3)))) + (if (string-match "^\\(.*\\)[<]EOF[>]$" expr) + (setq expr (substring expr (match-beginning 1) (match-end 1)))) + (switch-to-buffer buf) + (re-search-backward + (concat "^" (regexp-quote expr) "$") + (- orig 10)) + (goto-char (+ (match-beginning 0) column)) + (setq end (+ (point) width))) + (setq err beg)) + ((looking-at + "Toplevel input:\n>[.]*\\([^.].*\n\\)\\([>].*\n\\)*[>]\\(.*[^.]\\)[.]*\n") + (let* ((e1 (caml-match-string 1)) + (e2 (caml-match-string 3)) + (expr + (concat + (regexp-quote e1) "\\(.*\n\\)*" (regexp-quote e2)))) + (switch-to-buffer buf) + (re-search-backward expr orig 'move) + (setq end (match-end 0))) + (setq err beg)) + (t + (switch-to-buffer buf))) + (setq arg (- arg 1)) + ) + (pop-to-buffer inferior-caml-buffer-name) + (if err + (goto-char (point-max)) + (goto-char previous-output) + (goto-char (point-max))) + (pop-to-buffer buf)) + (if err (progn (beep) (caml-overlay-region (point) end)) + (if inferior-caml-output + (message "No error") + (message "No output yet...") + )) + err))) + +(defun caml-overlay-region (beg end &optional wait) + (interactive "%r") + (cond ((fboundp 'make-overlay) + (if caml-error-overlay () + (setq caml-error-overlay (make-overlay 1 1)) + (overlay-put caml-error-overlay 'face 'region)) + (unwind-protect + (progn + (move-overlay caml-error-overlay beg end (current-buffer)) + (beep) (if wait (read-event) (caml-sit-for 60))) + (delete-overlay caml-error-overlay))))) + +;; wait some amount for ouput, that is, until inferior-caml-output is set +;; to true. Hence, interleaves sitting for shorts delays and checking the +;; flag. Give up after some time. Typing into the source buffer will cancel +;; waiting, i.e. may report 'No result yet' + +(defun caml-wait-output (&optional before after) + (let ((c 1)) + (caml-sit-for 0 (or before 1)) + (let ((c 1)) + (while (and (not inferior-caml-output) (< c 99) (caml-sit-for 0 c t)) + (setq c (+ c 1)))) + (caml-sit-for (or after 0) 1))) + +;; To insert the last output from caml at point +(defun caml-insert-last-output () + "Insert the result of the evaluation of previous phrase" + (interactive) + (let ((pos (process-mark (get-buffer-process inferior-caml-buffer-name)))) + (insert-buffer-substring inferior-caml-buffer-name + caml-previous-output (- pos 2)))) + +;; additional bindings + +;(let ((map (lookup-key caml-mode-map [menu-bar caml]))) +; (define-key map [indent-buffer] '("Indent buffer" . caml-indent-buffer)) +; (define-key map [eval-buffer] '("Eval buffer" . caml-eval-buffer)) +;) +;(define-key caml-mode-map "\C-c\C-b" 'caml-eval-buffer) + + +(provide 'inf-caml) diff --git a/ocaml-binary-annot/emacs/ocamltags.in b/ocaml-binary-annot/emacs/ocamltags.in new file mode 100644 index 0000000000..aa3f8df1d2 --- /dev/null +++ b/ocaml-binary-annot/emacs/ocamltags.in @@ -0,0 +1,142 @@ +":" ; @EMACS@ -batch -l $0 "$@" ; status=$? ; : '--*-Emacs-Lisp-*--' <<';' + +;(***********************************************************************) +;(* *) +;(* Objective Caml *) +;(* *) +;(* Jacques Garrigue and Ian T Zimmerman *) +;(* *) +;(* Copyright 1998 Institut National de Recherche en Informatique et *) +;(* en Automatique. All rights reserved. This file is distributed *) +;(* under the terms of the GNU General Public License. *) +;(* *) +;(***********************************************************************) + +;(* $Id$ *) + +;; Copyright (C) 1998 Ian Zimmerman <itz@transbay.net> +;; 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. +;; $Id$ + +(require 'caml) + +;;itz Fri Oct 30 13:08:37 PST 1998 support for creating TAGS files +;; itz Sun Dec 27 10:26:08 PST 1998 adapted very slightly from +;; Jacques' caml-create-index-function +(defun caml-tags-create-index-function () + (let (all-alist index) + (goto-char (point-max)) + ;; collect definitions + (while (caml-prev-index-position-function) + (if (looking-at "[ \t]*val") nil + (setq index (cons (caml-match-string 5) (point))) + (setq all-alist (cons index all-alist)))) + all-alist)) + +(defun caml-tags-file (filename) + (let* ((output-buffer (current-buffer)) + (basename (file-name-nondirectory filename)) + (backpatch (prog2 + (insert "\n" basename) + (point)))) + (find-file-read-only filename) + (caml-mode) + (let ((all-alist (caml-tags-create-index-function)) + (done nil) + (current-line 1) + (last-point (point-min))) + (mapcar + (lambda (pair) + (let ((tag-name (car pair)) (tag-pos (cdr pair))) + (goto-char tag-pos) + (setq current-line + (+ current-line (count-lines last-point (point)))) + (setq last-point (point)) + (end-of-line 1) + (let ((output-line (format "%s%s%d,%d\n" + (buffer-substring last-point (point)) + tag-name current-line tag-pos))) + (save-excursion + (set-buffer output-buffer) + (insert output-line))))) + all-alist)) + (kill-buffer (current-buffer)) + (set-buffer output-buffer) + (let ((index-size (- (point) backpatch))) + (goto-char backpatch) + (insert "," (int-to-string index-size) "\n") + (goto-char (point-max))))) + +(defsubst prefix-p (prefix str) + (and (<= (length prefix) (length str)) + (string= prefix (substring str 0 (length prefix))))) + +(defsubst eat-args (n) + (setq command-line-args-left (nthcdr n command-line-args-left))) + +;; see Emacs source file print.c +(defun print-error-message (data) + (let ((errname (car data)) errmsg is-file-error tail i) + (if (eq errname 'error) + (progn + (setq data (cdr data)) + (if (not (consp data)) (setq data nil)) + (setq errmsg (car data)) + (setq is-file-error nil)) + (setq errmsg (get errname 'error-message)) + (setq is-file-error (memq 'file-error (get errname 'error-conditions)))) + (setq tail (cdr-safe data)) + (if (and is-file-error tail) + (setq errmsg (car tail) tail (cdr tail))) + (if (stringp errmsg) (princ errmsg) + (princ "peculiar error")) + (setq i 0) + (while (consp tail) + (princ (if (eq i 0) ": " ", ")) + (if is-file-error (princ (car tail)) + (prin1 (car tail))) + (setq tail (cdr tail) i (1+ i))) + (princ "\n"))) + + +(setq gc-cons-threshold 1000000) + +(setq output-file "TAGS") +(setq append-flag nil) +(setq status 0) + +(condition-case foobar + (progn + (while (and command-line-args-left + (let ((arg (car command-line-args-left))) + (cond + ((prefix-p arg "-output-file") + (setq output-file (nth 1 command-line-args-left)) + (eat-args 2) t) + ((prefix-p arg "-append") + (setq append-flag t) + (eat-args 1) t) + (t nil))))) + + (find-file output-file) + (if append-flag (goto-char (point-max)) + (erase-buffer)) + (while command-line-args-left + (caml-tags-file (car command-line-args-left)) + (setq command-line-args-left (cdr command-line-args-left))) + (save-buffer 0)) + (error (setq status 1) (print-error-message foobar))) + +(kill-emacs status) + +; + +":" ; exit $status |
