camlspotter avatar camlspotter committed b9247f8

added the original 2.0.4

Comments (0)

Files changed (12)

+		    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) 19yy  <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; see the file COPYING.  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) 19yy 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.
+Tuareg Mode is a thoroughly rewritten derivative of Caml Mode 0.9.x:
+--------------------------------------------------------------------
+
+First version -
+        By Xavier Leroy <Xavier.Leroy@inria.fr>
+        and Jerome Vouillon <Jerome.Vouillon@ens.fr>, 1993.
+Compilation interface -
+        By Ian Zimmerman <itz@rahul.net>, 1996;
+        Copyright (C) 1996 Ian Zimmerman, all rights reserved.
+First Font-Lock and XEmacs support -
+        By Pierre Boulet <Pierre.Boulet@ens-lyon.fr>, 1996.
+First OCaml and OLabl version -
+        By Jacques Garrigue <Jacques.Garrigue@kurims.kyoto-u.ac.jp>, 1996.
+
+New version for Objective Caml
+        Extension to Objective Caml (and Labl) syntax (including literals
+        and preserving compatibility with Camllight syntax) complete
+        rewritting of Zimmerman's mode, especially comment detection
+        and indentation, along with major improvement of
+        indentation capabilities, new Font-Lock and
+        Hilit19, compatibility over Emacs and XEmacs;
+        By Albert Cohen <Albert.Cohen@prism.uvsq.fr>, 1997.
+
+Tuareg Mode history:
+--------------------
+
+1.00  - January 8 1997 -
+        First verion of Tuareg
+        (previously known as Caml-Mode 0.9.2 -> 0.9.8).
+
+1.10  - From March 17 1997 to March 20 1997 -
+ to     First release of Tuareg
+1.12    Speed-up and fixes.
+
+1.20  - From March 23 1997 to July 28 1997 -
+ to     Support for symbol fontifying, adaptation of Font-Lock interface,
+1.27    Rewritting of a new Sym-Lock extension for Font-Lock (more powerful,
+        polyvalent, and fitting dynamic customization). Suggestion and first
+        adaptation by Chrstian Boos <boos@arthur.u-strasbg.fr>.
+	Improved phrase detection. `C-M-h' and `C-c C-e' now detect
+	both beginning and end of phrases ; `;;' is used, if present.
+	Improved `tuareg-interactive' mode. Support for Font-Lock
+	on toplevel inputs. Patchs for many phrase detection bugs.
+	New option for `=' indentation, `match-string' optimized, and
+	indentation of `;' sequences accelerated.
+
+1.30  - April 14 1998 -
+	Major improvement of syntax parsing code (including proper handling
+	of multi-line strings and speed-up). Strong speed-up of parenthesis
+	parsing. A few indentation and phrase-related commands bugs corrected.
+1.31  - June 8 1998 -
+	Lot of bugs corrected, new customization (more flexible and usable,
+        with some examples). Minor Sym-Lock changes, indentation changes in
+        some cases, simplified installation guidelines.
+1.32  - June 26 1998 -
+        Only with XEmacs: Correct string/comment hiliting.
+        A few bugs removed, especially in literal/comment detection.
+        New customization features.
+1.33  - November 24 1998 -
+	New support for OCaml 2.00 syntax (let module X=..., and {r with ...}).
+	Indentation bug corrected for arrays, records and objects.
+1.34  - December 15 1998 -
+	Bugs corrected in OCaml 2.00 syntax, added new indentation options
+	for parentheses and = symbols.
+1.35  - January 13 1999 -
+	Major improvement of interactive mode, thanks to contribution
+	of Michel Quercia. Bug removal in phrase detection and comment
+	indentation (paragraph and lines).
+1.36  - January 22 1999 -
+	Navigation support for OCaml manual, library, and buffer-dependent
+	definitions (adapted from original code by Michel Quercia). New
+	commands, and next-error in toplevel by Claude Marché.
+1.37  - May 18 2000 -
+	Many improvements and extended support for OCaml 3.00 (like label
+	hiliting). Improved FSF Emacs compatibility thanks to Rémi Vanicat.
+	Corrected bugs in string/comment recognition (the last ones?).
+1.38  - September 19 2000 -
+	Standard Customization interface, removal of most non-standard
+	font-lock faces, string/comment hiliting for FSF Emacs
+	eventually matches XEmacs performances; plus a lot of minor fixes.
+
+1.40  - June 26 2002 -
+	Major update: FSF Emacs 21 compatibility (lazy Font-Lock support),
+        new indentation features (e.g., smart comment justification styles),
+        robust hiliting for declarations, many bugs corrected.
+1.41  - December 8 2003 -
+	Indentation and hiliting features, many intermediate versions
+        with minor bug fixes, support for caml-types.
+1.42  - November 5 2004 -
+	MetaOCaml support, many bug fixes, major rewrite of hiliting code,
+        many improvements and bug fixes to the indentation code,
+        refactoring of some deprecated code (by Stefan Monnier).
+1.43  - November 21 2004 -
+	Improved MetaOCaml support, phrase mark/evaluation fixes,
+	many improvements to module indentation and marking, removed
+	aggresive inlining after `=' and fixed related bugs.
+1.44  - December 29 2004 -
+	Major fontification improvements, largely by Stefan Monnier.
+	Many bug fixes related with the improvements in 1.42 and 1.43.
+1.45  - March 28 2005 -
+	New symbol fontification, compatible with FSF Emacs, by
+        Stefan Monnier. Initiation of a migration of the syntax cache to
+        PPSS for comments and string.
+1.46  - May 21 2006 -
+	Integration of more language variants. A future version will
+	modularize this support, to improve flexibility and minimize
+	interference risks. Plus various bug fixes and new features.
+
+Changes made by Sam Steingold
+
+* 2010-02-09
+
+== Many indentation fixes.
+
+== Code cleaned up and updated to the modern Emacs Lisp;
+   compilation warnings eliminated.
+
+* 2010-03-10
+
+== Treat ">>>" just like ">>=" for indentation purposes.
+
+== `Jane style' indentation of `type' statements now requires
+   `tuareg-type-indent'=0.
+
+== `until' & `unless' are only special in ls3, not general ocaml.
+
+== Other indentation fixes.
+
+* 2010-04-20 (1.99.2)
+
+== Many indentation fixes.
+
+== Better regression testing.
+
+== Restore reasonable behavior without Jane custom settings.
+
+* 2010-05-03 (2.0)
+
+== Many indentation fixes.
+
+== Prepare the first official release from Jane Street.
+EMACS = emacs
+NOINIT = -q --no-site-file
+# when testing, we want all settings to be non-0
+TEST_INIT = -eval '(setq tuareg-in-indent 2)'
+BATCH = -batch $(NOINIT) --load tuareg.elc
+RM = rm -rf
+CP = cp -f
+LN = ln
+CMP = cmp
+# CMP = diff -u
+DIFF_W = diff -uw
+DEST = /usr/share/emacs/site-lisp/tuareg
+
+DIST_FILES = COPYING HISTORY README sample.ml
+ELS = append-tuareg.el camldebug.el custom-tuareg.el ocamlspot.el tuareg.el
+ifeq ("`$(EMACS) --version |grep 'GNU Emacs'`", "")
+ELS += sym-lock.el
+else
+DIST_FILES += sym-lock.el
+endif
+ELC = $(ELS:.el=.elc)
+
+INSTALL_RM_R = $(RM)
+INSTALL_MKDIR = mkdir
+INSTALL_CP = $(CP)
+
+all : elc
+
+elc : $(ELC)
+
+%.elc : %.el
+	$(EMACS) -batch $(NOINIT) -f batch-byte-compile $<
+
+camldebug.elc : camldebug.el tuareg.elc
+
+VERSION_FILE = version
+
+ifneq ($(realpath .hg),)
+POST_INSTALL_HOOK = $(RM) $(VERSION_FILE)
+MAKE_VERSION_FILE = hg id -i | fgrep -v '+' >/dev/null || \
+	(echo 'uncommitted changes' >&2; exit 1); \
+	hg id -i --debug > $(VERSION_FILE)
+else
+ifneq ($(realpath .svn),)
+POST_INSTALL_HOOK = $(RM) $(VERSION_FILE)
+MAKE_VERSION_FILE = svn info | grep Revision: | sed 's/Revision: //' > $(VERSION_FILE)
+else
+ifneq ($(realpath .bzr),)
+POST_INSTALL_HOOK = $(RM) $(VERSION_FILE)
+MAKE_VERSION_FILE = bzr log -l -1 | grep revno: > $(VERSION_FILE)
+else
+ifneq ($(realpath $(VERSION_FILE)),)
+POST_INSTALL_HOOK =
+MAKE_VERSION_FILE = @echo "Using \"$(VERSION_FILE)\" in the distribution."
+else
+POST_INSTALL_HOOK =
+MAKE_VERSION_FILE = @(echo "missing \"$(VERSION_FILE)\" in the distribution?" >&2; exit 1)
+endif
+endif
+endif
+endif
+
+$(VERSION_FILE) : force
+	$(MAKE_VERSION_FILE)
+
+install : $(ELC) $(VERSION_FILE)
+	fgrep `cat $(VERSION_FILE)` tuareg.elc >/dev/null 2>&1 || \
+	 ($(RM) tuareg.elc; $(MAKE) tuareg.elc)
+	$(INSTALL_RM_R) ${DEST}
+	$(INSTALL_MKDIR) ${DEST}
+	for f in $(ELS) $(ELC) $(VERSION_FILE); do $(INSTALL_CP) $$f $(DEST)/$$f; done
+	$(POST_INSTALL_HOOK)
+
+# have to indent twice because comments are indented to the _following_ code
+REINDENT = --file test.ml --eval '(with-current-buffer "test.ml" (tuareg-mode) (indent-region (point-min) (point-max)) (indent-region (point-min) (point-max)) (save-buffer))' --kill
+
+MANGLE = sed -e 's/^\(  *[a-z].*[^\"]\)$$/ \1/'
+
+EXTRA_CHECK_COMMANDS =
+
+check : $(ELC) sample.ml
+	@echo ====sample.ml====
+	$(MANGLE) sample.ml > test.ml
+	$(EMACS) $(BATCH) $(TEST_INIT) $(REINDENT)
+	$(CMP) sample.ml test.ml
+	$(EXTRA_CHECK_COMMANDS)
+	$(RM) test.ml test.ml~
+
+DIST_NAME = tuareg-$(shell grep 'Tuareg Version' tuareg.el | sed 's/.*Tuareg Version \([^ ]*\) .*/\1/')
+DIST_FILES += $(ELS) $(VERSION_FILE) Makefile
+$(DIST_NAME).tgz $(DIST_NAME).zip : $(DIST_FILES)
+	$(RM) $(DIST_NAME) $(DIST_NAME).tgz $(DIST_NAME).zip; mkdir $(DIST_NAME)
+	for f in $(DIST_FILES); do $(LN) $$f $(DIST_NAME); done
+	tar cvfz $(DIST_NAME).tgz $(DIST_NAME)
+	zip -9vr $(DIST_NAME).zip $(DIST_NAME)
+	$(RM) $(DIST_NAME)
+	$(POST_INSTALL_HOOK)
+
+distrib : $(DIST_NAME).tgz
+dist: distrib
+
+clean :
+	$(RM) $(ELC) test.ml test.ml~ $(DIST_NAME).tgz $(DIST_NAME).zip
+	$(POST_INSTALL_HOOK)
+
+.PHONY : all elc clean install force check distrib dist
+DESCRIPTION:
+
+This archive contains files to help editing Caml code, to hilight
+important parts of the code, to run a Caml toplevel, and to run the
+Caml debugger within GNU Emacs/XEmacs editors. It is designed for
+Objective Caml but handles Camllight syntax as well.
+
+CONTENTS:
+
+  README             This file.
+  HISTORY            Differences with previous versions.
+  tuareg.el          A major mode for editing Tuareg code in Emacs/XEmacs.
+  sym-lock.el        An extension to XEmacs Font-Lock for symbol fontifying.
+  camldebug.el       To run the Caml debugger under Emacs.
+  append-tuareg.el   Configuration file for quick installation
+  custom-tuareg.el   Tuareg customization example
+  sample.el          Sample file to check the indentation engine.
+
+INSTALL:
+
+  If you have the right to put files in Emacs / XEmacs `site-lisp'
+  directory, you only have to copy the `tuareg.el', `camldebug.el'
+  and `sym-lock.el' files in it (Sym-Lock works with XEmacs only).
+
+  Otherwise, choose a directory, e.g., `foo'. Copy the `tuareg.el'
+  `camldebug.el' and `sym-lock.el' files in it (Sym-Lock works with
+  XEmacs only). Then add the following line to your `.emacs', where
+  `foo' is replaced by the appropriate directory FULL PATH:
+
+  (add-to-list 'load-path "foo")
+
+  You can also do
+
+  $ make install DEST=foo
+
+  which will also byte-compile the files.
+
+QUICK CONFIGURATION:
+
+  If you are no Emacs-Lisp addict, and would like to use Tuareg NOW, append
+  (or copy) `append-tuareg.el' file to your `.emacs' configuration file.
+  It tells Emacs to load Tuareg and Sym-Lock (for XEmacs) automatically.
+
+  Consider updating your `.emacs' configuration file by hand if you
+  keep on using Tuareg.
+
+MANUAL CONFIGURATION:
+
+  Add the following lines to your .emacs file:
+
+  (add-to-list 'auto-mode-alist '("\\.ml[iylp]?" . tuareg-mode))
+  (autoload 'tuareg-mode "tuareg" "Major mode for editing Caml code" t)
+  (autoload 'camldebug "camldebug" "Run the Caml debugger" t)
+
+  The Tuareg major mode is triggered by visiting a file with extension
+  .ml, .mli, .mly, .mll, and .mlp or manually by M-x tuareg-mode. It
+  gives you the correct syntax table for the Caml language.
+
+USAGE:
+
+  Tuareg 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, the program fragment is temporarily hilighted.
+
+  M-x tuareg-run-caml starts a Caml toplevel with input and output in
+  an Emacs buffer named `*caml-toplevel*. 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. A hook named `tuareg-interactive-mode-hook' may be
+  used for customization.
+
+  Typing C-c C-e in a buffer in Caml mode sends the current phrase
+  (containing the point) to the Caml toplevel, and evaluates it.
+  If you type one of these commands before M-x tuareg-run-caml, the
+  toplevel will be started automatically.
+
+  M-x camldebug FILE starts the Caml debugger camldebug on the
+  executable FILE, with input and output in an Emacs buffer named
+  *camldebug-FILE*. It is similar to April 1996 version, with minor
+  changes to support XEmacs, Tuareg and OCaml. Furthermore, package
+  `thingatpt' is not required any more.
+
+CUSTOMIZATION
+
+  The standard Emacs customization tool can be used to configure
+  Tuareg options. It is available from the Options menu and Tuareg's
+  Customize sub-menu.
+
+  You may also customize the appearance of Caml code by twiddling the
+  variables listed at the start of tuareg.el (preferably using
+  `tuareg-mode-hook', you should not patch the file directly).
+  You should then add to your configuration file something like:
+  (add-hook 'tuareg-mode-hook
+    '(lambda () ... ; your customization code ))
+
+  `custom-tuareg.el' is a sample customization file for standard
+  changes. You can append it to your `.emacs' or use it as a tutorial.
+
+FEATURES, KNOWN BUGS:
+
+  Cf. online help.
+
+THANKS:
+
+  Ian Zimmerman for the previous mode, compilation interface and
+  debugger enhancement.
+
+  Jacques Garrigue enhanced Zimmerman's mode along with an adaptation
+  to Objective Caml (and Labl) syntax. Although this work was
+  performed independently, his useful test file and comments were of
+  great help.
+
+  Michel Quercia for excellent suggestions, patches, and helpful
+  emacs-lisp contributions (full, ready-to-work implementations, I
+  should say), especially for Tuareg interactive mode, and browser
+  capacities.
+
+  Denis Barthou, Pierre Boulet, Jean-Christophe Filliatre and Rémi
+  Vanicat for intensive testing, useful suggestions, and help.
+
+  Ralf Treinen for maintaining the Debian GNU/Linux package.
+
+  Every people who sent me bug reports, suggestions, comments and
+  patches. Nothing would have improved since version 0.9.2 without
+  their help. Special thanks to Eli Barzilay, Josh Berdine, Christian
+  Boos, Carsten Clasohm, Yann Coscoy, Prakash Countcham, Alvarado
+  Cuihtlauac, Erwan David, Gilles Défourneaux, Philippe Esperet,
+  Gilles Falcon, Tim Freeman, Alain Frisch, Christian Lindig, Claude
+  Marché, Charles Martin, Dave Mason, Stefan Monnier, Toby Moth,
+  Jean-Yves Moyen, Alex Ott, Christopher Quinn, Ohad Rodeh, Rauli
+  Ruohonen, Hendrik Tews, Christophe Troestler, Joseph Sudish, Mattias
+  Waldau and John Whitley.
+
+  Tuareg mode have been maintained by Albert Cohen until version 1.45.
+
+  Jane Street took over maintenance based on Albert Cohen's version 1.46
+  (later retracted by him), and released its first version as 2.0.
+
+REPORTING:
+
+  The official Tuareg home page is located at:
+  <https://forge.ocamlcore.org/projects/tuareg/>.
+
+  Bug reports & patches to: <tuareg@janestreet.com>
+  or use the tracker: <https://forge.ocamlcore.org/tracker/?group_id=43>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; append-tuareg.el - Tuareg quick installation: Append this file to .emacs.
+
+(add-to-list 'auto-mode-alist '("\\.ml[iylp]?" . tuareg-mode))
+(autoload 'tuareg-mode "tuareg" "Major mode for editing Caml code" t)
+(autoload 'camldebug "camldebug" "Run the Caml debugger" t)
+(dolist (ext '(".cmo" ".cmx" ".cma" ".cmxa" ".cmi"))
+  (add-to-list 'completion-ignored-extensions ext))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; camldebug.el - Run ocamldebug / camldebug under Emacs.
+;; Derived from gdb.el.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;         Copying is covered by the GNU General Public License.
+;;
+;;    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.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;                                 History
+;;
+;;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.
+
+;;Albert Cohen 04-97: Patch for Tuareg support.
+;;Albert Cohen 05-98: A few patches and OCaml customization.
+;;Albert Cohen 09-98: XEmacs support and some improvements.
+;;Erwan Jahier and Albert Cohen 11-05: support for camldebug 3.09.
+
+(require 'comint)
+(require 'shell)
+(require 'tuareg (expand-file-name
+                  "tuareg" (file-name-directory (or load-file-name
+                                                    byte-compile-current-file))))
+(require 'derived)
+
+;;; 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-kill-output)
+(defvar camldebug-current-buffer nil)
+(defvar camldebug-goto-position)
+(defvar camldebug-goto-output)
+(defvar camldebug-delete-file)
+(defvar camldebug-delete-position)
+(defvar camldebug-delete-output)
+(defvar camldebug-complete-list)
+
+(defvar camldebug-prompt-pattern "^(\\(ocd\\|cdb\\)) *"
+  "A regexp to recognize the prompt for camldebug.")
+
+(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
+ ((and (fboundp 'make-overlay) window-system)
+  (make-face 'camldebug-event)
+  (make-face 'camldebug-underline)
+  (unless (face-differs-from-default-p 'camldebug-event)
+    (invert-face 'camldebug-event))
+  (unless (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 "Caml-Debugger"
+
+  "Major mode for interacting with a 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."
+
+  (mapc '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)
+  (add-hook 'comint-input-filter-functions '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 'tuareg-mode-map
+		(concat "\C-x\C-a" key)
+		(list 'quote fun)))))
+
+(def-camldebug "step"	"\C-s"	"Step one source line with display.")
+(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 "open"   "\C-o"  "Open the current module." "%m")
+(def-camldebug "close"  "\C-c"  "Close the current module." "%m")
+(def-camldebug "finish" "\C-f"	"Finish executing current function.")
+(def-camldebug "print"	"\C-p"	"Print value of symbol at point."	"%e")
+(def-camldebug "next"   "\C-n"	"Step one source line (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-kill-filter (string)
+  ;gob up stupid questions :-)
+  (setq camldebug-filter-accumulator
+	(concat camldebug-filter-accumulator string))
+  (when (string-match "\\(.* \\)(y or n) "
+                      camldebug-filter-accumulator)
+    (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))
+    (with-current-buffer camldebug-current-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))
+  (when (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))
+    (setq camldebug-goto-output
+	  (match-string 2 camldebug-filter-accumulator))
+    (setq camldebug-filter-accumulator
+	  (substring camldebug-filter-accumulator (1- (match-end 0)))))
+  (when (string-match comint-prompt-regexp
+                      camldebug-filter-accumulator)
+    (setq camldebug-goto-output (or camldebug-goto-output 'fail))
+    (setq camldebug-filter-accumulator ""))
+  (when (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 camldebug-current-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) camldebug-current-buffer)
+      (let ((time (cond
+		   ((eobp) 0)
+		   ((save-excursion
+		      (beginning-of-line 1)
+		      (looking-at "^Time : \\([0-9]+\\) - pc : [0-9]+ "))
+		    (string-to-number (match-string 1)))
+		   ((string-to-number (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
+      (with-current-buffer camldebug-current-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 (unless (eq camldebug-goto-output 'fail)
+			  (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-number 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))
+  (when (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)
+    (setq camldebug-delete-output
+	  (match-string 2 camldebug-filter-accumulator))
+    (setq camldebug-filter-accumulator
+	  (substring camldebug-filter-accumulator (1- (match-end 0)))))
+  (when (string-match comint-prompt-regexp
+                      camldebug-filter-accumulator)
+    (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)
+	(with-current-buffer camldebug-current-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) camldebug-current-buffer)
+    (let* ((bpline "^Breakpoint \\([0-9]+\\) at [0-9]+ : file ")
+	   (arg (cond
+		 ((eobp)
+		  (save-excursion (re-search-backward bpline nil t))
+		  (string-to-number (match-string 1)))
+		 ((save-excursion
+		    (beginning-of-line 1)
+		    (looking-at bpline))
+		  (string-to-number (match-string 1)))
+		 ((string-to-number (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")))
+      (with-current-buffer camldebug-current-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-number 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)))))
+  (when (string-match comint-prompt-regexp
+                      camldebug-filter-accumulator)
+    (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.
+    (when (> (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)))))
+    (when (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 tuareg-mode-map "\C-x " 'camldebug-break)
+
+
+;;;###autoload
+(defvar camldebug-command-name "ocamldebug"
+  "Pathname for executing Caml debugger.")
+
+;;;###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 camldebug 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)
+    (setq camldebug-command-name
+	  (read-from-minibuffer "Caml debugguer to run: "
+				camldebug-command-name))
+    (make-comint (concat "camldebug-" file)
+		 (substitute-in-file-name camldebug-command-name)
+		 nil
+		 "-emacs" "-cd" default-directory path)
+    (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 camldebug-current-buffer (current-buffer))
+    (save-selected-window (pop-to-buffer camldebug-current-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
+	    (unless (char-equal ?H (aref camldebug-filter-accumulator
+                                         (1+ (1+ begin))))
+              (let ((isbefore
+                     (string= "before"
+                              (match-string 5 camldebug-filter-accumulator)))
+                    (startpos (string-to-number
+                               (match-string 3 camldebug-filter-accumulator)))
+                    (endpos (string-to-number
+                             (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))
+    (when (buffer-name (process-buffer proc))
+      (let ((process-window))
+        (with-current-buffer (process-buffer proc)
+          ;; If we have been so requested, delete the debugger prompt.
+          (when (marker-buffer camldebug-delete-prompt-marker)
+            (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))
+        (when 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 Caml debugger.
+The marker looks like \\032\\032FILENAME:CHARACTER\\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))
+    (with-current-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 pos (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 (and (fboundp 'make-overlay) 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 pos 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))
+    (with-current-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) camldebug-current-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 (save-excursion
+			(skip-chars-backward "_0-9A-Za-z\277-\377")
+			(looking-at "[_0-9A-Za-z\277-\377]*")
+			(match-string 0)))))
+	(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.
+  (with-current-buffer camldebug-current-buffer
+    (goto-char (process-mark (get-buffer-process camldebug-current-buffer)))
+    (let ((pt (point)))
+      (beginning-of-line)
+      (when (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 camldebug-current-buffer)
+			 (concat cmd "\n"))
+    cmd))
+
+
+(provide 'camldebug)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; custom-tuareg.el - Tuareg customization example: Append this file to .emacs.
+
+;; Here is an example of Tuareg variables customization:
+
+(add-hook 'tuareg-mode-hook
+	  '(lambda ()
+	     (setq tuareg-lazy-= t)
+					; indent `=' like a standard keyword
+	     (setq tuareg-lazy-paren t)
+					; indent [({ like standard keywords
+	     (setq tuareg-in-indent 0)
+					; no indentation after `in' keywords
+	     (auto-fill-mode 1)
+					; turn on auto-fill minor mode
+	     (if (featurep 'sym-lock)   ; Sym-Lock customization only
+		 (setq sym-lock-mouse-face-enabled nil))
+					; turn off special face under mouse
+	     ))
+
+;; If you use Sym-Lock, you could also add some customization code after the
+;; `(require 'sym-lock)' in your `.emacs'
+
+(if (featurep 'sym-lock)
+    (setq tuareg-sym-lock-keywords
+	  '(("<-" 0 1 172 nil) ("->" 0 1 174 nil)
+	    ;; (":=" 0 1 220 nil)
+	    ("<=" 0 1 163 nil) (">=" 0 1 179 nil)
+	    ("<>" 0 1 185 nil) ("==" 0 1 186 nil)
+	    ("||" 0 1 218 nil) ("&&" 0 1 217 nil)
+	    ("[^*]\\(\\*\\ nil)\\." 1 8 180 nil)
+	    ("\\(/\\ nil)\\." 1 3 184 nil)
+	    ;; (":>" 0 1 202 nil)
+	    ;; (";;" 0 1 191 nil)
+	    ("\\<_\\>" 0 3 188 nil) ("\\<sqrt\\>" 0 3 214 nil)
+	    ("\\<unit\\>" 0 3 198 nil) ("\\<fun\\>" 0 3 108 nil)
+	    ("\\<or\\>" 0 3 218 nil) ("\\<not\\>" 0 3 216 nil))))
+; (***********************************************************************)
+; (*                                                                     *)
+; (*                            OCamlSpotter                             *)
+; (*                                                                     *)
+; (*                             Jun FURUSE                              *)
+; (*                                                                     *)
+; (*   Copyright 2008, 2009 Jun Furuse. All rights reserved.             *)
+; (*   This file is distributed under the terms of the GNU Library       *)
+; (*   General Public License, with the special exception on linking     *)
+; (*   described in file LICENSE.                                        *)
+; (*                                                                     *)
+; (***********************************************************************)
+
+; How-to-use
+;
+; Write the following to your .emacs
+;
+;; load-path
+; (setq load-path (cons "WHERE-YOU-HAVE-INSTALLED-THE-ELISP" load-path))
+;
+;; set the path of the ocamlspot binary
+;; this can be a shell command, e.g., "ocamlfind ocamlspot"
+; (setq ocamlspot-command "WHERE-YOU-HAVE-INSTALLED-THE-BINARIES/ocamlspot")
+;
+;; autoload
+; (autoload 'ocamlspot-query "ocamlspot" "OCamlSpot")
+;
+;; tuareg mode hook (use caml-mode-hook instead if you use caml-mode)
+;   (add-hook 'tuareg-mode-hook
+;         '(lambda ()
+;            (local-set-key "\C-c;" 'ocamlspot-query)
+;            (local-set-key "\C-c\C-t" 'ocamlspot-type)
+;            (local-set-key "\C-c\C-y" 'ocamlspot-type-and-copy)
+;            (local-set-key "\C-c\C-u" 'ocamlspot-use)
+;            (local-set-key "\C-ct" 'caml-types-show-type)))
+;
+;; You can also change overlay colors as follows:
+; (set-face-background 'ocamlspot-spot-face "#660000")
+; (set-face-background 'ocamlspot-tree-face "#006600")
+;
+; ocamlspot-query
+;   Show the type of the inner-most subexpression under the cursor.
+;   If there is an identifier under the cursor, browse and show its definition
+;
+; ocamlspot-query-interface
+;   Same as ocamlspot-query but browse identifier's interface rather than its definition
+;   This is currently under construction and does not work properly.
+;
+; ocamlspot-type
+;   Show the type of the inner-most subexpression under the cursor.
+;
+; ocamlspot-type-and-copy
+;   Same as ocamlspot-type but it also copies the type expression to the kill buffer.
+;
+; ocamlspot-use
+;   Show the use information of the identifier under the cursor.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Configurable variables
+
+(eval-when-compile (require 'cl)) ; for `destructuring-bind'
+
+(defgroup ocamlspot ()
+  "OCamlSpotter: find the definition and type of variables."
+  :group 'languages)
+
+(defvar ocamlspot-older-version 0
+  "Does `ocamlspot-command' invoke an older version of the ocamlspot executable?
+0: unknown; t: yes; nil: no.")
+
+(defcustom ocamlspot-command "OCAML-SOURCE-TREE/ocamlspot/ocamlspot"
+  "*The command which invokes ocamlspot."
+  :set (lambda (var val)
+         ;; when `ocamlspot-command' is reset,
+         ;; we no longer know what version it invokes
+         (setq ocamlspot-older-version 0)
+         (set-default var val))
+  :type 'string :group 'ocamlspot)
+
+(defcustom ocamlspot-debug nil
+  "*Turn on ocamlspot debug output."
+  :type 'boolean :group 'ocamlspot)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Constants
+
+(defconst ocamlspot-buffer "*ocamlspot*"
+  "The name of ocamlspot communication buffer")
+
+(defconst ocamlspot-debug-buffer "*ocamlspot-debug*"
+  "The name of ocamlspot debugging buffer")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Debugging
+
+(defun ocamlspot-debug-message (s)
+  (with-current-buffer (get-buffer-create ocamlspot-debug-buffer)
+    (insert s)
+    (insert "\n")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; column chars => column bytes
+
+; This looks complicated, but we need this conversion for multi-byte characters
+
+(defun ocamlspot-string-of-line-to-point ()
+  (buffer-substring-no-properties
+   (line-beginning-position) (point)))
+
+(defun ocamlspot-bytes-of-line-to-point ()
+  (length
+   (encode-coding-string
+    (ocamlspot-string-of-line-to-point) buffer-file-coding-system)))
+
+(defun ocamlspot-lines-of-point ()
+  (count-lines (point-min) (point)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; column bytes => column chars
+
+; This looks complicated, but we need this conversion for multi-byte characters
+
+; goto-line set mark and we see the result in the minibuffer
+(defun ocamlspot-goto-line (line)
+  (goto-char (point-min))
+  (forward-line (1- line)))
+
+;; get the string at line
+(defun ocamlspot-buffer-substring-at-line (line)
+  ; no need of save-excursion
+  (ocamlspot-goto-line line)
+  (buffer-substring-no-properties (line-beginning-position)
+                                  (line-end-position)))
+
+(defun ocamlspot-chars-of-bytes-of-string (str bytes)
+  (length
+   (decode-coding-string
+    (substring (encode-coding-string str buffer-file-coding-system)
+               0 bytes)
+    buffer-file-coding-system)))
+
+(defun ocamlspot-pos-of-bytes-at-line (line bytes)
+  ; no need of save-excursion
+  (ocamlspot-goto-line line)
+  (let ((pos-at-beginning-of-line (line-beginning-position))
+        (chars-from-beginning-of-line
+         (ocamlspot-chars-of-bytes-of-string
+          (ocamlspot-buffer-substring-at-line line) bytes)))
+    (+ pos-at-beginning-of-line chars-from-beginning-of-line)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; location parser
+
+; parses lxxxcxxxbxxx and returns the triplet
+(defun ocamlspot-parse-location (s)
+  (if (string-match "^l\\([\-0-9]+\\)c\\([\-0-9]+\\)b\\([\-0-9]+\\)$" s)
+      (let ((line (string-to-number
+                   (substring s (match-beginning 1) (match-end 1))))
+            (colbytes (string-to-number
+                       (substring s (match-beginning 2) (match-end 2))))
+            (bytes (string-to-number
+                       (substring s (match-beginning 3) (match-end 3)))))
+        (list line colbytes bytes))
+    ; older version
+    (if (string-match "^\\([\-0-9]+\\)$" s)
+        (let ((line -1)
+              (colbytes -1)
+              (bytes (string-to-number
+                      (substring s (match-beginning 1) (match-end 1)))))
+          (list line colbytes (+ bytes 1)))
+      nil)))
+
+(defun ocamlspot-pos-of-location (buffer s)
+  (destructuring-bind (line colbytes bytes) (ocamlspot-parse-location s)
+    (if (= line -1) bytes
+      (with-current-buffer buffer
+        (ocamlspot-pos-of-bytes-at-line line colbytes)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Overlays
+
+;; the spot overlay
+(defvar ocamlspot-spot-overlay (make-overlay 1 1))
+(defface ocamlspot-spot-face
+    '((t (:foreground "#88FF44")))
+  "Face for ocamlspot spot highlight"
+  :group 'ocamlspot)
+(overlay-put ocamlspot-spot-overlay 'face 'ocamlspot-spot-face)
+
+;; the tree overlay
+(defvar ocamlspot-tree-overlay (make-overlay 1 1))
+(defface ocamlspot-tree-face
+    '((t (:foreground "#FF88FF")))
+  "Face for ocamlspot tree highlight"
+  :group 'ocamlspot)
+(overlay-put ocamlspot-tree-overlay 'face 'ocamlspot-tree-face)
+
+(defun ocamlspot-delete-overlays-now ()
+  (interactive)
+  (delete-overlay ocamlspot-tree-overlay)
+  (delete-overlay ocamlspot-spot-overlay))
+
+(defun ocamlspot-delete-overlays ()
+  (unwind-protect
+      (sit-for 10)
+    (ocamlspot-delete-overlays-now)))
+
+; obsolete code, but probably useful in future
+; (defun ocamlspot-display-overlay (filename position overlay)
+;   (if (string-match "\.cm[ioxa]$" filename)
+;       ;; It is not an .ml or .mli. Packed module.
+;       (progn
+;         (message "Packed module: %s" filename)
+;         ;; CR jfuruse: opening a binary file is not good
+;         (setq target-buffer (ocamlspot-find-file-existing filename)))
+;     (progn
+;       (setq target-buffer (ocamlspot-find-file-existing filename))
+;       (if (string-match "^\\(l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[\-0-9]+\\):\\(l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[\-0-9]+\\)$" position)
+;           (let ((start (substring position (match-beginning 1) (match-end 1)))
+;                 (end   (substring position (match-beginning 2) (match-end 2))))
+;             (let ((start (ocamlspot-pos-of-location target-buffer start))
+;                   (end   (ocamlspot-pos-of-location target-buffer end)))
+;               ;; display the result
+;               (save-excursion
+;                 (set-buffer target-buffer)
+;                 (goto-char start)
+;                 (move-overlay overlay start end target-buffer))))))))
+
+(defun ocamlspot-display-overlay (buffer position overlay)
+  (if (string-match "^\\(l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[\-0-9]+\\):\\(l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[\-0-9]+\\)$" position)
+      (let ((start (substring position (match-beginning 1) (match-end 1)))
+            (end   (substring position (match-beginning 2) (match-end 2))))
+        (let ((start (ocamlspot-pos-of-location buffer start))
+              (end   (ocamlspot-pos-of-location buffer end)))
+          ;; display the result
+          (set-buffer buffer)
+          (goto-char start)
+          (move-overlay overlay start end buffer)))
+    ; this should be all
+    (display-buffer buffer)
+    (move-overlay overlay (point-min) (point-max) buffer)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Warnings
+
+(defun ocamlspot-warning ()
+  (and (re-search-forward "^\\(Warning: .*\\)$" nil t)
+       (buffer-substring-no-properties (match-beginning 1) (match-end 1))))
+
+(defun ocamlspot-warnings-rev (lst)
+  (let ((warning (ocamlspot-warning)))
+    (if warning (ocamlspot-warnings-rev (concat lst warning "\n"))
+      lst)))
+
+(defun ocamlspot-warnings ()
+  (goto-char (point-min))
+  (ocamlspot-warnings-rev ""))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; File access
+
+(defun ocamlspot-find-file-existing (path)
+  (if (file-exists-p path)
+      (find-file-other-window path)
+    (message "ERROR: source file %s was not found" path)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Queries
+
+; It is all my failure, but the first versions of ocamlspot lacks clear notion
+; of versions. This function infers the command option interface of the command
+; from the help string. If t, ocamlspot cannot take line-bytes specifications.
+(defun ocamlspot-older-version ()
+  (when (eq 0 ocamlspot-older-version) ; not yet known
+    (with-current-buffer (get-buffer-create ocamlspot-buffer)
+      (erase-buffer)
+      (call-process shell-file-name nil t nil shell-command-switch
+                    (concat ocamlspot-command " -help"))
+      (goto-char (point-min))
+      (setq ocamlspot-older-version
+            (not (null (re-search-forward "^ocamlspot path:charpos" nil t))))))
+  ocamlspot-older-version)
+
+; launch ocamlspot
+; result is stored in the buffer "ocamlspot-buffer"
+; the current buffer is stored in source_buffer
+(defun ocamlspot-gen-query (extra_args)
+  (interactive)
+  (save-excursion
+    (ocamlspot-delete-overlays-now)
+    ;; arguments
+    (let ((file-name (buffer-file-name))
+          (arg (if (ocamlspot-older-version)
+                   ; older pos spec
+                   (format "%s:%d"
+                           (buffer-file-name)
+                           (1- (point)))
+                   ; newer pos spec
+                   (format "%s:l%dc%d"
+                           (buffer-file-name)
+                           (ocamlspot-lines-of-point)
+                           (ocamlspot-bytes-of-line-to-point))))
+          (source-buffer (current-buffer))) ; ocamlspot buffer
+      (with-current-buffer (get-buffer-create ocamlspot-buffer)
+        (erase-buffer)
+        ;; chdir is required
+        (cd (file-name-directory file-name))
+        (call-process shell-file-name nil t nil shell-command-switch
+                      (concat ocamlspot-command " " arg
+                              (if ocamlspot-debug " -debug " " ")
+                              extra_args))
+        ;; search the found tree element
+        (goto-char (point-min))
+        (if (re-search-forward "^Tree: \\(l[\-0-9]+c[\-0-9]+b[\-0-9]+:l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[0-9]+:[0-9]+\\)$"
+                             nil t)
+            (let ((pos (buffer-substring (match-beginning 1) (match-end 1))))
+              ;; display the result
+              (save-current-buffer
+                (ocamlspot-display-overlay source-buffer pos ocamlspot-tree-overlay))
+              (message (ocamlspot-warnings))
+              t)
+          (if (re-search-forward "^\\(Error: .*\\)" nil t)
+              (message (buffer-substring (match-beginning 1) (match-end 1)))
+              ;; display debug info
+              (message "ERROR: no tree node found there"))
+            nil)))))
+
+(defun ocamlspot-jump-to-spot (filename position)
+  (if (string-match "\.cm[ioxa]$" filename)
+      ;; It is not an .ml or .mli. Packed module.
+      (progn
+        (message "Packed module: %s" filename)
+        ;; CR jfuruse: opening a binary file is not good
+        )
+    (ocamlspot-display-overlay
+     (ocamlspot-find-file-existing filename)
+     position ocamlspot-spot-overlay)))
+
+(defun ocamlspot-find-type-in-buffer (&optional to-kill)
+  (set-buffer (get-buffer-create ocamlspot-buffer))
+  (goto-char (point-min))
+  (if (re-search-forward "^Type: \\(.*\\(\n +.*\\)*\\)" nil t)
+      (let ((type (buffer-substring (match-beginning 1) (match-end 1))))
+        (if to-kill (kill-new type))
+        (message "Type: %s" type)
+        type)
+    (message "no type found here")
+    nil))
+
+(defun ocamlspot-find-val-or-type-in-buffer (&optional to-kill)
+  (set-buffer (get-buffer-create ocamlspot-buffer))
+  (goto-char (point-min))
+  (if (re-search-forward "^Val: \\(.*\\(\n +.*\\)*\\)" nil t)
+      (let ((type (buffer-substring (match-beginning 1) (match-end 1))))
+        (if to-kill (kill-new type))
+        (message "Val: %s" type)
+        type)
+    (ocamlspot-find-type-in-buffer to-kill)))
+
+(defun ocamlspot-find-spot-in-buffer ()
+  (set-buffer (get-buffer-create ocamlspot-buffer))
+  (goto-char (point-min))
+  (if (re-search-forward "^Spot: \\(.*\\):\\(l[\-0-9]+c[\-0-9]+b[\-0-9]+:l[\-0-9]+c[\-0-9]+b[\-0-9]+\\|[0-9]+:[0-9]+\\|all\\)$"
+                         nil t)
+      (let ((filename (buffer-substring (match-beginning 1)
+                                        (match-end 1)))
+            (position (buffer-substring (match-beginning 2)
+                                        (match-end 2))))
+        ;; display the result
+        (let ((type (ocamlspot-find-val-or-type-in-buffer)))
+          (ocamlspot-jump-to-spot filename position)
+          (if type (message "Type: %s" type))))
+    (if (re-search-forward "^Spot: \\(.*\\)" nil t)
+        (message (buffer-substring (match-beginning 1) (match-end 1)))
+      (if (re-search-forward "^\\(Error: .*\\)" nil t)
+          (message (buffer-substring (match-beginning 1) (match-end 1)))
+        ;; display debug info
+        (message "No spot found there")
+        (ocamlspot-find-val-or-type-in-buffer)
+        ;; (display-buffer ocamlspot-buffer)
+        ))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Interactives
+
+(defun ocamlspot-query ()
+  (interactive)
+  (let ((sel-window (selected-window)))
+  (save-selected-window
+    (when (ocamlspot-gen-query nil)
+      ;; search the result
+      (ocamlspot-find-spot-in-buffer))
+    (ocamlspot-delete-overlays)) ; CR jfuruse: it depends on one's taste
+  ; I dunno why but we need the following line to list-buffers work nicely
+  (select-window sel-window)))
+
+(defun ocamlspot-type (&optional to-kill)
+  (interactive)
+  (if (ocamlspot-gen-query "-n")
+      (save-current-buffer
+        (ocamlspot-find-val-or-type-in-buffer to-kill)))
+  (ocamlspot-delete-overlays))
+
+(defun ocamlspot-type-and-copy ()
+  (interactive)
+  (ocamlspot-type t))
+
+; CR can be shared with ocamlspot-type
+(defun ocamlspot-use ()
+  (interactive)
+  (if (ocamlspot-gen-query "-n")
+      (save-current-buffer
+        (set-buffer (get-buffer-create ocamlspot-buffer))
+        (goto-char (point-min))
+        (if (re-search-forward "^Use: \\(.*\\(\n +.*\\)*\\)" nil t)
+            (let ((type (buffer-substring (match-beginning 1) (match-end 1))))
+              (message type))
+          (message "no use information found here"))))
+  (ocamlspot-delete-overlays))
+
+(defun ocamlspot-display-ocamlspot-buffer ()
+  (interactive)
+  (display-buffer ocamlspot-buffer))
+
+(provide 'ocamlspot)
+(* sample file indented as we want it to be *)
+
+;; (* http://mantis/view.php?id=4247 *)
+let x = {
+  Foo.
+  a = b;
+  c = d;
+  e = {Bar.
+       f = 1;
+       g = 2;
+      };
+  h = {  Quux.
+         i = 3;
+         j = 4;
+      };
+}
+
+;; (* http://mantis/view.php?id=4249 *)
+let x = { a = b;
+          c = d;
+        }
+
+;; (* http://mantis/view.php?id=4255 *)
+{ foo: [ `Foo of int
+       | `Bar of string ];
+}
+
+let s = { a with
+  b = 1;
+}
+;;
+
+let a = {
+  M.
+  foo = foo;
+  bar = bar;
+}
+
+let a = { t with M.
+  foo = foo;
+  bar = bar;
+}
+
+let a = { t with
+  M.
+  foo = foo;
+  bar = bar;
+}
+
+type t = [ `Foo of int
+         | `Bar of string ]
+
+type t =
+  | A
+  | B
+  | C
+with sexp
+
+type t = | A
+         | B
+         | C
+
+type t = [
+| `A
+| `B
+| `C
+]
+
+type t = [                              (* comment *)
+| `A
+| `B
+| `C
+]
+
+type t =
+  [ `A
+  | `B
+  | `C
+  ]
+
+type t = a
+and x = b
+
+module M = struct
+  type t =
+    | A
+    | B
+    | C
+  with sexp
+
+  type s = [
+  | `A
+  | `B
+  | `C
+  ]
+
+  type u =
+    | D
+    | E
+  with sexp
+end
+
+type m =
+  | T
+with sexp
+
+;; (* http://mantis/view.php?id=4334 *)
+type foo =
+    a
+    -> b
+    -> c
+    -> d
+
+val f :
+  a:a
+  -> b:b
+  -> c:c
+
+type bar = a -> b
+    -> c -> d
+    -> e -> f
+
+type baz = a -> b ->
+    c -> d ->
+    e -> f
+
+val quux : a -> b ->
+  c -> d ->
+  e -> f
+
+type t : a:b -> c:d
+    -> e:f -> g
+
+val f : a:b -> c:d
+  -> e:f -> g
+
+type t = {
+  foo : (a
+         -> b
+         -> c
+         -> d);
+}
+
+type t = {
+  foo : (    a ->
+             b ->
+             c ->
+             d);
+}
+
+type t = {
+  foo : a
+        -> b
+        -> c
+        -> d;
+  bar :
+    a
+    -> b
+    -> c;
+}
+
+type t = {
+  foo : a ->
+        b ->
+        c ->
+        d;
+  bar :
+    a ->
+    b ->
+    c;
+}
+
+type t = {
+  a : B.t;
+  c : D.t;
+
+  e : F.t;
+
+  g : H.t I.t;
+  j :
+    K.t L.t;
+  m : N.t O.t;
+  p :
+    ((q:R.t
+      -> s:T.U.t
+      -> v:(W.t -> X.t option)
+      -> y:(Z.t -> A.t -> B.t C.D.t E.t)
+      -> f:(G.t -> H.t I.t option)
+      -> j:(K.t -> L.t M.t option)
+      -> n:(O.t -> p option)
+      -> q:R.t
+      -> s:(string -> unit) -> T.t
+     )
+     -> U.t
+     -> V.W.t
+     -> X.t);
+  y : Z.t A.t;
+  b : C.t D.t E.t;
+  f : (G.t -> H.t -> I.t J.t);
+} with sexp_of
+
+type 'a v = id:O.t ->
+    ssss:Ssss.t ->
+    dddd:ddd.t ->
+    t:S_m.t ->
+    mmm:Safe_float.t ->
+    qqq:int ->
+    c:C.t ->
+    uuuu:string option ->
+    aaaaaa:Aaaaaa.t ->
+    a:A.t ->
+    rrrrr:Rrrrr.t ->
+    time:Time.t ->
+    typ:[ `L_p of Safe_float.t ] ->
+    bazonk:present option ->
+    o_p_e:O_m.t option ->
+    only_hjkl:present option ->
+    show_junk:int option ->
+    d_p_o: Safe_float.t option ->
+    asdf:present option ->
+    generic:Sexp.t list ->
+    'a
+
+type 'a v =
+    id:O.t
+    -> ssss:Ssss.t
+    -> dddd:ddd.t
+    -> t:S_m.t
+    -> mmm:Safe_float.t
+    -> qqq:int
+    -> c:C.t
+    -> uuuu:string option
+    -> aaaaaa:Aaaaaa.t
+    -> a:A.t
+    -> rrrrr:Rrrrr.t
+    -> time:Time.t
+    -> typ:[ `L_p of Safe_float.t ]
+    -> bazonk:present option
+    -> o_p_e:O_m.t option
+    -> only_hjkl:present option
+    -> show_junk:int option
+    -> d_p_o: Safe_float.t option
+    -> asdf:present option
+    -> generic:Sexp.t list
+    -> 'a
+
+;; (* not in mantis *)
+let bar x =
+  if y
+  then x
+  else z
+
+let zot x =
+  quux ~f:(if x
+    then y
+    else z)
+
+let zot x = quux ~f:(if x
+  then y
+  else z)
+
+let () =
+  if foo
+  then bar
+  else if foo1
+  then zot
+  else bazonk
+
+let () =
+  if foo
+  then bar
+  else
+    if foo1
+    then zot
+    else bazonk
+
+let _ =
+  if until
+  then _
+
+let () =
+  if a then (
+    b
+  ) else (
+    c
+  )
+
+let rec count_append l1 l2 count =
+  match l1 with
+    | []               ->                         l2
+    | [x1]             -> x1                   :: l2
+    | [x1; x2]         -> x1 :: x2             :: l2
+    | [x1; x2; x3]     -> x1 :: x2 :: x3       :: l2
+    | [x1; x2; x3; x4] -> x1 :: x2 :: x3 :: x4 :: l2
+    | x1 :: x2 :: x3 :: x4 :: x5 :: tl ->
+      x1 :: x2 :: x3 :: x4 :: x5 ::
+        (if count > 1000
+         then slow_append tl l2
+         else count_append tl l2 (count + 1))
+
+let foo =
+  (
+    if a
+    then b
+    else c
+  )
+
+let quux list = List.map list ~f:(fun item ->
+  print_item item
+)
+
+let foo x = function
+  | Some _ -> true
+  | None -> false
+
+let bar x = fun u ->
+  | Some _ -> true
+  | None -> false
+
+let zot u = match u with
+  | Some _ -> true
+  | None -> false
+
+let () = match x with
+    Foo -> 1
+  | Bar -> 2
+
+let () =
+  match x with
+      Foo -> 1
+    | Bar -> 2
+
+let r x =
+  try  f x;
+       g x;
+       y x;
+  with e -> raise e
+
+let g x =
+  try let a = b in
+        f x;
+        g x;
+        y x;
+  with e -> raise e
+
+let h x =
+  try  ff a b
+         c d;
+       gg 1 2
+         3 4;
+  with e -> raise e
+
+let () =
+  try
+    _
+  with
+      Bar -> ()
+
+let () =
+  try () with
+    |e ->
+      let x = z in
+
+        yyyyy
+          (a b)
+
+let d x = function
+  | A -> (match x with
+      | X ->
+        false
+      | Y -> true
+      |  Z ->
+        false)
+  | B -> false
+
+let a f = function
+  | A ->
+    1
+  |   B ->
+    2
+  |      C ->
+    (function
+      |  X  ->
+        a
+      | Y ->
+        b) 12
+  | D ->
+    (match z with
+      | 4 -> 3
+      |  5 -> 7)
+
+let x = foo ~f:(fun _ -> 0              (* comment *)
+)
+
+let f x =
+  (let y = x in
+     f x;
+     g y;
+     h z)
+
+let f x =
+  (let y = x in
+     f x);