summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2012-10-03 23:38:45 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2012-10-03 23:38:45 -0400
commit3b36fd37f2e5bcba5973af60599d3bcee40a4dc2 (patch)
treed9d30432f1517f45120fc5cac9319ddb7b046e2a
parent16268c2858dde29363eebfef613ad46ccc96e135 (diff)
downloademacs-3b36fd37f2e5bcba5973af60599d3bcee40a4dc2.tar.gz
Start preparing for the move to ELPA.
-rw-r--r--Makefile9
-rw-r--r--sml-mode.el639
-rw-r--r--sml-proc.el338
3 files changed, 387 insertions, 599 deletions
diff --git a/Makefile b/Makefile
index 4bc79e19bf9..0e54d795db5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
# Makefile for emacs-lisp package
-# Copyright (C) 1998, 1999, 2004, 2007, 2010 Stefan Monnier <monnier@gnu.org>
+# Copyright (C) 1998,1999,2004,2007,2010-2012 Stefan Monnier <monnier@gnu.org>
# 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
@@ -159,14 +159,15 @@ $(PACKAGE)-startup.el: $(ELFILES)
#TAG = $(shell echo v$(VERSION) | tr '.' '_')
URL=$(shell sed -n -e '5p' .svn/entries)
-TAG=$(shell dirname "$(URL)")/releases/$(PACKAGE)-$(VERSION)
+#TAG=$(shell dirname "$(URL)")/releases/$(PACKAGE)-$(VERSION)
+TAG="v$(VERSION)"
ftpdir=/u/monnier/html/elisp/
cvsmodule=$(shell cat CVS/Repository)
cvsroot=$(shell cat CVS/Root)
dist:
- svn cp . "$(TAG)" &&\
- svn export "$(TAG)" "$(TMP)/$(PACKAGE)-$(VERSION)" &&\
+ echo bzr tag "$(TAG)" &&\
+ bzr export "$(TMP)/$(PACKAGE)-$(VERSION)" &&\
cd "$(TMP)/$(PACKAGE)-$(VERSION)" &&\
$(MAKE) info $(PACKAGE)-startup.el &&\
cd .. &&\
diff --git a/sml-mode.el b/sml-mode.el
index 3daeb880be8..f32478aeebb 100644
--- a/sml-mode.el
+++ b/sml-mode.el
@@ -1,4 +1,4 @@
-;;; sml-mode.el --- Major mode for editing (Standard) ML
+;;; sml-mode.el --- Major mode for editing (Standard) ML -*- lexical-binding: t; coding: utf-8 -*-
;; Copyright (C) 1999,2000,2004,2007,2010-2012 Stefan Monnier
;; Copyright (C) 1994-1997 Matthew J. Morley
@@ -76,35 +76,13 @@
"Editing SML code."
:group 'languages)
-;;; VARIABLES CONTROLLING INDENTATION
-
(defcustom sml-indent-level 4
- "Indentation of blocks in ML (see also `sml-indent-rule')."
- :type '(integer))
+ "Basic indentation step for SML code."
+ :type 'integer)
(defcustom sml-indent-args sml-indent-level
"Indentation of args placed on a separate line."
- :type '(integer))
-
-;; (defvar sml-indent-align-args t
-;; "*Whether the arguments should be aligned.")
-
-;; (defvar sml-case-indent nil
-;; "*How to indent case-of expressions.
-;; If t: case expr If nil: case expr of
-;; of exp1 => ... exp1 => ...
-;; | exp2 => ... | exp2 => ...
-
-;; The first seems to be the standard in SML/NJ, but the second
-;; seems nicer...")
-
-(defcustom sml-electric-semi-mode nil
- "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] \;)."
- :type 'boolean)
-(when (fboundp 'electric-layout-mode)
- (make-obsolete-variable 'sml-electric-semi-mode
- 'electric-layout-mode "Emacs-24"))
+ :type 'integer)
(defcustom sml-rightalign-and t
"If non-nil, right-align `and' with its leader.
@@ -113,39 +91,12 @@ If nil: If t:
and b = B and b = B"
:type 'boolean)
-;;; OTHER GENERIC MODE VARIABLES
-
-(defvar sml-mode-info "sml-mode"
- "*Where to find Info file for `sml-mode'.
-The default assumes the info file \"sml-mode.info\" is on Emacs' info
-directory path. If it is not, either put the file on the standard path
-or set the variable `sml-mode-info' to the exact location of this file
-
- (setq sml-mode-info \"/usr/me/lib/info/sml-mode\")
-
-in your .emacs file. You can always set it interactively with the
-set-variable command.")
-
(defvar sml-mode-hook nil
- "*Run upon entering `sml-mode'.
+ "Run upon entering `sml-mode'.
This is a good place to put your preferred key bindings.")
-;;; CODE FOR SML-MODE
-
-(defun sml-mode-info ()
- "Command to access the TeXinfo documentation for `sml-mode'.
-See doc for the variable `sml-mode-info'."
- (interactive)
- (require 'info)
- (condition-case nil
- (info sml-mode-info)
- (error (progn
- (describe-variable 'sml-mode-info)
- (message "Can't find it... set this variable first!")))))
-
-
;;; Autoload functions -- no-doc is another idea cribbed from AucTeX!
-
+;; FIXME-copyright: probably include sml-proc.el in sml-mode.el.
(let ((sml-no-doc
"This function is part of sml-proc, and has not yet been loaded.
Full documentation will be available after autoloading the function."))
@@ -160,7 +111,7 @@ Full documentation will be available after autoloading the function."))
(defvar sml-outline-regexp
;; `st' and `si' are to match structure and signature.
- " \\|s[ti]\\|[ \t]*\\(let[ \t]+\\)?\\(fun\\|and\\)\\>"
+ " \\|s[ti]\\|[ \t]*\\(let[ \t]+\\)?\\(fun\\|and\\)\\_>"
"Regexp matching a major heading.
This actually can't work without extending `outline-minor-mode' with the
notion of \"the end of an outline\".")
@@ -171,15 +122,10 @@ notion of \"the end of an outline\".")
(defvar sml-mode-map
(let ((map (make-sparse-keymap)))
- ;; Smarter cursor movement.
- ;; (define-key map [remap forward-sexp] 'sml-user-forward-sexp)
- ;; (define-key map [remap backward-sexp] 'sml-user-backward-sexp)
;; Text-formatting commands:
(define-key map "\C-c\C-m" 'sml-insert-form)
- (define-key map "\C-c\C-i" 'sml-mode-info)
(define-key map "\M-|" 'sml-electric-pipe)
(define-key map "\M-\ " 'sml-electric-space)
- (define-key map "\;" 'sml-electric-semi)
(define-key map [backtab] 'sml-back-to-outer-indent)
;; Process commands added to sml-mode-map -- these should autoload.
(define-key map "\C-c\C-l" 'sml-load-file)
@@ -190,18 +136,9 @@ notion of \"the end of an outline\".")
map)
"The keymap used in `sml-mode'.")
-(defconst sml-builtin-nested-comments-flag
- (ignore-errors
- (not (equal (let ((st (make-syntax-table)))
- (modify-syntax-entry ?\* ". 23n" st) st)
- (let ((st (make-syntax-table)))
- (modify-syntax-entry ?\* ". 23" st) st))))
- "Non-nil means this Emacs understands the `n' in syntax entries.")
-
(defvar sml-mode-syntax-table
(let ((st (make-syntax-table)))
- (modify-syntax-entry ?\* (if sml-builtin-nested-comments-flag
- ". 23n" ". 23") st)
+ (modify-syntax-entry ?\* ". 23n" st)
(modify-syntax-entry ?\( "()1" st)
(modify-syntax-entry ?\) ")(4" st)
(mapc (lambda (c) (modify-syntax-entry c "_" st)) "._'")
@@ -215,7 +152,7 @@ notion of \"the end of an outline\".")
(easy-menu-define sml-mode-menu sml-mode-map "Menu used in `sml-mode'."
'("SML"
- ("Process"
+ ("Process" ;FIXME-copyright.
["Start default ML compiler" run-sml t]
["-" nil nil]
["run CM.make" sml-compile t]
@@ -224,18 +161,14 @@ notion of \"the end of an outline\".")
["--" nil nil]
["send buffer contents" sml-send-buffer t]
["send region" sml-send-region t]
- ["send paragraph" sml-send-function t]
+ ["send function" sml-send-function t]
["goto next error" next-error (featurep 'sml-proc)]
["---" nil nil]
- ;; ["Standard ML of New Jersey" sml-smlnj (fboundp 'sml-smlnj)]
- ;; ["Poly/ML" sml-poly-ml (fboundp 'sml-poly-ml)]
- ;; ["Moscow ML" sml-mosml (fboundp 'sml-mosml)]
["Help for Inferior ML" (describe-function 'inferior-sml-mode)
:active (featurep 'sml-proc)])
- ["electric pipe" sml-electric-pipe t]
- ["insert SML form" sml-insert-form t]
+ ["insert SML form" sml-insert-form t] ;FIXME-copyright.
("Forms" :filter sml-forms-menu)
- ("Format/Mode Variables"
+ ("Format/Mode Variables" ;FIXME-copyright.
["indent region" indent-region t]
["outdent" sml-back-to-outer-indent t]
;; ["-" nil nil]
@@ -244,34 +177,16 @@ notion of \"the end of an outline\".")
;; ["--" nil nil]
;; ["toggle type-of-indent" sml-type-of-indent t]
;; ["toggle nested-if-indent" sml-nested-if-indent t]
- ;; ["toggle electric-semi-mode" sml-electric-semi-mode t]
)
["-----" nil nil]
- ["SML mode help (brief)" describe-mode t]
- ["SML mode *info*" sml-mode-info t]
- ["Remove overlay" (sml-error-overlay 'undo)
- :visible (or (and (boundp 'sml-error-overlay)
- sml-error-overlay)
- (not (fboundp 'compilation-fake-loc)))
- :active (and (boundp 'sml-error-overlay)
- (overlayp sml-error-overlay)
- (overlay-start sml-error-overlay))
- ]))
-
-;; 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."
-;; (and (eq major-mode 'sml-mode)
-;; (easy-menu-add sml-mode-menu sml-mode-map)))
-;; (add-hook 'sml-mode-hook 'sml-mode-menu-bar)
+ ["SML mode help (brief)" describe-mode t])) ;FIXME-copyright.
;;
-;; regexps
+;; Regexps
;;
(defun sml-syms-re (syms)
- (concat "\\<" (regexp-opt syms t) "\\>"))
+ (concat "\\_<" (regexp-opt syms t) "\\_>"))
;;
@@ -307,81 +222,52 @@ notion of \"the end of an outline\".")
(sml-syms-re '("abstraction" "abstype" "and" "andalso" "as" "before" "case"
"datatype" "else" "end" "eqtype" "exception" "do" "fn"
"fun" "functor" "handle" "if" "in" "include" "infix"
- "infixr" "let" "local" "nonfix" "of" "op" "open" "orelse"
+ "infixr" "let" "local" "nonfix" "o" "of" "op" "open" "orelse"
"overload" "raise" "rec" "sharing" "sig" "signature"
"struct" "structure" "then" "type" "val" "where" "while"
- "with" "withtype" "o"))
+ "with" "withtype"))
"A regexp that matches any and all keywords of SML.")
+(eval-and-compile
+ (defconst sml-id-re "\\sw\\(?:\\sw\\|\\s_\\)*"))
+
(defconst sml-tyvarseq-re
- "\\(\\('+\\(\\sw\\|\\s_\\)+\\|(\\([,']\\|\\sw\\|\\s_\\|\\s-\\)+)\\)\\s-+\\)?")
+ (concat "\\(\\('+" sml-id-re "\\|(\\([,']\\|" sml-id-re
+ "\\|\\s-\\)+)\\)\\s-+\\)?"))
;;; Font-lock settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defcustom sml-font-lock-symbols nil
"Display \\ and -> and such using symbols in fonts.
This may sound like a neat trick, but be extra careful: it changes the
-alignment and can thus lead to nasty surprises w.r.t layout.
-If t, try to use whichever font is available. Otherwise you can
-set it to a particular font of your preference among `japanese-jisx0208'
-and `unicode'."
- :type '(choice (const nil)
- (const t)
- (const unicode)
- (const japanese-jisx0208)))
+alignment and can thus lead to nasty surprises w.r.t layout."
+ :type 'boolean)
(defconst sml-font-lock-symbols-alist
- (append
- ;; The symbols can come from a JIS0208 font.
- (and (fboundp 'make-char) (charsetp 'japanese-jisx0208)
- (memq sml-font-lock-symbols '(t japanese-jisx0208))
- (list (cons "fn" (make-char 'japanese-jisx0208 38 75))
- (cons "andalso" (make-char 'japanese-jisx0208 34 74))
- (cons "orelse" (make-char 'japanese-jisx0208 34 75))
- ;; (cons "as" (make-char 'japanese-jisx0208 34 97))
- (cons "not" (make-char 'japanese-jisx0208 34 76))
- (cons "div" (make-char 'japanese-jisx0208 33 96))
- ;; (cons "*" (make-char 'japanese-jisx0208 33 95))
- (cons "->" (make-char 'japanese-jisx0208 34 42))
- (cons "=>" (make-char 'japanese-jisx0208 34 77))
- (cons "<-" (make-char 'japanese-jisx0208 34 43))
- (cons "<>" (make-char 'japanese-jisx0208 33 98))
- (cons ">=" (make-char 'japanese-jisx0208 33 102))
- (cons "<=" (make-char 'japanese-jisx0208 33 101))
- (cons "..." (make-char 'japanese-jisx0208 33 68))
- ;; Some greek letters for type parameters.
- (cons "'a" (make-char 'japanese-jisx0208 38 65))
- (cons "'b" (make-char 'japanese-jisx0208 38 66))
- (cons "'c" (make-char 'japanese-jisx0208 38 67))
- (cons "'d" (make-char 'japanese-jisx0208 38 68))
- ))
- ;; Or a unicode font.
- (and (fboundp 'decode-char)
- (memq sml-font-lock-symbols '(t unicode))
- (list (cons "fn" (decode-char 'ucs 955))
- (cons "andalso" (decode-char 'ucs 8896))
- (cons "orelse" (decode-char 'ucs 8897))
- ;; (cons "as" (decode-char 'ucs 8801))
- (cons "not" (decode-char 'ucs 172))
- (cons "div" (decode-char 'ucs 247))
- (cons "*" (decode-char 'ucs 215))
- (cons "o" (decode-char 'ucs 9675))
- (cons "->" (decode-char 'ucs 8594))
- (cons "=>" (decode-char 'ucs 8658))
- (cons "<-" (decode-char 'ucs 8592))
- (cons "<>" (decode-char 'ucs 8800))
- (cons ">=" (decode-char 'ucs 8805))
- (cons "<=" (decode-char 'ucs 8804))
- (cons "..." (decode-char 'ucs 8943))
- ;; (cons "::" (decode-char 'ucs 8759))
- ;; Some greek letters for type parameters.
- (cons "'a" (decode-char 'ucs 945))
- (cons "'b" (decode-char 'ucs 946))
- (cons "'c" (decode-char 'ucs 947))
- (cons "'d" (decode-char 'ucs 948))
- ))))
-
-(defun sml-font-lock-compose-symbol (alist)
+ '(("fn" . ?λ)
+ ("andalso" . ?∧) ;; ?⋀
+ ("orelse" . ?∨) ;; ?⋁
+ ;; ("as" . ?≡)
+ ("not" . ?¬)
+ ("div" . ?÷)
+ ("*" . ?×)
+ ("o" . ?○)
+ ("->" . ?→)
+ ("=>" . ?⇒)
+ ("<-" . ?←)
+ ("<>" . ?≠)
+ (">=" . ?≥)
+ ("<=" . ?≤)
+ ("..." . ?⋯)
+ ;; ("::" . ?∷)
+ ;; Some greek letters for type parameters.
+ ("'a" . ?α)
+ ("'b" . ?β)
+ ("'c" . ?γ)
+ ("'d" . ?δ)
+ ))))
+
+(defun sml-font-lock-compose-symbol ()
"Compose a sequence of ascii chars into a symbol.
Regexp match data 0 points to the chars."
;; Check that the chars should really be composed into a symbol.
@@ -398,41 +284,38 @@ Regexp match data 0 points to the chars."
;; we may have added earlier and which is now incorrect.
(remove-text-properties start end '(composition))
;; That's a symbol alright, so add the composition.
- (compose-region start end (cdr (assoc (match-string 0) alist)))))
+ (compose-region start end (cdr (assoc (match-string 0)
+ sml-font-lock-symbols-alist)))))
;; Return nil because we're not adding any face property.
nil)
(defun sml-font-lock-symbols-keywords ()
- (when (fboundp 'compose-region)
- (let ((alist nil))
- (dolist (x sml-font-lock-symbols-alist)
- (when (and (if (fboundp 'char-displayable-p)
- (char-displayable-p (cdr x))
- t)
- (not (assoc (car x) alist))) ;Not yet in alist.
- (push x alist)))
- (when alist
- `((,(regexp-opt (mapcar 'car alist) t)
- (0 (sml-font-lock-compose-symbol ',alist))))))))
+ (when sml-font-lock-symbols
+ `((,(regexp-opt (mapcar 'car sml-font-lock-symbols-alist) t)
+ (0 (sml-font-lock-compose-symbol))))))
;; The font lock regular expressions.
(defconst sml-font-lock-keywords
`(;;(sml-font-comments-and-strings)
- (,(concat "\\<\\(fun\\|and\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)\\s-+[^ \t\n=]")
+ (,(concat "\\_<\\(fun\\|and\\)\\s-+" sml-tyvarseq-re
+ "\\(" sml-re-id "\\)\\s-+[^ \t\n=]")
(1 font-lock-keyword-face)
(6 font-lock-function-name-face))
- (,(concat "\\<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)")
+ (,(concat "\\_<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+"
+ sml-tyvarseq-re "\\(" sml-id-re "\\)")
(1 font-lock-keyword-face)
(7 font-lock-type-def-face))
- ("\\<\\(val\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
+ (,(concat "\\_<\\(val\\)\\s-+\\(" sml-id-re "\\_>\\s-*\\)?\\("
+ sml-id-re "\\)\\s-*[=:]")
(1 font-lock-keyword-face)
;;(6 font-lock-variable-def-face nil t)
(3 font-lock-variable-name-face))
- ("\\<\\(structure\\|functor\\|abstraction\\)\\s-+\\(\\sw+\\)"
+ (,(concat "\\_<\\(structure\\|functor\\|abstraction\\)\\s-+\\("
+ sml-re-id "\\)")
(1 font-lock-keyword-face)
(2 font-lock-module-def-face))
- ("\\<\\(signature\\)\\s-+\\(\\sw+\\)"
+ (,(concat "\\_<\\(signature\\)\\s-+\\(" sml-id-re "\\)")
(1 font-lock-keyword-face)
(2 font-lock-interface-def-face))
@@ -472,134 +355,110 @@ Regexp match data 0 points to the chars."
st)
"Syntax table for text-properties")
-;; For Emacsen that have no built-in support for nested comments
-(defun sml-get-depth-st ()
- (save-excursion
- (let* ((disp (if (eq (char-before) ?\)) (progn (backward-char) -1) nil))
- (_ (backward-char))
- (disp (if (eq (char-before) ?\() (progn (backward-char) 0) disp))
- (pt (point)))
- (when disp
- (let* ((depth
- (save-match-data
- (if (re-search-backward "\\*)\\|(\\*" nil t)
- (+ (or (get-char-property (point) 'comment-depth) 0)
- (case (char-after) (?\( 1) (?* 0))
- disp)
- 0)))
- (depth (if (> depth 0) depth)))
- (put-text-property pt (1+ pt) 'comment-depth depth)
- (when depth sml-syntax-prop-table))))))
-
(defconst sml-font-lock-syntactic-keywords
- `(("^\\s-*\\(\\\\\\)" (1 ',sml-syntax-prop-table))
- ,@(unless sml-builtin-nested-comments-flag
- '(("(?\\(\\*\\))?" (1 (sml-get-depth-st)))))))
+ `(("^\\s-*\\(\\\\\\)" (1 ',sml-syntax-prop-table))))
(defconst sml-font-lock-defaults
- '(sml-font-lock-keywords nil nil ((?_ . "w") (?' . "w")) nil
+ '(sml-font-lock-keywords nil nil nil nil
(font-lock-syntactic-keywords . sml-font-lock-syntactic-keywords)))
;;; Indentation with SMIE
-(defvar sml-use-smie t)
-
(defconst sml-smie-grammar
- (when (fboundp 'smie-prec2->grammar)
- ;; We have several problem areas where SML's syntax can't be handled by an
- ;; operator precedence grammar:
- ;;
- ;; "= A before B" is "= A) before B" if this is the
- ;; `boolean-=' but it is "= (A before B)" if it's the `definitional-='.
- ;; We can work around the problem by tweaking the lexer to return two
- ;; different tokens for the two different kinds of `='.
- ;; "of A | B" in a "case" we want "of (A | B, but in a `datatype'
- ;; we want "of A) | B".
- ;; "= A | B" can be "= A ) | B" if the = is from a "fun" definition,
- ;; but it is "= (A | B" if it is a `datatype' definition (of course, if
- ;; the previous token introducing the = is `and', deciding whether
- ;; it's a datatype or a function requires looking even further back).
- ;; "functor foo (...) where type a = b = ..." the first `=' looks very much
- ;; like a `definitional-=' even tho it's just an equality constraint.
- ;; Currently I don't even try to handle `where' at all.
- (smie-prec2->grammar
- (smie-merge-prec2s
- (smie-bnf->prec2
- '((exp ("if" exp "then" exp "else" exp)
- ("case" exp "of" branches)
- ("let" decls "in" cmds "end")
- ("struct" decls "end")
- ("sig" decls "end")
- (sexp)
- (sexp "handle" branches)
- ("fn" sexp "=>" exp))
- ;; "simple exp"s are the ones that can appear to the left of `handle'.
- (sexp (sexp ":" type) ("(" exps ")")
- (sexp "orelse" sexp)
- (marg ":>" type)
- (sexp "andalso" sexp))
- (cmds (cmds ";" cmds) (exp))
- (exps (exps "," exps) (exp)) ; (exps ";" exps)
- (branches (sexp "=>" exp) (branches "|" branches))
- ;; Operator precedence grammars handle separators much better then
- ;; starters/terminators, so let's pretend that let/fun are separators.
- (decls (sexp "d=" exp)
- (sexp "d=" databranches)
- (funbranches "|" funbranches)
- (sexp "=of" type) ;After "exception".
- ;; FIXME: Just like PROCEDURE in Pascal and Modula-2, this
- ;; interacts poorly with the other constructs since I
- ;; can't make "local" a separator like fun/val/type/...
- ("local" decls "in" decls "end")
- ;; (decls "local" decls "in" decls "end")
- (decls "functor" decls)
- (decls "signature" decls)
- (decls "structure" decls)
- (decls "type" decls)
- (decls "open" decls)
- (decls "and" decls)
- (decls "infix" decls)
- (decls "infixr" decls)
- (decls "nonfix" decls)
- (decls "abstype" decls)
- (decls "datatype" decls)
- (decls "exception" decls)
- (decls "fun" decls)
- (decls "val" decls))
- (type (type "->" type)
- (type "*" type))
- (funbranches (sexp "d=" exp))
- (databranches (sexp "=of" type) (databranches "d|" databranches))
- ;; Module language.
- ;; (mexp ("functor" marg "d=" mexp)
- ;; ("structure" marg "d=" mexp)
- ;; ("signature" marg "d=" mexp))
- (marg (marg ":" type) (marg ":>" type))
- (toplevel (decls) (exp) (toplevel ";" toplevel)))
- ;; '(("local" . opener))
- ;; '((nonassoc "else") (right "handle"))
- '((nonassoc "of") (assoc "|")) ; "case a of b => case c of d => e | f"
- '((nonassoc "handle") (assoc "|")) ; Idem for "handle".
- '((assoc "->") (assoc "*"))
- '((assoc "val" "fun" "type" "datatype" "abstype" "open" "infix" "infixr"
- "nonfix" "functor" "signature" "structure" "exception"
- ;; "local"
- )
- (assoc "and"))
- '((assoc "orelse") (assoc "andalso") (nonassoc ":"))
- '((assoc ";")) '((assoc ",")) '((assoc "d|")))
-
- (smie-precs->prec2
- '((nonassoc "andalso") ;To anchor the prec-table.
- (assoc "before") ;0
- (assoc ":=" "o") ;3
- (nonassoc ">" ">=" "<>" "<" "<=" "=") ;4
- (assoc "::" "@") ;5
- (assoc "+" "-" "^") ;6
- (assoc "/" "*" "quot" "rem" "div" "mod") ;7
- (nonassoc " -dummy- "))) ;Bogus anchor at the end.
- ))))
+ ;; We have several problem areas where SML's syntax can't be handled by an
+ ;; operator precedence grammar:
+ ;;
+ ;; "= A before B" is "= A) before B" if this is the
+ ;; `boolean-=' but it is "= (A before B)" if it's the `definitional-='.
+ ;; We can work around the problem by tweaking the lexer to return two
+ ;; different tokens for the two different kinds of `='.
+ ;; "of A | B" in a "case" we want "of (A | B, but in a `datatype'
+ ;; we want "of A) | B".
+ ;; "= A | B" can be "= A ) | B" if the = is from a "fun" definition,
+ ;; but it is "= (A | B" if it is a `datatype' definition (of course, if
+ ;; the previous token introducing the = is `and', deciding whether
+ ;; it's a datatype or a function requires looking even further back).
+ ;; "functor foo (...) where type a = b = ..." the first `=' looks very much
+ ;; like a `definitional-=' even tho it's just an equality constraint.
+ ;; Currently I don't even try to handle `where' at all.
+ (smie-prec2->grammar
+ (smie-merge-prec2s
+ (smie-bnf->prec2
+ '((exp ("if" exp "then" exp "else" exp)
+ ("case" exp "of" branches)
+ ("let" decls "in" cmds "end")
+ ("struct" decls "end")
+ ("sig" decls "end")
+ (sexp)
+ (sexp "handle" branches)
+ ("fn" sexp "=>" exp))
+ ;; "simple exp"s are the ones that can appear to the left of `handle'.
+ (sexp (sexp ":" type) ("(" exps ")")
+ (sexp "orelse" sexp)
+ (marg ":>" type)
+ (sexp "andalso" sexp))
+ (cmds (cmds ";" cmds) (exp))
+ (exps (exps "," exps) (exp)) ; (exps ";" exps)
+ (branches (sexp "=>" exp) (branches "|" branches))
+ ;; Operator precedence grammars handle separators much better then
+ ;; starters/terminators, so let's pretend that let/fun are separators.
+ (decls (sexp "d=" exp)
+ (sexp "d=" databranches)
+ (funbranches "|" funbranches)
+ (sexp "=of" type) ;After "exception".
+ ;; FIXME: Just like PROCEDURE in Pascal and Modula-2, this
+ ;; interacts poorly with the other constructs since I
+ ;; can't make "local" a separator like fun/val/type/...
+ ("local" decls "in" decls "end")
+ ;; (decls "local" decls "in" decls "end")
+ (decls "functor" decls)
+ (decls "signature" decls)
+ (decls "structure" decls)
+ (decls "type" decls)
+ (decls "open" decls)
+ (decls "and" decls)
+ (decls "infix" decls)
+ (decls "infixr" decls)
+ (decls "nonfix" decls)
+ (decls "abstype" decls)
+ (decls "datatype" decls)
+ (decls "exception" decls)
+ (decls "fun" decls)
+ (decls "val" decls))
+ (type (type "->" type)
+ (type "*" type))
+ (funbranches (sexp "d=" exp))
+ (databranches (sexp "=of" type) (databranches "d|" databranches))
+ ;; Module language.
+ ;; (mexp ("functor" marg "d=" mexp)
+ ;; ("structure" marg "d=" mexp)
+ ;; ("signature" marg "d=" mexp))
+ (marg (marg ":" type) (marg ":>" type))
+ (toplevel (decls) (exp) (toplevel ";" toplevel)))
+ ;; '(("local" . opener))
+ ;; '((nonassoc "else") (right "handle"))
+ '((nonassoc "of") (assoc "|")) ; "case a of b => case c of d => e | f"
+ '((nonassoc "handle") (assoc "|")) ; Idem for "handle".
+ '((assoc "->") (assoc "*"))
+ '((assoc "val" "fun" "type" "datatype" "abstype" "open" "infix" "infixr"
+ "nonfix" "functor" "signature" "structure" "exception"
+ ;; "local"
+ )
+ (assoc "and"))
+ '((assoc "orelse") (assoc "andalso") (nonassoc ":"))
+ '((assoc ";")) '((assoc ",")) '((assoc "d|")))
+
+ (smie-precs->prec2
+ '((nonassoc "andalso") ;To anchor the prec-table.
+ (assoc "before") ;0
+ (assoc ":=" "o") ;3
+ (nonassoc ">" ">=" "<>" "<" "<=" "=") ;4
+ (assoc "::" "@") ;5
+ (assoc "+" "-" "^") ;6
+ (assoc "/" "*" "quot" "rem" "div" "mod") ;7
+ (nonassoc " -dummy- "))) ;Bogus anchor at the end.
+ )))
(defvar sml-indent-separator-outdent 2)
@@ -712,7 +571,7 @@ Assumes point is right before the = sign."
Assumes point is right before the \"of\" symbol."
(save-excursion
(and (re-search-backward (concat "\\(" sml-non-nested-of-starter-re
- "\\)\\|\\<case\\>") nil t)
+ "\\)\\|\\_<case\\_>") nil t)
(match-beginning 1))))
(defun sml-smie-datatype-|-p ()
@@ -778,7 +637,7 @@ Assumes point is right before the | symbol."
(concat "^[ \t]*\\(let[ \t]+\\)?"
(regexp-opt (append sml-module-head-syms
'("and" "fun" "datatype" "abstype" "type")) t)
- "\\>"))
+ "\\_>"))
(defun sml-imenu-create-index ()
(let (alist)
@@ -808,15 +667,15 @@ Assumes point is right before the | symbol."
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . sml-mode))
-(unless (fboundp 'prog-mode) (defalias 'prog-mode 'fundamental-mode))
(defvar comment-quote-nested)
(defvar electric-indent-chars)
(defvar electric-layout-rules)
;;;###autoload
(define-derived-mode sml-mode prog-mode "SML"
- "\\<sml-mode-map>Major mode for editing ML code.
+ "\\<sml-mode-map>Major mode for editing Standard ML code.
This mode runs `sml-mode-hook' just before exiting.
+See also (info \"(sml-mode)Top\").
\\{sml-mode-map}"
(set (make-local-variable 'font-lock-defaults) sml-font-lock-defaults)
(set (make-local-variable 'outline-regexp) sml-outline-regexp)
@@ -839,23 +698,15 @@ This mode runs `sml-mode-hook' just before exiting.
(progn (skip-chars-forward " \t;")
(eolp)))
'after))))))
- ;; For XEmacs
- (easy-menu-add sml-mode-menu)
- ;; Compatibility. FIXME: we should use `-' in Emacs-CVS.
- (unless (boundp 'skeleton-positions) (set (make-local-variable '@) nil))
(sml-mode-variables))
(defun sml-mode-variables ()
(set-syntax-table sml-mode-syntax-table)
(setq local-abbrev-table sml-mode-abbrev-table)
;; Setup indentation and sexp-navigation.
- (when (fboundp 'smie-setup)
- (smie-setup sml-smie-grammar #'sml-smie-rules
- :backward-token #'sml-smie-backward-token
- :forward-token #'sml-smie-forward-token))
- (unless (and sml-use-smie (fboundp 'smie-setup))
- (set (make-local-variable 'forward-sexp-function) 'sml-user-forward-sexp)
- (set (make-local-variable 'indent-line-function) 'sml-indent-line))
+ (smie-setup sml-smie-grammar #'sml-smie-rules
+ :backward-token #'sml-smie-backward-token
+ :forward-token #'sml-smie-forward-token)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'comment-start) "(* ")
(set (make-local-variable 'comment-end) " *)")
@@ -880,7 +731,7 @@ Point has to be right after the `and' symbol and is not preserved."
(not (looking-at re)))
(or (ignore-errors (forward-sexp 1) t) (forward-char 1))))
-(defun sml-electric-pipe ()
+(defun sml-electric-pipe () ;FIXME: Use post-self-insert-hook?
"Insert a \"|\".
Depending on the context insert the name of function, a \"=>\" etc."
;; FIXME: Make it a skeleton.
@@ -921,39 +772,28 @@ Depending on the context insert the name of function, a \"=>\" etc."
(indent-according-to-mode)
(beginning-of-line)
(skip-chars-forward "\t |")
- (skip-syntax-forward "w")
+ (skip-syntax-forward "w_")
(skip-chars-forward "\t ")
(when (eq ?= (char-after)) (backward-char))))
-(defun sml-electric-semi ()
- "Insert a \;.
-If variable `sml-electric-semi-mode' is t, indent the current line, insert
-a newline, and indent."
- (interactive)
- (self-insert-command 1)
- (if sml-electric-semi-mode
- (reindent-then-newline-and-indent)))
-
;;; Misc
(defun sml-mark-function ()
"Mark the surrounding function. Or try to at least."
(interactive)
- (if (not (fboundp 'smie-setup))
- (mark-paragraph)
- ;; FIXME: Provide beginning-of-defun-function so mark-defun "just works".
- (let ((start (point)))
- (sml-beginning-of-defun)
- (let ((beg (point)))
- (smie-forward-sexp 'halfsexp)
- (if (or (< start beg) (> start (point)))
- (progn
- (goto-char start)
- (mark-paragraph))
- (push-mark nil t t)
- (goto-char beg))))))
-
-(defun sml-back-to-outer-indent ()
+ ;; FIXME: Provide beginning-of-defun-function so mark-defun "just works".
+ (let ((start (point)))
+ (sml-beginning-of-defun)
+ (let ((beg (point)))
+ (smie-forward-sexp 'halfsexp)
+ (if (or (< start beg) (> start (point)))
+ (progn
+ (goto-char start)
+ (mark-paragraph))
+ (push-mark nil t t)
+ (goto-char beg)))))
+
+(defun sml-back-to-outer-indent () ;FIXME-copyright.
"Unindents to the next outer level of indentation."
(interactive)
(save-excursion
@@ -965,12 +805,12 @@ a newline, and indent."
(progn
(save-excursion
(while (>= indent start-column)
- (if (re-search-backward "^[^\n]" nil t)
- (setq indent (current-indentation))
- (setq indent 0))))
+ (setq indent (if (re-search-backward "^[^\n]" nil t)
+ (current-indentation)
+ 0))))
(backward-delete-char-untabify (- start-column indent)))))))
-(defun sml-smie-find-matching-starter (syms)
+(defun sml-find-matching-starter (syms)
(let ((halfsexp nil)
tok)
;;(sml-smie-forward-token)
@@ -984,14 +824,7 @@ a newline, and indent."
(if (nth 2 tok) (goto-char (cadr tok)))
(nth 2 tok)))
-(defun sml-find-matching-starter (syms)
- (cond
- ((and sml-use-smie (fboundp 'smie-backward-sexp))
- (sml-smie-find-matching-starter syms))
- ((fboundp 'sml-old-find-matching-starter)
- (sml-old-find-matching-starter syms))))
-
-(defun sml-smie-skip-siblings ()
+(defun sml-skip-siblings ()
(let (tok)
(while (and (not (bobp))
(progn (setq tok (smie-backward-sexp 'half))
@@ -1002,14 +835,6 @@ a newline, and indent."
(if (nth 2 tok) (goto-char (cadr tok)))
(nth 2 tok)))
-(defun sml-skip-siblings ()
- (cond
- ((and sml-use-smie (fboundp 'smie-backward-sexp))
- (sml-smie-skip-siblings))
- ((fboundp 'sml-old-skip-siblings)
- (sml-old-skip-siblings))
- (t (up-list -1))))
-
(defun sml-beginning-of-defun ()
(let ((sym (sml-find-matching-starter sml-starters-syms)))
(if (member sym '("fun" "and" "functor" "signature" "structure"
@@ -1043,7 +868,7 @@ a newline, and indent."
;;; INSERTING PROFORMAS (COMMON SML-FORMS)
(defvar sml-forms-alist nil
- "*Alist of code templates.
+ "Alist of code templates.
You can extend this alist to your heart's content. For each additional
template NAME in the list, declare a keyboard macro or function (or
interactive command) called 'sml-form-NAME'.
@@ -1056,26 +881,23 @@ and `sml-addto-forms-alist'.
signature, structure, and functor by default.")
(defmacro sml-def-skeleton (name interactor &rest elements)
- (when (fboundp 'define-skeleton)
- (let ((fsym (intern (concat "sml-form-" name))))
- ;; TODO: don't do the expansion in comments and strings.
- `(progn
- (add-to-list 'sml-forms-alist ',(cons name fsym))
- (condition-case err
- ;; Try to use the new `system' flag.
- (define-abbrev sml-mode-abbrev-table ,name "" ',fsym nil 'system)
- (wrong-number-of-arguments
- (define-abbrev sml-mode-abbrev-table ,name "" ',fsym)))
- (when (fboundp 'abbrev-put)
- (let ((abbrev (abbrev-symbol ,name sml-mode-abbrev-table)))
- (abbrev-put abbrev :case-fixed t)
- (abbrev-put abbrev :enable-function
- (lambda () (not (nth 8 (syntax-ppss)))))))
- (define-skeleton ,fsym
- ,(format "SML-mode skeleton for `%s..' expressions" name)
- ,interactor
- ,(concat name " ") >
- ,@elements)))))
+ (let ((fsym (intern (concat "sml-form-" name))))
+ `(progn
+ (add-to-list 'sml-forms-alist ',(cons name fsym))
+ (condition-case err
+ ;; Try to use the new `system' flag.
+ (define-abbrev sml-mode-abbrev-table ,name "" ',fsym nil 'system)
+ (wrong-number-of-arguments
+ (define-abbrev sml-mode-abbrev-table ,name "" ',fsym)))
+ (let ((abbrev (abbrev-symbol ,name sml-mode-abbrev-table)))
+ (abbrev-put abbrev :case-fixed t)
+ (abbrev-put abbrev :enable-function
+ (lambda () (not (nth 8 (syntax-ppss))))))
+ (define-skeleton ,fsym
+ ,(format "SML-mode skeleton for `%s..' expressions" name)
+ ,interactor
+ ,(concat name " ") >
+ ,@elements))))
(put 'sml-def-skeleton 'lisp-indent-function 2)
(sml-def-skeleton "let" nil
@@ -1141,7 +963,7 @@ the corresponding form is inserted."
(this-command 'self-insert-command))
(call-interactively 'self-insert-command)))
-(defun sml-insert-form (name newline)
+(defun sml-insert-form (name newline) ;FIXME-copyright.
"Interactive short-cut to insert the NAME common ML form.
If a prefix argument is given insert a NEWLINE and indent first, or
just move to the proper indentation if the line is blank\; otherwise
@@ -1152,24 +974,23 @@ The default form to insert is 'whatever you inserted last time'
completion from `sml-forms-alist'."
(interactive
(list (completing-read
- (format "Form to insert: (default %s) " sml-last-form)
- sml-forms-alist nil t nil)
+ (format "Form to insert (default %s): " sml-last-form)
+ sml-forms-alist nil t nil nil sml-forms-alist)
current-prefix-arg))
- ;; default is whatever the last insert was...
- (if (string= name "") (setq name sml-last-form) (setq sml-last-form name))
+ (setq sml-last-form name)
(unless (or (not newline)
(save-excursion (beginning-of-line) (looking-at "\\s-*$")))
(insert "\n"))
- (unless (/= ?w (char-syntax (preceding-char))) (insert " "))
+ (when (memq (char-syntax (preceding-char)) '(?_ ?w)) (insert " "))
(let ((f (cdr (assoc name sml-forms-alist))))
(cond
((commandp f) (command-execute f))
(f (funcall f))
- (t (error "Undefined form: %s" name)))))
+ (t (error "Undefined SML form: %s" name)))))
;; See also macros.el in emacs lisp dir.
-(defun sml-addto-forms-alist (name)
+(defun sml-addto-forms-alist (name) ;FIXME-copyright.
"Assign a name to the last keyboard macro defined.
Argument NAME is transmogrified to sml-form-NAME which is the symbol
actually defined.
@@ -1204,7 +1025,7 @@ See also `edit-kbd-macro' which is bound to \\[edit-kbd-macro]."
`(("^\\(?:Error\\|\\(Warning\\)\\): \\(.+\\) \\([0-9]+\\)\\.\\([0-9]+\\)\\.$"
2 3 4
;; If subgroup 1 matched, then it's a warning, otherwise it's an error.
- ,@(if (fboundp 'compilation-fake-loc) '((1))))))
+ (1))))
(defvar compilation-error-regexp-alist)
(eval-after-load "compile"
@@ -1307,9 +1128,9 @@ See also `edit-kbd-macro' which is bound to \\[edit-kbd-macro]."
(defvar sml-cm-mode-syntax-table sml-mode-syntax-table)
(defvar sml-cm-font-lock-keywords
- `(,(concat "\\<" (regexp-opt '("library" "group" "is" "structure"
+ `(,(concat "\\_<" (regexp-opt '("library" "group" "is" "structure"
"functor" "signature" "funsig") t)
- "\\>")))
+ "\\_>")))
;;;###autoload
(add-to-list 'completion-ignored-extensions ".cm/")
;; This was used with the old compilation manager.
@@ -1329,7 +1150,7 @@ See also `edit-kbd-macro' which is bound to \\[edit-kbd-macro]."
(defvar sml-lex-font-lock-keywords
(append
- '(("^%\\sw+" . font-lock-builtin-face)
+ `((,(concat "^%" sml-id-re) . font-lock-builtin-face)
("^%%" . font-lock-module-def-face))
sml-font-lock-keywords))
(defconst sml-lex-font-lock-defaults
@@ -1364,16 +1185,18 @@ If nil, align it with previous cases."
:type 'integer)
(defvar sml-yacc-font-lock-keywords
- (cons '("^\\(\\sw+\\s-*:\\|\\s-*|\\)\\(\\s-*\\sw+\\)*\\s-*\\(\\(%\\sw+\\)\\s-+\\sw+\\|\\)"
- (0 (save-excursion
- (save-match-data
- (goto-char (match-beginning 0))
- (unless (or (re-search-forward "\\<of\\>" (match-end 0) 'move)
- (progn (forward-comment (point-max))
- (not (looking-at "("))))
- sml-yacc-bnf-face))))
- (4 font-lock-builtin-face t t))
- sml-lex-font-lock-keywords))
+ (cons `((concat "^\\(" sml-id-re "\\s-*:\\|\\s-*|\\)\\(\\s-*" sml-id-re
+ "\\)*\\s-*\\(\\(%" sml-id-re "\\)\\s-+" sml-id-re "\\|\\)")
+ (0 (save-excursion
+ (save-match-data
+ (goto-char (match-beginning 0))
+ (unless (or (re-search-forward "\\_<of\\_>"
+ (match-end 0) 'move)
+ (progn (forward-comment (point-max))
+ (not (looking-at "("))))
+ sml-yacc-bnf-face))))
+ (4 font-lock-builtin-face t t))
+ sml-lex-font-lock-keywords))
(defconst sml-yacc-font-lock-defaults
(cons 'sml-yacc-font-lock-keywords (cdr sml-font-lock-defaults)))
@@ -1388,7 +1211,9 @@ If nil, align it with previous cases."
(defun sml-yacc-indentation ()
(save-excursion
(back-to-indentation)
- (or (and (looking-at "%\\|\\(\\sw\\|\\s_\\)+\\s-*:") 0)
+ (or (and (looking-at (eval-when-compile
+ (concat "%\\|" sml-id-re "\\s-*:")))
+ 0)
(when (save-excursion
(condition-case nil (progn (up-list -1) nil) (scan-error t)))
;; We're outside an action.
@@ -1415,10 +1240,7 @@ If nil, align it with previous cases."
(skip-syntax-forward " ")
(- (current-column) 2))))))
;; default to SML rules
- (cond
- ((and sml-use-smie (fboundp 'smie-indent-calculate))
- (smie-indent-calculate))
- ((fboundp 'sml-calculate-indentation) (sml-calculate-indentation))))))
+ (smie-indent-calculate))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.grm\\'" . sml-yacc-mode))
@@ -1431,7 +1253,4 @@ If nil, align it with previous cases."
(provide 'sml-mode)
-(unless (and sml-use-smie (fboundp 'smie-setup))
- (require 'sml-oldindent))
-
;;; sml-mode.el ends here
diff --git a/sml-proc.el b/sml-proc.el
index 84e5e65670a..08d88085800 100644
--- a/sml-proc.el
+++ b/sml-proc.el
@@ -1,4 +1,4 @@
-;;; sml-proc.el --- Comint based interaction mode for Standard ML.
+;;; sml-proc.el --- Comint based interaction mode for Standard ML. -*- lexical-binding: t; coding: utf-8 -*-
;; Copyright (C) 1999,2000,2003,2004,2005,2007,2012 Stefan Monnier
;; Copyright (C) 1994-1997 Matthew J. Morley
@@ -26,12 +26,10 @@
;; ====================================================================
-;; [MJM 10/94] Separating this from sml-mode means sml-mode will run
-;; under 18.59 (or anywhere without comint, if there are such places).
-;; See sml-mode.el for further information.
-
;;; Commentary:
+;; FIXME-copyright.
+
;; Inferior-sml-mode is for interacting with an ML process run under
;; emacs. This uses the comint package so you get history, expansion,
;; backup and all the other benefits of comint. Interaction is
@@ -82,7 +80,6 @@
;; Todo:
;; - Keep improving `sml-compile'.
-;; - ignore warnings (if requested) for next-error
;;; Code:
@@ -126,18 +123,11 @@ It is perfectly OK to associate several files with a command or several
commands with the same file.")
(defvar inferior-sml-mode-hook nil
- "*This hook is run when the inferior ML process is started.
+ "Hook is run when the inferior ML process is started.
All buffer local customisations for the interaction buffers go here.")
-(defvar sml-error-overlay nil
- "*Non-nil means use an overlay to highlight errorful code in the buffer.
-The actual value is the name of a face to use for the overlay.
-Instead of setting this variable to 'region, you can also simply keep
-it NIL and use (transient-mark-mode) which will provide similar
-benefits (but with several side effects).")
-
(defvar sml-buffer nil
- "*The current ML process buffer.
+ "The current ML process buffer.
MULTIPLE PROCESS SUPPORT (Whoever wants multi-process support anyway?)
=====================================================================
@@ -182,12 +172,12 @@ use the command \\[sml-buffer] in the interaction buffer of choice.")
;;; ALL STUFF THAT DEFAULTS TO THE SML/NJ COMPILER (0.93)
(defvar sml-use-command "use \"%s\""
- "*Template for loading a file into the inferior ML process.
+ "Template for loading a file into the inferior ML process.
Set to \"use \\\"%s\\\"\" for SML/NJ or Edinburgh ML;
set to \"PolyML.use \\\"%s\\\"\" for Poly/ML, etc.")
(defvar sml-cd-command "OS.FileSys.chDir \"%s\""
- "*Command template for changing working directories under ML.
+ "Command template for changing working directories under ML.
Set this to nil if your compiler can't change directories.
The format specifier \"%s\" will be converted into the directory name
@@ -205,14 +195,10 @@ specified when running the command \\[sml-cd].")
;; SML/NJ: the file-pattern is anchored to avoid
;; pathological behavior with very long lines.
("^[-= ]*\\(.*[^\n)]\\)\\( (.*)\\)?:\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)? \\(Error\\|Warnin\\(g\\)\\): .*" 1
- ,@(if (fboundp 'compilation-fake-loc) ;New compile.el.
- '((3 . 6) (4 . 7) (9))
- '(sml-make-error 3 4 6 7)))
+ (3 . 6) (4 . 7) (9))
;; SML/NJ's exceptions: see above.
("^ +\\(raised at: \\)?\\(.+\\):\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)" 2
- ,@(if (fboundp 'compilation-fake-loc) ;New compile.el.
- '((3 . 6) (4 . 7))
- '(sml-make-error 3 4 6 7))))
+ (3 . 6) (4 . 7)))
"Alist that specifies how to match errors in compiler output.
See `compilation-error-regexp-alist' for a description of the format.")
@@ -226,11 +212,7 @@ See `compilation-error-regexp-alist' for a description of the format.")
;; CM's messages
("^\\[\\(.*GC #.*\n\\)*.*\\]" . font-lock-comment-face)
;; SML/NJ's irritating GC messages
- ("^GC #.*" . font-lock-comment-face)
- ;; error messages
- ,@(unless (fboundp 'compilation-fake-loc)
- (mapcar (lambda (ra) (cons (car ra) 'font-lock-warning-face))
- sml-error-regexp-alist)))
+ ("^GC #.*" . font-lock-comment-face))
"Font-locking specification for inferior SML mode.")
(defface font-lock-prompt-face
@@ -258,17 +240,13 @@ See `compilation-error-regexp-alist' for a description of the format.")
(set-keymap-parent map comint-mode-map)
(define-key map "\C-c\C-s" 'run-sml)
(define-key map "\C-c\C-l" 'sml-load-file)
- (define-key map "\t"
- (if (fboundp 'completion-at-point)
- 'completion-at-point 'comint-dynamic-complete))
+ (define-key map "\t" 'completion-at-point)
map)
"Keymap for inferior-sml mode")
;; buffer-local
(defvar sml-temp-file nil)
-;;(defvar sml-error-file nil) ; file from which the last error came
-(defvar sml-error-cursor nil) ; ditto
(defun sml-proc-buffer ()
"Return the current ML process buffer.
@@ -310,7 +288,7 @@ If prefix argument ECHO is set, then it only reports on the current state."
;; but this doesn't catch the case when the user types commands directly
;; at the prompt.
(compilation-forget-errors) ;Has to run before compilation-fake-loc.
- (if (and (fboundp 'compilation-fake-loc) sml-temp-file)
+ (if sml-temp-file
(compilation-fake-loc (cdr sml-temp-file) (car sml-temp-file)))
str)
@@ -346,22 +324,20 @@ If prefix argument ECHO is set, then it only reports on the current state."
;; The position of `point' is not guaranteed :-(
(looking-at (concat ".*\\[tycon mismatch\\]\n"
" \\(operator domain\\|expression\\|rule domain\\): +")))
- (ignore-errors (require 'smerge-mode))
- (if (not (fboundp 'smerge-refine-subst))
- (remove-hook 'next-error-hook 'inferior-sml-next-error-hook)
- (save-excursion
- (let ((b1 (match-end 0))
- e1 b2 e2)
- (when (re-search-forward "\n in \\(expression\\|declaration\\):\n"
- nil t)
- (setq e2 (match-beginning 0))
- (when (re-search-backward
- "\n \\(operand\\|result type\\|object\\): +"
- b1 t)
- (setq e1 (match-beginning 0))
- (setq b2 (match-end 0))
- (smerge-refine-subst b1 e1 b2 e2
- '((face . smerge-refined-change)))))))))))
+ (require 'smerge-mode)
+ (save-excursion
+ (let ((b1 (match-end 0))
+ e1 b2 e2)
+ (when (re-search-forward "\n in \\(expression\\|declaration\\):\n"
+ nil t)
+ (setq e2 (match-beginning 0))
+ (when (re-search-backward
+ "\n \\(operand\\|result type\\|object\\): +"
+ b1 t)
+ (setq e1 (match-beginning 0))
+ (setq b2 (match-end 0))
+ (smerge-refine-subst b1 e1 b2 e2
+ '((face . smerge-refined-change))))))))))
(define-derived-mode inferior-sml-mode comint-mode "Inferior-SML"
"Major mode for interacting with an inferior ML process.
@@ -420,35 +396,28 @@ TAB file name completion, as in shell-mode, etc.."
(set (make-local-variable 'font-lock-defaults)
inferior-sml-font-lock-defaults)
- ;; For sequencing through error messages:
- (set (make-local-variable 'sml-error-cursor) (point-max-marker))
- (set-marker-insertion-type sml-error-cursor nil)
;; Compilation support (used for `next-error').
;; The keymap of compilation-minor-mode is too unbearable, so we
;; just can't use the minor-mode if we can't override the map.
- (when (boundp 'minor-mode-overriding-map-alist)
- (set (make-local-variable 'compilation-error-regexp-alist)
- sml-error-regexp-alist)
- (compilation-minor-mode 1)
- ;; Eliminate compilation-minor-mode's map.
- (let ((map (make-sparse-keymap)))
- (dolist (keys '([menu-bar] [follow-link]))
- ;; Preserve some of the bindings.
- (define-key map keys (lookup-key compilation-minor-mode-map keys)))
- (add-to-list 'minor-mode-overriding-map-alist
- (cons 'compilation-minor-mode map)))
- ;; I'm sure people might kill me for that
- (setq compilation-error-screen-columns nil)
- (make-local-variable 'sml-endof-error-alist))
- ;;(make-local-variable 'sml-error-overlay)
+ (set (make-local-variable 'compilation-error-regexp-alist)
+ sml-error-regexp-alist)
+ (compilation-minor-mode 1)
+ ;; Eliminate compilation-minor-mode's map.
+ (let ((map (make-sparse-keymap)))
+ (dolist (keys '([menu-bar] [follow-link]))
+ ;; Preserve some of the bindings.
+ (define-key map keys (lookup-key compilation-minor-mode-map keys)))
+ (add-to-list 'minor-mode-overriding-map-alist
+ (cons 'compilation-minor-mode map)))
+ ;; I'm sure people might kill me for that. ;FIXME: move it to sml-mode?
+ (set (make-local-variable 'compilation-error-screen-columns) nil)
(setq mode-line-process '(": %s")))
;;; FOR RUNNING ML FROM EMACS
-;;;###autoload
-(autoload 'run-sml "sml-proc" nil t)
+;;;###autoload (autoload 'run-sml "sml-proc" nil t)
(defalias 'run-sml 'sml-run)
(defun sml-run (cmd arg &optional host)
"Run the program CMD with given arguments ARG.
@@ -456,14 +425,10 @@ The command is run in buffer *CMD* using mode `inferior-sml-mode'.
If the buffer already exists and has a running process, then
just go to this buffer.
-This updates `sml-buffer' to the new buffer.
-You can have several inferior M(or L process running, but only one (> s
-current one -- given by `sml-buffer' (qv).
-
If a prefix argument is used, the user is also prompted for a HOST
on which to run CMD using `remote-shell-program'.
-\(Type \\[describe-mode] in the process buffer for a list of commands.)"
+\(Type \\[describe-mode] in the process's buffer for a list of commands.)"
(interactive
(list
(read-string "ML command: " sml-program-name)
@@ -474,7 +439,7 @@ on which to run CMD using `remote-shell-program'.
(read-string "On host: " sml-host-name)
sml-host-name)))
(let* ((pname (file-name-nondirectory cmd))
- (args (if (equal arg "") () (split-string arg)))
+ (args (split-string arg))
(file (when (and sml-config-file (file-exists-p sml-config-file))
sml-config-file)))
;; and this -- to keep these as defaults even if
@@ -487,7 +452,8 @@ on which to run CMD using `remote-shell-program'.
(setq args (list* host "cd" default-directory ";" cmd args))
(setq cmd remote-shell-program))
;; go for it
- (let ((exec-path (if (file-name-directory cmd)
+ (let ((exec-path (if (and (file-name-directory cmd)
+ (not (file-name-absolute-p cmd)))
;; If the command has slashes, make sure we
;; first look relative to the current directory.
;; Emacs-21 does it for us, but not Emacs-20.
@@ -495,7 +461,6 @@ on which to run CMD using `remote-shell-program'.
(setq sml-buffer (apply 'make-comint pname cmd file args)))
(pop-to-buffer sml-buffer)
- ;;(message (format "Starting \"%s\" in background." pname))
(inferior-sml-mode)
(goto-char (point-max))
sml-buffer))
@@ -509,11 +474,9 @@ Move point to the end of buffer unless prefix argument EOBP is set."
(push-mark (point) t)
(goto-char (point-max))))
-;; Fakes it with a "use <temp-file>;" if necessary.
-
(defun sml-send-region (start end &optional and-go)
"Send current region START..END to the inferior ML process.
-Prefix AND-GO argument means switch-to-sml afterwards.
+Prefix AND-GO argument means `switch-to-sml' afterwards.
The region is written out to a temporary file and a \"use <temp-file>\" command
is sent to the compiler.
@@ -547,7 +510,7 @@ With a prefix argument AND-GO switch to the sml buffer as well
(if and-go (switch-to-sml nil)))
(defvar sml-source-modes '(sml-mode)
- "*Used to determine if a buffer contains ML source code.
+ "Used to determine if a buffer contains ML source code.
If it's loaded into a buffer that is in one of these major modes, it's
considered an ML source file by `sml-load-file'. Used by these commands
to determine defaults.")
@@ -557,8 +520,7 @@ to determine defaults.")
With a prefix argument AND-GO switch to the sml buffer as well
\(cf. `sml-send-region'\)."
(interactive "P")
- (if (memq major-mode sml-source-modes)
- (sml-send-region (point-min) (point-max) and-go)))
+ (sml-send-region (point-min) (point-max) and-go))
;; Since sml-send-function/region take an optional prefix arg, these
;; commands are redundant. But they are kept around for the user to
@@ -579,7 +541,7 @@ With a prefix argument AND-GO switch to the sml buffer as well
(defvar sml-prev-dir/file nil
"Cache for (DIRECTORY . FILE) pair last.
Set in `sml-load-file' and `sml-cd' commands.
-Used to determine the default in the next `ml-load-file'.")
+Used to determine the default in the next `sml-load-file'.")
(defun sml-load-file (&optional and-go)
"Load an ML file into the current inferior ML process.
@@ -592,7 +554,7 @@ automatically."
(let ((file (car (comint-get-source
"Load ML file: " sml-prev-dir/file sml-source-modes t))))
(with-current-buffer (sml-proc-buffer)
- ;; Check if buffer needs saved. Should (save-some-buffers) instead?
+ ;; Check if buffer needs saving. Should (save-some-buffers) instead?
(comint-check-source file)
(setq sml-prev-dir/file
(cons (file-name-directory file) (file-name-nondirectory file)))
@@ -608,7 +570,7 @@ be executed to change the compiler's working directory\; a trailing
(let ((dir (expand-file-name dir)))
(with-current-buffer (sml-proc-buffer)
(sml-send-string (format sml-cd-command dir) t)
- (setq default-directory dir))
+ (setq default-directory (file-name-as-directory dir)))
(setq sml-prev-dir/file (cons dir nil))))
(defun sml-send-string (str &optional print and-go)
@@ -618,7 +580,6 @@ be executed to change the compiler's working directory\; a trailing
(when win (select-window win))
(goto-char (point-max))
(when print (insert str))
- (sml-update-cursor)
(set-marker (process-mark proc) (point-max))
(setq compilation-last-buffer (current-buffer))
(comint-send-string proc str)
@@ -637,7 +598,7 @@ Prefix arg AND-GO also means to `switch-to-sml' afterwards."
(interactive
(let* ((dir default-directory)
(cmd "cd \"."))
- ;; look for files to determine the default command
+ ;; Look for files to determine the default command.
(while (and (stringp dir)
(dolist (cf sml-compile-commands-alist 1)
(when (file-exists-p (expand-file-name (cdr cf) dir))
@@ -682,103 +643,110 @@ Prefix arg AND-GO also means to `switch-to-sml' afterwards."
(sml-send-string (concat (format sml-cd-command dir) "; " command)
t and-go))))
-;;; PARSING ERROR MESSAGES
-
-;; This should need no modification to support other compilers.
-
-;; Update the buffer-local error-cursor in proc-buffer to be its
-;; current proc mark.
-
-(defvar sml-endof-error-alist nil)
-
-(defun sml-update-cursor ()
- ;; Update buffer local variable.
- (set-marker sml-error-cursor (1- (process-mark (sml-proc))))
- (setq sml-endof-error-alist nil)
- ;; This is now done in comint-input-filter-functions.
- ;; (compilation-forget-errors) ;Has to run before compilation-fake-loc.
- ;; (if (and (fboundp 'compilation-fake-loc) sml-temp-file)
- ;; (compilation-fake-loc (cdr sml-temp-file) (car sml-temp-file)))
- (if (markerp compilation-parsing-end)
- (set-marker compilation-parsing-end sml-error-cursor)
- (setq compilation-parsing-end sml-error-cursor)))
-
-(defun sml-make-error (f c)
- (let ((err (point-marker))
- (linenum (string-to-number c))
- (filename (list (first f) (second f)))
- (column (string-to-number (match-string (third f)))))
- ;; record the end of error, if any
- (when (fourth f)
- (let ((endlinestr (match-string (fourth f))))
- (when endlinestr
- (let* ((endline (string-to-number endlinestr))
- (endcol (string-to-number
- (or (match-string (fifth f)) "0")))
- (linediff (- endline linenum)))
- (push (list err linediff (if (= 0 linediff) (- endcol column) endcol))
- sml-endof-error-alist)))))
- ;; build the error descriptor
- (if (string= (car sml-temp-file) (first f))
- ;; special case for code sent via sml-send-region
- (let ((marker (cdr sml-temp-file)))
- (with-current-buffer (marker-buffer marker)
- (goto-char marker)
- (forward-line (1- linenum))
- (forward-char (1- column))
- ;; A pair of markers is the right thing to return, but some
- ;; code in compile.el doesn't like it (when we reach the end
- ;; of the errors). So we could try to avoid it, but we don't
- ;; because that doesn't work correctly if the current buffer
- ;; has unsaved modifications. And it's fixed in Emacs-21.
- ;; (if buffer-file-name
- ;; (list err buffer-file-name
- ;; (count-lines (point-min) (point)) (current-column))
- (cons err (point-marker)))) ;; )
- ;; taken from compile.el
- (list err filename linenum column))))
-
-(unless (fboundp 'compilation-fake-loc)
-(defadvice compilation-goto-locus (after sml-endof-error activate)
- (let* ((next-error (ad-get-arg 0))
- (err (car next-error))
- (pos (cdr next-error))
- (endof (with-current-buffer (marker-buffer err)
- (assq err sml-endof-error-alist))))
- (if (not endof) (sml-error-overlay 'undo)
- (with-current-buffer (marker-buffer pos)
- (goto-char pos)
- (let ((linediff (second endof))
- (coldiff (third endof)))
- (when (> 0 linediff) (forward-line linediff))
- (forward-char coldiff))
- (sml-error-overlay nil pos (point))
- (push-mark nil t (not sml-error-overlay))
- (goto-char pos))))))
-
-(defun sml-error-overlay (undo &optional beg end)
- "Move `sml-error-overlay' to the text region in the current buffer.
-If the buffer-local variable `sml-error-overlay' is
-non-nil it should be an overlay \(or extent, in XEmacs speak\)\; this
-function moves the overlay over the current region. If the optional
-BUFFER argument is given, move the overlay in that buffer instead of
-the current buffer.
-
-Called interactively, the optional prefix argument UNDO indicates that
-the overlay should simply be removed: \\[universal-argument] \
-\\[sml-error-overlay]."
- (interactive "P")
- (when sml-error-overlay
- (unless (overlayp sml-error-overlay)
- (let ((ol sml-error-overlay))
- (setq sml-error-overlay (make-overlay (point) (point)))
- (overlay-put sml-error-overlay 'face (if (symbolp ol) ol 'region))))
- (if undo (delete-overlay sml-error-overlay)
- ;; If active regions, signals mark not active if no region set.
- (move-overlay sml-error-overlay
- (or beg (region-beginning)) (or end (region-end))
- (current-buffer)))))
(provide 'sml-proc)
+;;; Prog-Proc: Interacting with an inferior process from a source buffer.
+
+;; Prog-Proc is a package designed to complement Comint: while Comint was
+;; designed originally to handle the needs of inferior process buffers, such
+;; as a buffer running a Scheme repl, Comint does not actually provide any
+;; functionality that links this process buffer with some source code.
+;;
+;; That's where Prog-Proc comes into play: it provides the usual commands and
+;; key-bindings that lets the user send his code to the underlying repl.
+
+(defvar sml-prog-proc-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key [?\C-c ?\C-l] 'sml-prog-proc-load-file)
+ (define-key [?\C-c ?\C-c] 'sml-prog-proc-compile)
+ (define-key [?\C-c ?\C-z] 'sml-prog-proc-switch-to)
+ (define-key [?\C-c ?\C-r] 'sml-prog-proc-send-region)
+ (define-key [?\C-c ?\C-b] 'sml-prog-proc-send-buffer)
+ map)
+ "Keymap for `sml-prog-proc-mode'.")
+
+(defvar sml-prog-proc-buffer nil
+ "The inferior-process buffer to which to send code.")
+(make-variable-buffer-local 'sml-prog-proc-buffer)
+
+(defstruct (sml-prog-proc-functions
+ (:predicate nil)
+ (:copy nil))
+ (run :read-only t)
+ (load-cmd :read-only t))
+
+(defvar sml-prog-proc-functions nil
+ "Struct containing the various functions to create a new process, ...")
+
+(defmacro sml-prog-proc--call (method &rest args)
+ `(sml-prog-proc--apply
+ #',(intern (format "sml-prog-proc-functions-%s" method))
+ args))
+(defun sml-prog-proc--apply (selector &rest args)
+ (if (not sml-prog-proc-functions)
+ (error "Not an `sml-prog-proc' buffer")
+ (apply (funcall selector sml-prog-proc-functions) args)))
+
+(defun sml-prog-proc-proc ()
+ "Return the inferior process for the code in current buffer."
+ (or (and (buffer-live-p sml-prog-proc-buffer)
+ (get-buffer-process sml-prog-proc-buffer))
+ (sml-prog-proc--call run)))
+
+(defun sml-prog-proc-switch-to ()
+ "Switch to the buffer running the read-eval-print process."
+ (let ((proc (sml-prog-proc-proc)))
+ (pop-to-buffer (process-buffer proc))))
+
+(defun sml-prog-proc-send-string (proc str)
+ (with-current-buffer (process-buffer proc)
+ (comint-send-string proc str)))
+
+(defun sml-prog-proc-load-file (file &optional and-go)
+ "Load FILE into the read-eval-print process.
+FILE is the file visited by the current buffer.
+If prefix argument AND-GO is used, then we additionally switch
+to the buffer where the process is running."
+ (interactive
+ (list (or buffer-file-name
+ (read-file-name "File to load: " nil nil t))
+ current-prefix-arg))
+ (comint-check-source file)
+ (let ((proc (sml-prog-proc-proc)))
+ (sml-prog-proc-send-string proc (sml-prog-proc--call load-cmd file))
+ (when and-go (pop-to-buffer (process-buffer proc)))))
+
+(defvar sml-prog-proc-tmp-file nil)
+
+(defun sml-prog-proc-send-region (start end &optional and-go)
+ "Send the content of the region to the read-eval-print process.
+START..END delimit the region; AND-GO if non-nil indicate to additionally
+switch to the process's buffer."
+ (interactive "r\nP")
+ (if (> start end) (let ((tmp end)) (setq end start) (setq start tmp))
+ (if (= start end) (error "Nothing to send: the region is empty")))
+ (let ((proc (sml-prog-proc-proc))
+ (tmp (make-temp-file "sml-prog-proc")))
+ (write-region start end tmp nil 'silently)
+ (when sml-prog-proc-tmp-file
+ (ignore-errors (delete-file (car sml-prog-proc-tmp-file)))
+ (set-marker (cdr sml-prog-proc-tmp-file) nil))
+ (setq sml-prog-proc-tmp-file (cons tmp (copy-marker start)))
+ (sml-prog-proc-send-string proc (sml-prog-proc--call load-cmd tmp))
+ (when and-go (pop-to-buffer (process-buffer proc)))))
+
+(defun sml-prog-proc-send-buffer (&optional and-go)
+ "Send the content of the current buffer to the read-eval-print process.
+AND-GO if non-nil indicate to additionally switch to the process's buffer."
+ (interactive "P")
+ (sml-prog-proc-send-region (point-min) (point-max) and-go))
+
+;; FIXME: How 'bout a menu? Now, that's trickier because keymap inheritance
+;; doesn't play nicely with menus!
+
+(define-derived-mode sml-prog-proc-mode prog-mode "Prog-Proc"
+ "Major mode for editing source code and interact with an interactive loop."
+ )
+
;;; sml-proc.el ends here