1 : |
monnier |
32 |
;;; sml-mode.el. Major mode for editing (Standard) ML. Version 3.3(beta)
|
2 : |
|
|
|
3 : |
|
|
;; Copyright (C) 1989, Lars Bo Nielsen; 1994,1997, Matthew J. Morley
|
4 : |
|
|
|
5 : |
|
|
;; $Revision$
|
6 : |
|
|
;; $Date$
|
7 : |
|
|
|
8 : |
|
|
;; This file is not part of GNU Emacs, but it is distributed under the
|
9 : |
|
|
;; same conditions.
|
10 : |
|
|
|
11 : |
|
|
;; ====================================================================
|
12 : |
|
|
|
13 : |
|
|
;; This program is free software; you can redistribute it and/or
|
14 : |
|
|
;; modify it under the terms of the GNU General Public License as
|
15 : |
|
|
;; published by the Free Software Foundation; either version 2, or (at
|
16 : |
|
|
;; your option) any later version.
|
17 : |
|
|
|
18 : |
|
|
;; This program is distributed in the hope that it will be useful, but
|
19 : |
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
20 : |
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
21 : |
|
|
;; General Public License for more details.
|
22 : |
|
|
|
23 : |
|
|
;; You should have received a copy of the GNU General Public License
|
24 : |
|
|
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
25 : |
|
|
;; Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
26 : |
|
|
|
27 : |
|
|
;; ====================================================================
|
28 : |
|
|
|
29 : |
|
|
;;; HISTORY
|
30 : |
|
|
|
31 : |
|
|
;; Still under construction: History obscure, needs a biographer as
|
32 : |
|
|
;; well as a M-x doctor. Change Log on request.
|
33 : |
|
|
|
34 : |
|
|
;; Hacked by Olin Shivers for comint from Lars Bo Nielsen's sml.el.
|
35 : |
|
|
|
36 : |
|
|
;; Hacked by Matthew Morley to incorporate Fritz Knabe's hilite and
|
37 : |
|
|
;; font-lock patterns, some of Steven Gilmore's (reduced) easy-menus,
|
38 : |
|
|
;; and numerous bugs and bug-fixes.
|
39 : |
|
|
|
40 : |
|
|
;;; DESCRIPTION
|
41 : |
|
|
|
42 : |
|
|
;; See accompanying info file: sml-mode.info
|
43 : |
|
|
|
44 : |
|
|
;;; FOR YOUR .EMACS FILE
|
45 : |
|
|
|
46 : |
|
|
;; If sml-mode.el lives in some non-standard directory, you must tell
|
47 : |
|
|
;; emacs where to get it. This may or may not be necessary:
|
48 : |
|
|
|
49 : |
|
|
;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path))
|
50 : |
|
|
|
51 : |
|
|
;; Then to access the commands autoload sml-mode with that command:
|
52 : |
|
|
|
53 : |
|
|
;; (autoload 'sml-mode "sml-mode" "Major mode for editing ML programs." t)
|
54 : |
|
|
;;
|
55 : |
|
|
;; If files ending in ".sml" or ".ML" are hereafter considered to contain
|
56 : |
|
|
;; Standard ML source, put their buffers into sml-mode automatically:
|
57 : |
|
|
|
58 : |
|
|
;; (setq auto-mode-alist
|
59 : |
|
|
;; (cons '(("\\.sml$" . sml-mode)
|
60 : |
|
|
;; ("\\.ML$" . sml-mode)) auto-mode-alist))
|
61 : |
|
|
|
62 : |
|
|
;; Here's an example of setting things up in the sml-mode-hook:
|
63 : |
|
|
|
64 : |
|
|
;; (setq sml-mode-hook
|
65 : |
|
|
;; '(lambda() "ML mode hacks"
|
66 : |
|
|
;; (setq sml-indent-level 2 ; conserve on horiz. space
|
67 : |
|
|
;; indent-tabs-mode nil))) ; whatever
|
68 : |
|
|
|
69 : |
|
|
;; sml-mode-hook is run whenever a new sml-mode buffer is created.
|
70 : |
|
|
;; There is an sml-load-hook too, which is only run when this file is
|
71 : |
|
|
;; loaded. One use for this hook is to select your preferred
|
72 : |
|
|
;; highlighting scheme, like this:
|
73 : |
|
|
|
74 : |
|
|
;; (setq sml-load-hook
|
75 : |
|
|
;; '(lambda() "Highlights." (require 'sml-hilite)))
|
76 : |
|
|
|
77 : |
|
|
;; hilit19 is the magic that actually does the highlighting. My set up
|
78 : |
|
|
;; for hilit19 runs something like this:
|
79 : |
|
|
|
80 : |
|
|
;; (if window-system
|
81 : |
|
|
;; (setq hilit-background-mode t ; monochrome (alt: 'dark or 'light)
|
82 : |
|
|
;; hilit-inhibit-hooks nil
|
83 : |
|
|
;; hilit-inhibit-rebinding nil
|
84 : |
|
|
;; hilit-quietly t))
|
85 : |
|
|
|
86 : |
|
|
;; Alternatively, you can (require 'sml-font) which uses the font-lock
|
87 : |
|
|
;; package instead.
|
88 : |
|
|
|
89 : |
|
|
;; Finally, there are inferior-sml-{mode,load}-hooks -- see comments
|
90 : |
|
|
;; in sml-proc.el. For much more information consult the mode's *info*
|
91 : |
|
|
;; tree.
|
92 : |
|
|
|
93 : |
|
|
;;; VERSION STRING
|
94 : |
|
|
|
95 : |
|
|
(defconst sml-mode-version-string
|
96 : |
|
|
"sml-mode, version 3.3(beta)")
|
97 : |
|
|
|
98 : |
monnier |
33 |
(require 'cl)
|
99 : |
monnier |
32 |
(provide 'sml-mode)
|
100 : |
|
|
|
101 : |
|
|
;;; VARIABLES CONTROLLING INDENTATION
|
102 : |
|
|
|
103 : |
|
|
(defvar sml-indent-level 4
|
104 : |
|
|
"*Indentation of blocks in ML (see also `sml-structure-indent').")
|
105 : |
|
|
|
106 : |
|
|
(defvar sml-structure-indent 4 ; Not currently an option.
|
107 : |
|
|
"Indentation of signature/structure/functor declarations.")
|
108 : |
|
|
|
109 : |
|
|
(defvar sml-pipe-indent -2
|
110 : |
|
|
"*Extra (usually negative) indentation for lines beginning with |.")
|
111 : |
|
|
|
112 : |
|
|
(defvar sml-case-indent nil
|
113 : |
|
|
"*How to indent case-of expressions.
|
114 : |
|
|
If t: case expr If nil: case expr of
|
115 : |
|
|
of exp1 => ... exp1 => ...
|
116 : |
|
|
| exp2 => ... | exp2 => ...
|
117 : |
|
|
|
118 : |
|
|
The first seems to be the standard in SML/NJ, but the second
|
119 : |
|
|
seems nicer...")
|
120 : |
|
|
|
121 : |
|
|
(defvar sml-nested-if-indent nil
|
122 : |
|
|
"*Determine how nested if-then-else will be formatted:
|
123 : |
|
|
If t: if exp1 then exp2 If nil: if exp1 then exp2
|
124 : |
|
|
else if exp3 then exp4 else if exp3 then exp4
|
125 : |
|
|
else if exp5 then exp6 else if exp5 then exp6
|
126 : |
|
|
else exp7 else exp7")
|
127 : |
|
|
|
128 : |
|
|
(defvar sml-type-of-indent t
|
129 : |
|
|
"*How to indent `let' `struct' etc.
|
130 : |
|
|
If t: fun foo bar = let If nil: fun foo bar = let
|
131 : |
|
|
val p = 4 val p = 4
|
132 : |
|
|
in in
|
133 : |
|
|
bar + p bar + p
|
134 : |
|
|
end end
|
135 : |
|
|
|
136 : |
|
|
Will not have any effect if the starting keyword is first on the line.")
|
137 : |
|
|
|
138 : |
|
|
(defvar sml-electric-semi-mode nil
|
139 : |
|
|
"*If t, `\;' will self insert, reindent the line, and do a newline.
|
140 : |
|
|
If nil, just insert a `\;'. (To insert while t, do: C-q \;).")
|
141 : |
|
|
|
142 : |
|
|
(defvar sml-paren-lookback 1000
|
143 : |
|
|
"*How far back (in chars) the indentation algorithm should look
|
144 : |
|
|
for open parenthesis. High value means slow indentation algorithm. A
|
145 : |
|
|
value of 1000 (being the equivalent of 20-30 lines) should suffice
|
146 : |
|
|
most uses. (A value of nil, means do not look at all)")
|
147 : |
|
|
|
148 : |
|
|
;;; OTHER GENERIC MODE VARIABLES
|
149 : |
|
|
|
150 : |
|
|
(defvar sml-mode-info "sml-mode"
|
151 : |
|
|
"*Where to find Info file for sml-mode.
|
152 : |
|
|
The default assumes the info file \"sml-mode.info\" is on Emacs' info
|
153 : |
|
|
directory path. If it is not, either put the file on the standard path
|
154 : |
|
|
or set the variable sml-mode-info to the exact location of this file
|
155 : |
|
|
which is part of the sml-mode 3.2 (and later) distribution. E.g:
|
156 : |
|
|
|
157 : |
|
|
(setq sml-mode-info \"/usr/me/lib/info/sml-mode\")
|
158 : |
|
|
|
159 : |
|
|
in your .emacs file. You can always set it interactively with the
|
160 : |
|
|
set-variable command.")
|
161 : |
|
|
|
162 : |
|
|
(defvar sml-mode-hook nil
|
163 : |
|
|
"*This hook is run when sml-mode is loaded, or a new sml-mode buffer created.
|
164 : |
|
|
This is a good place to put your preferred key bindings.")
|
165 : |
|
|
|
166 : |
|
|
(defvar sml-load-hook nil
|
167 : |
|
|
"*This hook is run when sml-mode (sml-mode.el) is loaded into Emacs.")
|
168 : |
|
|
|
169 : |
|
|
(defvar sml-mode-abbrev-table nil "*SML mode abbrev table (default nil)")
|
170 : |
|
|
|
171 : |
|
|
(defvar sml-error-overlay t
|
172 : |
|
|
"*Non-nil means use an overlay to highlight errorful code in the buffer.
|
173 : |
|
|
|
174 : |
|
|
This gets set when `sml-mode' is invoked\; if you don't like/want SML
|
175 : |
|
|
source errors to be highlighted in this way, do something like
|
176 : |
|
|
|
177 : |
|
|
\(setq-default sml-error-overlay nil\)
|
178 : |
|
|
|
179 : |
|
|
in your `sml-load-hook', say.")
|
180 : |
|
|
|
181 : |
|
|
(make-variable-buffer-local 'sml-error-overlay)
|
182 : |
|
|
|
183 : |
|
|
;;; CODE FOR SML-MODE
|
184 : |
|
|
|
185 : |
|
|
(defun sml-mode-info ()
|
186 : |
|
|
"Command to access the TeXinfo documentation for sml-mode.
|
187 : |
|
|
See doc for the variable sml-mode-info."
|
188 : |
|
|
(interactive)
|
189 : |
|
|
(require 'info)
|
190 : |
|
|
(condition-case nil
|
191 : |
|
|
(funcall 'Info-goto-node (concat "(" sml-mode-info ")"))
|
192 : |
|
|
(error (progn
|
193 : |
|
|
(describe-variable 'sml-mode-info)
|
194 : |
|
|
(message "Can't find it... set this variable first!")))))
|
195 : |
|
|
|
196 : |
|
|
(defun sml-indent-level (&optional indent)
|
197 : |
|
|
"Allow the user to change the block indentation level. Numeric prefix
|
198 : |
|
|
accepted in lieu of prompting."
|
199 : |
|
|
(interactive "NIndentation level: ")
|
200 : |
|
|
(setq sml-indent-level indent))
|
201 : |
|
|
|
202 : |
|
|
(defun sml-pipe-indent (&optional indent)
|
203 : |
|
|
"Allow to change pipe indentation level (usually negative). Numeric prefix
|
204 : |
|
|
accepted in lieu of prompting."
|
205 : |
|
|
(interactive "NPipe Indentation level: ")
|
206 : |
|
|
(setq sml-pipe-indent indent))
|
207 : |
|
|
|
208 : |
|
|
(defun sml-case-indent (&optional of)
|
209 : |
|
|
"Toggle sml-case-indent. Prefix means set it to nil."
|
210 : |
|
|
(interactive "P")
|
211 : |
|
|
(setq sml-case-indent (and (not of) (not sml-case-indent)))
|
212 : |
|
|
(if sml-case-indent (message "%s" "true") (message "%s" nil)))
|
213 : |
|
|
|
214 : |
|
|
(defun sml-nested-if-indent (&optional of)
|
215 : |
|
|
"Toggle sml-nested-if-indent. Prefix means set it to nil."
|
216 : |
|
|
(interactive "P")
|
217 : |
|
|
(setq sml-nested-if-indent (and (not of) (not sml-nested-if-indent)))
|
218 : |
|
|
(if sml-nested-if-indent (message "%s" "true") (message "%s" nil)))
|
219 : |
|
|
|
220 : |
|
|
(defun sml-type-of-indent (&optional of)
|
221 : |
|
|
"Toggle sml-type-of-indent. Prefix means set it to nil."
|
222 : |
|
|
(interactive "P")
|
223 : |
|
|
(setq sml-type-of-indent (and (not of) (not sml-type-of-indent)))
|
224 : |
|
|
(if sml-type-of-indent (message "%s" "true") (message "%s" nil)))
|
225 : |
|
|
|
226 : |
|
|
(defun sml-electric-semi-mode (&optional of)
|
227 : |
|
|
"Toggle sml-electric-semi-mode. Prefix means set it to nil."
|
228 : |
|
|
(interactive "P")
|
229 : |
|
|
(setq sml-electric-semi-mode (and (not of) (not sml-electric-semi-mode)))
|
230 : |
|
|
(message "%s" (concat "Electric semi mode is "
|
231 : |
|
|
(if sml-electric-semi-mode "on" "off"))))
|
232 : |
|
|
|
233 : |
|
|
;;; BINDINGS: these should be common to the source and process modes...
|
234 : |
|
|
|
235 : |
|
|
(defun install-sml-keybindings (map)
|
236 : |
|
|
;; Text-formatting commands:
|
237 : |
|
|
(define-key map "\C-c\C-m" 'sml-insert-form)
|
238 : |
|
|
(define-key map "\C-c\C-i" 'sml-mode-info)
|
239 : |
|
|
(define-key map "\M-|" 'sml-electric-pipe)
|
240 : |
|
|
(define-key map "\;" 'sml-electric-semi)
|
241 : |
|
|
(define-key map "\M-\t" 'sml-back-to-outer-indent)
|
242 : |
|
|
(define-key map "\C-j" 'newline-and-indent)
|
243 : |
|
|
(define-key map "\177" 'backward-delete-char-untabify)
|
244 : |
|
|
(define-key map "\C-\M-\\" 'sml-indent-region)
|
245 : |
|
|
(define-key map "\t" 'sml-indent-line) ; ...except this one
|
246 : |
|
|
;; Process commands added to sml-mode-map -- these should autoload
|
247 : |
|
|
(define-key map "\C-c\C-l" 'sml-load-file)
|
248 : |
|
|
(define-key map "\C-c`" 'sml-next-error))
|
249 : |
|
|
|
250 : |
|
|
;;; Autoload functions -- no-doc is another idea cribbed from AucTeX!
|
251 : |
|
|
|
252 : |
|
|
(defvar sml-no-doc
|
253 : |
|
|
"This function is part of sml-proc, and has not yet been loaded.
|
254 : |
|
|
Full documentation will be available after autoloading the function."
|
255 : |
|
|
"Documentation for autoloading functions.")
|
256 : |
|
|
|
257 : |
monnier |
33 |
(autoload 'run-sml "sml-proc" sml-no-doc t)
|
258 : |
|
|
(autoload 'sml-make "sml-proc" sml-no-doc t)
|
259 : |
monnier |
32 |
(autoload 'sml-load-file "sml-proc" sml-no-doc t)
|
260 : |
|
|
|
261 : |
|
|
(autoload 'switch-to-sml "sml-proc" sml-no-doc t)
|
262 : |
|
|
(autoload 'sml-send-region "sml-proc" sml-no-doc t)
|
263 : |
|
|
(autoload 'sml-send-buffer "sml-proc" sml-no-doc t)
|
264 : |
|
|
(autoload 'sml-next-error "sml-proc" sml-no-doc t)
|
265 : |
|
|
|
266 : |
|
|
(defvar sml-mode-map nil "The keymap used in sml-mode.")
|
267 : |
|
|
(cond ((not sml-mode-map)
|
268 : |
|
|
(setq sml-mode-map (make-sparse-keymap))
|
269 : |
|
|
(install-sml-keybindings sml-mode-map)
|
270 : |
monnier |
33 |
(define-key sml-mode-map "\C-c\C-c" 'sml-make)
|
271 : |
monnier |
32 |
(define-key sml-mode-map "\C-c\C-s" 'switch-to-sml)
|
272 : |
|
|
(define-key sml-mode-map "\C-c\C-r" 'sml-send-region)
|
273 : |
|
|
(define-key sml-mode-map "\C-c\C-b" 'sml-send-buffer)))
|
274 : |
|
|
|
275 : |
monnier |
33 |
;; font-lock setup
|
276 : |
|
|
|
277 : |
|
|
(defvar sml-font-lock-keywords
|
278 : |
|
|
'((sml-font-comments-and-strings)
|
279 : |
|
|
("\\<\\(fun\\|and\\)\\s-+\\(\\sw+\\)"
|
280 : |
|
|
(1 font-lock-keyword-face)
|
281 : |
|
|
(2 font-lock-function-def-face))
|
282 : |
|
|
("\\<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+\\('\\s-*\\sw+\\s-+\\)*\\(\\sw+\\)"
|
283 : |
|
|
(1 font-lock-keyword-face)
|
284 : |
|
|
(4 font-lock-type-def-face))
|
285 : |
|
|
("\\<\\(val\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*="
|
286 : |
|
|
(1 font-lock-keyword-face)
|
287 : |
|
|
;;(6 font-lock-variable-def-face nil t)
|
288 : |
|
|
(3 font-lock-variable-def-face))
|
289 : |
|
|
("\\<\\(structure\\|functor\\|abstraction\\)\\s-+\\(\\sw+\\)"
|
290 : |
|
|
(1 font-lock-keyword-face)
|
291 : |
|
|
(2 font-lock-module-def-face))
|
292 : |
|
|
("\\<\\(signature\\)\\s-+\\(\\sw+\\)"
|
293 : |
|
|
(1 font-lock-keyword-face)
|
294 : |
|
|
(2 font-lock-interface-def-face))
|
295 : |
|
|
|
296 : |
|
|
;; Generated with Simon Marshall's make-regexp:
|
297 : |
|
|
;; (make-regexp
|
298 : |
|
|
;; '("abstype" "and" "andalso" "as" "case" "datatype"
|
299 : |
|
|
;; "else" "end" "eqtype" "exception" "do" "fn" "fun" "functor"
|
300 : |
|
|
;; "handle" "if" "in" "include" "infix" "infixr" "let" "local"
|
301 : |
|
|
;; "nonfix" "of" "op" "open" "orelse" "overload" "raise" "rec"
|
302 : |
|
|
;; "sharing" "sig" "signature" "struct" "structure" "then" "type"
|
303 : |
|
|
;; "val" "where" "while" "with" "withtype") t)
|
304 : |
|
|
("\\<\\(a\\(bstype\\|nd\\(\\|also\\)\\|s\\)\\|case\\|d\\(atatype\\|o\\)\\|\
|
305 : |
|
|
e\\(lse\\|nd\\|qtype\\|xception\\)\\|f\\(n\\|un\\(\\|ctor\\)\\)\\|\handle\\|\
|
306 : |
|
|
i\\([fn]\\|n\\(clude\\|fixr?\\)\\)\\|l\\(et\\|ocal\\)\\|nonfix\\|\
|
307 : |
|
|
o\\([fp]\\|pen\\|relse\\|verload\\)\\|r\\(aise\\|ec\\)\\|\
|
308 : |
|
|
s\\(haring\\|ig\\(\\|nature\\)\\|truct\\(\\|ure\\)\\)\\|t\\(hen\\|ype\\)\\|\
|
309 : |
|
|
val\\|w\\(h\\(ere\\|ile\\)\\|ith\\(\\|type\\)\\)\\)\\>"
|
310 : |
|
|
. font-lock-keyword-face))
|
311 : |
|
|
"Regexps matching standard SML keywords.")
|
312 : |
|
|
|
313 : |
|
|
;; default faces values
|
314 : |
|
|
(defvar font-lock-function-def-face
|
315 : |
|
|
(if (facep 'font-lock-function-def-face)
|
316 : |
|
|
'font-lock-function-name-face
|
317 : |
|
|
'font-lock-function-name-face))
|
318 : |
|
|
(defvar font-lock-type-def-face
|
319 : |
|
|
(if (facep 'font-lock-type-def-face)
|
320 : |
|
|
'font-lock-type-def-face
|
321 : |
|
|
'font-lock-type-face))
|
322 : |
|
|
(defvar font-lock-module-def-face
|
323 : |
|
|
(if (facep 'font-lock-module-def-face)
|
324 : |
|
|
'font-lock-module-def-face
|
325 : |
|
|
'font-lock-function-name-face))
|
326 : |
|
|
(defvar font-lock-interface-def-face
|
327 : |
|
|
(if (facep 'font-lock-interface-def-face)
|
328 : |
|
|
'font-lock-interface-def-face
|
329 : |
|
|
'font-lock-type-face))
|
330 : |
|
|
(defvar font-lock-variable-def-face
|
331 : |
|
|
(if (facep 'font-lock-variable-def-face)
|
332 : |
|
|
'font-lock-variable-def-face
|
333 : |
|
|
'font-lock-variable-name-face))
|
334 : |
|
|
|
335 : |
|
|
(defvar sml-font-lock-defaults
|
336 : |
|
|
'(sml-font-lock-keywords t nil nil nil))
|
337 : |
|
|
|
338 : |
|
|
;; code to get comment fontification working in the face of recursive
|
339 : |
|
|
;; comments. It's lots more work than it should be. -- stefan
|
340 : |
|
|
(defvar sml-font-cache '((0 . normal))
|
341 : |
|
|
"List of (POSITION . STATE) pairs for an SML buffer.
|
342 : |
|
|
The STATE is either `normal', `comment', or `string'. The POSITION is
|
343 : |
|
|
immediately after the token that caused the state change.")
|
344 : |
|
|
(make-variable-buffer-local 'sml-font-cache)
|
345 : |
|
|
|
346 : |
|
|
(defun sml-font-comments-and-strings (limit)
|
347 : |
|
|
"Fontify SML comments and strings up to LIMIT.
|
348 : |
|
|
Handles nested comments and SML's escapes for breaking a string over lines.
|
349 : |
|
|
Uses sml-font-cache to maintain the fontification state over the buffer."
|
350 : |
|
|
(let ((beg (point))
|
351 : |
|
|
last class)
|
352 : |
|
|
(while (< beg limit)
|
353 : |
|
|
(while (and sml-font-cache
|
354 : |
|
|
(> (caar sml-font-cache) beg))
|
355 : |
|
|
(pop sml-font-cache))
|
356 : |
|
|
(setq last (caar sml-font-cache))
|
357 : |
|
|
(setq class (cdar sml-font-cache))
|
358 : |
|
|
(goto-char last)
|
359 : |
|
|
(cond
|
360 : |
|
|
((eq class 'normal)
|
361 : |
|
|
(cond
|
362 : |
|
|
((not (re-search-forward "\\((\\*\\)\\|\\(\"\\)" limit t))
|
363 : |
|
|
(goto-char limit))
|
364 : |
|
|
((match-beginning 1)
|
365 : |
|
|
(push (cons (point) 'comment) sml-font-cache))
|
366 : |
|
|
((match-beginning 2)
|
367 : |
|
|
(push (cons (point) 'string) sml-font-cache))))
|
368 : |
|
|
((eq class 'comment)
|
369 : |
|
|
(cond
|
370 : |
|
|
((let ((nest 1))
|
371 : |
|
|
(while (and (> nest 0)
|
372 : |
|
|
(re-search-forward "\\((\\*\\)\\|\\(\\*)\\)" limit t))
|
373 : |
|
|
(cond
|
374 : |
|
|
((match-beginning 1) (incf nest))
|
375 : |
|
|
((match-beginning 2) (decf nest))))
|
376 : |
|
|
(> nest 0))
|
377 : |
|
|
(goto-char limit))
|
378 : |
|
|
(t
|
379 : |
|
|
(push (cons (point) 'normal) sml-font-cache)))
|
380 : |
|
|
(put-text-property (- last 2) (point) 'face 'font-lock-comment-face))
|
381 : |
|
|
((eq class 'string)
|
382 : |
|
|
(while (and (re-search-forward
|
383 : |
|
|
"\\(\"\\)\\|\\(\\\\\\s-*\\\\\\)\\|\\(\\\\\"\\)" limit t)
|
384 : |
|
|
(not (match-beginning 1))))
|
385 : |
|
|
(cond
|
386 : |
|
|
((match-beginning 1)
|
387 : |
|
|
(push (cons (point) 'normal) sml-font-cache))
|
388 : |
|
|
(t
|
389 : |
|
|
(goto-char limit)))
|
390 : |
|
|
(put-text-property (- last 1) (point) 'face 'font-lock-string-face)))
|
391 : |
|
|
(setq beg (point)))))
|
392 : |
|
|
|
393 : |
monnier |
32 |
;;; H A C K A T T A C K ! X E M A C S V E R S U S E M A C S
|
394 : |
|
|
|
395 : |
|
|
(cond ((fboundp 'make-extent)
|
396 : |
|
|
;; suppose this is XEmacs
|
397 : |
|
|
|
398 : |
|
|
(defun sml-make-overlay ()
|
399 : |
|
|
"Create a new text overlay (extent) for the SML buffer."
|
400 : |
|
|
(let ((ex (make-extent 1 1)))
|
401 : |
|
|
(set-extent-property ex 'face 'zmacs-region) ex))
|
402 : |
|
|
|
403 : |
|
|
(defalias 'sml-is-overlay 'extentp)
|
404 : |
|
|
|
405 : |
|
|
(defun sml-overlay-active-p ()
|
406 : |
|
|
"Determine whether the current buffer's error overlay is visible."
|
407 : |
|
|
(and (sml-is-overlay sml-error-overlay)
|
408 : |
|
|
(not (zerop (extent-length sml-error-overlay)))))
|
409 : |
|
|
|
410 : |
|
|
(defalias 'sml-move-overlay 'set-extent-endpoints))
|
411 : |
|
|
|
412 : |
|
|
((fboundp 'make-overlay)
|
413 : |
|
|
;; otherwise assume it's Emacs
|
414 : |
|
|
|
415 : |
|
|
(defun sml-make-overlay ()
|
416 : |
|
|
"Create a new text overlay (extent) for the SML buffer."
|
417 : |
|
|
(let ((ex (make-overlay 0 0)))
|
418 : |
|
|
(overlay-put ex 'face 'region) ex))
|
419 : |
|
|
|
420 : |
|
|
(defalias 'sml-is-overlay 'overlayp)
|
421 : |
|
|
|
422 : |
|
|
(defun sml-overlay-active-p ()
|
423 : |
|
|
"Determine whether the current buffer's error overlay is visible."
|
424 : |
|
|
(and (sml-is-overlay sml-error-overlay)
|
425 : |
|
|
(not (equal (overlay-start sml-error-overlay)
|
426 : |
|
|
(overlay-end sml-error-overlay)))))
|
427 : |
|
|
|
428 : |
|
|
(defalias 'sml-move-overlay 'move-overlay))
|
429 : |
|
|
(t
|
430 : |
|
|
;; what *is* this!?
|
431 : |
|
|
(defalias 'sml-is-overlay 'ignore)
|
432 : |
|
|
(defalias 'sml-overlay-active-p 'ignore)
|
433 : |
|
|
(defalias 'sml-make-overlay 'ignore)
|
434 : |
|
|
(defalias 'sml-move-overlay 'ignore)))
|
435 : |
|
|
|
436 : |
|
|
;;; MORE CODE FOR SML-MODE
|
437 : |
|
|
|
438 : |
|
|
(defun sml-mode-version ()
|
439 : |
|
|
"This file's version number (sml-mode)."
|
440 : |
|
|
(interactive)
|
441 : |
|
|
(message sml-mode-version-string))
|
442 : |
|
|
|
443 : |
|
|
(defvar sml-mode-syntax-table nil "The syntax table used in sml-mode.")
|
444 : |
|
|
(if sml-mode-syntax-table
|
445 : |
|
|
()
|
446 : |
|
|
(setq sml-mode-syntax-table (make-syntax-table))
|
447 : |
|
|
;; Set everything to be "." (punctuation) except for [A-Za-z0-9],
|
448 : |
|
|
;; which will default to "w" (word-constituent).
|
449 : |
|
|
(let ((i 0))
|
450 : |
|
|
(while (< i ?0)
|
451 : |
|
|
(modify-syntax-entry i "." sml-mode-syntax-table)
|
452 : |
|
|
(setq i (1+ i)))
|
453 : |
|
|
(setq i (1+ ?9))
|
454 : |
|
|
(while (< i ?A)
|
455 : |
|
|
(modify-syntax-entry i "." sml-mode-syntax-table)
|
456 : |
|
|
(setq i (1+ i)))
|
457 : |
|
|
(setq i (1+ ?Z))
|
458 : |
|
|
(while (< i ?a)
|
459 : |
|
|
(modify-syntax-entry i "." sml-mode-syntax-table)
|
460 : |
|
|
(setq i (1+ i)))
|
461 : |
|
|
(setq i (1+ ?z))
|
462 : |
|
|
(while (< i 128)
|
463 : |
|
|
(modify-syntax-entry i "." sml-mode-syntax-table)
|
464 : |
|
|
(setq i (1+ i))))
|
465 : |
|
|
|
466 : |
|
|
;; Now we change the characters that are meaningful to us.
|
467 : |
monnier |
33 |
(modify-syntax-entry ?\\ "\\" sml-mode-syntax-table)
|
468 : |
monnier |
32 |
(modify-syntax-entry ?\( "()1" sml-mode-syntax-table)
|
469 : |
|
|
(modify-syntax-entry ?\) ")(4" sml-mode-syntax-table)
|
470 : |
|
|
(modify-syntax-entry ?\[ "(]" sml-mode-syntax-table)
|
471 : |
|
|
(modify-syntax-entry ?\] ")[" sml-mode-syntax-table)
|
472 : |
|
|
(modify-syntax-entry ?{ "(}" sml-mode-syntax-table)
|
473 : |
|
|
(modify-syntax-entry ?} "){" sml-mode-syntax-table)
|
474 : |
|
|
(modify-syntax-entry ?\* ". 23" sml-mode-syntax-table)
|
475 : |
|
|
(modify-syntax-entry ?\" "\"" sml-mode-syntax-table)
|
476 : |
|
|
(modify-syntax-entry ? " " sml-mode-syntax-table)
|
477 : |
|
|
(modify-syntax-entry ?\t " " sml-mode-syntax-table)
|
478 : |
|
|
(modify-syntax-entry ?\n " " sml-mode-syntax-table)
|
479 : |
|
|
(modify-syntax-entry ?\f " " sml-mode-syntax-table)
|
480 : |
|
|
(modify-syntax-entry ?\' "w" sml-mode-syntax-table)
|
481 : |
|
|
(modify-syntax-entry ?\_ "w" sml-mode-syntax-table))
|
482 : |
|
|
|
483 : |
|
|
;;;###Autoload
|
484 : |
|
|
(defun sml-mode ()
|
485 : |
|
|
"Major mode for editing ML code.
|
486 : |
|
|
Tab indents for ML code.
|
487 : |
|
|
Comments are delimited with (* ... *).
|
488 : |
|
|
Blank lines and form-feeds separate paragraphs.
|
489 : |
|
|
Delete converts tabs to spaces as it moves back.
|
490 : |
|
|
|
491 : |
|
|
For information on running an inferior ML process, see the documentation
|
492 : |
|
|
for inferior-sml-mode (set this up with \\[sml]).
|
493 : |
|
|
|
494 : |
|
|
Customisation: Entry to this mode runs the hooks on sml-mode-hook.
|
495 : |
|
|
|
496 : |
|
|
Variables controlling the indentation
|
497 : |
|
|
=====================================
|
498 : |
|
|
|
499 : |
|
|
Seek help (\\[describe-variable]) on individual variables to get current settings.
|
500 : |
|
|
|
501 : |
|
|
sml-indent-level (default 4)
|
502 : |
|
|
The indentation of a block of code.
|
503 : |
|
|
|
504 : |
|
|
sml-pipe-indent (default -2)
|
505 : |
|
|
Extra indentation of a line starting with \"|\".
|
506 : |
|
|
|
507 : |
|
|
sml-case-indent (default nil)
|
508 : |
|
|
Determine the way to indent case-of expression.
|
509 : |
|
|
|
510 : |
|
|
sml-nested-if-indent (default nil)
|
511 : |
|
|
Determine how nested if-then-else expressions are formatted.
|
512 : |
|
|
|
513 : |
|
|
sml-type-of-indent (default t)
|
514 : |
|
|
How to indent let, struct, local, etc.
|
515 : |
|
|
Will not have any effect if the starting keyword is first on the line.
|
516 : |
|
|
|
517 : |
|
|
sml-electric-semi-mode (default nil)
|
518 : |
|
|
If t, a `\;' will reindent line, and perform a newline.
|
519 : |
|
|
|
520 : |
|
|
sml-paren-lookback (default 1000)
|
521 : |
|
|
Determines how far back (in chars) the indentation algorithm should
|
522 : |
|
|
look to match parenthesis. A value of nil, means do not look at all.
|
523 : |
|
|
|
524 : |
|
|
Mode map
|
525 : |
|
|
========
|
526 : |
|
|
\\{sml-mode-map}"
|
527 : |
|
|
|
528 : |
|
|
(interactive)
|
529 : |
|
|
(kill-all-local-variables)
|
530 : |
|
|
(sml-mode-variables)
|
531 : |
|
|
(use-local-map sml-mode-map)
|
532 : |
|
|
(setq major-mode 'sml-mode)
|
533 : |
|
|
(setq mode-name "SML")
|
534 : |
|
|
(run-hooks 'sml-mode-hook)) ; Run the hook last
|
535 : |
|
|
|
536 : |
|
|
(defun sml-mode-variables ()
|
537 : |
|
|
(set-syntax-table sml-mode-syntax-table)
|
538 : |
|
|
(setq local-abbrev-table sml-mode-abbrev-table)
|
539 : |
|
|
;; A paragraph is separated by blank lines or ^L only.
|
540 : |
monnier |
33 |
|
541 : |
|
|
(set (make-local-variable 'paragraph-start)
|
542 : |
|
|
(concat "^[\t ]*$\\|" page-delimiter))
|
543 : |
|
|
(set (make-local-variable 'paragraph-separate) paragraph-start)
|
544 : |
|
|
(set (make-local-variable 'indent-line-function) 'sml-indent-line)
|
545 : |
|
|
(set (make-local-variable 'comment-start) "(* ")
|
546 : |
|
|
(set (make-local-variable 'comment-end) " *)")
|
547 : |
|
|
(set (make-local-variable 'comment-column) 40)
|
548 : |
|
|
(set (make-local-variable 'comment-start-skip) "(\\*+[ \t]?")
|
549 : |
|
|
(set (make-local-variable 'comment-indent-function) 'sml-comment-indent)
|
550 : |
|
|
(set (make-local-variable 'font-lock-defaults) sml-font-lock-defaults)
|
551 : |
monnier |
32 |
(setq sml-error-overlay (and sml-error-overlay (sml-make-overlay))))
|
552 : |
|
|
|
553 : |
|
|
;; Adding these will fool the matching of parens -- because of a
|
554 : |
|
|
;; bug in Emacs (in scan_lists, i think)... it would be nice to
|
555 : |
|
|
;; have comments treated as white-space.
|
556 : |
|
|
;;(make-local-variable 'parse-sexp-ignore-comments)
|
557 : |
|
|
;;(setq parse-sexp-ignore-comments t)
|
558 : |
|
|
|
559 : |
|
|
(defun sml-error-overlay (undo &optional beg end buffer)
|
560 : |
|
|
"Move `sml-error-overlay' so it surrounds the text region in the
|
561 : |
|
|
current buffer. If the buffer-local variable `sml-error-overlay' is
|
562 : |
|
|
non-nil it should be an overlay \(or extent, in XEmacs speak\)\; this
|
563 : |
|
|
function moves the overlay over the current region. If the optional
|
564 : |
|
|
BUFFER argument is given, move the overlay in that buffer instead of
|
565 : |
|
|
the current buffer.
|
566 : |
|
|
|
567 : |
|
|
Called interactively, the optional prefix argument UNDO indicates that
|
568 : |
|
|
the overlay should simply be removed: \\[universal-argument] \
|
569 : |
|
|
\\[sml-error-overlay]."
|
570 : |
|
|
(interactive "P")
|
571 : |
|
|
(save-excursion
|
572 : |
|
|
(set-buffer (or buffer (current-buffer)))
|
573 : |
|
|
(if (sml-is-overlay sml-error-overlay)
|
574 : |
|
|
(if undo
|
575 : |
|
|
(sml-move-overlay sml-error-overlay 1 1)
|
576 : |
|
|
;; if active regions, signals mark not active if no region set
|
577 : |
|
|
(let ((beg (or beg (region-beginning)))
|
578 : |
|
|
(end (or end (region-end))))
|
579 : |
|
|
(sml-move-overlay sml-error-overlay beg end))))))
|
580 : |
|
|
|
581 : |
|
|
(defconst sml-pipe-matchers-reg
|
582 : |
|
|
"\\bcase\\b\\|\\bfn\\b\\|\\bfun\\b\\|\\bhandle\\b\
|
583 : |
|
|
\\|\\bdatatype\\b\\|\\babstype\\b\\|\\band\\b"
|
584 : |
|
|
"The keywords a `|' can follow.")
|
585 : |
|
|
|
586 : |
|
|
(defun sml-electric-pipe ()
|
587 : |
|
|
"Insert a \"|\".
|
588 : |
|
|
Depending on the context insert the name of function, a \"=>\" etc."
|
589 : |
|
|
(interactive)
|
590 : |
|
|
(let ((case-fold-search nil) ; Case sensitive
|
591 : |
|
|
(here (point))
|
592 : |
|
|
(match (save-excursion
|
593 : |
|
|
(sml-find-matching-starter sml-pipe-matchers-reg)
|
594 : |
|
|
(point)))
|
595 : |
|
|
(tmp " => ")
|
596 : |
|
|
(case-or-handle-exp t))
|
597 : |
|
|
(if (/= (save-excursion (beginning-of-line) (point))
|
598 : |
|
|
(save-excursion (skip-chars-backward "\t ") (point)))
|
599 : |
|
|
(insert "\n"))
|
600 : |
|
|
(insert "|")
|
601 : |
|
|
(save-excursion
|
602 : |
|
|
(goto-char match)
|
603 : |
|
|
(cond
|
604 : |
|
|
;; It was a function, insert the function name
|
605 : |
|
|
((looking-at "fun\\b")
|
606 : |
|
|
(setq tmp (concat " " (buffer-substring
|
607 : |
|
|
(progn (forward-char 3)
|
608 : |
|
|
(skip-chars-forward "\t\n ") (point))
|
609 : |
|
|
(progn (forward-word 1) (point))) " "))
|
610 : |
|
|
(setq case-or-handle-exp nil))
|
611 : |
|
|
;; It was a datatype, insert nothing
|
612 : |
|
|
((looking-at "datatype\\b\\|abstype\\b")
|
613 : |
|
|
(setq tmp " ") (setq case-or-handle-exp nil))
|
614 : |
|
|
;; If it is an and, then we have to see what is was
|
615 : |
|
|
((looking-at "and\\b")
|
616 : |
|
|
(let (isfun)
|
617 : |
|
|
(save-excursion
|
618 : |
|
|
(condition-case ()
|
619 : |
|
|
(progn
|
620 : |
|
|
(re-search-backward "datatype\\b\\|abstype\\b\\|fun\\b")
|
621 : |
|
|
(setq isfun (looking-at "fun\\b")))
|
622 : |
|
|
(error (setq isfun nil))))
|
623 : |
|
|
(if isfun
|
624 : |
|
|
(progn
|
625 : |
|
|
(setq tmp
|
626 : |
|
|
(concat " " (buffer-substring
|
627 : |
|
|
(progn (forward-char 3)
|
628 : |
|
|
(skip-chars-forward "\t\n ") (point))
|
629 : |
|
|
(progn (forward-word 1) (point))) " "))
|
630 : |
|
|
(setq case-or-handle-exp nil))
|
631 : |
|
|
(setq tmp " ") (setq case-or-handle-exp nil))))))
|
632 : |
|
|
(insert tmp)
|
633 : |
|
|
(sml-indent-line)
|
634 : |
|
|
(beginning-of-line)
|
635 : |
|
|
(skip-chars-forward "\t ")
|
636 : |
|
|
(forward-char (1+ (length tmp)))
|
637 : |
|
|
(if case-or-handle-exp
|
638 : |
|
|
(forward-char -4))))
|
639 : |
|
|
|
640 : |
|
|
(defun sml-electric-semi ()
|
641 : |
|
|
"Inserts a \;.
|
642 : |
|
|
If variable sml-electric-semi-mode is t, indent the current line, insert
|
643 : |
|
|
a newline, and indent."
|
644 : |
|
|
(interactive)
|
645 : |
|
|
(insert "\;")
|
646 : |
|
|
(if sml-electric-semi-mode
|
647 : |
|
|
(reindent-then-newline-and-indent)))
|
648 : |
|
|
|
649 : |
|
|
;;; INDENTATION !!!
|
650 : |
|
|
|
651 : |
|
|
(defun sml-mark-function ()
|
652 : |
|
|
"Synonym for mark-paragraph -- sorry.
|
653 : |
|
|
If anyone has a good algorithm for this..."
|
654 : |
|
|
(interactive)
|
655 : |
|
|
(mark-paragraph))
|
656 : |
|
|
|
657 : |
|
|
(defun sml-indent-region (begin end)
|
658 : |
|
|
"Indent region of ML code."
|
659 : |
|
|
(interactive "r")
|
660 : |
|
|
(message "Indenting region...")
|
661 : |
|
|
(save-excursion
|
662 : |
|
|
(goto-char end) (setq end (point-marker)) (goto-char begin)
|
663 : |
|
|
(while (< (point) end)
|
664 : |
|
|
(skip-chars-forward "\t\n ")
|
665 : |
|
|
(sml-indent-line)
|
666 : |
|
|
(end-of-line))
|
667 : |
|
|
(move-marker end nil))
|
668 : |
|
|
(message "Indenting region... done"))
|
669 : |
|
|
|
670 : |
|
|
(defun sml-indent-line ()
|
671 : |
|
|
"Indent current line of ML code."
|
672 : |
|
|
(interactive)
|
673 : |
|
|
(let ((indent (sml-calculate-indentation)))
|
674 : |
|
|
(if (/= (current-indentation) indent)
|
675 : |
|
|
(save-excursion ;; Added 890601 (point now stays)
|
676 : |
|
|
(let ((beg (progn (beginning-of-line) (point))))
|
677 : |
|
|
(skip-chars-forward "\t ")
|
678 : |
|
|
(delete-region beg (point))
|
679 : |
|
|
(indent-to indent))))
|
680 : |
|
|
;; If point is before indentation, move point to indentation
|
681 : |
|
|
(if (< (current-column) (current-indentation))
|
682 : |
|
|
(skip-chars-forward "\t "))))
|
683 : |
|
|
|
684 : |
|
|
(defun sml-back-to-outer-indent ()
|
685 : |
|
|
"Unindents to the next outer level of indentation."
|
686 : |
|
|
(interactive)
|
687 : |
|
|
(save-excursion
|
688 : |
|
|
(beginning-of-line)
|
689 : |
|
|
(skip-chars-forward "\t ")
|
690 : |
|
|
(let ((start-column (current-column))
|
691 : |
|
|
(indent (current-column)))
|
692 : |
|
|
(if (> start-column 0)
|
693 : |
|
|
(progn
|
694 : |
|
|
(save-excursion
|
695 : |
|
|
(while (>= indent start-column)
|
696 : |
|
|
(if (re-search-backward "^[^\n]" nil t)
|
697 : |
|
|
(setq indent (current-indentation))
|
698 : |
|
|
(setq indent 0))))
|
699 : |
|
|
(backward-delete-char-untabify (- start-column indent)))))))
|
700 : |
|
|
|
701 : |
|
|
(defconst sml-indent-starters-reg
|
702 : |
|
|
"abstraction\\b\\|abstype\\b\\|and\\b\\|case\\b\\|datatype\\b\
|
703 : |
|
|
\\|else\\b\\|fun\\b\\|functor\\b\\|if\\b\\|sharing\\b\
|
704 : |
|
|
\\|in\\b\\|infix\\b\\|infixr\\b\\|let\\b\\|local\\b\
|
705 : |
|
|
\\|nonfix\\b\\|of\\b\\|open\\b\\|raise\\b\\|sig\\b\\|signature\\b\
|
706 : |
|
|
\\|struct\\b\\|structure\\b\\|then\\b\\|\\btype\\b\\|val\\b\
|
707 : |
|
|
\\|while\\b\\|with\\b\\|withtype\\b"
|
708 : |
|
|
"The indentation starters. The next line will be indented.")
|
709 : |
|
|
|
710 : |
|
|
(defconst sml-starters-reg
|
711 : |
|
|
"\\babstraction\\b\\|\\babstype\\b\\|\\bdatatype\\b\
|
712 : |
|
|
\\|\\bexception\\b\\|\\bfun\\b\\|\\bfunctor\\b\\|\\blocal\\b\
|
713 : |
|
|
\\|\\binfix\\b\\|\\binfixr\\b\\|\\bsharing\\b\
|
714 : |
|
|
\\|\\bnonfix\\b\\|\\bopen\\b\\|\\bsignature\\b\\|\\bstructure\\b\
|
715 : |
|
|
\\|\\btype\\b\\|\\bval\\b\\|\\bwithtype\\b\\|\\bwith\\b"
|
716 : |
|
|
"The starters of new expressions.")
|
717 : |
|
|
|
718 : |
|
|
(defconst sml-end-starters-reg
|
719 : |
|
|
"\\blet\\b\\|\\blocal\\b\\|\\bsig\\b\\|\\bstruct\\b\\|\\bwith\\b"
|
720 : |
|
|
"Matching reg-expression for the \"end\" keyword.")
|
721 : |
|
|
|
722 : |
|
|
(defconst sml-starters-indent-after
|
723 : |
|
|
"let\\b\\|local\\b\\|struct\\b\\|in\\b\\|sig\\b\\|with\\b"
|
724 : |
|
|
"Indent after these.")
|
725 : |
|
|
|
726 : |
|
|
(defun sml-calculate-indentation ()
|
727 : |
|
|
(save-excursion
|
728 : |
|
|
(let ((case-fold-search nil))
|
729 : |
|
|
(beginning-of-line)
|
730 : |
|
|
(if (bobp) ; Beginning of buffer
|
731 : |
|
|
0 ; Indentation = 0
|
732 : |
|
|
(skip-chars-forward "\t ")
|
733 : |
|
|
(cond
|
734 : |
|
|
;; Indentation for comments alone on a line, matches the
|
735 : |
|
|
;; proper indentation of the next line. Search only for the
|
736 : |
|
|
;; next "*)", not for the matching.
|
737 : |
|
|
((looking-at "(\\*")
|
738 : |
|
|
(if (not (search-forward "*)" nil t))
|
739 : |
|
|
(error "Comment not ended."))
|
740 : |
|
|
(end-of-line)
|
741 : |
|
|
(skip-chars-forward "\n\t ")
|
742 : |
|
|
;; If we are at eob, just indent 0
|
743 : |
|
|
(if (eobp) 0 (sml-calculate-indentation)))
|
744 : |
|
|
;; Continued string ? (Added 890113 lbn)
|
745 : |
|
|
((looking-at "\\\\")
|
746 : |
|
|
(save-excursion
|
747 : |
|
|
(if (save-excursion (previous-line 1)
|
748 : |
|
|
(beginning-of-line)
|
749 : |
|
|
(looking-at "[\t ]*\\\\"))
|
750 : |
|
|
(progn (previous-line 1) (current-indentation))
|
751 : |
|
|
(if (re-search-backward "[^\\\\]\"" nil t)
|
752 : |
|
|
(1+ (current-indentation))
|
753 : |
|
|
0))))
|
754 : |
|
|
;; Are we looking at a case expression ?
|
755 : |
|
|
((looking-at "|.*=>")
|
756 : |
|
|
(sml-skip-block)
|
757 : |
|
|
(sml-re-search-backward "=>")
|
758 : |
|
|
;; Dont get fooled by fn _ => in case statements (890726)
|
759 : |
|
|
;; Changed the regexp a bit, so fn has to be first on line,
|
760 : |
|
|
;; in order to let the loop continue (Used to be ".*\bfn....")
|
761 : |
|
|
;; (900430).
|
762 : |
|
|
(let ((loop t))
|
763 : |
|
|
(while (and loop (save-excursion
|
764 : |
|
|
(beginning-of-line)
|
765 : |
|
|
(looking-at "[^ \t]+\\bfn\\b.*=>")))
|
766 : |
|
|
(setq loop (sml-re-search-backward "=>"))))
|
767 : |
|
|
(beginning-of-line)
|
768 : |
|
|
(skip-chars-forward "\t ")
|
769 : |
|
|
(cond
|
770 : |
|
|
((looking-at "|") (current-indentation))
|
771 : |
monnier |
37 |
((looking-at "of\\b")
|
772 : |
monnier |
32 |
(1+ (current-indentation)))
|
773 : |
|
|
((looking-at "fn\\b") (1+ (current-indentation)))
|
774 : |
|
|
((looking-at "handle\\b") (+ (current-indentation) 5))
|
775 : |
|
|
(t (+ (current-indentation) sml-pipe-indent))))
|
776 : |
|
|
((looking-at "and\\b")
|
777 : |
|
|
(if (sml-find-matching-starter sml-starters-reg)
|
778 : |
|
|
(current-column)
|
779 : |
|
|
0))
|
780 : |
|
|
((looking-at "in\\b") ; Match the beginning let/local
|
781 : |
|
|
(sml-find-match-indent "in" "\\bin\\b" "\\blocal\\b\\|\\blet\\b"))
|
782 : |
|
|
((looking-at "end\\b") ; Match the beginning
|
783 : |
|
|
(sml-find-match-indent "end" "\\bend\\b" sml-end-starters-reg))
|
784 : |
monnier |
37 |
((and sml-nested-if-indent (looking-at "else\\b"))
|
785 : |
monnier |
32 |
(sml-re-search-backward "\\bif\\b\\|\\belse\\b")
|
786 : |
|
|
(current-indentation))
|
787 : |
|
|
((looking-at "else\\b") ; Match the if
|
788 : |
|
|
(sml-find-match-indent "else" "\\belse\\b" "\\bif\\b" t))
|
789 : |
|
|
((looking-at "then\\b") ; Match the if + extra indentation
|
790 : |
|
|
(+ (sml-find-match-indent "then" "\\bthen\\b" "\\bif\\b" t)
|
791 : |
monnier |
38 |
(if sml-type-of-indent sml-indent-level 0)))
|
792 : |
monnier |
37 |
((looking-at "of\\b")
|
793 : |
monnier |
32 |
(sml-re-search-backward "\\bcase\\b")
|
794 : |
|
|
(+ (current-column) 2))
|
795 : |
|
|
((looking-at sml-starters-reg)
|
796 : |
|
|
(let ((start (point)))
|
797 : |
|
|
(sml-backward-sexp)
|
798 : |
|
|
(if (and (looking-at sml-starters-indent-after)
|
799 : |
|
|
(/= start (point)))
|
800 : |
|
|
(+ (if sml-type-of-indent
|
801 : |
|
|
(current-column)
|
802 : |
|
|
(if (progn (beginning-of-line)
|
803 : |
|
|
(skip-chars-forward "\t ")
|
804 : |
|
|
(looking-at "|"))
|
805 : |
|
|
(- (current-indentation) sml-pipe-indent)
|
806 : |
|
|
(current-indentation)))
|
807 : |
|
|
sml-indent-level)
|
808 : |
|
|
(beginning-of-line)
|
809 : |
|
|
(skip-chars-forward "\t ")
|
810 : |
|
|
(if (and (looking-at sml-starters-indent-after)
|
811 : |
|
|
(/= start (point)))
|
812 : |
|
|
(+ (if sml-type-of-indent
|
813 : |
|
|
(current-column)
|
814 : |
|
|
(current-indentation))
|
815 : |
|
|
sml-indent-level)
|
816 : |
|
|
(goto-char start)
|
817 : |
|
|
(if (sml-find-matching-starter sml-starters-reg)
|
818 : |
|
|
(current-column)
|
819 : |
|
|
0)))))
|
820 : |
|
|
(t
|
821 : |
|
|
(let ((indent (sml-get-indent)))
|
822 : |
|
|
(cond
|
823 : |
|
|
((looking-at "|")
|
824 : |
|
|
;; Lets see if it is the follower of a function definition
|
825 : |
|
|
(if (sml-find-matching-starter
|
826 : |
|
|
"\\bfun\\b\\|\\bfn\\b\\|\\band\\b\\|\\bhandle\\b")
|
827 : |
|
|
(cond
|
828 : |
|
|
((looking-at "fun\\b") (- (current-column) sml-pipe-indent))
|
829 : |
|
|
((looking-at "fn\\b") (1+ (current-column)))
|
830 : |
|
|
((looking-at "and\\b") (1+ (1+ (current-column))))
|
831 : |
|
|
((looking-at "handle\\b") (+ (current-column) 5)))
|
832 : |
|
|
(+ indent sml-pipe-indent)))
|
833 : |
|
|
(t
|
834 : |
|
|
(if sml-paren-lookback ; Look for open parenthesis ?
|
835 : |
|
|
(max indent (sml-get-paren-indent))
|
836 : |
|
|
indent))))))))))
|
837 : |
|
|
|
838 : |
|
|
(defun sml-get-indent ()
|
839 : |
|
|
(save-excursion
|
840 : |
|
|
(let ((case-fold-search nil))
|
841 : |
|
|
(beginning-of-line)
|
842 : |
|
|
(skip-chars-backward "\t\n; ")
|
843 : |
|
|
(if (looking-at ";") (sml-backward-sexp))
|
844 : |
|
|
(cond
|
845 : |
|
|
((save-excursion (sml-backward-sexp) (looking-at "end\\b"))
|
846 : |
|
|
(- (current-indentation) sml-indent-level))
|
847 : |
|
|
(t
|
848 : |
|
|
(while (/= (current-column) (current-indentation))
|
849 : |
|
|
(sml-backward-sexp))
|
850 : |
|
|
(skip-chars-forward "\t |")
|
851 : |
|
|
(let ((indent (current-column)))
|
852 : |
|
|
(skip-chars-forward "\t (")
|
853 : |
|
|
(cond
|
854 : |
monnier |
37 |
;; a "let fun" or "let val"
|
855 : |
|
|
((looking-at "let \\(fun\\|val\\)\\b")
|
856 : |
|
|
(+ (current-column) 4 sml-indent-level))
|
857 : |
monnier |
32 |
;; Started val/fun/structure...
|
858 : |
|
|
((looking-at sml-indent-starters-reg)
|
859 : |
|
|
(+ (current-column) sml-indent-level))
|
860 : |
|
|
;; Indent after "=>" pattern, but only if its not an fn _ =>
|
861 : |
|
|
;; (890726)
|
862 : |
|
|
((looking-at ".*=>")
|
863 : |
|
|
(if (looking-at ".*\\bfn\\b.*=>")
|
864 : |
|
|
indent
|
865 : |
|
|
(+ indent sml-indent-level)))
|
866 : |
|
|
;; else keep the same indentation as previous line
|
867 : |
|
|
(t indent))))))))
|
868 : |
|
|
|
869 : |
|
|
(defun sml-get-paren-indent ()
|
870 : |
|
|
(save-excursion
|
871 : |
|
|
(let ((levelpar 0) ; Level of "()"
|
872 : |
|
|
(levelcurl 0) ; Level of "{}"
|
873 : |
|
|
(levelsqr 0) ; Level of "[]"
|
874 : |
|
|
(backpoint (max (- (point) sml-paren-lookback) (point-min))))
|
875 : |
|
|
(catch 'loop
|
876 : |
|
|
(while (and (/= levelpar 1) (/= levelsqr 1) (/= levelcurl 1))
|
877 : |
|
|
(if (re-search-backward "[][{}()]" backpoint t)
|
878 : |
|
|
(if (not (sml-inside-comment-or-string-p))
|
879 : |
|
|
(cond
|
880 : |
|
|
((looking-at "(") (setq levelpar (1+ levelpar)))
|
881 : |
|
|
((looking-at ")") (setq levelpar (1- levelpar)))
|
882 : |
|
|
((looking-at "\\[") (setq levelsqr (1+ levelsqr)))
|
883 : |
|
|
((looking-at "\\]") (setq levelsqr (1- levelsqr)))
|
884 : |
|
|
((looking-at "{") (setq levelcurl (1+ levelcurl)))
|
885 : |
|
|
((looking-at "}") (setq levelcurl (1- levelcurl)))))
|
886 : |
|
|
(throw 'loop 0))) ; Exit with value 0
|
887 : |
|
|
(if (save-excursion
|
888 : |
|
|
(forward-char 1)
|
889 : |
|
|
(looking-at sml-indent-starters-reg))
|
890 : |
|
|
(1+ (+ (current-column) sml-indent-level))
|
891 : |
|
|
(1+ (current-column)))))))
|
892 : |
|
|
|
893 : |
|
|
(defun sml-inside-comment-or-string-p ()
|
894 : |
|
|
(let ((start (point)))
|
895 : |
|
|
(if (save-excursion
|
896 : |
|
|
(condition-case ()
|
897 : |
|
|
(progn
|
898 : |
|
|
(search-backward "(*")
|
899 : |
|
|
(search-forward "*)")
|
900 : |
|
|
(forward-char -1) ; A "*)" is not inside the comment
|
901 : |
|
|
(> (point) start))
|
902 : |
|
|
(error nil)))
|
903 : |
|
|
t
|
904 : |
|
|
(let ((numb 0))
|
905 : |
|
|
(save-excursion
|
906 : |
|
|
(save-restriction
|
907 : |
|
|
(narrow-to-region (progn (beginning-of-line) (point)) start)
|
908 : |
|
|
(condition-case ()
|
909 : |
|
|
(while t
|
910 : |
|
|
(search-forward "\"")
|
911 : |
|
|
(setq numb (1+ numb)))
|
912 : |
|
|
(error (if (and (not (zerop numb))
|
913 : |
|
|
(not (zerop (% numb 2))))
|
914 : |
|
|
t nil)))))))))
|
915 : |
|
|
|
916 : |
|
|
(defun sml-skip-block ()
|
917 : |
|
|
(let ((case-fold-search nil))
|
918 : |
|
|
(sml-backward-sexp)
|
919 : |
|
|
(if (looking-at "end\\b")
|
920 : |
|
|
(progn
|
921 : |
|
|
(goto-char (sml-find-match-backward "end" "\\bend\\b"
|
922 : |
|
|
sml-end-starters-reg))
|
923 : |
|
|
(skip-chars-backward "\n\t "))
|
924 : |
|
|
;; Here we will need to skip backward past if-then-else
|
925 : |
|
|
;; and case-of expression. Please - tell me how !!
|
926 : |
|
|
)))
|
927 : |
|
|
|
928 : |
|
|
(defun sml-find-match-backward (unquoted-this this match &optional start)
|
929 : |
|
|
(save-excursion
|
930 : |
|
|
(let ((case-fold-search nil)
|
931 : |
|
|
(level 1)
|
932 : |
|
|
(pattern (concat this "\\|" match)))
|
933 : |
|
|
(if start (goto-char start))
|
934 : |
|
|
(while (not (zerop level))
|
935 : |
|
|
(if (sml-re-search-backward pattern)
|
936 : |
|
|
(setq level (cond
|
937 : |
|
|
((looking-at this) (1+ level))
|
938 : |
|
|
((looking-at match) (1- level))))
|
939 : |
|
|
;; The right match couldn't be found
|
940 : |
|
|
(error (concat "Unbalanced: " unquoted-this))))
|
941 : |
|
|
(point))))
|
942 : |
|
|
|
943 : |
|
|
(defun sml-find-match-indent (unquoted-this this match &optional indented)
|
944 : |
|
|
(save-excursion
|
945 : |
|
|
(goto-char (sml-find-match-backward unquoted-this this match))
|
946 : |
|
|
(if (or sml-type-of-indent indented)
|
947 : |
|
|
(current-column)
|
948 : |
|
|
(if (progn
|
949 : |
|
|
(beginning-of-line)
|
950 : |
|
|
(skip-chars-forward "\t ")
|
951 : |
|
|
(looking-at "|"))
|
952 : |
|
|
(- (current-indentation) sml-pipe-indent)
|
953 : |
|
|
(current-indentation)))))
|
954 : |
|
|
|
955 : |
|
|
(defun sml-find-matching-starter (regexp)
|
956 : |
|
|
(let ((case-fold-search nil)
|
957 : |
|
|
(start-let-point (sml-point-inside-let-etc))
|
958 : |
|
|
(start-up-list (sml-up-list))
|
959 : |
|
|
(found t))
|
960 : |
|
|
(if (sml-re-search-backward regexp)
|
961 : |
|
|
(progn
|
962 : |
|
|
(condition-case ()
|
963 : |
|
|
(while (or (/= start-up-list (sml-up-list))
|
964 : |
|
|
(/= start-let-point (sml-point-inside-let-etc)))
|
965 : |
|
|
(re-search-backward regexp))
|
966 : |
|
|
(error (setq found nil)))
|
967 : |
|
|
found)
|
968 : |
|
|
nil)))
|
969 : |
|
|
|
970 : |
|
|
(defun sml-point-inside-let-etc ()
|
971 : |
|
|
(let ((case-fold-search nil) (last nil) (loop t) (found t) (start (point)))
|
972 : |
|
|
(save-excursion
|
973 : |
|
|
(while loop
|
974 : |
|
|
(condition-case ()
|
975 : |
|
|
(progn
|
976 : |
|
|
(re-search-forward "\\bend\\b")
|
977 : |
|
|
(while (sml-inside-comment-or-string-p)
|
978 : |
|
|
(re-search-forward "\\bend\\b"))
|
979 : |
|
|
(forward-char -3)
|
980 : |
|
|
(setq last (sml-find-match-backward "end" "\\bend\\b"
|
981 : |
|
|
sml-end-starters-reg last))
|
982 : |
|
|
(if (< last start)
|
983 : |
|
|
(setq loop nil)
|
984 : |
|
|
(forward-char 3)))
|
985 : |
|
|
(error (progn (setq found nil) (setq loop nil)))))
|
986 : |
|
|
(if found
|
987 : |
|
|
last
|
988 : |
|
|
0))))
|
989 : |
|
|
|
990 : |
|
|
(defun sml-re-search-backward (regexpr)
|
991 : |
|
|
(let ((case-fold-search nil) (found t))
|
992 : |
|
|
(if (re-search-backward regexpr nil t)
|
993 : |
|
|
(progn
|
994 : |
|
|
(condition-case ()
|
995 : |
|
|
(while (sml-inside-comment-or-string-p)
|
996 : |
|
|
(re-search-backward regexpr))
|
997 : |
|
|
(error (setq found nil)))
|
998 : |
|
|
found)
|
999 : |
|
|
nil)))
|
1000 : |
|
|
|
1001 : |
|
|
(defun sml-up-list ()
|
1002 : |
|
|
(save-excursion
|
1003 : |
|
|
(condition-case ()
|
1004 : |
|
|
(progn
|
1005 : |
|
|
(up-list 1)
|
1006 : |
|
|
(point))
|
1007 : |
|
|
(error 0))))
|
1008 : |
|
|
|
1009 : |
|
|
(defun sml-backward-sexp ()
|
1010 : |
|
|
(condition-case ()
|
1011 : |
|
|
(progn
|
1012 : |
|
|
(let ((start (point)))
|
1013 : |
|
|
(backward-sexp 1)
|
1014 : |
|
|
(while (and (/= start (point)) (looking-at "(\\*"))
|
1015 : |
|
|
(setq start (point))
|
1016 : |
|
|
(backward-sexp 1))))
|
1017 : |
|
|
(error (forward-char -1))))
|
1018 : |
|
|
|
1019 : |
|
|
(defun sml-comment-indent ()
|
1020 : |
|
|
(if (looking-at "^(\\*") ; Existing comment at beginning
|
1021 : |
|
|
0 ; of line stays there.
|
1022 : |
|
|
(save-excursion
|
1023 : |
|
|
(skip-chars-backward " \t")
|
1024 : |
|
|
(max (1+ (current-column)) ; Else indent at comment column
|
1025 : |
|
|
comment-column)))) ; except leave at least one space.
|
1026 : |
|
|
|
1027 : |
|
|
;;; INSERTING PROFORMAS (COMMON SML-FORMS)
|
1028 : |
|
|
|
1029 : |
|
|
(defvar sml-forms-alist
|
1030 : |
|
|
'(("let") ("local") ("case") ("abstype") ("datatype")
|
1031 : |
|
|
("signature") ("structure") ("functor"))
|
1032 : |
|
|
"*The list of templates to auto-insert.
|
1033 : |
|
|
|
1034 : |
|
|
You can extend this alist to your heart's content. For each additional
|
1035 : |
|
|
template NAME in the list, declare a keyboard macro or function (or
|
1036 : |
|
|
interactive command) called 'sml-form-NAME'.
|
1037 : |
|
|
|
1038 : |
|
|
If 'sml-form-NAME' is a function it takes no arguments and should
|
1039 : |
|
|
insert the template at point\; if this is a command it may accept any
|
1040 : |
|
|
sensible interactive call arguments\; keyboard macros can't take
|
1041 : |
|
|
arguments at all. Apropos keyboard macros, see `name-last-kbd-macro'
|
1042 : |
|
|
and `sml-addto-forms-alist'.
|
1043 : |
|
|
|
1044 : |
|
|
`sml-forms-alist' understands let, local, case, abstype, datatype,
|
1045 : |
|
|
signature, structure, and functor by default.")
|
1046 : |
|
|
|
1047 : |
|
|
;; See also macros.el in emacs lisp dir.
|
1048 : |
|
|
|
1049 : |
|
|
(defun sml-addto-forms-alist (name)
|
1050 : |
|
|
"Assign a name to the last keyboard macro defined.
|
1051 : |
|
|
Argument NAME is transmogrified to sml-form-NAME which is the symbol
|
1052 : |
|
|
actually defined.
|
1053 : |
|
|
|
1054 : |
|
|
The symbol's function definition becomes the keyboard macro string.
|
1055 : |
|
|
|
1056 : |
|
|
If that works, NAME is added to `sml-forms-alist' so you'll be able to
|
1057 : |
|
|
reinvoke the macro through \\[sml-insert-form]. You might want to save
|
1058 : |
|
|
the macro to use in a later editing session -- see `insert-kbd-macro'
|
1059 : |
|
|
and add these macros to your .emacs file.
|
1060 : |
|
|
|
1061 : |
|
|
See also `edit-kbd-macro' which is bound to \\[edit-kbd-macro]."
|
1062 : |
|
|
(interactive "sName for last kbd macro (\"sml-form-\" will be added): ")
|
1063 : |
|
|
(if (string-equal name "")
|
1064 : |
|
|
(error "No command name given")
|
1065 : |
|
|
(name-last-kbd-macro (intern (concat "sml-form-" name)))
|
1066 : |
|
|
(message (concat "Macro bound to sml-form-" name))
|
1067 : |
|
|
(or (assoc name sml-forms-alist)
|
1068 : |
|
|
(setq sml-forms-alist (cons (list name) sml-forms-alist)))))
|
1069 : |
|
|
|
1070 : |
|
|
;; at a pinch these could be added to SML/Forms menu through the good
|
1071 : |
|
|
;; offices of activate-menubar-hook or something... but documentation
|
1072 : |
|
|
;; of this and/or menu-bar-update-hook is sparse in 19.33. anyway, use
|
1073 : |
|
|
;; completing read for sml-insert-form prompt...
|
1074 : |
|
|
|
1075 : |
|
|
(defvar sml-last-form "let"
|
1076 : |
|
|
"The most recent sml form inserted.")
|
1077 : |
|
|
|
1078 : |
|
|
(defun sml-insert-form (arg)
|
1079 : |
|
|
"Interactive short-cut to insert a common ML form.
|
1080 : |
|
|
If a perfix argument is given insert a newline and indent first, or
|
1081 : |
|
|
just move to the proper indentation if the line is blank\; otherwise
|
1082 : |
|
|
insert at point (which forces indentation to current column).
|
1083 : |
|
|
|
1084 : |
|
|
The default form to insert is 'whatever you inserted last time'
|
1085 : |
|
|
\(just hit return when prompted\)\; otherwise the command reads with
|
1086 : |
|
|
completion from `sml-forms-alist'."
|
1087 : |
|
|
(interactive "P")
|
1088 : |
|
|
(let ((name (completing-read
|
1089 : |
|
|
(format "Form to insert: (default %s) " sml-last-form)
|
1090 : |
|
|
sml-forms-alist nil t nil)))
|
1091 : |
|
|
;; default is whatever the last insert was...
|
1092 : |
|
|
(if (string= name "") (setq name sml-last-form))
|
1093 : |
|
|
(setq sml-last-form name)
|
1094 : |
|
|
(if arg
|
1095 : |
|
|
(if (save-excursion (beginning-of-line) (looking-at "[ \t]*$"))
|
1096 : |
|
|
(sml-indent-line)
|
1097 : |
|
|
(newline-and-indent)))
|
1098 : |
|
|
(cond ((string= name "let") (sml-form-let))
|
1099 : |
|
|
((string= name "local") (sml-form-local))
|
1100 : |
|
|
((string= name "case") (sml-form-case))
|
1101 : |
|
|
((string= name "abstype") (sml-form-abstype))
|
1102 : |
|
|
((string= name "datatype") (sml-form-datatype))
|
1103 : |
|
|
((string= name "functor") (sml-form-functor))
|
1104 : |
|
|
((string= name "structure") (sml-form-structure))
|
1105 : |
|
|
((string= name "signature") (sml-form-signature))
|
1106 : |
|
|
(t
|
1107 : |
|
|
(let ((template (intern (concat "sml-form-" name))))
|
1108 : |
|
|
(if (fboundp template)
|
1109 : |
|
|
(if (commandp template)
|
1110 : |
|
|
;; it may be a named kbd macro too
|
1111 : |
|
|
(command-execute template)
|
1112 : |
|
|
(funcall template))
|
1113 : |
|
|
(error
|
1114 : |
|
|
(format "Undefined format function: %s" template))))))))
|
1115 : |
|
|
|
1116 : |
|
|
(defun sml-form-let ()
|
1117 : |
|
|
"Insert a `let in end' template."
|
1118 : |
|
|
(interactive)
|
1119 : |
|
|
(sml-let-local "let"))
|
1120 : |
|
|
|
1121 : |
|
|
(defun sml-form-local ()
|
1122 : |
|
|
"Insert a `local in end' template."
|
1123 : |
|
|
(interactive)
|
1124 : |
|
|
(sml-let-local "local"))
|
1125 : |
|
|
|
1126 : |
|
|
(defun sml-let-local (starter)
|
1127 : |
|
|
"Insert a let or local template, depending on STARTER string."
|
1128 : |
|
|
(let ((indent (current-column)))
|
1129 : |
|
|
(insert starter)
|
1130 : |
|
|
(insert "\n") (indent-to (+ sml-indent-level indent))
|
1131 : |
|
|
(save-excursion ; so point returns here
|
1132 : |
|
|
(insert "\n")
|
1133 : |
|
|
(indent-to indent)
|
1134 : |
|
|
(insert "in\n")
|
1135 : |
|
|
(indent-to (+ sml-indent-level indent))
|
1136 : |
|
|
(insert "\n")
|
1137 : |
|
|
(indent-to indent)
|
1138 : |
|
|
(insert "end"))))
|
1139 : |
|
|
|
1140 : |
|
|
(defun sml-form-case ()
|
1141 : |
|
|
"Insert a case expression template, prompting for the case-expresion."
|
1142 : |
|
|
(interactive)
|
1143 : |
|
|
(let ((expr (read-string "Case expr: "))
|
1144 : |
|
|
(indent (current-column)))
|
1145 : |
|
|
(insert (concat "case " expr))
|
1146 : |
|
|
(if sml-case-indent
|
1147 : |
|
|
(progn
|
1148 : |
|
|
(insert "\n")
|
1149 : |
|
|
(indent-to (+ 2 indent))
|
1150 : |
|
|
(insert "of "))
|
1151 : |
|
|
(insert " of\n")
|
1152 : |
|
|
(indent-to (+ indent sml-indent-level)))
|
1153 : |
|
|
(save-excursion (insert " => "))))
|
1154 : |
|
|
|
1155 : |
|
|
(defun sml-form-signature ()
|
1156 : |
|
|
"Insert a generative signature binding, prompting for the name."
|
1157 : |
|
|
(interactive)
|
1158 : |
|
|
(let ((indent (current-column))
|
1159 : |
|
|
(name (read-string "Signature name: ")))
|
1160 : |
|
|
(insert (concat "signature " name " ="))
|
1161 : |
|
|
(insert "\n")
|
1162 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1163 : |
|
|
(insert "sig\n")
|
1164 : |
|
|
(indent-to (+ sml-structure-indent sml-indent-level indent))
|
1165 : |
|
|
(save-excursion
|
1166 : |
|
|
(insert "\n")
|
1167 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1168 : |
|
|
(insert "end"))))
|
1169 : |
|
|
|
1170 : |
|
|
(defun sml-form-structure ()
|
1171 : |
|
|
"Insert a generative structure binding, prompting for the name.
|
1172 : |
|
|
The command also prompts for any signature constraint -- you should
|
1173 : |
|
|
specify \":\" or \":>\" and the constraining signature."
|
1174 : |
|
|
(interactive)
|
1175 : |
|
|
(let ((indent (current-column))
|
1176 : |
|
|
(name (read-string (concat "Structure name: ")))
|
1177 : |
|
|
(signame (read-string "Signature constraint (default none): ")))
|
1178 : |
|
|
(insert (concat "structure " name " "))
|
1179 : |
|
|
(insert (if (string= "" signame) "=" (concat signame " =")))
|
1180 : |
|
|
(insert "\n")
|
1181 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1182 : |
|
|
(insert "struct\n")
|
1183 : |
|
|
(indent-to (+ sml-structure-indent sml-indent-level indent))
|
1184 : |
|
|
(save-excursion
|
1185 : |
|
|
(insert "\n")
|
1186 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1187 : |
|
|
(insert "end"))))
|
1188 : |
|
|
|
1189 : |
|
|
(defun sml-form-functor ()
|
1190 : |
|
|
"Insert a genarative functor binding, prompting for the name.
|
1191 : |
|
|
The command also prompts for the required signature constraint -- you
|
1192 : |
|
|
should specify \":\" or \":>\" and the constraining signature."
|
1193 : |
|
|
(interactive)
|
1194 : |
|
|
(let ((indent(current-indentation))
|
1195 : |
|
|
(name (read-string "Name of functor: "))
|
1196 : |
|
|
(signame (read-string "Signature constraint: " ":" )))
|
1197 : |
|
|
(insert (concat "functor " name " () " signame " ="))
|
1198 : |
|
|
(insert "\n")
|
1199 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1200 : |
|
|
(insert "struct\n")
|
1201 : |
|
|
(indent-to (+ sml-structure-indent sml-indent-level indent))
|
1202 : |
|
|
(save-excursion ; return to () instead?
|
1203 : |
|
|
(insert "\n")
|
1204 : |
|
|
(indent-to (+ sml-structure-indent indent))
|
1205 : |
|
|
(insert "end"))))
|
1206 : |
|
|
|
1207 : |
|
|
(defun sml-form-datatype ()
|
1208 : |
|
|
"Insert a datatype declaration, prompting for name and type parameter."
|
1209 : |
|
|
(interactive)
|
1210 : |
|
|
(let ((indent (current-indentation))
|
1211 : |
|
|
(type (read-string "Datatype type parameter (default none): "))
|
1212 : |
|
|
(name (read-string (concat "Name of datatype: "))))
|
1213 : |
|
|
(insert (concat "datatype "
|
1214 : |
|
|
(if (string= type "") "" (concat type " "))
|
1215 : |
|
|
name " ="))
|
1216 : |
|
|
(insert "\n")
|
1217 : |
|
|
(indent-to (+ sml-indent-level indent))))
|
1218 : |
|
|
|
1219 : |
|
|
(defun sml-form-abstype ()
|
1220 : |
|
|
"Insert an abstype declaration, prompting for name and type parameter."
|
1221 : |
|
|
(interactive)
|
1222 : |
|
|
(let ((indent(current-indentation))
|
1223 : |
|
|
(type (read-string "Abstype type parameter (default none): "))
|
1224 : |
|
|
(name (read-string "Name of abstype: ")))
|
1225 : |
|
|
(insert (concat "abstype "
|
1226 : |
|
|
(if (string= type "") "" (concat type " "))
|
1227 : |
|
|
name " ="))
|
1228 : |
|
|
(insert "\n")
|
1229 : |
|
|
(indent-to (+ sml-indent-level indent))
|
1230 : |
|
|
(save-excursion
|
1231 : |
|
|
(insert "\n")
|
1232 : |
|
|
(indent-to indent)
|
1233 : |
|
|
(insert "with\n")
|
1234 : |
|
|
(indent-to (+ sml-indent-level indent))
|
1235 : |
|
|
(insert "\n")
|
1236 : |
|
|
(indent-to indent)
|
1237 : |
|
|
(insert "end"))))
|
1238 : |
|
|
|
1239 : |
|
|
;;; Load the menus, if they can be found on the load-path
|
1240 : |
|
|
|
1241 : |
|
|
(condition-case nil
|
1242 : |
|
|
(require 'sml-menus)
|
1243 : |
|
|
(error (message "Sorry, not able to load SML mode menus.")))
|
1244 : |
|
|
|
1245 : |
|
|
;;; & do the user's customisation
|
1246 : |
|
|
|
1247 : |
|
|
(add-hook 'sml-load-hook 'sml-mode-version t)
|
1248 : |
|
|
|
1249 : |
|
|
(run-hooks 'sml-load-hook)
|
1250 : |
|
|
|
1251 : |
|
|
;;; sml-mode.el has just finished.
|