Commits

Anonymous committed 6a710b3

Synced sml-mode with author's CVS and applied derived-mode autoload workarounds. It actually works now :)

  • Participants
  • Parent commits 2640f0a

Comments (0)

Files changed (17)

 custom-load.el
 package-info
 pdepends.mk
+sml-mode-startup.el
+sml-mode.cp
+sml-mode.cps
+sml-mode.fn
+sml-mode.fns
+sml-mode.info
+sml-mode.ky
+sml-mode.kys
+sml-mode.pg
+sml-mode.tp
+sml-mode.vr
+sml-mode.vrs

File .cvsignore.upstream

-sml-mode-startup.el
-sml-mode.cp
-sml-mode.cps
-sml-mode.fn
-sml-mode.fns
-sml-mode.info
-sml-mode.ky
-sml-mode.kys
-sml-mode.pg
-sml-mode.tp
-sml-mode.vr
-sml-mode.vrs
+2002-08-01  Ville Skyttä  <ville.skytta@xemacs.org>
+
+	* Updated by grabbing the current author version from CVS:
+	cvs -d :pserver:guest@flint.cs.yale.edu:/guest co sml-mode
+
+	* sml-mode.el: Add autoload hacks to make them work out of the
+	box with derived modes.
+
+	* Makefile (VERSION): Bump to 0.02.
+
 2002-06-20  Ville Skyttä  <ville.skytta@xemacs.org>
 
 	* Makefile: Include XEmacs.rules the official way.

File ChangeLog.upstream

+2001-09-18  Stefan Monnier  <monnier@cs.yale.edu>
+
+	* sml-mode.el (sml-tyvarseq-re): Fix typo.
+
+2001-07-20  Stefan Monnier  <monnier@cs.yale.edu>
+
+	* sml-mode.el (sml-rightalign-and): New defcustom.
+	(sml-tyvarseq-re): New var.
+	(sml-font-lock-keywords): Use it.
+	(sml-imenu-create-index): Don't get confused by tyvarseq's.
+	(sml-mode-variables): Don't set `comment-column'.
+	(sml-funname-of-and): New function.
+	(sml-electric-pipe): Use it.
+	(sml-find-comment-indent): Try to ignore comment-markers in strings.
+	(sml-calculate-indentation): Handle closing parens specially.
+	(sml-indent-pipe): Recognize the case where `and' defines a datatype.
+	(sml-dangling-sym): Make it work if the symbol is an open-paren.
+	(sml-indent-default): Change the behavior when preceded by `end',
+	although I'm not quite sure why.
+	Understand dangling open-parens.
+	Properly skip *all* subexpressions of lower precedence.
+	Allow use of sml-symbol-indent to outdent lines starting with , or ;.
+	(sml-insert-form): Use preceding-char to avoid bug at bobp.
+
+2001-07-19  Stefan Monnier  <monnier@cs.yale.edu>
+
+	* sml-proc.el (sml-proc-buffer): Save excursion when calling run-sml.
+
+	* sml-move.el (sml-syntax-prec): Split ; and , from `in' and `with'.
+
+	* sml-mode.texi: Put the entry in `Emacs' rather than `Editors'.
+
+	* sml-mode.spec (BuildArch): Simplify call to `install-info'.
+
+	* sml-defs.el (sml-mode-menu): Add an explicit t for always-active.
+	(sml-symbol-indent): Add entries for , and ; and turn into defcustom.
+
+	* sml-compat.el: Add more stuff.  It might help for Emacs-19.34.
+
+	* makefile.pkg (test): Use elisp files in current dir.
+
 2000-12-24  Stefan Monnier  <monnier@cs.yale.edu>
 
 	* Makefile (install): Also install .el files.
 	(sml-mode): Use them.
 	(sml-beginning-of-defun): Add `and' as function-leader.
 	(sml-lex-mode): New trivial mode.
-	(sml-yacc-bnf-face, sml-yacc-indent-action, sml-yacc-indent-pipe) 
-	(sml-yacc-indent-term, sml-yacc-font-lock-keywords) 
+	(sml-yacc-bnf-face, sml-yacc-indent-action, sml-yacc-indent-pipe)
+	(sml-yacc-indent-term, sml-yacc-font-lock-keywords)
 	(sml-yacc-font-lock-defaults): New vars.
 	(sml-yacc-indent-line, sml-yacc-indentation, sml-yacc-mode): New funs.
 
 	define-derived-mode).
 	(sml-mode): Setup add-log's current-defun-function.
 	(sml-indent-line): Never indent to a negative level.
-	(sml-skip-siblings, sml-beginning-of-defun, sml-max-name-components) 
+	(sml-skip-siblings, sml-beginning-of-defun, sml-max-name-components)
 	(sml-current-fun-name): New funs and vars for add-log support.
 	(sml-comment-indent): Simplify.
 	(sml-def-skeleton): Also create the skeleton as an abbrev.
 	(skeletons): New for "struct", "sig", "val", "fn" and "fun".
 	(sml-electric-space): Rewrite to use abbrev's machinery.
 
-	* sml-defs.el (sml-mode-map): merge with sml-bindings.
+	* sml-defs.el (sml-mode-map): Merge with sml-bindings.
 	(sml-bindings): Remove.
 
 2000-02-22  Stefan Monnier  <monnier@cs.yale.edu>
 
 	* testcases.sml: New file.
 
