Commits

Anonymous committed 45b0444

Add ocaml.

Comments (0)

Files changed (17)

+_pkg.el
+auto-autoloads.el
+custom-load.el
+package-info
+pdepends.mk
+ocamltags
+2002-07-31  Ville Skyttä  <ville.skytta@xemacs.org>
+
+	* First cut at packaging.
+# Makefile for the ocaml package.
+
+# This file is part of XEmacs.
+
+# XEmacs is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+
+# XEmacs 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 XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+VERSION = 0.01
+AUTHOR_VERSION = 3.05
+MAINTAINER = Ville Skyttä <ville.skytta@xemacs.org>
+PACKAGE = ocaml
+PKG_TYPE = regular
+REQUIRES = xemacs-base fsf-compat
+CATEGORY = unsupported
+
+# caml-hilit left out on purpose, we don't need it in XEmacs.
+ELCS = caml-font.elc caml.elc camldebug.elc inf-caml.elc caml-compat.elc \
+	caml-help.elc
+
+EXTRA_SOURCES = README README.itz
+
+PRELOADS = -l font-lock -l overlay -l add-log -l imenu -l camldebug -l inf-caml
+
+include ../../XEmacs.rules
+
+GENERATED +=
+
+all:: $(ELCS) auto-autoloads.elc
+
+srckit: srckit-std
+
+binkit: binkit-common

Makefile.upstream

+# $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
+
+# 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.el") \
+              (byte-compile-file "inf-caml.el") \
+              (byte-compile-file "caml-help.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
+
+simple-install:
+	@echo "Installing in $(EMACSDIR)..."
+	if test -d $(EMACSDIR); then : ; else mkdir -p $(EMACSDIR); fi
+	cp $(FILES) $(EMACSDIR)
+	cd $(EMACSDIR); $(EMACS) --batch --eval '$(COMPILECMD)'
+
+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 *~ #*#
+        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.
+
+    (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.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@kurims.kyoto-u.ac.jp>
+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      +-------------------------------------------+
+;; 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)
+
+;; useful colors
+
+(cond
+ ((x-display-color-p)
+  (cond
+   ((not (memq 'font-lock-type-face (face-list)))
+    ; 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\\(ue\\)?\\|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
+(setq caml-mode-hook
+      '(lambda ()
+         (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)))
+
+(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)
+;; 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.)
+;;       
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+;; Loading or building databases.
+;; 
+
+;; variables to be customized
+
+(defvar ocaml-lib-path 'lazy
+  "Path 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)
+  (concat (downcase (substring s 0 1)) (substring s 1)))
+
+(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-module-alist ()
+  "Call by need value of valriable 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\\|external\\) \\([^ (:=]*\\)" (point-max) 'move)
+          (setq alist (cons (match-string 2) 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 (member module ocaml-visible-modules) nil
+              (setq ocaml-visible-modules
+                    (cons (ocaml-get-or-make-module module)
+                          ocaml-visible-modules)))))
+        )))
+  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
+            (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-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 qualified identifiers. 
+
+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))
+         (module) 
+         (entry (cdr module-entry))
+         (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* ((table 'ocaml-completion)
+             (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))
+                    (hist)
+                    (module
+                     (cond
+                      ((null modules)
+                       nil)
+                      ((equal (length modules) 1)
+                       (caar modules))
+                      (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)
+               (insert completion))
+
+              (t
+                (with-output-to-temp-buffer "*Completions*"
+                  (display-completion-list all-completions))
+                ))
+               ))))
+
+
+;; Info files (only in ocamldoc style)
+
+
+(defvar ocaml-info-basename "ocaml"
+  "Basename 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 with basename `ocaml-info-basename' 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-basename))
+               (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 "HERE"))
+      (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 with basename `ocaml-info-basename' 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 nil
+  "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-hevea-info' and
+`ocaml-ocamldoc-info'. 
+
+  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)))
+    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)
+  "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 ((info-section (assoc module (ocaml-info-alist))))
+    (if info-section (info (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
+          (view-file (concat location (ocaml-uncapitalize module) ".mli"))
+          (bury-buffer (current-buffer)))
+         (info-section (error "Aborted"))
+         (t (error "No help for module %s" module))))
+      ))
+  (if (stringp entry)
+      (let ((here (point)))
+        (goto-char (point-min))
+        (or (re-search-forward
+             (concat "\\(val\\|exception\\|external\\|[|{;]\\) +"
+                     (regexp-quote entry))
+             (point-max) t)
+            (search-forward entry (point-max) t)
+            (progn
+              (message "Help for entry %s not found in module %s"
+                       entry module)
+              (goto-char here)))))
+  )
+
+(defun caml-help (arg)
+  "Find help for qualified identifiers. 
+
+It attemps to recognize an qualified identifier of the form Module . entry 
+around point using function `ocaml-qualified-identifier'.
+
+If Module is undefined it finds it from indentifier and visible modules, 
+or asks the user interactively. 
+
+It then opens the info documentation for Module if available or 
+to the Module.mli file otherwises, and searches for entry. 
+
+With prefix arg 0, it recomputes visible modules and their content. 
+With prefix arg 4, it prompt for Module instead of its contectual value. 
+"
+  (interactive "p")
+  (let ((module) (entry))
+    (cond
+     ((= arg 4)
+      (or (and
+           (setq module
+                (completing-read "Module: " ocaml-module-alist nil t))
+           (not (string-equal module "")))
+          (error "Quit")))
+     (t
+      (if (= arg 0) (setq ocaml-visible-modules 'lazy))
+      (let ((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))
+                    (cond
+                     ((null modules)
+                      (error "No module found for entry %s" entry))
+                     ((equal (length modules) 1)
+                      (caar modules))
+                     (t
+                      (setq hist (mapcar 'car modules))
+                      (completing-read "Module: " modules nil t
+                                       "" (cons 'hist 0)))
+                     ))))
+        )))
+     (message "Help for %s%s%s" module (if entry "." "") (or entry ""))
+     (ocaml-goto-help module entry)
+     ))
+
+
+;; bindings
+
+(if (and (boundp 'caml-mode-map) (keymapp caml-mode-map))
+    (progn 
+      (define-key caml-mode-map [?\C-c?\C-h] 'caml-help)
+      (define-key caml-mode-map [?\C-c?\t] 'caml-complete)
+      ))
+
+(provide 'caml-help)

caml-hilit.el.upstream

+; 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\\(ue\\)?\\|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)
+;;; 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 nil
+  "Non nil when using xemacs.")
+
+(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))
+  (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))
+      (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 ]))
+  "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 ?\( "()1" caml-mode-syntax-table)
+  ; * is second character of comment start,
+  ; and first character of comment end
+  (modify-syntax-entry ?*  ". 23" 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)))
+
+;;;###autoload
+(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))
+
+;;; 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)
+          (setq count (- count (caml-char-bytes (char-after))))
+          (forward-char))
+      (while (< 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)
+
+;;itz 04-21-96 somebody didn't get the documetation 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 (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
+                     (string-to-int
+                      (buffer-substring (match-beginning 1) (match-end 1)))
+                     end
+                     (string-to-int
+                      (buffer-substring (match-beginning 2) (match-end 2)))))))
+       (cond (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)))))))))
+
+;; 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.
+  (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.")
+