emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] externals/caml bf4ed0f 001/197: Mode OCaml Garrigue/Zimmerman


From: Stefan Monnier
Subject: [nongnu] externals/caml bf4ed0f 001/197: Mode OCaml Garrigue/Zimmerman
Date: Sat, 21 Nov 2020 01:19:26 -0500 (EST)

branch: externals/caml
commit bf4ed0f926f3181a06b93396b2c59662da1e2711
Author: Xavier Leroy <xavier.leroy@inria.fr>
Commit: Xavier Leroy <xavier.leroy@inria.fr>

    Mode OCaml Garrigue/Zimmerman
    
    
    git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@1286 
f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
---
 README.itz    |  178 +++++++
 caml-font.el  |  100 ++++
 caml-hilit.el |   57 +++
 caml.el       | 1438 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 camldebug.el  |  753 ++++++++++++++++++++++++++++++
 inf-caml.el   |  100 ++++
 6 files changed, 2626 insertions(+)

diff --git a/README.itz b/README.itz
new file mode 100644
index 0000000..60678cf
--- /dev/null
+++ b/README.itz
@@ -0,0 +1,178 @@
+DESCRIPTION:
+
+This directory contains files to help editing Caml code, running a
+Caml toplevel, and running the Caml debugger under the Gnu Emacs editor.
+
+AUTHORS:
+
+Ian T Zimmerman <itz@rahul.net> added indentation to caml mode, beefed
+up camldebug to work much like gud/gdb.
+
+Xavier Leroy (Xavier.Leroy@inria.fr), Jerome Vouillon (Jerome.Vouillon@ens.fr).
+camldebug.el is derived from FSF code.
+
+CONTENTS:
+
+    caml.el         A major mode for editing Caml code in Gnu Emacs
+    inf-caml.el     To run a Caml toplevel under Emacs, with input and
+                    output in an Emacs buffer.    
+    camldebug.el    To run the Caml debugger under Emacs.
+    
+
+NOTE FOR EMACS 18 USERS:
+
+This package will no longer work with Emacs 18.x. Sorry. You really
+should consider upgrading to Emacs 19.
+
+USAGE:
+
+Add the following lines to your .emacs file:
+
+(setq auto-mode-alist (cons '("\\.ml[iylp]?" . caml-mode) auto-mode-alist))
+(autoload 'caml-mode "caml" "Major mode for editing Caml code." t)
+(autoload 'run-caml "inf-caml" "Run an inferior Caml process." t)
+(autoload 'camldebug "camldebug" "Run the Caml debugger." t)
+
+The Caml major mode is triggered by visiting a file with extension .ml,
+.mli, .mly. .mll or .mlp, or manually by M-x caml-mode. It gives you the
+correct syntax table for the Caml language. For a brief description of
+the indentation capabilities, see below under NEWS.
+
+The Caml mode also allows you to run batch Caml compilations from
+Emacs (using M-x compile) and browse the errors (C-x `). Typing C-x `
+sets the point at the beginning of the erroneous program fragment, and
+the mark at the end. Under Emacs 19, the program fragment is
+temporarily highlighted.
+
+M-x run-caml starts a Caml toplevel with input and output in an Emacs
+buffer named *inferior-caml*. This gives you the full power of Emacs
+to edit the input to the Caml toplevel. This mode is based on comint
+so you get all the usual comint features, including command history.
+
+After M-x run-caml, typing C-c C-e or M-C-x in a buffer in Caml mode
+sends the current phrase (containing the point) to the Caml toplevel,
+and evaluates it.
+
+M-x camldebug FILE starts the Caml debugger camldebug on the executable
+FILE, with input and output in an Emacs buffer named *camldebug-FILE*.
+For a brief description of the commands available in this buffer, see
+NEWS below.
+
+NEWS:
+
+Ok, so this is the really important part of this file :-) I took the
+original package from the contrib subdirectory of the caml-light
+distribution, and hacked on it. First, I added real syntax dependent
+indentation to caml mode. Like Xavier has said, it was hard (and I
+knew it would be), but I refused to believe it was impossible, partly
+because I knew of a Standard ML mode with indentation (written by
+Matthew Morley). 
+
+Indentation works pretty much like in other programming modes. C-j at
+the end of a line starts a new line properly indented. M-C-\ indents
+the current region (this may take a while :-)). I incorporated a
+slightly different TAB function, one that I use in other modes: if TAB
+is pressed while the point is not in line indentation, the line is
+indented to the column where point is (instead of just inserting a TAB
+character - you can always to that with C-q C-i). This way, you can
+indent a line any time, regardless of where the point lies, by hitting
+TAB twice in succession. If you don't like this behaviour (but you
+should), it's quite easy to add to your startup code like this:
+
+(defun caml-old-style-indent ()
+       (if (caml-in-indentation)
+               (caml-indent-command)
+               (insert "\t")))
+
+(add-hook 'caml-mode-hook
+       (function (lambda ()
+               (define-key 'caml-mode-map "\t"
+                       caml-old-style-indent))))
+
+You can customize the appearance of your caml code by twiddling the
+variables listed at the start of caml.el. Good luck. :-)
+
+Other news in caml mode are the various caml-insert-*-form commands. I
+believe they are self-explanatory - just do a C-h m in a caml buffer
+to see what you've got.
+
+The ohter major news is that I changed camldebug mode considerably. I
+took many clues from the gud "Grand Unified Debugger" mode distributed
+with modern versions of Emacs. The main benefit here is that you can
+do debugger commands _from your caml source buffer_. Commands with the
+C-c prefix in the debugger buffer have counterparts which do the same
+thing (well, a similar thing) in the source buffer, with the C-x C-a
+prefix. 
+
+I made the existing debugger commands smarter in that they now attempt
+to guess the correct parameter to the underlying camldebug command. A
+numeric argument will always override that guess. For example, the
+guess for C-c C-b (camldebug-break) is to set a breakpoint at the
+current event (which was the only behaviour provided with the old
+camldebug.el). But C-u 1 C-c C-b will now send "break 1" to the
+camldebug process, setting a break at code address 1.
+
+This also allowed me to add many more commands for which the
+underlying camldebug commands require a parameter. The best way to
+learn about them is to do C-h m in the camldebug buffer, and then C-h
+f for the commands you'll see listed.
+
+Finally, I added command completion. To use it, you'll have to apply
+the provided patch to the debugger itself
+(contrib/debugger/command_line_interpreter.ml), and recompile it
+(you'll get one warning from the compiler; it is safe to ignore
+it). Then hitting TAB in the following situation, for example:
+
+(cdb) pri_
+
+will complete the "pri" to "print".
+
+CAVEATS:
+
+I don't use X and haven't tested this stuff under the X mode of
+emacs. It is entirely possible (though not very probable) that I
+introduced some undesirable interaction between X (fontification,
+highlighting,...) and caml mode. I will welcome reports of such
+problems (see REPORTING below), but I won't be able to do much about
+them unless you also provide a patch.
+
+I don't know if the informational messages produced by camldebug are
+internationalized. If they are, the debugger mode won't work unless
+you set the language to English. The mode uses the messages to
+synchronize with camldebug, and looks for fixed Emacs regular
+expressions that match them. This may be fixed (if necessary) in a
+future release.
+
+BUGS:
+
+In the debugger buffer, it's possible to overflow your mental stack by
+asking for help on help on help on help on help on help on help on
+help...
+
+THANKS:
+
+Xavier Leroy <Xavier.Leroy@inria.fr> for Caml-light. Used together with the
+Emacs interface, it is about the most pleasant programming environment
+I've known on any platform.
+
+Eric Raymond <esr@thyrsus.com> for gud, which camldebug mode apes.
+
+Barry Warsaw <bwarsaw@cen.com> for elp, without which I wouldn't have
+been able to get the indentation code to perform acceptably.
+
+Gareth Rees <Gareth.Rees@cl.cam.ac.uk> for suggestions how to speed up
+Emacs regular expression search, even if I didn't use them in the end.
+
+Bill Dubuque <wgd@martigny.ai.mit.edu> for alerting me to the
+necessity of guarding against C-g inside Emacs code which modifies
+syntax tables.
+
+REPORTING:
+
+Bug reports (preferably with patches), suggestions, donations etc. to:
+
+Ian T Zimmerman           +-------------------------------------------+
+Box 13445                 I    With so many executioners available,   I
+Berkeley CA 94712 USA     I suicide is a really foolish thing to do.  I
+mailto:itz@rahul.net      +-------------------------------------------+
+
diff --git a/caml-font.el b/caml-font.el
new file mode 100644
index 0000000..a1b959d
--- /dev/null
+++ b/caml-font.el
@@ -0,0 +1,100 @@
+;; useful colors
+
+; I don't know exactly when font-lock turned color...
+
+(cond
+ ((and (x-display-color-p)
+       (not (string< "19.30" emacs-version)))
+  (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 "DarkOliveGreen3")
+  (make-face 'CadetBlue)
+  (set-face-foreground 'CadetBlue "CadetBlue")))
+
+(cond
+ ((and (x-display-color-p)
+       (not (string< "19.30" emacs-version)))
+  (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)))
+
+; 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
+;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)
+;labels (and open)
+   '("\\([?]?\\<[A-Za-z][A-Za-z0-9_']*:\\)\\([^:=]\\|\\'\\|$\\)" 1
+     font-lock-variable-name-face)
+   '("\\<\\(open\\|include\\)\\>\\|[?]?\\<:[A-Za-z][A-Za-z0-9_']*\\>"
+     . font-lock-variable-name-face)
+;modules and constructors
+   '("\\(\\<\\|:\\)\\([A-Z][A-Za-z0-9_']*\\)\\>"
+     2 font-lock-function-name-face)
+   '("`[A-Za-z][A-Za-z0-9_']*\\>" . font-lock-function-name-face)
+;definition
+   (cons (concat
+         "\\<\\(and\\|as\\|c\\(onstraint\\|losed\\)"
+         "\\|ex\\(ception\\|ternal\\)\\|fun\\(ct\\(ion\\|or\\)\\)?"
+         "\\|in\\(herit\\)?\\|let\\|m\\(ethod\\|utable\\|odule\\)"
+         "\\|of\\|p\\(arser\\|rivate\\)\\|rec\\|type"
+         "\\|v\\(al\\(ue\\)?\\|irtual\\)\\)\\>")
+        'font-lock-type-face)
+;blocking
+   '("\\(\\<\\|:\\)\\(begin\\|class\\|end\\|s\\(ig\\|truct\\)\\)\\>"
+     2 font-lock-keyword-face)
+;control
+   (cons (concat
+         "\\<\\(do\\(ne\\|wnto\\)?\\|else\\|for\\|if"
+         "\\|match\\|new\\|or\\|t\\(hen\\|o\\|ry\\)"
+         "\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\)\\>"
+         "\\|\|\\|->\\|&\\|#")
+        'font-lock-reference-face) 
+   '("\\<raise\\>" . font-lock-comment-face)))
+
+(defconst inferior-caml-font-lock-keywords
+  (append
+   (list
+;inferior
+    '("^[#-]" . font-lock-comment-face)
+;labels
+    '("[? \t]:[A-Za-z][A-Za-z0-9_']*\\>" . font-lock-variable-name-face))
+   caml-font-lock-keywords))
+    
+;; font-lock commands are similar for caml-mode and inferior-caml-mode
+(setq caml-mode-hook
+      '(lambda ()
+        (setq font-lock-keywords caml-font-lock-keywords)
+        (setq font-lock-no-comments t)
+        (font-lock-mode 1)))
+
+(setq inferior-caml-mode-hooks
+      '(lambda ()
+        (setq font-lock-keywords inferior-caml-font-lock-keywords)
+        (setq font-lock-no-comments t)
+        (font-lock-mode 1)))
+
+(provide 'caml-font)
diff --git a/caml-hilit.el b/caml-hilit.el
new file mode 100644
index 0000000..712c299
--- /dev/null
+++ b/caml-hilit.el
@@ -0,0 +1,57 @@
+; 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-Za-z][A-Za-z0-9_\']*:" nil brown)
+   '("[?]?\\<:[A-Za-z][A-Za-z0-9_\']*\\>" nil brown)
+;modules
+   '("\\<open\\>" nil brown)
+   '("\\<[A-Z][A-Za-z0-9_\']*\\>" nil MidnightBlue)
+   '("`[A-Za-z][A-Za-z0-9_\']*\\>" nil MidnightBlue)
+;definition
+   (list (concat
+         "\\<\\(let\\|rec\\|in\\|type\\|of\\|and"
+         "\\|exception\\|val\\|and\\|function\\|fun"
+         "\\|parser\\|mutable\\|module\\|inherit"
+         "\\|external\\|method\\|virtual\\|private"
+         "\\|constraint\\|as\\|closed\\)\\>")
+        nil 'ForestGreen)
+;blocking
+   '("\\(\\<\\|:\\)\\(class\\|struct\\|sig\\|begin\\|end\\)\\>"
+     2 include)
+;control
+   (list (concat
+         "\\<\\(if\\|then\\|else\\|match\\|when"
+         "\\|with\\|try\\|for\\|do\\|while\\|done"
+         "\\|downto\\|to\\|or\\|new\\)\\>"
+         "\\|\|\\|->\\|&\\|#")
+        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)
+   '("`[A-Za-z][A-Za-z0-9_\']*\\>" nil MidnightBlue)
+   '("[? \t]:[A-Za-z][A-Za-z0-9_\']*\\>" nil brown))
+  caml-mode-patterns))
+
+(provide 'caml-hilit)
diff --git a/caml.el b/caml.el
new file mode 100644
index 0000000..45acff3
--- /dev/null
+++ b/caml.el
@@ -0,0 +1,1438 @@
+;;; caml.el --- Caml code editing commands for Emacs
+
+;; Initial code written by 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,
+;; october 1996. <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-mode-indentation 2
+  "*Used for \\[caml-unindent-command].")
+
+(defvar caml-lookback-limit 2000
+  "*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-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-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 3
+  "*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  3
+  "*How many spaces to indent from a := operator in caml mode.")
+(make-variable-buffer-local 'caml-:=-indent)
+
+(defvar caml-<--indent 3
+  "*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-|-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-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.")
+
+;;compatibility function for old emacs.
+
+(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))))
+
+;;code
+(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)
+  (define-key caml-mode-map "\M-\C-h" 'caml-mark-phrase)
+
+;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)
+
+  (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\C-a" 'caml-find-alternate-file)
+  (define-key caml-mode-map "\C-c\C-c" 'compile)
+  (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))
+
+(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)
+  ; : is part of words (labels)
+  (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))
+
+;;; The major mode
+
+(defun caml-mode ()
+  "Major mode for editing Caml code.
+
+\\{caml-mode-map}"
+
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'caml-mode)
+  (setq mode-name "caml")
+  (use-local-map caml-mode-map)
+  (set-syntax-table caml-mode-syntax-table)
+  (setq local-abbrev-table caml-mode-abbrev-table)
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start (concat "^$\\|" page-delimiter))
+  (make-local-variable 'paragraph-separate)
+  (setq paragraph-separate paragraph-start)
+  (make-local-variable 'paragraph-ignore-fill-prefix)
+  (setq paragraph-ignore-fill-prefix t)
+  (make-local-variable 'require-final-newline)
+  (setq require-final-newline t)
+  (make-local-variable 'comment-start)
+  (setq comment-start "(*")
+  (make-local-variable 'comment-end)
+  (setq comment-end "*)")
+  (make-local-variable 'comment-column)
+  (setq comment-column 40)
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip "(\\*+ *")
+  (make-local-variable 'parse-sexp-ignore-comments)
+  (setq parse-sexp-ignore-comments nil)
+  (make-local-variable 'indent-line-function)
+  (setq indent-line-function 'caml-indent-command)
+  ;itz 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)
+  (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"))))))
+
+;;; 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
+
+(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 ((beg nil) (end nil))
+       (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 beg (+ (point) beg)
+                   end (+ (point) end))
+             (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.
+
+(cond
+ ((fboundp 'buffer-substring-no-properties)
+  (defun caml-buffer-substring (b e)
+    (buffer-substring-no-properties b e)))
+ ((fboundp 'buffer-substring-without-properties)
+  (defun caml-buffer-substring (b e)
+    (buffer-substring-without-properties b e)))
+ (t (defun caml-buffer-substring (b e) (buffer-substring b e))))
+
+(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)
+      (caml-buffer-substring begin end))))
+
+;;; 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\\)"
+         "\\|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) (looking-at caml-phrase-start-keywords)))
+
+(defun caml-mark-phrase ()
+  "Put mark at end of this Caml phrase, point at beginning.
+
+The Caml phrase is the phrase just before the point.
+Completely rewritten by J. Garrigue, to handle both Objective Caml
+and Caml-Light syntax. \";;\" is left out of the region, and
+eventually added when sending to the subprocess."
+
+  (interactive)
+  (let (use-semi end)
+    (if (and (looking-at ";;") (not (caml-in-comment-p))) nil
+      (if (caml-at-phrase-start-p) (forward-char))
+      (while (and (cond
+                  ((re-search-forward
+                    (concat ";;\\|" caml-phrase-start-keywords) nil 'move)
+                   (goto-char (match-beginning 0)) t))
+                 (or (not (or (bolp) (looking-at ";;")))
+                     (caml-in-comment-p)
+                     (caml-in-literal-p)))
+       (forward-char)))
+    (setq use-semi (looking-at ";;"))
+    (skip-chars-backward " \n\t")
+    (while (and (eq (preceding-char) ?\)) (eq (char-after (- (point) 2)) ?*))
+      (backward-char 2)
+      (while (caml-in-comment-p) (up-list -1))
+      (skip-chars-backward " \n\t"))
+    (push-mark)
+    (setq end (point))
+    (cond
+     (use-semi
+      (if (caml-find-kwop ";;") (forward-char 2)
+       (goto-char (point-min)))
+      (skip-chars-forward " \n\t")
+      (while (or (looking-at comment-start-skip) (caml-in-comment-p))
+       (forward-list 1)
+       (skip-chars-forward " \n\t")))
+     (t
+      (if (not (caml-find-kwop caml-phrase-start-keywords))
+         (error "No phrase preceding point"))
+      (while (and (or (not (bolp))
+                     (caml-in-comment-p)
+                     (caml-in-literal-p))
+                 (caml-find-kwop caml-phrase-start-keywords)))))
+    (cons (point) end)))
+
+(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)
+
+(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-list-safe ()
+  (condition-case nil
+      (forward-list 1)
+    (error (goto-char (point-max)))))
+
+
+
+(defun caml-in-comment-p ()
+  "Returns non-nil if point is inside a caml 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)))
+       (let ((inside) (done nil) (here (point)))
+         (goto-char cached-pos)
+         (while (not done)
+           (setq inside nil)
+           (if (not (search-forward "(*" (1+ here) 'move))
+               (setq here 0)
+             (goto-char (match-beginning 0))
+             (setq inside (point))
+             (caml-forward-list-safe))
+           (setq done (< here (point))))
+         (if (not inside)
+             (setq caml-last-noncomment-pos here)
+           (set-marker caml-last-comment-start inside)
+           (set-marker caml-last-comment-end (point)))
+         inside))
+       (cached-pos
+       (let ((inside) (done nil) (here (point)))
+         (goto-char cached-pos)
+         (while (not done)
+           (setq inside nil)
+           (if (not (search-backward "*)" (1- here) 'move))
+               (setq here (point-max))
+             (goto-char (match-end 0))
+             (setq inside (point))
+             (backward-list 1))
+           (setq done (> here (point))))
+         (if (not inside)
+             (setq caml-last-noncomment-pos here)
+           (set-marker caml-last-comment-start (point))
+           (set-marker caml-last-comment-end inside))
+         inside))          
+       (t   
+       (let* ((here (point)) (done nil)
+              (limit (- (point) caml-lookback-limit))
+              (begin (condition-case nil
+                         (prog2
+                             (while (and (not done) (< limit (point)))
+                               (up-list -1)
+                               (setq done (looking-at comment-start-skip)))
+                             (if done (point)))
+                       (error nil))))
+         (if (not begin) (setq caml-last-noncomment-pos here) 
+           (goto-char begin)
+           (caml-forward-list-safe)
+           (set-marker caml-last-comment-start begin)
+           (set-marker caml-last-comment-end (point)))
+         begin))))))
+
+(defconst caml-before-expr-prefix
+  (concat "\\<\\(asr\\|begin\\|class\\|do\\(wnto\\)?\\|else"
+         "\\|i\\(f\\|n\\(herit\\)?\\)"
+         "\\|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.")
+
+(defun caml-in-expr-p ()
+  (let ((pos (point)) (in-expr t))
+    (caml-find-kwop
+     (concat caml-before-expr-prefix "\\|"
+            caml-matching-kw-regexp "\\|"
+            (aref caml-kwop-regexps caml-max-indent-priority)))
+    (cond ((looking-at caml-before-expr-prefix)
+          (goto-char (match-end 0))
+          (skip-chars-forward " \t\n")
+          (while (looking-at "(\\*")
+            (forward-sexp 1)
+            (skip-chars-forward " \t\n"))
+          (if (<= pos (point)) (setq in-expr nil))))
+    (goto-char pos)
+    in-expr))
+
+(defun caml-at-top-let-p ()
+  (and (looking-at "\\<let\\>")
+       (or (bolp)
+          (caml-in-expr-p))))
+
+
+(defun caml-at-sexp-close-p ()
+  (or (char-equal ?\) (following-char))
+      (char-equal ?\] (following-char))
+      (char-equal ?} (following-char))))
+
+(defun caml-find-kwop (kwop-regexp)
+  "Look back for a caml keyword or operator matching KWOP-REGEXP.
+
+Ignore occurences inside literals. If found, return a list of two
+values: the actual text of the keyword or operator, and a boolean
+indicating whether the keyword was one we looked for explicitly
+{non-nil}, or on the other hand one of the block-terminating
+keywords."
+  
+  (let ((start-literal (concat "[\"" caml-quote-char "]"))
+       found kwop)
+    (progn
+      (while (and (not found)
+                 (re-search-backward kwop-regexp nil t))
+       (setq kwop (caml-match-string 0))
+       (cond
+        ((caml-in-comment-p)
+         (up-list -1))
+        ((looking-at "(\\*")
+         (backward-char))
+        ((looking-at start-literal))
+        ((caml-in-literal-p)
+         (re-search-backward start-literal))  ;ugly hack
+        ((setq found t)))))
+    (if found
+       (if (not (string-match "\\`[^|[]|[^]|]?\\'" kwop)) ;arrrrgh!!
+           kwop
+         (forward-char 1) "|") nil)))
+
+;  Association list of indentation values based on governing keywords.
+;
+;Each element is of the form (KEYWORD OP-TYPE PRIO INDENT). OP-TYPE is
+;non-nil for operator-type nodes, which affect indentation in a
+;different way from keywords: subsequent lines are indented to the
+;actual occurrence of an operator, but relative to the indentation of
+;the line where the governing keyword occurs.
+
+(defconst caml-no-indent 0)
+
+(defconst caml-kwop-alist
+  '(("begin"           nil     6       caml-begin-indent)
+    (":begin"          nil     6       caml-begin-indent) ; hack
+    ("class"           nil     0       caml-class-indent)
+    ("constraint"      nil     0       caml-val-indent)
+    ("sig"             nil     1       caml-sig-indent)
+    ("struct"          nil     1       caml-struct-indent)
+    ("exception"       nil     0       caml-exception-indent)
+    ("for"             nil     6       caml-for-indent)
+    ("fun"             nil     3       caml-fun-indent)
+    ("function"                nil     3       caml-function-indent)
+    ("if"              nil     6       caml-if-indent)
+    ("if-else"         nil     6       caml-if-else-indent)
+    ("include"         nil     0       caml-include-indent)
+    ("inherit"         nil     0       caml-inherit-indent)
+    ("let"             nil     6       caml-let-indent)
+    ("let-in"          nil     6       caml-let-in-indent)
+    ("match"           nil     6       caml-match-indent)
+    ("method"          nil     0       caml-method-indent)
+    ("module"          nil     0       caml-module-indent)
+    ("of"              nil     7       caml-of-indent)
+    ("open"            nil     0       caml-no-indent)
+    ("parser"          nil     3       caml-parser-indent)
+    ("try"             nil     6       caml-try-indent)
+    ("type"            nil     0       caml-type-indent)
+    ("val"             nil     0       caml-val-indent)
+    ("virtual"         nil     0       caml-val-indent)
+    ("while"           nil     6       caml-while-indent)
+    ("::"              t       5       caml-::-indent)
+    ("@"               t       4       caml-@-indent)
+    ("^"               t       4       caml-@-indent)
+    (":="              nil     3       caml-:=-indent)
+    ("<-"              nil     3       caml-<--indent)
+    ("->"              nil     2       caml-->-indent)
+    ("\["              t       8       caml-lb-indent)
+    ("{"               t       8       caml-lc-indent)
+    ("\("              t       8       caml-lp-indent)
+    ("|"               nil     2       caml-no-indent))
+; if-else and let-in are not keywords but idioms
+; "|" is not in the regexps
+; all these 3 values correspond to hard-coded names
+
+"Association list of indentation values based on governing keywords.
+
+Each element is of the form (KEYWORD OP-TYPE PRIO INDENT). OP-TYPE is
+non-nil for operator-type nodes, which affect indentation in a
+different way from keywords: subsequent lines are indented to the
+actual occurrence of an operator, but relative to the indentation of
+the line where the governing keyword occurs.")
+
+;;Originally, we had caml-kwop-regexp create these at runtime, from an
+;;additional field in caml-kwop-alist. That proved way too slow,
+;;although I still can't understand why. itz
+
+(defconst caml-kwop-regexps (make-vector 9 nil)
+  "Array of regexps representing caml keywords of different priorities.")
+
+(aset caml-kwop-regexps 0
+      (concat 
+       "\\<\\(begin\\|class\\|for\\|s\\(ig\\|truct\\)\\|while\\)\\>"
+       "\\|:begin\\>\\|[[({]"))
+(aset caml-kwop-regexps 1
+      (concat (aref caml-kwop-regexps 0) "\\|\\<module\\>"))
+(aset caml-kwop-regexps 2
+      (concat
+       (aref caml-kwop-regexps 1)
+       "\\|\\<\\(fun\\(ction\\)?\\|let\\|m\\(atch\\|ethod\\)"
+       "\\|parser\\|try\\|val\\)\\>\\|->"))
+(aset caml-kwop-regexps 3
+      (concat (aref caml-kwop-regexps 2) "\\|\\<if\\>"))
+(aset caml-kwop-regexps 4
+      (concat (aref caml-kwop-regexps 3) "\\|:=\\|<-"))
+(aset caml-kwop-regexps 5
+      (concat (aref caml-kwop-regexps 4) "\\|@"))
+(aset caml-kwop-regexps 6
+      (concat (aref caml-kwop-regexps 5) "\\|::\\|\\^"))
+(aset caml-kwop-regexps 7
+      (concat
+       (aref caml-kwop-regexps 0)
+       "\\|\\<\\(constraint\\|exception\\|in\\(herit\\|clude\\)"
+       "\\|o\\(f\\|pen\\)\\|type\\|v\\(al\\|irtual\\)\\)\\>"))
+(aset caml-kwop-regexps 8
+      (concat (aref caml-kwop-regexps 6)
+       "\\|\\<\\(constraint\\|exception\\|in\\(herit\\|clude\\)"
+       "\\|o\\(f\\|pen\\)\\|type\\|virtual\\)\\>"))
+
+(defun caml-find-done-match ()
+  (let ((unbalanced 1) (kwop t))
+    (while (and (not (= 0 unbalanced)) kwop)
+      (setq kwop (caml-find-kwop "\\<\\(done\\|for\\|while\\)\\>"))
+      (cond
+       ((not kwop))
+       ((string= kwop "done") (setq unbalanced (1+ unbalanced)))
+       (t (setq unbalanced (1- unbalanced)))))
+    kwop))
+      
+(defun caml-find-end-match ()
+  (let ((unbalanced 1) (kwop t))
+    (while (and (not (= 0 unbalanced)) kwop)
+      (setq kwop
+           (caml-find-kwop
+            "\\<\\(end\\|begin\\|class\\|s\\(ig\\|truct\\)\\)\\>\\|:begin\\>"))
+      (cond
+       ((not kwop))
+       ((string= kwop "end") (setq unbalanced (1+ unbalanced)))
+       ( t (setq unbalanced (1- unbalanced)))))
+    (if (string= kwop ":begin") "begin"
+      kwop)))
+
+(defun caml-find-in-match ()
+  (let ((unbalanced 1) (kwop t))
+    (while (and (not (= 0 unbalanced)) kwop)
+      (setq kwop (caml-find-kwop "\\<\\(in\\|let\\)\\>"))
+      (cond
+       ((not kwop))
+       ((string= kwop "in") (setq unbalanced (1+ unbalanced)))
+       ( t (setq unbalanced (1- unbalanced)))))
+    kwop))
+  
+(defun caml-find-with-match ()
+  (let ((unbalanced 1) (kwop t))
+    (while (and (not (= 0 unbalanced)) kwop)
+      (setq kwop (caml-find-kwop "\\<\\(with\\|try\\|match\\)\\>"))
+      (cond
+       ((not kwop))
+       ((string= kwop "with") (setq unbalanced (1+ unbalanced)))
+       ( t (setq unbalanced (1- unbalanced)))))
+    kwop))
+
+(defun caml-find-then-match (&optional from-else)
+  (let ((bol (if from-else
+                (save-excursion
+                  (progn (beginning-of-line) (point)))))
+       kwop done matching-fun)
+    (while (not done)
+      (setq kwop (caml-find-kwop
+                 "\\<\\(e\\(nd\\|lse\\)\\|done\\|then\\|if\\)\\>\\|[])};]"))
+      (cond
+       ((not kwop) (setq done t))
+       ((caml-at-sexp-close-p)
+       (forward-char 1)
+       (backward-list 1))
+       ((string= kwop "if") (setq done t))
+       ((string= kwop "then")
+       (if (not from-else) (setq kwop (caml-find-then-match))))
+       ((setq matching-fun (cdr-safe (assoc kwop caml-matching-kw-alist)))
+       (setq kwop (funcall matching-fun)))
+       ((string= kwop "then")
+       (if (not from-else) (setq kwop (caml-find-then-match))))))
+    (if (and bol (>= (point) bol))
+       "if-else"
+      kwop)))
+
+(defun caml-find-pipe-match ()
+  (let ((done nil) (kwop)
+       (re (concat
+            "\\<\\(try\\|match\\|with\\|function\\|type"
+            "\\|e\\(nd\\|lse\\)\\|done\\|then\\|in\\)\\>"
+            "\\|[^[|]|\\|[])}]")))
+    (while (not done)
+      (setq kwop (caml-find-kwop re))
+      (cond
+       ((not kwop) (setq done t))
+       ((looking-at "[^[|]\\(|\\)")
+       (goto-char (match-beginning 1))
+       (setq kwop "|")
+       (setq done t))
+       ((caml-at-sexp-close-p)
+       (forward-char 1)
+       (backward-list 1))
+       ((string= kwop "with")
+       (setq kwop (caml-find-with-match))
+       (setq done t))
+       ((string= kwop "done") (caml-find-done-match))
+       ((string= kwop "end") (caml-find-end-match))
+       ((string= kwop "then") (caml-find-then-match))
+       ((string= kwop "else") (caml-find-else-match))
+       ((string= kwop "in") (caml-find-in-match))
+       (t (setq done t))))
+    kwop))
+
+(defun caml-find-and-match ()
+  (let ((done nil) (kwop))
+    (while (not done)
+      (setq kwop (caml-find-kwop
+                 "\\<\\(class\\|exception\\|let\\|type\\|end\\|in\\)\\>"))
+      (cond
+       ((not kwop) (setq done t))
+       ((string= kwop "end") (caml-find-end-match))
+       ((string= kwop "in") (caml-find-in-match))
+       (t (setq done t))))
+    kwop))
+
+(defun caml-find-else-match ()
+  (caml-find-then-match t))
+
+(defun caml-find-semi-match ()
+  (caml-find-kwop-skipping-blocks 2))
+
+(defun caml-find-comma-match ()
+  (caml-find-kwop-skipping-blocks 3))
+
+(defconst caml-matching-kw-regexp
+  (concat
+   "\\<\\(and\\|do\\(ne\\)?\\|e\\(lse\\|nd\\)\\|in\\|t\\(hen\\|o\\)"
+   "\\|with\\)\\>\\|[^[|]|")
+  "Regexp used in caml mode for skipping back over nested blocks.")
+
+(defconst caml-matching-kw-alist
+  '(("|" . caml-find-pipe-match)
+    (";" . caml-find-semi-match)
+    ("," . caml-find-comma-match)
+    ("end" . caml-find-end-match)
+    ("done" . caml-find-done-match)
+    ("in"  . caml-find-in-match)
+    ("with" . caml-find-with-match)
+    ("else" . caml-find-else-match)
+    ("then" . caml-find-then-match)
+    ("to" . caml-find-done-match)
+    ("do" . caml-find-done-match)
+    ("and" . caml-find-and-match))
+
+  "Association list used in caml mode for skipping back over nested blocks.")
+
+(defun caml-find-kwop-skipping-blocks (prio)
+  "Look back for a caml keyword matching caml-kwop-regexps [PRIO].
+
+ Skip nested blocks."
+
+  (let ((done nil) (kwop nil) (matching-fun)
+       (kwop-list (aref caml-kwop-regexps prio)))
+    (while (not done)
+      (setq kwop (caml-find-kwop
+                 (concat caml-matching-kw-regexp
+                         (cond ((> prio 3) "\\|[])},;]\\|")
+                               ((> prio 2) "\\|[])};]\\|")
+                               (t "\\|[])}]\\|"))
+                         kwop-list)))
+      (cond
+       ((not kwop) (setq done t))
+       ((caml-at-sexp-close-p)
+       (forward-char 1)
+       (backward-list 1))
+       ((and (>= prio 2) (string= kwop "|")) (setq done t))
+       ((string= kwop "end") (caml-find-end-match))
+       ((string= kwop "done") (caml-find-done-match))
+       ((string= kwop "in")
+       (cond ((and (caml-find-in-match) (>= prio 2))
+              (setq kwop "let-in")
+              (setq done t))))
+       ((setq matching-fun (cdr-safe (assoc kwop caml-matching-kw-alist)))
+       (setq kwop (funcall matching-fun))
+       (if (looking-at kwop-list) (setq done t)))
+       (t (let* ((kwop-info (assoc kwop caml-kwop-alist))
+                (is-op (nth 1 kwop-info)))
+           (if (and is-op (looking-at 
+                           (concat (regexp-quote kwop)
+                                   "|?[ \t]*\\(\n\\|(\\*\\)")))
+               (setq kwop-list
+                     (aref caml-kwop-regexps (nth 2 kwop-info)))
+             (setq done t))))))
+    kwop))
+
+(defun caml-compute-basic-indent (prio)
+  "Compute indent of current caml line, ignoring leading keywords.
+
+Find the `governing node' for current line. Compute desired
+indentation based on the node and the indentation alists.
+Assumes point is exactly at line indentation.
+Does not preserve point."
+  
+  (let* (in-expr
+        (kwop (cond
+               ((looking-at "|\\([^]|]\\|\\'\\)")
+                (caml-find-pipe-match))
+               ((caml-at-top-let-p)
+                (caml-find-kwop-skipping-blocks 0))
+               ((and (looking-at caml-matching-kw-regexp)
+                     (assoc (caml-match-string 0) caml-matching-kw-alist))
+                (funcall (cdr-safe (assoc (caml-match-string 0)
+                                     caml-matching-kw-alist))))
+               ((looking-at
+                 (aref caml-kwop-regexps caml-max-indent-priority))
+                (let* ((kwop (caml-match-string 0))
+                       (kwop-info (assoc kwop caml-kwop-alist))
+                       (is-op (if kwop-info (nth 1 kwop-info)))
+                       (prio (if kwop-info (nth 2 kwop-info)
+                               caml-max-indent-priority)))
+                  (if (and (looking-at (aref caml-kwop-regexps 0))
+                           (caml-in-expr-p))
+                      (setq in-expr t))
+                  (caml-find-kwop-skipping-blocks prio)))
+               (t
+                (if (and (= prio caml-max-indent-priority) (caml-in-expr-p))
+                    (setq in-expr t))
+                (caml-find-kwop-skipping-blocks prio))))
+        (kwop-info (assoc kwop caml-kwop-alist))
+        (indent-diff
+         (cond
+          ((not kwop-info) (beginning-of-line 1) 0)
+          ((nth 1 kwop-info) (symbol-value (nth 3 kwop-info)))
+          (t (back-to-indentation)
+             (let* ((indent (symbol-value (nth 3 kwop-info)))
+                    (kwop-extra
+                     (if (looking-at "|")
+                         (assoc (caml-match-string 0)
+                                caml-leading-kwops-alist))))
+               (if kwop-extra
+                   (- indent (symbol-value (nth 1 kwop-extra)))
+                 indent)))))
+        (extra (if in-expr caml-apply-extra-indent 0)))
+        (+ indent-diff extra (current-column))))
+
+(defconst caml-leading-kwops-regexp
+  (concat
+   "\\<\\(and\\|do\\(ne\\)?\\|e\\(lse\\|nd\\)\\|in"
+   "\\|t\\(hen\\|o\\)\\|with\\)\\>\\|[]|}]")
+
+  "Regexp matching caml keywords which need special indentation.")
+
+(defconst caml-leading-kwops-alist
+  '(("and" caml-and-extra-indent 2)
+    ("do" caml-do-extra-indent 0)
+    ("done" caml-done-extra-indent 0)
+    ("else" caml-else-extra-indent 3)
+    ("end" caml-end-extra-indent 0)
+    ("in" caml-in-extra-indent 2)
+    ("then" caml-then-extra-indent 3)
+    ("to" caml-to-extra-indent 0)
+    ("with" caml-with-extra-indent 2)
+    ("|" caml-|-extra-indent 2)
+    ("]" caml-rb-extra-indent 0)
+    ("}" caml-rc-extra-indent 0))
+
+  "Association list of special caml keyword indent values.
+
+Each member is of the form (KEYWORD EXTRA-INDENT PRIO) where
+EXTRA-INDENT is the variable holding extra indentation amount for
+KEYWORD (usually negative) and PRIO is upper bound on priority of
+matching nodes to determine KEYWORD's final indentation.")
+
+(defun caml-compute-final-indent ()
+  (save-excursion
+    (back-to-indentation)
+    (cond
+     ((looking-at comment-start-skip)
+      (current-column))
+     ((caml-in-comment-p)
+      (let ((done nil))
+       (while (not done)
+         (up-list -1)
+         (setq done (not (caml-in-comment-p))))
+       (looking-at comment-start-skip)
+       (goto-char (match-end 0))
+       (current-column)))
+     ((caml-at-phrase-start-p) 0)
+     (t (let* ((leading (looking-at caml-leading-kwops-regexp))
+              (assoc-val (if leading (assoc (caml-match-string 0)
+                                            caml-leading-kwops-alist)))
+              (extra (if leading (symbol-value (nth 1 assoc-val)) 0))
+              (prio (if leading (nth 2 assoc-val)
+                      caml-max-indent-priority))
+              (basic (caml-compute-basic-indent prio)))
+         (max 0 (if extra (+ extra basic) (current-column))))))))
+                   
+
+
+(defun caml-split-string ()
+  "Called whenever a line is broken inside a caml string literal."
+  (insert-before-markers "\"^\"")
+  (backward-char 1))
+
+(defadvice indent-new-comment-line (around
+                                   caml-indent-new-comment-line
+                                   activate)
+  
+  "Handle multi-line strings in caml mode."
+
+;this advice doesn't make sense in other modes. I wish there were a
+;cleaner way to do this: I haven't found one.
+
+  (let ((hooked (and (eq major-mode 'caml-mode) (caml-in-literal-p)))
+       (split-mark))
+    (if (not hooked) nil
+      (setq split-mark (set-marker (make-marker) (point)))
+      (caml-split-string))
+    ad-do-it
+    (if (not hooked) nil
+      (goto-char split-mark)
+      (set-marker split-mark nil))))  
+  
+(defadvice newline-and-indent (around
+                              caml-newline-and-indent
+                              activate)
+
+  "Handle multi-line strings in caml mode."
+
+    (let ((hooked (and (eq major-mode 'caml-mode) (caml-in-literal-p)))
+       (split-mark))
+    (if (not hooked) nil
+      (setq split-mark (set-marker (make-marker) (point)))
+      (caml-split-string))
+    ad-do-it
+    (if (not hooked) nil
+      (goto-char split-mark)
+      (set-marker split-mark nil))))
+
+(defun caml-electric-pipe ()
+  "If inserting a | or } operator at beginning of line, reindent the line.
+
+Unfortunately there is a situation where this mechanism gets
+confused. It's when | is the first character of a |] sequence. This is
+a misfeature of caml syntax and cannot be fixed, however, as a
+workaround, the electric ] inserts | itself if the matching [ is
+followed by |."
+  
+  (interactive "*")
+  (let ((electric (and caml-electric-indent
+                      (caml-in-indentation)
+                      (not (caml-in-comment-p)))))
+    (self-insert-command 1)
+    (if electric
+       (let ((indent
+              (save-excursion
+                (backward-char 1)
+                (caml-indent-command)
+                (current-column))))
+         (indent-to (- indent
+                       (symbol-value
+                        (nth 1 (assoc
+                                (char-to-string last-command-char)
+                                caml-leading-kwops-alist)))))))))
+
+(defun caml-electric-rb ()
+  "If inserting a ] operator at beginning of line, reindent the line.
+
+Also, if the matching [ is followed by a | and this ] is not preceded
+by |, insert one."
+
+  (interactive "*")
+  (let* ((prec (preceding-char))
+        (look-pipe (and caml-electric-close-vector
+                        (not (caml-in-comment-p))
+                        (not (caml-in-literal-p))
+                        (or (not (numberp prec))
+                            (not (char-equal ?| prec)))
+                        (set-marker (make-marker) (point))))
+        (electric (and caml-electric-indent
+                       (caml-in-indentation)
+                       (not (caml-in-comment-p)))))
+    (self-insert-command 1)
+    (if electric
+       (let ((indent
+              (save-excursion
+                (backward-char 1)
+                (caml-indent-command)
+                (current-column))))
+         (indent-to (- indent
+                       (symbol-value
+                        (nth 1 (assoc
+                                (char-to-string last-command-char)
+                                caml-leading-kwops-alist)))))))
+    (if look-pipe
+       (save-excursion
+         (let ((insert-pipe
+                (condition-case nil
+                    (prog2
+                      (backward-list 1)
+                      (if (looking-at "\\[|") "|" ""))
+                  (error ""))))
+           (goto-char look-pipe)
+           (insert insert-pipe))
+         (set-marker look-pipe nil)))))                 
+
+(defun caml-abbrev-hook ()
+  "If inserting a leading keyword at beginning of line, reindent the line."
+  ;itz unfortunately we need a special case 
+  (if (and (not (caml-in-comment-p)) (not (= last-command-char ?_)))
+      (let* ((bol (save-excursion (beginning-of-line) (point)))
+            (kw (save-excursion
+                  (and (re-search-backward "^[ \t]*\\(\\sw+\\)\\=" bol t)
+                       (caml-match-string 1)))))
+       (if kw
+           (let ((indent (save-excursion
+                           (goto-char (match-beginning 1))
+                           (caml-indent-command)
+                           (current-column)))
+                 (abbrev-correct (if (= last-command-char ?\ ) 1 0)))
+             (indent-to (- indent
+                           (symbol-value
+                            (nth 1 (assoc kw caml-leading-kwops-alist)))
+                           abbrev-correct)))))))
+
+(defun caml-indent-phrase ()
+  (interactive "*")
+  (let ((bounds (caml-mark-phrase)))
+    (indent-region (car bounds) (cdr bounds) nil)))
+
+(defun caml-backward-to-less-indent (&optional n)
+  "Move cursor back  N lines with less or same indentation."
+  (interactive "p")
+  (beginning-of-line 1)
+  (if (< n 0) (caml-forward-to-less-indent (- n))
+    (while (> n 0)
+      (let ((i (current-indentation)))
+       (forward-line -1)
+       (while (or (> (current-indentation) i)
+                  (caml-in-comment-p)
+                  (looking-at
+                   (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
+         (forward-line -1)))
+      (setq n (1- n))))
+  (back-to-indentation))
+
+(defun caml-forward-to-less-indent (&optional n)
+  "Move cursor back N lines with less or same indentation."
+  (interactive "p")
+  (beginning-of-line 1)
+  (if (< n 0) (caml-backward-to-less-indent (- n))
+    (while (> n 0)
+      (let ((i (current-indentation)))
+       (forward-line 1)
+       (while (or (> (current-indentation) i)
+                  (caml-in-comment-p)
+                  (looking-at
+                   (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
+         (forward-line 1)))
+      (setq n (1- n))))
+  (back-to-indentation))  
+
+(defun caml-insert-begin-form ()
+  "Inserts a nicely formatted begin-end form, leaving a mark after end."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-begin-indent c)))
+    (insert "begin\n\nend")
+    (push-mark)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)))
+
+(defun caml-insert-for-form ()
+  "Inserts a nicely formatted for-do-done form, leaving a mark after do(ne)."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-for-indent c)))
+    (insert "for  do\n\ndone")
+    (push-mark)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)
+    (push-mark)
+    (beginning-of-line 1)
+    (backward-char 4)))
+  
+(defun caml-insert-if-form ()
+  "Insert nicely formatted if-then-else form leaving mark after then, else."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-if-indent c)))
+    (insert "if\n\nthen\n\nelse\n")
+    (indent-line-to i)
+    (push-mark)
+    (forward-line -1)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)
+    (push-mark)
+    (forward-line -1)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)))
+
+(defun caml-insert-match-form ()
+  "Insert nicely formatted match-with form leaving mark after with."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-match-indent c)))
+    (insert "match\n\nwith\n")
+    (indent-line-to i)
+    (push-mark)
+    (forward-line -1)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)))
+
+(defun caml-insert-let-form ()
+  "Insert nicely formatted let-in form leaving mark after in."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)))
+    (insert "let  in\n")
+    (indent-line-to c)
+    (push-mark)
+    (forward-line -1)
+    (forward-char (+ c 4))))
+
+(defun caml-insert-try-form ()
+  "Insert nicely formatted try-with form leaving mark after with."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-try-indent c)))
+    (insert "try\n\nwith\n")
+    (indent-line-to i)
+    (push-mark)
+    (forward-line -1)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)))
+
+(defun caml-insert-while-form ()
+  "Insert nicely formatted while-do-done form leaving mark after do, done."
+  (interactive "*")
+  (let ((prec (preceding-char)))
+    (if (and (numberp prec) (not (char-equal ?\  (char-syntax prec))))
+       (insert " ")))
+  (let* ((c (current-indentation)) (i (+ caml-if-indent c)))
+    (insert "while  do\n\ndone")
+    (push-mark)
+    (indent-line-to c)
+    (forward-line -1)
+    (indent-line-to i)
+    (push-mark)
+    (beginning-of-line 1)
+    (backward-char 4)))
+
+;;; caml.el ends here
+
+(provide 'caml)
diff --git a/camldebug.el b/camldebug.el
new file mode 100644
index 0000000..b74c9a7
--- /dev/null
+++ b/camldebug.el
@@ -0,0 +1,753 @@
+;;; Run camldebug under Emacs
+;;; Derived from gdb.el.
+;;; gdb.el is Copyright (C) 1988 Free Software Foundation, Inc, and is part
+;;; of GNU Emacs
+;;; Modified by Jerome Vouillon, 1994.
+;;; Modified by Ian T. Zimmerman, 1996.
+;;; Modified by Xavier Leroy, 1997.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 1, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;;itz 04-06-96 I pondered basing this on gud. The potential advantages
+;;were: automatic bugfix , keymaps and menus propagation.
+;;Disadvantages: gud is not so clean itself, there is little common
+;;functionality it abstracts (most of the stuff is done in the
+;;debugger specific parts anyway), and, most seriously, gud sees it
+;;fit to add C-x C-a bindings to the _global_ map, so there would be a
+;;conflict between camldebug and gdb, for instance. While it's OK to
+;;assume that a sane person doesn't use gdb and dbx at the same time,
+;;it's not so OK (IMHO) for gdb and camldebug.
+
+;; Xavier Leroy, 21/02/97: adaptation to ocamldebug.
+
+(require 'comint)
+(require 'shell)
+(require 'caml)
+(require 'derived)
+(require 'thingatpt)
+
+;;; Variables.
+
+(defvar camldebug-last-frame)
+(defvar camldebug-delete-prompt-marker)
+(defvar camldebug-filter-accumulator nil)
+(defvar camldebug-last-frame-displayed-p)
+(defvar camldebug-filter-function)
+
+(defvar camldebug-prompt-pattern "^(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
+ (window-system
+  (make-face 'camldebug-event)
+  (make-face 'camldebug-underline)
+  (if (not (face-differs-from-default-p 'camldebug-event))
+      (invert-face 'camldebug-event))
+  (if (not (face-differs-from-default-p 'camldebug-underline))
+      (set-face-underline-p 'camldebug-underline t))
+  (setq camldebug-overlay-event (make-overlay 1 1))
+  (overlay-put camldebug-overlay-event 'face 'camldebug-event)
+  (setq camldebug-overlay-under (make-overlay 1 1))
+  (overlay-put camldebug-overlay-under 'face 'camldebug-underline))
+ (t
+  (setq camldebug-event-marker (make-marker))
+  (setq overlay-arrow-string "=>")))
+
+;;; Camldebug mode.
+
+(define-derived-mode camldebug-mode comint-mode "Inferior CDB"
+
+  "Major mode for interacting with an inferior Camldebug process.
+
+The following commands are available:
+
+\\{camldebug-mode-map}
+
+\\[camldebug-display-frame] displays in the other window
+the last line referred to in the camldebug buffer.
+
+\\[camldebug-step], \\[camldebug-back] and \\[camldebug-next], in the 
camldebug window,
+call camldebug to step, backstep or next and then update the other window
+with the current file and position.
+
+If you are in a source file, you may select a point to break
+at, by doing \\[camldebug-break].
+
+Commands:
+Many commands are inherited from comint mode. 
+Additionally we have:
+
+\\[camldebug-display-frame] display frames file in other window
+\\[camldebug-step] advance one line in program
+C-x SPACE sets break point at current line."
+
+  (mapcar 'make-local-variable
+         '(camldebug-last-frame-displayed-p  camldebug-last-frame
+           camldebug-delete-prompt-marker camldebug-filter-function
+           camldebug-filter-accumulator))
+  (setq
+   camldebug-last-frame nil
+   camldebug-delete-prompt-marker (make-marker)
+   camldebug-filter-accumulator ""
+   camldebug-filter-function 'camldebug-marker-filter
+   comint-prompt-regexp camldebug-prompt-pattern
+   comint-dynamic-complete-functions (cons 'camldebug-complete
+                                          comint-dynamic-complete-functions)
+   paragraph-start comint-prompt-regexp
+   camldebug-last-frame-displayed-p t)
+  (make-local-variable 'shell-dirtrackp)
+  (setq shell-dirtrackp t)
+  (setq comint-input-sentinel 'shell-directory-tracker))
+
+;;; Keymaps.
+
+(defun camldebug-numeric-arg (arg)
+  (and arg (prefix-numeric-value arg)))
+
+(defmacro def-camldebug (name key &optional doc args)
+
+  "Define camldebug-NAME to be a command sending NAME ARGS and bound
+to KEY, with optional doc string DOC.  Certain %-escapes in ARGS are
+interpreted specially if present.  These are:
+
+  %m   module name of current module. 
+  %d   directory of current source file. 
+  %c   number of current character position
+  %e   text of the caml variable surrounding point.
+
+  The `current' source file is the file of the current buffer (if
+we're in a caml buffer) or the source file current at the last break
+or step (if we're in the camldebug buffer), and the `current' module
+name is the filename stripped of any *.ml* suffixes (this assumes the
+usual correspondence between module and file naming is observed).  The
+`current' position is that of the current buffer (if we're in a source
+file) or the position of the last break or step (if we're in the
+camldebug buffer).
+
+If a numeric is present, it overrides any ARGS flags and its string
+representation is simply concatenated with the COMMAND."
+
+  (let* ((fun (intern (format "camldebug-%s" name))))
+    (list 'progn
+         (if doc
+             (list 'defun fun '(arg)
+                   doc 
+                   '(interactive "P")
+                   (list 'camldebug-call name args
+                         '(camldebug-numeric-arg arg))))
+         (list 'define-key 'camldebug-mode-map
+               (concat "\C-c" key)
+               (list 'quote fun))
+         (list 'define-key 'caml-mode-map
+               (concat "\C-x\C-a" key)
+               (list 'quote fun)))))
+
+(def-camldebug "step"  "\C-s"  "Step one 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 "finish" "\C-f" "Finish executing current function.")
+(def-camldebug "print" "\C-p"  "Print value of symbol at point."       "%e")
+(def-camldebug "display" "\C-d"        "Display value of symbol at point."     
"%e")
+(def-camldebug "next"   "\C-n" "Step one 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-mouse-display (click)
+  "Display value of symbol clicked on."
+  (interactive "e")
+  (let* ((start (event-start click))
+        (window (car start))
+        (pos (car (cdr start))))
+    (save-excursion
+      (select-window window)
+      (goto-char pos)
+      (camldebug-call "display" "%e"))))
+
+(define-key camldebug-mode-map [mouse-2] 'camldebug-mouse-display)
+
+(defun camldebug-kill-filter (string)
+  ;gob up stupid questions :-)
+  (setq camldebug-filter-accumulator
+       (concat camldebug-filter-accumulator string))
+  (if (not (string-match "\\(.* \\)(y or n) "
+                        camldebug-filter-accumulator)) nil
+    (setq camldebug-kill-output
+         (cons t (match-string 1 camldebug-filter-accumulator)))
+    (setq camldebug-filter-accumulator ""))
+  (if (string-match comint-prompt-regexp camldebug-filter-accumulator)
+      (let ((output (substring camldebug-filter-accumulator
+                              (match-beginning 0))))
+       (setq camldebug-kill-output 
+             (cons nil (substring camldebug-filter-accumulator 0
+                                  (1- (match-beginning 0)))))
+       (setq camldebug-filter-accumulator "")
+       output)
+    ""))
+
+(def-camldebug "kill"  "\C-k")
+
+(defun camldebug-kill ()
+  "Kill the program."
+  (interactive)
+  (let ((camldebug-kill-output))
+    (save-excursion
+      (set-buffer current-camldebug-buffer)
+      (let ((proc (get-buffer-process (current-buffer)))
+           (camldebug-filter-function 'camldebug-kill-filter))
+       (camldebug-call "kill")
+       (while (not (and camldebug-kill-output
+                        (zerop (length camldebug-filter-accumulator))))
+         (accept-process-output proc))))
+    (if (not (car camldebug-kill-output))
+       (error (cdr camldebug-kill-output))
+      (sit-for 0 300)
+      (camldebug-call-1 (if (y-or-n-p (cdr camldebug-kill-output)) "y" "n")))))
+;;FIXME: camldebug doesn't output the Hide marker on kill
+
+(defun camldebug-goto-filter (string)
+  ;accumulate onto previous output
+  (setq camldebug-filter-accumulator
+       (concat camldebug-filter-accumulator string))
+  (if (not (string-match (concat "\\(\n\\|\\`\\)[ \t]*\\([0-9]+\\)[ \t]+"
+                         camldebug-goto-position
+                         "[ \t]*\\(before\\|after\\)\n")
+                 camldebug-filter-accumulator)) nil
+    (setq camldebug-goto-output
+         (match-string 2 camldebug-filter-accumulator))
+    (setq camldebug-filter-accumulator
+         (substring camldebug-filter-accumulator (1- (match-end 0)))))
+  (if (not (string-match comint-prompt-regexp
+                        camldebug-filter-accumulator)) nil
+    (setq camldebug-goto-output (or camldebug-goto-output 'fail))
+    (setq camldebug-filter-accumulator ""))
+  (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator)
+      (setq camldebug-filter-accumulator
+           (match-string 1 camldebug-filter-accumulator)))
+  "")
+
+(def-camldebug "goto" "\C-g")
+(defun camldebug-goto (&optional time)
+
+  "Go to the execution time TIME.
+
+Without TIME, the command behaves as follows: In the camldebug buffer,
+if the point at buffer end, goto time 0\; otherwise, try to obtain the 
+time from context around point. In a caml mode buffer, try to find the
+time associated in execution history with the current point location.
+
+With a negative TIME, move that many lines backward in the camldebug
+buffer, then try to obtain the time from context around point."
+
+  (interactive "P")
+  (cond
+   (time
+    (let ((ntime (camldebug-numeric-arg time)))
+      (if (>= ntime 0) (camldebug-call "goto" nil ntime)
+       (save-selected-window
+         (select-window (get-buffer-window current-camldebug-buffer))
+         (save-excursion
+           (if (re-search-backward "^Time : [0-9]+ - pc : [0-9]+ "
+                                   nil t (- 1 ntime))
+               (camldebug-goto nil)
+             (error "I don't have %d times in my history"
+                    (- 1 ntime))))))))
+   ((eq (current-buffer) current-camldebug-buffer)
+      (let ((time (cond
+                  ((eobp) 0)
+                  ((save-excursion
+                     (beginning-of-line 1)
+                     (looking-at "^Time : \\([0-9]+\\) - pc : [0-9]+ "))
+                   (string-to-int (match-string 1)))
+                  ((string-to-int (camldebug-format-command "%e"))))))
+       (camldebug-call "goto" nil time)))
+   (t
+    (let ((module (camldebug-module-name (buffer-file-name)))
+         (camldebug-goto-position (int-to-string (1- (point))))
+         (camldebug-goto-output) (address))
+      ;get a list of all events in the current module
+      (save-excursion
+       (set-buffer current-camldebug-buffer)
+       (let* ((proc (get-buffer-process (current-buffer)))
+              (camldebug-filter-function 'camldebug-goto-filter))
+         (camldebug-call-1 (concat "info events " module))
+         (while (not (and camldebug-goto-output
+                     (zerop (length camldebug-filter-accumulator))))
+           (accept-process-output proc))
+         (setq address (if (eq camldebug-goto-output 'fail) nil
+                         (re-search-backward
+                          (concat "^Time : \\([0-9]+\\) - pc : "
+                                  camldebug-goto-output
+                                  " - module "
+                                  module "$") nil t)
+                         (match-string 1)))))
+      (if address (camldebug-call "goto" nil (string-to-int address))
+       (error "No time at %s at %s" module camldebug-goto-position))))))
+
+
+(defun camldebug-delete-filter (string)
+  (setq camldebug-filter-accumulator
+       (concat camldebug-filter-accumulator string))
+  (if (not (string-match
+           (concat "\\(\n\\|\\`\\)[ \t]*\\([0-9]+\\)[ \t]+[0-9]+[ \t]*in "
+                   (regexp-quote camldebug-delete-file)
+                   ", character "
+                   camldebug-delete-position "\n")
+                 camldebug-filter-accumulator)) nil
+    (setq camldebug-delete-output
+         (match-string 2 camldebug-filter-accumulator))
+    (setq camldebug-filter-accumulator
+         (substring camldebug-filter-accumulator (1- (match-end 0)))))
+  (if (not (string-match comint-prompt-regexp
+                        camldebug-filter-accumulator)) nil
+    (setq camldebug-delete-output (or camldebug-delete-output 'fail))
+    (setq camldebug-filter-accumulator ""))
+  (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator)
+      (setq camldebug-filter-accumulator
+           (match-string 1 camldebug-filter-accumulator)))
+  "")
+  
+
+(def-camldebug "delete" "\C-d")
+
+(defun camldebug-delete (&optional arg)
+  "Delete the breakpoint numbered ARG.
+
+Without ARG, the command behaves as follows: In the camldebug buffer,
+try to obtain the time from context around point. In a caml mode
+buffer, try to find the breakpoint associated with the current point
+location.
+
+With a negative ARG, look for the -ARGth breakpoint pattern in the
+camldebug buffer, then try to obtain the breakpoint info from context
+around point."
+
+  (interactive "P")
+  (cond
+   (arg
+    (let ((narg (camldebug-numeric-arg arg)))
+      (if (> narg 0) (camldebug-call "delete" nil narg)
+       (save-excursion
+         (set-buffer current-camldebug-buffer)
+         (if (re-search-backward "^Breakpoint [0-9]+ at [0-9]+ : file "
+                                 nil t (- 1 narg))
+             (camldebug-delete nil)
+           (error "I don't have %d breakpoints in my history"
+                    (- 1 narg)))))))
+   ((eq (current-buffer) current-camldebug-buffer)
+    (let* ((bpline "^Breakpoint \\([0-9]+\\) at [0-9]+ : file ")
+          (arg (cond
+                ((eobp)
+                 (save-excursion (re-search-backward bpline nil t))
+                 (string-to-int (match-string 1)))
+                ((save-excursion
+                   (beginning-of-line 1)
+                   (looking-at bpline))
+                 (string-to-int (match-string 1)))
+                ((string-to-int (camldebug-format-command "%e"))))))
+      (camldebug-call "delete" nil arg)))
+   (t
+    (let ((camldebug-delete-file
+          (concat (camldebug-format-command "%m") ".ml"))
+         (camldebug-delete-position (camldebug-format-command "%c")))
+      (save-excursion
+       (set-buffer current-camldebug-buffer)
+       (let ((proc (get-buffer-process (current-buffer)))
+             (camldebug-filter-function 'camldebug-delete-filter)
+             (camldebug-delete-output))
+         (camldebug-call-1 "info break")
+         (while (not (and camldebug-delete-output
+                          (zerop (length
+                                  camldebug-filter-accumulator))))
+           (accept-process-output proc))
+         (if (eq camldebug-delete-output 'fail)
+             (error "No breakpoint in %s at %s"
+                    camldebug-delete-file
+                    camldebug-delete-position)   
+           (camldebug-call "delete" nil
+                           (string-to-int camldebug-delete-output)))))))))  
+
+(defun camldebug-complete-filter (string)
+  (setq camldebug-filter-accumulator
+       (concat camldebug-filter-accumulator string))
+  (while (string-match "\\(\n\\|\\`\\)\\(.+\\)\n"
+                      camldebug-filter-accumulator) 
+    (setq camldebug-complete-list
+         (cons (match-string 2 camldebug-filter-accumulator)
+               camldebug-complete-list))
+    (setq camldebug-filter-accumulator
+         (substring camldebug-filter-accumulator
+                    (1- (match-end 0)))))
+  (if (not (string-match comint-prompt-regexp
+                        camldebug-filter-accumulator)) nil
+    (setq camldebug-complete-list
+         (or camldebug-complete-list 'fail))
+    (setq camldebug-filter-accumulator ""))
+  (if (string-match "\n\\(.*\\)\\'" camldebug-filter-accumulator)
+      (setq camldebug-filter-accumulator
+           (match-string 1 camldebug-filter-accumulator)))
+  "")
+     
+(defun camldebug-complete ()
+
+  "Perform completion on the camldebug command preceding point."
+
+  (interactive)
+  (let* ((end (point))
+        (command (save-excursion
+                   (beginning-of-line)
+                   (and (looking-at comint-prompt-regexp)
+                        (goto-char (match-end 0)))
+                   (buffer-substring (point) end)))
+        (camldebug-complete-list nil) (command-word))
+
+    ;; Find the word break.  This match will always succeed.
+    (string-match "\\(\\`\\| \\)\\([^ ]*\\)\\'" command)
+    (setq command-word (match-string 2 command))
+    
+    ;itz 04-21-96 if we are trying to complete a word of nonzero
+    ;length, chop off the last character. This is a nasty hack, but it
+    ;works - in general, not just for this set of words: the comint
+    ;call below will weed out false matches - and it avoids further
+    ;mucking with camldebug's lexer.
+    (if (> (length command-word) 0)
+       (setq command (substring command 0 (1- (length command)))))
+    
+    (let ((camldebug-filter-function 'camldebug-complete-filter))
+      (camldebug-call-1 (concat "complete " command))
+      (set-marker camldebug-delete-prompt-marker nil)
+      (while (not (and camldebug-complete-list
+                      (zerop (length camldebug-filter-accumulator))))
+       (accept-process-output (get-buffer-process
+                               (current-buffer)))))
+    (if (eq camldebug-complete-list 'fail)
+       (setq camldebug-complete-list nil))
+    (setq camldebug-complete-list
+         (sort camldebug-complete-list 'string-lessp))
+    (comint-dynamic-simple-complete command-word camldebug-complete-list)))
+       
+(define-key camldebug-mode-map "\C-l" 'camldebug-refresh)
+(define-key camldebug-mode-map "\t" 'comint-dynamic-complete)
+(define-key camldebug-mode-map "\M-?" 'comint-dynamic-list-completions)
+
+(define-key caml-mode-map "\C-x " 'camldebug-break)
+
+
+(defvar current-camldebug-buffer nil)
+
+
+;;;###autoload
+(defvar camldebug-command-name "ocamldebug"
+  "Pathname for executing camldebug.")
+
+;;;###autoload
+(defun camldebug (path)
+  "Run camldebug on program FILE in buffer *camldebug-FILE*.
+The directory containing FILE becomes the initial working directory
+and source-file directory for camldebug.  If you wish to change this, use
+the camldebug commands `cd DIR' and `directory'."
+  (interactive "fRun 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)
+    (make-comint (concat "camldebug-" file)
+                (substitute-in-file-name camldebug-command-name)
+                nil
+                "-emacs" "-cd" default-directory file)
+    (set-process-filter (get-buffer-process (current-buffer))
+                       'camldebug-filter)
+    (set-process-sentinel (get-buffer-process (current-buffer))
+                         'camldebug-sentinel)
+    (camldebug-mode)
+    (camldebug-set-buffer)))
+
+(defun camldebug-set-buffer ()
+  (if (eq major-mode 'camldebug-mode)
+      (setq current-camldebug-buffer (current-buffer))
+    (save-selected-window (pop-to-buffer current-camldebug-buffer))))
+
+;;; Filter and sentinel.
+
+(defun camldebug-marker-filter (string)
+  (setq camldebug-filter-accumulator
+       (concat camldebug-filter-accumulator string))
+  (let ((output "") (begin))
+    ;; Process all the complete markers in this chunk.
+    (while (setq begin
+                (string-match 
+                 "\032\032\\(H\\|M\\(.+\\):\\(.+\\):\\(before\\|after\\)\\)\n"
+                 camldebug-filter-accumulator))
+      (setq camldebug-last-frame
+           (if (char-equal ?H (aref camldebug-filter-accumulator
+                                    (1+ (1+ begin)))) nil
+             (list (match-string 2 camldebug-filter-accumulator)
+                   (string-to-int
+                    (match-string 3 camldebug-filter-accumulator))
+                   (string= "before"
+                            (match-string 4
+                                          camldebug-filter-accumulator))))
+           output (concat output
+                          (substring camldebug-filter-accumulator
+                                     0 begin))
+           ;; Set the accumulator to the remaining text.
+           camldebug-filter-accumulator (substring
+                                         camldebug-filter-accumulator
+                                         (match-end 0))
+           camldebug-last-frame-displayed-p nil))
+
+    ;; Does the remaining text look like it might end with the
+    ;; beginning of another marker?  If it does, then keep it in
+    ;; camldebug-filter-accumulator until we receive the rest of it.  Since we
+    ;; know the full marker regexp above failed, it's pretty simple to
+    ;; test for marker starts.
+    (if (string-match "\032.*\\'" camldebug-filter-accumulator)
+       (progn
+         ;; Everything before the potential marker start can be output.
+         (setq output (concat output (substring camldebug-filter-accumulator
+                                                0 (match-beginning 0))))
+
+         ;; Everything after, we save, to combine with later input.
+         (setq camldebug-filter-accumulator
+               (substring camldebug-filter-accumulator (match-beginning 0))))
+
+      (setq output (concat output camldebug-filter-accumulator)
+           camldebug-filter-accumulator ""))
+
+    output))
+
+(defun camldebug-filter (proc string)
+  (let ((output))
+    (if (buffer-name (process-buffer proc))
+       (let ((process-window))
+         (save-excursion
+           (set-buffer (process-buffer proc))
+           ;; If we have been so requested, delete the debugger prompt.
+           (if (marker-buffer camldebug-delete-prompt-marker)
+               (progn
+                 (delete-region (process-mark proc)
+                                camldebug-delete-prompt-marker)
+                 (set-marker camldebug-delete-prompt-marker nil)))
+           (setq output (funcall camldebug-filter-function string))
+           ;; Don't display the specified file unless
+           ;; (1) point is at or after the position where output appears
+           ;; and (2) this buffer is on the screen.
+           (setq process-window (and camldebug-track-frame
+                                     (not camldebug-last-frame-displayed-p)
+                                     (>= (point) (process-mark proc))
+                                     (get-buffer-window (current-buffer))))
+           ;; Insert the text, moving the process-marker.
+           (comint-output-filter proc output))
+         (if process-window
+             (save-selected-window
+               (select-window process-window)
+               (camldebug-display-frame)))))))
+
+(defun camldebug-sentinel (proc msg)
+  (cond ((null (buffer-name (process-buffer proc)))
+        ;; buffer killed
+        ;; Stop displaying an arrow in a source file.
+        (camldebug-remove-current-event)
+        (set-process-buffer proc nil))
+       ((memq (process-status proc) '(signal exit))
+        ;; Stop displaying an arrow in a source file.
+        (camldebug-remove-current-event)
+        ;; Fix the mode line.
+        (setq mode-line-process
+              (concat ": "
+                      (symbol-name (process-status proc))))
+        (let* ((obuf (current-buffer)))
+          ;; save-excursion isn't the right thing if
+          ;;  process-buffer is current-buffer
+          (unwind-protect
+              (progn
+                ;; Write something in *compilation* and hack its mode line,
+                (set-buffer (process-buffer proc))
+                ;; Force mode line redisplay soon
+                (set-buffer-modified-p (buffer-modified-p))
+                (if (eobp)
+                    (insert ?\n mode-name " " msg)
+                  (save-excursion
+                    (goto-char (point-max))
+                    (insert ?\n mode-name " " msg)))
+                ;; If buffer and mode line will show that the process
+                ;; is dead, we can delete it now.  Otherwise it
+                ;; will stay around until M-x list-processes.
+                (delete-process proc))
+            ;; Restore old buffer, but don't restore old point
+            ;; if obuf is the cdb buffer.
+            (set-buffer obuf))))))
+
+
+(defun camldebug-refresh (&optional arg)
+  "Fix up a possibly garbled display, and redraw the mark."
+  (interactive "P")
+  (camldebug-display-frame)
+  (recenter arg))
+
+(defun camldebug-display-frame ()
+  "Find, obey and delete the last filename-and-line marker from CDB.
+The marker looks like \\032\\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 (car camldebug-last-frame)
+                           (car (cdr camldebug-last-frame))
+                           (cdr (cdr 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 character 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))
+        (pos))
+    (save-excursion
+      (set-buffer buffer)
+      (save-restriction
+       (widen)
+       (setq pos (+ (point-min) character))
+       (camldebug-set-current-event 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 window-system
+      (progn
+        (delete-overlay camldebug-overlay-event)
+        (delete-overlay camldebug-overlay-under))
+    (setq overlay-arrow-position nil)))
+
+(defun camldebug-set-current-event (pos buffer before)
+  (if window-system
+      (progn
+        (if (save-excursion
+              (set-buffer buffer)
+              (goto-char (1+ pos))
+              (looking-at "\n"))
+            (setq pos (1- pos)))
+        (move-overlay camldebug-overlay-event pos (1+ pos) buffer)
+        (if before
+            (move-overlay camldebug-overlay-under (+ pos 1) (+ pos 3) buffer)
+          (move-overlay camldebug-overlay-under (- pos 2) pos buffer)))
+    (save-excursion
+      (set-buffer buffer)
+      (goto-char pos)
+      (beginning-of-line)
+      (move-marker camldebug-event-marker (point))
+      (setq overlay-arrow-position camldebug-event-marker))))
+
+;;; Miscellaneous.
+
+(defun camldebug-module-name (filename)
+  (substring filename (string-match "\\([^/]*\\)\\.ml$" filename) (match-end 
1)))
+
+;;; The camldebug-call function must do the right thing whether its
+;;; invoking keystroke is from the camldebug buffer itself (via
+;;; major-mode binding) or a caml buffer.  In the former case, we want
+;;; to supply data from camldebug-last-frame.  Here's how we do it:
+
+(defun camldebug-format-command (str)
+  (let* ((insource (not (eq (current-buffer) current-camldebug-buffer)))
+       (frame (if insource nil camldebug-last-frame)) (result))
+    (while (and str (string-match "\\([^%]*\\)%\\([mdcep]\\)" str))
+      (let ((key (string-to-char (substring str (match-beginning 2))))
+           (cmd (substring str (match-beginning 1) (match-end 1)))
+           (subst))
+       (setq str (substring str (match-end 2)))
+       (cond
+        ((eq key ?m)
+         (setq subst (camldebug-module-name
+                      (if insource (buffer-file-name) (nth 0 frame)))))
+        ((eq key ?d)
+         (setq subst (file-name-directory
+                      (if insource (buffer-file-name) (nth 0 frame)))))
+        ((eq key ?c)
+         (setq subst (int-to-string
+                      (if insource (1- (point)) (nth 1 frame)))))
+        ((eq key ?e)
+         (setq subst (thing-at-point 'symbol))))
+       (setq result (concat result cmd subst))))
+    ;; There might be text left in STR when the loop ends.
+    (concat result str)))
+
+(defun camldebug-call (command &optional fmt arg)
+  "Invoke camldebug COMMAND displaying source in other window.
+
+Certain %-escapes in FMT are interpreted specially if present.
+These are:
+
+  %m   module name of current module. 
+  %d   directory of current source file. 
+  %c   number of current character position
+  %e   text of the caml variable surrounding point.
+
+  The `current' source file is the file of the current buffer (if
+we're in a caml buffer) or the source file current at the last break
+or step (if we're in the camldebug buffer), and the `current' module
+name is the filename stripped of any *.ml* suffixes (this assumes the
+usual correspondence between module and file naming is observed).  The
+`current' position is that of the current buffer (if we're in a source
+file) or the position of the last break or step (if we're in the
+camldebug buffer).
+
+If ARG is present, it overrides any FMT flags and its string
+representation is simply concatenated with the COMMAND."
+
+  ;; Make sure debugger buffer is displayed in a window.
+  (camldebug-set-buffer)
+  (message "Command: %s" (camldebug-call-1 command fmt arg)))
+
+(defun camldebug-call-1 (command &optional fmt arg)
+  
+  ;; Record info on the last prompt in the buffer and its position.
+  (save-excursion
+    (set-buffer current-camldebug-buffer)
+    (goto-char (process-mark (get-buffer-process current-camldebug-buffer)))
+    (let ((pt (point)))
+      (beginning-of-line)
+      (if (looking-at comint-prompt-regexp)
+         (set-marker camldebug-delete-prompt-marker (point)))))
+  (let ((cmd (cond
+             (arg (concat command " " (int-to-string arg)))
+             (fmt (camldebug-format-command
+                   (concat command " " fmt)))
+             (command))))
+    (process-send-string (get-buffer-process current-camldebug-buffer)
+                        (concat cmd "\n"))
+    cmd))
+
+
+(provide 'camldebug)
diff --git a/inf-caml.el b/inf-caml.el
new file mode 100644
index 0000000..e573b4c
--- /dev/null
+++ b/inf-caml.el
@@ -0,0 +1,100 @@
+;;; inf-caml.el --- run the Caml toplevel in an Emacs buffer
+
+;; Xavier Leroy, july 1993.
+
+(require 'comint)
+(require 'caml)
+
+(defvar inferior-caml-mode-map nil)
+(if inferior-caml-mode-map nil
+  (setq inferior-caml-mode-map
+        (copy-keymap comint-mode-map)))
+
+;; Augment Caml mode, so you can process Caml code in the source files.
+
+(define-key caml-mode-map "\M-\C-x" 'caml-eval-phrase)
+(define-key caml-mode-map "\C-x\C-e" 'caml-eval-phrase)
+(define-key caml-mode-map "\C-c\C-e" 'caml-eval-phrase)
+(define-key caml-mode-map "\C-c\C-r" 'caml-eval-region)
+
+(defvar inferior-caml-program "ocaml"
+  "*Program name for invoking an inferior Caml from Emacs.")
+
+(defun inferior-caml-mode ()
+  "Major mode for interacting with an inferior Caml process.
+Runs a Caml toplevel as a subprocess of Emacs, with I/O through an
+Emacs buffer. A history of input phrases is maintained. Phrases can
+be sent from another buffer in Caml mode.
+
+\\{inferior-caml-mode-map}"
+  (interactive)
+  (comint-mode)
+  (setq comint-prompt-regexp "^# ?")
+  (setq major-mode 'inferior-caml-mode)
+  (setq mode-name "Inferior Caml")
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start (concat "^$\\|" page-delimiter))
+  (make-local-variable 'paragraph-separate)
+  (setq paragraph-separate paragraph-start)
+  (make-local-variable 'paragraph-ignore-fill-prefix)
+  (setq paragraph-ignore-fill-prefix t)
+  (make-local-variable 'require-final-newline)
+  (setq require-final-newline t)
+  (make-local-variable 'comment-start)
+  (setq comment-start "(*")
+  (make-local-variable 'comment-end)
+  (setq comment-end "*)")
+  (make-local-variable 'comment-column)
+  (setq comment-column 40)
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip "(\\*+ *")
+  (make-local-variable 'parse-sexp-ignore-comments)
+  (setq parse-sexp-ignore-comments nil)
+  (use-local-map inferior-caml-mode-map)
+  (run-hooks 'inferior-caml-mode-hooks))
+
+(defun run-caml (cmd)
+  "Run an inferior Caml process.
+Input and output via buffer `*inferior-caml*'."
+  (interactive (list (read-from-minibuffer "Caml command to run: "
+                                           inferior-caml-program)))
+  (setq inferior-caml-program cmd)
+  (if (not (comint-check-proc "*inferior-caml*"))
+      (let ((cmdlist (inferior-caml-args-to-list cmd))
+            (process-connection-type nil))
+       (set-buffer (apply (function make-comint)
+                          "inferior-caml" (car cmdlist) nil (cdr cmdlist)))
+       (inferior-caml-mode)))
+  (switch-to-buffer "*inferior-caml*"))
+
+(defun inferior-caml-args-to-list (string)
+  (let ((where (string-match "[ \t]" string)))
+    (cond ((null where) (list string))
+         ((not (= where 0))
+          (cons (substring string 0 where)
+                (inferior-caml-args-to-list (substring string (+ 1 where)
+                                                       (length string)))))
+         (t (let ((pos (string-match "[^ \t]" string)))
+              (if (null pos)
+                  nil
+                (inferior-caml-args-to-list (substring string pos
+                                                       (length string)))))))))
+
+(defun caml-eval-region (start end)
+  "Send the current region to the inferior Caml process."
+  (interactive"r")
+  (comint-send-region "*inferior-caml*" start end)
+  (comint-send-string "*inferior-caml*" ";;\n")
+  (if (not (get-buffer-window "*inferior-caml*" t))
+      (display-buffer "*inferior-caml*")))
+
+(defun caml-eval-phrase ()
+  "Send the current Caml phrase to the inferior Caml process."
+  (interactive)
+  (save-excursion
+    (let ((bounds (caml-mark-phrase)))
+    (caml-eval-region (car bounds) (cdr bounds)))))
+
+;;; inf-caml.el ends here
+
+(provide 'inf-caml)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]