-	* makefile.pkg (test): new target to run the test suite.
+	* makefile.pkg (test): New target to run the test suite.
 
 2000-02-18  Stefan Monnier  <monnier@cs.yale.edu>
 
 
 	* sml-util.el (make-temp-dir, make-temp-file, temp-file-dir)
 	(delete-temp-dirs): Replaced by the make-temp-file from Emacs-21.
-	(custom-create-map): add :group arg and allow key to be a list.
+	(custom-create-map): Add :group arg and allow key to be a list.
 	(define-major-mode): Removed (use define-derived-mode instead).
 	(sml-builtin-nested-comments-flag): New var.
 	(concatq): Remove.
 
 	* Makefile: Update.
 
-	* sml-mode-startup.el: Remove since it's now autogenerated.
+	* sml-mode-startup.el: Remove since it's now auto-generated.
 
 	* sml-defs.el (sml-bindings): Remove left over C-c` binding.
 	(sml-mode-map): Add binding for sml-drag-region (was in sml-proc.el).
 
 1999-08-11  Stefan Monnier  <monnier@cs.yale.edu>
 
-	* release: version 3.9.3
+	* release: Version 3.9.3
 
 	* sml-mode.texi: Somewhat update the doc.
 
 
 1999-06-13  Stefan Monnier  <monnier@cs.yale.edu>
 
-	* sml-smlnj.el, sml-mosml.el, sml-poly-ml.el: removed.
+	* sml-smlnj.el, sml-mosml.el, sml-poly-ml.el: Remove.
 
 	* sml-proc.el (...): Get rid of sml-next-error by spicing up the
 	interface with compile.el so that intervals can be displayed.
 	smlnj as well as polyml prompts.
 	(sml-update-cursor, sml-send-command, inferior-sml-mode):
 	Make it work with compile.el's `next-error'.
-	(sml-temp-threshold): dropped: Always use a temp file.
+	(sml-temp-threshold): Dropped: Always use a temp file.
 
 1999-06-10  Stefan Monnier  <monnier@cs.yale.edu>
 
 
 1999-05-29  Stefan Monnier  <monnier@cs.yale.edu>
 
-	* sml-defs.el (sml-mode-syntax-table): added ~ of prefix-syntax.
+	* sml-defs.el (sml-mode-syntax-table): Add ~ of prefix-syntax.
 
 	* sml-mode.el (sml-find-match-indent): (nilp sml-type-of-indent) is
 	only applied if the `let' is alone at the end of the line.
 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 # Boston, MA 02111-1307, USA.
 
-VERSION = 0.01
+VERSION = 0.02
 AUTHOR_VERSION = 3.9.5
 MAINTAINER = Ville Skyttä <ville.skytta@xemacs.org>
 PACKAGE = sml-mode
 Changes since 3.9.3:
 
+* Indentation rules improved.  New customizable variable
+  `sml-rightalign-and'.  Also `sml-symbol-indent' is now customizable.
+
 * New add-log support (try C-x 4 a from within an SML function).
 
 * Imenu support
 
 * obey fixity directives.
 
-* right-align "and" with its correspondent.
+* dangling `case e' in stuff like
+
+  fun myfunction x = case x
+   of bla =>
+    | bli =>
+
+* deal with CPS kind of code ???
+
+  function1 (arg1, arg2, fn v1 =>
+  function2 (arg2, fn v2 =>
+  function3 (arg5, arg3, arg8, fn v3 =>
+  function4 (v1, v2, v3))))
+
+  or even just
+
+  F.LET (v1, foo,
+  F.LET (v2, bar,
+  F.LET (v3, baz,
+  F.RET [v1, v2, v3])))

File makefile.pkg

 
 test:
 	$(RM) $(TESTCASE).new
-	$(EMACS) -batch $(TESTCASE) \
+	$(EMACS) \
+	    --eval '(add-to-list (quote load-path) ".")' \
+	    -batch $(TESTCASE) \
 	    --eval '(indent-region (point-min) (point-max) nil)' \
 	    --eval '(write-region (point-min) (point-max) "$(TESTCASE).new")'
-	diff -u $(TESTCASE) $(TESTCASE).new
+	diff -u -B $(TESTCASE) $(TESTCASE).new

File sml-compat.el

 
 ;;; Code:
 
+(require 'cl)
+
 (unless (fboundp 'set-keymap-parents)
   (defun set-keymap-parents (m parents)
     (if (keymapp parents) (setq parents (list parents)))
     file)))
 
 
+
+(unless (fboundp 'regexp-opt)
+  (defun regexp-opt (strings &optional paren)
+    (let ((open (if paren "\\(" "")) (close (if paren "\\)" "")))
+      (concat open (mapconcat 'regexp-quote strings "\\|") close))))
+
+
+;;;; 
+;;;; Custom
+;;;; 
+
+;; doesn't exist in Emacs < 20.1
+(unless (fboundp 'set-face-bold-p)
+  (defun set-face-bold-p (face v &optional f)
+    (when v (ignore-errors (make-face-bold face)))))
+(unless (fboundp 'set-face-italic-p)
+  (defun set-face-italic-p (face v &optional f)
+    (when v (ignore-errors (make-face-italic face)))))
+
+;; doesn't exist in Emacs < 20.1
+(ignore-errors (require 'custom))
+(unless (fboundp 'defgroup)
+  (defmacro defgroup (&rest rest) ()))
+(unless (fboundp 'defcustom)
+  (defmacro defcustom (sym val str &rest rest) `(defvar ,sym ,val ,str)))
+(unless (fboundp 'defface)
+  (defmacro defface (sym val str &rest rest)
+    `(defvar ,sym (make-face ',sym) ,str)))
+
+(defvar :group ':group)
+(defvar :type ':type)
+(defvar :copy ':copy)
+(defvar :dense ':dense)
+(defvar :inherit ':inherit)
+(defvar :suppress ':suppress)
+
 (provide 'sml-compat)
 
 ;;; sml-compat.el ends here
   "The syntax table used in `sml-mode'.")
 
 
-(easy-menu-define sml-mode-menu sml-mode-map "Menu used in sml-mode."
+(easy-menu-define sml-mode-menu sml-mode-map "Menu used in `sml-mode'."
   '("SML"
     ("Process"
-     ["Start default ML compiler" sml		(fboundp 'sml)]
+     ["Start default ML compiler" run-sml		t]
      ["-" nil nil]
-     ["run CM.make"		sml-make	(featurep 'sml-proc)]
-     ["load ML source file"	sml-load-file	(featurep 'sml-proc)]
-     ["switch to ML buffer"	switch-to-sml	(featurep 'sml-proc)]
+     ["run CM.make"		sml-make	t]
+     ["load ML source file"	sml-load-file	t]
+     ["switch to ML buffer"	switch-to-sml	t]
      ["--" nil nil]
-     ["send buffer contents"	sml-send-buffer	(featurep 'sml-proc)]
-     ["send region"		sml-send-region	(featurep 'sml-proc)]
-     ["send paragraph"		sml-send-function (featurep 'sml-proc)]
-     ;;["goto next error"		sml-next-error	(featurep 'sml-proc)]
+     ["send buffer contents"	sml-send-buffer	t]
+     ["send region"		sml-send-region	t]
+     ["send paragraph"		sml-send-function t]
      ["goto next error"		next-error	(featurep 'sml-proc)]
      ["---" nil nil]
      ;; ["Standard ML of New Jersey" sml-smlnj	(fboundp 'sml-smlnj)]
     ["SML mode help (brief)"       describe-mode t]
     ["SML mode *info*"             sml-mode-info t]
     ["-----" nil nil]
-    ["Remove overlay"    (sml-error-overlay 'undo) ;:active (sml-overlay-active-p)
+    ["Remove overlay"    (sml-error-overlay 'undo) t ;:active (sml-overlay-active-p)
      ]))
 
-;;; Make's sure they appear in the menu bar when sml-mode-map is active.
+;; Make's sure they appear in the menu bar when sml-mode-map is active.
 ;; On the hook for XEmacs only -- see easy-menu-add in auc-menu.el.
 ;; (defun sml-mode-menu-bar ()
 ;;   "Make sure menus appear in the menu bar as well as under mouse 3."
      ("in" . t)))
   "Words which might delegate indentation to their parent.")
 
-(defconst sml-symbol-indent
+(defcustom sml-symbol-indent
   '(("fn" . -3)
     ("of" . 1)
     ("|" . -2)
+    ("," . -2)
+    (";" . -2)
     ;;("in" . 1)
     ("d=" . 2))
-  "Special indentation alist for some symbols.")
+  "Special indentation alist for some symbols.
+An entry like (\"in\" . 1) indicates that a line starting with the
+symbol `in' should be indented one char further to the right.
+This is only used in a few specific cases, so it does not work
+for all symbols and in all lines starting with the given symbol."
+  :group 'sml
+  :type '(repeat (cons string integer)))
 
 (defconst sml-open-paren
   (sml-preproc-alist

File sml-mode-startup.el

-
-;;;### (autoloads (sml-yacc-mode sml-lex-mode sml-cm-mode sml-mode)
-;;;;;;  "sml-mode" "sml-mode.el" (14918 21945))
-;;; Generated autoloads from sml-mode.el
-
-(add-to-list (quote auto-mode-alist) (quote ("\\.s\\(ml\\|ig\\)\\'" . sml-mode)))
-
-(autoload (quote sml-mode) "sml-mode" "\
-\\<sml-mode-map>Major mode for editing ML code.
-This mode runs `sml-mode-hook' just before exiting.
-\\{sml-mode-map}" t nil)
-
-(add-to-list (quote completion-ignored-extensions) "CM/")
-
-(add-to-list (quote auto-mode-alist) (quote ("\\.cm\\'" . sml-cm-mode)))
-
-(autoload (quote sml-cm-mode) "sml-mode" "\
-Major mode for SML/NJ's Compilation Manager configuration files." t nil)
-
-(autoload (quote sml-lex-mode) "sml-mode" "\
-Major Mode for editing ML-Lex files." t nil)
-
-(add-to-list (quote auto-mode-alist) (quote ("\\.grm\\'" . sml-yacc-mode)))
-
-(autoload (quote sml-yacc-mode) "sml-mode" "\
-Major Mode for editing ML-Yacc files." t nil)
-
-;;;***
-
-;;;### (autoloads nil "sml-proc" "sml-proc.el" (14918 21909))
-;;; Generated autoloads from sml-proc.el
-
-(autoload (quote run-sml) "sml-proc" nil t)
-
-;;;***
-
 ;;      (Stefan Monnier) monnier@cs.yale.edu
 ;; Maintainer: (Stefan Monnier) monnier+lists/emacs/sml@flint.cs.yale.edu
 ;; Keywords: SML
-;; 1.25
-;; 2000/12/24 19:59:53
+;; $Revision$
+;; $Date$
 
 ;; This file is not part of GNU Emacs, but it is distributed under the
 ;; same conditions.
   "*If non-nil, `\;' will self insert, reindent the line, and do a newline.
 If nil, just insert a `\;'.  (To insert while t, do: \\[quoted-insert] \;)."
   :group 'sml
-  :type '(boolean))
+  :type 'boolean)
+
+(defcustom sml-rightalign-and t
+  "If non-nil, right-align `and' with its leader.
+If nil:					If t:
+	datatype a = A				datatype a = A
+	and b = B				     and b = B"
+  :group 'sml
+  :type 'boolean)
 
 ;;; OTHER GENERIC MODE VARIABLES
 
 	       "with" "withtype" "o")
   "A regexp that matches any and all keywords of SML.")
 
+(defconst sml-tyvarseq-re
+  "\\(\\('+\\(\\sw\\|\\s_\\)+\\|(\\([,']\\|\\sw\\|\\s_\\|\\s-\\)+)\\)\\s-+\\)?")
+
 (defconst sml-font-lock-keywords
   `(;;(sml-font-comments-and-strings)
-    ("\\<\\(fun\\|and\\)\\s-+\\('\\sw+\\s-+\\)*\\(\\sw+\\)"
+    (,(concat "\\<\\(fun\\|and\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)\\s-+[^ \t\n=]")
      (1 font-lock-keyword-face)
-     (3 font-lock-function-name-face))
-    ("\\<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+\\('\\sw+\\s-+\\)*\\(\\sw+\\)"
+     (6 font-lock-function-name-face))
+    (,(concat "\\<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)")
      (1 font-lock-keyword-face)
-     (4 font-lock-type-def-face))
+     (7 font-lock-type-def-face))
     ("\\<\\(val\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
      (1 font-lock-keyword-face)
      ;;(6 font-lock-variable-def-face nil t)
 (defvar font-lock-interface-def-face 'font-lock-interface-def-face
   "Face name to use for interface definitions.")
 
-;;;
-;;; Code to handle nested comments and unusual string escape sequences
-;;;
+;;
+;; Code to handle nested comments and unusual string escape sequences
+;;
 
 (defsyntax sml-syntax-prop-table
   '((?\\ . ".") (?* . "."))
 	(let ((kind (match-string 2))
 	      (column (progn (goto-char (match-beginning 2)) (current-column)))
 	      (location
-	       (progn (goto-char (match-end 0)) (sml-forward-spaces) (point)))
+	       (progn (goto-char (match-end 0))
+		      (sml-forward-spaces)
+		      (when (looking-at sml-tyvarseq-re)
+			(goto-char (match-end 0)))
+		      (point)))
 	      (name (sml-forward-sym)))
 	  ;; Eliminate trivial renamings.
 	  (when (or (not (member kind '("structure" "signature")))
 ;;;###Autoload
 (add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . sml-mode))
 
-;;;###Autoload
+;; XEmacs hack, autoload a dummy autoload instead of a derived mode.
+;;;###autoload
+(autoload 'sml-mode "sml-mode")
 (define-derived-mode sml-mode fundamental-mode "SML"
   "\\<sml-mode-map>Major mode for editing ML code.
 This mode runs `sml-mode-hook' just before exiting.
   (set (make-local-variable 'comment-nested) t)
   ;;(set (make-local-variable 'block-comment-start) "* ")
   ;;(set (make-local-variable 'block-comment-end) "")
-  (set (make-local-variable 'comment-column) 40)
+  ;; (set (make-local-variable 'comment-column) 40)
   (set (make-local-variable 'comment-start-skip) "(\\*+\\s-*"))
 
+(defun sml-funname-of-and ()
+  "Name of the function this `and' defines, or nil if not a function.
+Point has to be right after the `and' symbol and is not preserved."
+  (sml-forward-spaces)
+  (if (looking-at sml-tyvarseq-re) (goto-char (match-end 0)))
+  (let ((sym (sml-forward-sym)))
+    (sml-forward-spaces)
+    (unless (or (member sym '(nil "d="))
+		(member (sml-forward-sym) '("d=")))
+      sym)))
+
 (defun sml-electric-pipe ()
   "Insert a \"|\".
 Depending on the context insert the name of function, a \"=>\" etc."
 		   ((looking-at "=") (concat f "  = "))))) ;a function
 	       ((string= sym "and")
 		;; could be a datatype or a function
-		(while (and (setq sym (sml-forward-sym))
-			    (string-match "^'" sym))
-		  (sml-forward-spaces))
-		(sml-forward-spaces)
-		(if (or (not sym)
-			(equal (sml-forward-sym) "d="))
-		    ""
-		  (concat sym "  = ")))
+		(setq sym (sml-funname-of-and))
+		(if sym (concat sym "  = ") ""))
 	       ;; trivial cases
 	       ((string= sym "fun")
 		(while (and (setq sym (sml-forward-sym))
       (while (> depth 0)
 	(if (re-search-backward "(\\*\\|\\*)" nil t)
 	    (cond
+	     ;; FIXME: That's just a stop-gap.
+	     ((eq (get-text-property (point) 'face) 'font-lock-string-face))
 	     ((looking-at "*)") (incf depth))
 	     ((looking-at comment-start-skip) (decf depth)))
 	  (setq depth -1)))
 	   (sml-point (point))
 	   (sym (save-excursion (sml-forward-sym))))
        (or
-	;; allow the user to override the indentation
+	;; Allow the user to override the indentation.
 	(when (looking-at (concat ".*" (regexp-quote comment-start)
 				  "[ \t]*fixindent[ \t]*"
 				  (regexp-quote comment-end)))
 	  (current-indentation))
 
-	;; continued comment
+	;; Continued comment.
 	(and (looking-at "\\*") (sml-find-comment-indent))
 
 	;; Continued string ? (Added 890113 lbn)
 		     (1+ (current-column))
 		   0))))
 
+	;; Closing parens.  Could be handled below with `sml-indent-relative'?
+	(and (looking-at "\\s)")
+	     (save-excursion
+	       (skip-syntax-forward ")")
+	       (backward-sexp 1)
+	       (if (sml-dangling-sym)
+		   (sml-indent-default 'noindent)
+		 (current-column))))
+
 	(and (setq data (assoc sym sml-close-paren))
 	     (sml-indent-relative sym data))
 
-	(and (member (save-excursion (sml-forward-sym)) sml-starters-syms)
-	     (let ((sym (unless (save-excursion (sml-backward-arg))
-			  (sml-backward-spaces)
-			  (sml-backward-sym))))
-	       (if sym (sml-get-sym-indent sym)
-		 ;; FIXME: this can take a *long* time !!
-		 (sml-find-matching-starter sml-starters-syms)
-		 (current-column))))
+	(and (member sym sml-starters-syms)
+	     (sml-indent-starter sym))
 
 	(and (string= sym "|") (sml-indent-pipe))
 
 	(sml-indent-arg)
 	(sml-indent-default))))))
 
+(defsubst sml-bolp ()
+  (save-excursion (skip-chars-backward " \t|") (bolp)))
+
+(defun sml-indent-starter (orig-sym)
+  "Return the indentation to use for a symbol in `sml-starters-syms'.
+Point should be just before the symbol ORIG-SYM and is not preserved."
+  (let ((sym (unless (save-excursion (sml-backward-arg))
+	       (sml-backward-spaces)
+	       (sml-backward-sym))))
+    (if (equal sym "d=") (setq sym nil))
+    (if sym (sml-get-sym-indent sym)
+      ;; FIXME: this can take a *long* time !!
+      (setq sym (sml-find-matching-starter sml-starters-syms))
+      ;; Don't align with `and' because it might be specially indented.
+      (if (and (or (equal orig-sym "and") (not (equal sym "and")))
+	       (sml-bolp))
+	  (+ (current-column)
+	     (if (and sml-rightalign-and (equal orig-sym "and"))
+		 (- (length sym) 3) 0))
+	(sml-indent-starter orig-sym)))))
+
 (defun sml-indent-relative (sym data)
   (save-excursion
     (sml-forward-sym) (sml-backward-sexp nil)
       (if (string= sym "|")
 	  (if (sml-bolp) (current-column) (sml-indent-pipe))
 	(let ((pipe-indent (or (cdr (assoc "|" sml-symbol-indent)) -2)))
-	  (when (member sym '("datatype" "abstype"))
+	  (when (or (member sym '("datatype" "abstype"))
+		    (and (equal sym "and")
+			 (save-excursion
+			   (forward-word 1)
+			   (not (sml-funname-of-and)))))
 	    (re-search-forward "="))
 	  (sml-forward-sym)
 	  (sml-forward-spaces)
      (t sml-indent-level))))
 
 (defun sml-dangling-sym ()
+  "Non-nil if the symbol after point is dangling.
+The symbol can be an SML symbol or an open-paren. \"Dangling\" means that
+it is not on its own line but is the last element on that line."
   (save-excursion
     (and (not (sml-bolp))
 	 (< (sml-point-after (end-of-line))
-	    (sml-point-after (sml-forward-sym)
+	    (sml-point-after (or (sml-forward-sym) (skip-syntax-forward "("))
 			     (sml-forward-spaces))))))
 
 (defun sml-delegated-indent ()
 
 (defun sml-get-sym-indent (sym &optional style)
   "Find the indentation for the SYM we're `looking-at'.
-If indentation is delegated, the point will be at the start of
-the parent at the end of this function.
-Optional argument STYLE is currently ignored"
+If indentation is delegated, point will move to the start of the parent.
+Optional argument STYLE is currently ignored."
   (assert (equal sym (save-excursion (sml-forward-sym))))
   (save-excursion
     (let ((delegate (assoc sym sml-close-paren))
   (let* ((sym-after (save-excursion (sml-forward-sym)))
 	 (_ (sml-backward-spaces))
 	 (sym-before (sml-backward-sym))
-	 (sym-indent (and sym-before (sml-get-sym-indent sym-before))))
-    (if sym-indent
-	;; the previous sym is an indentation introducer: follow the rule
-	(let ((indent-after (or (cdr (assoc sym-after sml-symbol-indent)) 0)))
-	  (if noindent
-	      ;;(current-column)
-	      sym-indent
-	    (+ sym-indent indent-after)))
+	 (sym-indent (and sym-before (sml-get-sym-indent sym-before)))
+	 (indent-after (or (cdr (assoc sym-after sml-symbol-indent)) 0)))
+    (when (equal sym-before "end")
+      ;; I don't understand what's really happening here, but when
+      ;; it's `end' clearly, we need to do something special.
+      (forward-word 1)
+      (setq sym-before nil sym-indent nil))
+    (cond
+     (sym-indent
+      ;; the previous sym is an indentation introducer: follow the rule
+      (if noindent
+	  ;;(current-column)
+	  sym-indent
+	(+ sym-indent indent-after)))
+     ;; If we're just after a hanging open paren.
+     ((and (eq (char-syntax (preceding-char)) ?\()
+	   (save-excursion (backward-char) (sml-dangling-sym)))
+      (backward-char)
+      (sml-indent-default))
+     (t
       ;; default-default
       (let* ((prec-after (sml-op-prec sym-after 'back))
 	     (prec (or (sml-op-prec sym-before 'back) prec-after 100)))
 	;; "current one", or until you backed over a sym that has the same prec
 	;; but is at the beginning of a line.
 	(while (and (not (sml-bolp))
-		    (sml-move-if (sml-backward-sexp (1- prec)))
+		    (while (sml-move-if (sml-backward-sexp (1- prec))))
 		    (not (sml-bolp)))
 	  (while (sml-move-if (sml-backward-sexp prec))))
-	;; the `noindent' case does back over an introductory symbol
-	;; such as `fun', ...
-	(when noindent
-	  (sml-move-if
-	   (sml-backward-spaces)
-	   (member (sml-backward-sym) sml-starters-syms)))
-	(current-column)))))
-
-
-(defun sml-bolp ()
-  (save-excursion
-    (skip-chars-backward " \t|") (bolp)))
+	(if noindent
+	    ;; the `noindent' case does back over an introductory symbol
+	    ;; such as `fun', ...
+	    (progn
+	      (sml-move-if
+	       (sml-backward-spaces)
+	       (member (sml-backward-sym) sml-starters-syms))
+	      (current-column))
+	  ;; Use `indent-after' for cases such as when , or ; should be
+	  ;; outdented so that their following terms are aligned.
+	  (+ (if (progn
+		   (if (equal sym-after ";")
+		       (sml-move-if
+			(sml-backward-spaces)
+			(member (sml-backward-sym) sml-starters-syms)))
+		   (and sym-after (not (looking-at sym-after))))
+		 indent-after 0)
+	     (current-column))))))))
 
 
 ;; maybe `|' should be set to word-syntax in our temp syntax table ?
   (unless (or (not newline)
 	      (save-excursion (beginning-of-line) (looking-at "\\s-*$")))
     (insert "\n"))
-  (unless (/= ?w (char-syntax (char-before))) (insert " "))
+  (unless (/= ?w (char-syntax (preceding-char))) (insert " "))
   (let ((f (cdr (assoc name sml-forms-alist))))
     (cond
      ((commandp f) (command-execute f))
 (add-to-list 'completion-ignored-extensions "CM/")
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.cm\\'" . sml-cm-mode))
+;; XEmacs hack, autoload a dummy autoload instead of a derived mode.
 ;;;###autoload
+(autoload 'sml-cm-mode "sml-mode")
 (define-derived-mode sml-cm-mode fundamental-mode "SML-CM"
   "Major mode for SML/NJ's Compilation Manager configuration files."
   (local-set-key "\C-c\C-c" 'sml-compile)
 (defconst sml-lex-font-lock-defaults
   (cons 'sml-lex-font-lock-keywords (cdr sml-font-lock-defaults)))
 
+;; XEmacs hack, autoload a dummy autoload instead of a derived mode.
 ;;;###autoload
+(autoload 'sml-lex-mode "sml-mode")
 (define-derived-mode sml-lex-mode sml-mode "SML-Lex"
   "Major Mode for editing ML-Lex files."
   (set (make-local-variable 'font-lock-defaults) sml-lex-font-lock-defaults))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.grm\\'" . sml-yacc-mode))
+;; XEmacs hack, autoload a dummy autoload instead of a derived mode.
 ;;;###autoload
+(autoload 'sml-yacc-mode "sml-mode")
 (define-derived-mode sml-yacc-mode sml-mode "SML-Yacc"
   "Major Mode for editing ML-Yacc files."
   (set (make-local-variable 'indent-line-function) 'sml-yacc-indent-line)

File sml-mode.spec

 
 Summary:	Emacs mode for editing Standard ML source code
 Name:		sml-mode
-Version:	v3_9_5
+Version:	$Name$
 Release:	0.1
 Group:		Applications/Editors
 Copyright:	GPL
 ;; sml-mode-end
 EOF
 
-/sbin/install-info %{_infodir}/sml-mode.info.gz %{_infodir}/dir \
-    --section=Emacs \
-    --entry="* SML: (sml-mode).    Editing & Running Standard ML from Emacs"
+/sbin/install-info %{_infodir}/sml-mode.info.gz %{_infodir}/dir
 
 %postun
 ed -s %{lispdir}/site-start.el <<EOF

File sml-mode.texi

 \input texinfo @c -*-texinfo-*-
 
-@comment "@(#)v3_9_5:sml-mode.texi,v 1.5 2000/10/07 03:21:46 monnier Exp"
+@comment "@(#)$Name$:$Id$"
 
 @comment Documentation for the GNU Emacs SML mode.
 @comment Copyright (C) 1997-1999 Matthew J.@: Morley
 
 @setfilename sml-mode.info
 @settitle SML mode - The Emacs SML editing mode
-@dircategory Editors
+@dircategory Emacs
 @direntry
 * sml:(sml-mode).	Emacs mode for editing SML
 @end direntry
 @center @titlefont{Editing and Running Standard ML}
 @center @titlefont{under GNU Emacs}
 @sp 5
-@center {SML mode, Version v3_9_5}
+@center {SML mode, Version $Name$}
 @center {August 1999}
 @sp 2
 @author Authors: Matthew J.@: Morley and Stefan Monnier
 
 @noindent
 You are looking at the top node of the Info tree documenting
-@sc{sml-mode} (Version v3_9_5). Not all functions are documented here, but
+@sc{sml-mode} (Version $Name$). Not all functions are documented here, but
 those that aren't you probably won't miss. All commands and settable
 variables have built-in documentation, as per usual Emacs conventions.
 @end ifinfo
 
 (defconst sml-syntax-prec
   (sml-preproc-alist
-   `(((";" "," "in" "with") . 10)
+   `((("in" "with") . 10)
+     ((";" ",") . 20)
      (("=>" "d=" "=of") . (65 . 40))
      ("|" . (47 . 30))
      (("case" "of" "fn") . 45)
       (save-excursion
 	(sml-backward-sym-1)
 	(if (sml-nested-of-p) "of" "=of")))
+     ;; ((equal sym "datatype")
+     ;;  (save-excursion
+     ;; 	(sml-backward-sym-1)
+     ;; 	(sml-backward-spaces)
+     ;; 	(if (eq (preceding-char) ?=) "=datatype" sym)))
      (t sym))))
 
 (defun sml-backward-sym-1 ()
 	  (cond
 	   ((string= sym "=") (if (sml-poly-equal-p) "=" "d="))
 	   ((string= sym "of") (if (sml-nested-of-p) "of" "=of"))
+	   ;; ((string= sym "datatype")
+	   ;;  (save-excursion (sml-backward-spaces)
+	   ;; 		    (if (eq (preceding-char) ?=) "=datatype" sym)))
 	   (t sym)))))))
     
 
 (defun sml-backward-sexp (prec)
-  "Moves one sexp backward if possible, or one char else.
-Returns T if the move indeed moved through one sexp and NIL if not."
+  "Move one sexp backward if possible, or one char else.
+Returns t if the move indeed moved through one sexp and nil if not.
+PREC is the precedence currently looked for."
   (let ((parse-sexp-lookup-properties t)
 	(parse-sexp-ignore-comments t))
     (sml-backward-spaces)
 ;; Copyright (C) 1994-1997  Matthew J. Morley
 ;; Copyright (C) 1999-2000  Stefan Monnier
 
-;; 1.16
-;; 2000/12/24 19:59:17
+;; $Revision$
+;; $Date$
 
 ;; ====================================================================
 
 	     ;; buffer-name returns nil if the buffer has been killed
 	     (and buf (buffer-name buf) buf)))
       ;; no buffer found, make a new one
-      (call-interactively 'run-sml)))
+      (save-excursion (call-interactively 'run-sml))))
 
 (defun sml-buffer (echo)
   "Make the current buffer the current `sml-buffer' if that is sensible.

File testcases.sml

 (* monnier@cs.yale.edu *)
 
 (let val a = 1 val b = 2
-     val c = 3
+     val c = 3
  in 1
- end)
+ end);
 
 (x := 1;
  case x of
      FOO => 1
-   | BAR => 2;
+   | BAR =>
+     2;
  case x of
      FOO => 1
    | BAR =>
      (case y of
 	  FAR => 2
 	| FRA => 3);
- hello)
+ hello);
 
 let datatype foobar
       = FooB of int
       | FooA of bool * int
-		
+    datatype foo = FOO | BAR of baz
+	 and baz = BAZ | QUUX of foo
+
+    datatype foo = FOO
+                 | BAR of baz
+      and baz = BAZ			(* fixindent *)
+	      | QUUX of foo
+      and b = g
+
+    datatype foo = datatype M.foo
+    val _ = 42 val x = 5
+		       
+    signature S = S' where type foo = int
+    val _ = 42
+
+    val foo = [
+	"blah"
+      , let val x = f 42 in g (x,x,44) end
+    ]
+	      
+    val foo = [ "blah"
+	      , let val x = f 42 in g (x,x,44) end
+	      , foldl (fn ((p,q),s) => g (p,q,Vector.length q) ^ ":" ^ s)
+                      "" (Beeblebrox.masterCountList mlist2)
+              , if null mlist2 then ";" else ""
+	      ]
+	      
+    fun foo (true::rest)
+      = 1 + 2 * foo rest
+      | foo (false::rest)
+      = let val _ = 1 in 2 end
+	+ 2 * foo rest
+
     val x = if foo then
 		1
 	    else if bar then
 	    else if foo
 	    then 2
 	    else 3
+
+  ; val yt = 4
+
 in
     if a then b else c;
     case M.find(m,f)
     x := x + 1;
     (case foo
       of a => f
-     )
-end
+    )
+end;
 
 let
 in a;
-   b
-end
+   foo("(*")
+   * 2;
+end;
+
+let
+in a
+ ; b
+end;
+
+let
+in
+    a
+  ; b
+end;
 
 let
 in if a then
        b
    else
        c
-end
+end;
 
 let
 in case a of
-    (* Do I really want that ? *)
-    F => 1
+       F => 1
+     | D => 2
+end;
+
+let
+in case a
+ of F => 1
   | D => 2
-end
+end;
 
 let
 in if a then b else
    c
-end
-    
+end;
+
 structure Foo = struct
 val x = 1
 end
     type flint = FLINT.prog
     val split: flint -> flint * flint option
 end
-    
+
 structure FSplit :> FSPLIT =
 struct
 
 	       then (leE, leI, fvI, leRet)
 	       else (leE, lewrap leI, addvs(S_rmv(lv, fvI), vs), leRet)
 	    end
-		
+	    
     in case lexp
 	(* we can completely move both RET and TAPP to the I part *)
 	of F.RECORD (rk,vs,lv,le as F.RET [F.VAR lv']) =>
 	   let val (leE,leI,fvI,leRet) = sexp (S.union(S.addList(S.empty, lvs), env)) le
 	   in (fn e => F.LET(lvs, body, leE e), leI, fvI, leRet)
 	   end
-	       
+	   
 	 (* useless sophistication *)
 	 | F.APP (F.VAR f,args) =>
 	   if funeffect f
 	 | (F.SWITCH _ | F.RAISE _ | F.BRANCH _ | F.HANDLE _) =>
 	   (fn e => e, F.RET[], S.empty, lexp)
     end
-	
+    
 (* Functions definitions fall into the following categories:
  * - inlinable:  if exported, copy to leI
  * - (mutually) recursive:  don't bother
 	   
 	 | _ => (nleE, leI, fvI, leRet)
     end
-	
+    
 and sfdec env (leE,leI,fvI,leRet) (fk,f,args,body) =
     let val benv = S.union(S.addList(S.empty, map #1 args), env)
 	val (bodyE,bodyI,fvbI,bodyRet) = sexp benv body
 			  known=true, isrec=NONE}
 	       val argsI =
 		   (map (fn lv => (lv, getLty(F.VAR lv))) fvbIs) @ args
-	       (* val argI = mklv()
-		  val argsI = (argI, LT.ltc_str(map (getLty o F.VAR) fvbIs))::args
-			      
-		  val (_,bodyI) = foldl (fn (lv,(n,le)) =>
-					    (n+1, F.SELECT(F.VAR argI, n, lv, le)))
-					(0, bodyI) fvbIs *)
 	       val fdecI as (_,fI,_,_) = FU.copyfdec(fkI,f,argsI,bodyI)
 	       val _ = addpurefun fI
 		       
 		    leRet)
 	   end
     end
-	
+    
 (* TFNs are kinda like FIX except there's no recursion *)
 and stfn env (tfdec as (tfk,tf,args,body),le) =
     let val (bodyE,bodyI,fvbI,bodyRet) =
 	       (* tfdecI *)
 	       val tfkI = {inline=F.IH_ALWAYS}
 	       val argsI = map (fn (v,k) => (cplv v, k)) args
-	       val tmap = ListPair.map (fn (a1,a2) =>
-					(#1 a1, LT.tcc_nvar(#1 a2)))
-				       (args, argsI)
+	       (* val tmap = ListPair.map (fn (a1,a2) =>
+	        * 				(#1 a1, LT.tcc_nvar(#1 a2)))
+	        * 			       (args, argsI) *)
 	       val bodyI = FU.copy tmap M.empty
 				   (F.LET(fvbIs, F.TAPP(F.VAR tfE, map #2 tmap),
 					  bodyI))
 		    leRet)
 	   end
     end
-	
+    
 (* here, we use B-decomposition, so the args should not be
  * considered as being in scope *)
 val (bodyE,bodyI,fvbI,bodyRet) = sexp S.empty body
 			      F.APP(F.VAR fI, [F.VAR argI]))))),
 	   NONE) *)
        end
-	   
+       
      | _ => (fdec, NONE)		(* sorry, can't do that *)
 (* (PPFlint.printLexp bodyRet; bug "couldn't find the returned record") *)
 	    
 end
-    
+				       
 end
 end