]> code.delx.au - gnu-emacs-elpa/blob - sml-oldindent.el
Merge from trunk
[gnu-emacs-elpa] / sml-oldindent.el
1 ;;; sml-oldindent.el --- Navigation and indentation for SML without SMIE
2
3 ;; Copyright (C) 1999,2000,2004,2007,2012 Stefan Monnier <monnier@gnu.org>
4 ;;
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation; either version 3 of the License, or
8 ;; (at your option) any later version.
9 ;;
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
14 ;;
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program; if not, write to the Free Software
17 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19
20 ;;; Commentary:
21
22
23 ;;; Code:
24
25 (eval-when-compile (require 'cl))
26 (require 'sml-defs)
27
28 (defun sml-preproc-alist (al)
29 "Expand an alist AL where keys can be lists of keys into a normal one."
30 (apply #'nconc
31 (mapcar (lambda (x)
32 (let ((k (car x))
33 (v (cdr x)))
34 (if (consp k)
35 (mapcar (lambda (y) (cons y v)) k)
36 (list x))))
37 al)))
38
39 (defconst sml-begin-syms
40 '("let" "abstype" "local" "struct" "sig")
41 "Symbols matching the `end' symbol.")
42
43 (defconst sml-begin-syms-re
44 (sml-syms-re sml-begin-syms)
45 "Symbols matching the `end' symbol.")
46
47 ;; (defconst sml-user-begin-symbols-re
48 ;; (sml-syms-re '("let" "abstype" "local" "struct" "sig" "in" "with"))
49 ;; "Symbols matching (loosely) the `end' symbol.")
50
51 (defconst sml-sexp-head-symbols-re
52 (sml-syms-re `("let" "abstype" "local" "struct" "sig" "in" "with"
53 "if" "then" "else" "case" "of" "fn" "fun" "val" "and"
54 "datatype" "type" "exception" "open" "infix" "infixr" "nonfix"
55 ,@sml-module-head-syms
56 "handle" "raise"))
57 "Symbols starting an sexp.")
58
59 ;; (defconst sml-not-arg-start-re
60 ;; (sml-syms-re '("in" "of" "end" "andalso"))
61 ;; "Symbols that can't be found at the head of an arg.")
62
63 ;; (defconst sml-not-arg-re
64 ;; (sml-syms-re '("in" "of" "end" "andalso"))
65 ;; "Symbols that should not be confused with an arg.")
66
67 (defconst sml-indent-rule
68 (sml-preproc-alist
69 `(("struct" . 0)
70 (,sml-module-head-syms "d=" 0)
71 ("local" "in" 0)
72 ;;("of" . (3 nil))
73 ;;("else" . (sml-indent-level 0))
74 ;;(("in" "fun" "and" "of") . (sml-indent-level nil))
75 ("if" "else" 0)
76 (,sml-=-starter-syms nil)
77 (("abstype" "case" "datatype" "if" "then" "else" "sharing" "infix" "infixr"
78 "let" "local" "nonfix" "open" "raise" "sig" "struct" "type" "val" "while"
79 "do" "with" "withtype")))))
80
81 (defconst sml-delegate
82 (sml-preproc-alist
83 `((("of" "else" "then" "d=") . (not (sml-bolp)))
84 ("in" . t)))
85 "Words which might delegate indentation to their parent.")
86
87 (defcustom sml-symbol-indent
88 '(("fn" . -3)
89 ("of" . 1)
90 ("|" . -2)
91 ("," . -2)
92 (";" . -2)
93 ;;("in" . 1)
94 ("d=" . 2))
95 "Special indentation alist for some symbols.
96 An entry like (\"in\" . 1) indicates that a line starting with the
97 symbol `in' should be indented one char further to the right.
98 This is only used in a few specific cases, so it does not work
99 for all symbols and in all lines starting with the given symbol."
100 :group 'sml
101 :type '(repeat (cons string integer)))
102
103 (defconst sml-open-paren
104 (sml-preproc-alist
105 `((,(list* "with" "in" sml-begin-syms) ,sml-begin-syms-re "\\<end\\>")))
106 "Symbols that should behave somewhat like opening parens.")
107
108 (defconst sml-close-paren
109 `(("in" "\\<l\\(ocal\\|et\\)\\>")
110 ("with" "\\<abstype\\>")
111 ("withtype" "\\<\\(abs\\|data\\)type\\>")
112 ("end" ,sml-begin-syms-re)
113 ("then" "\\<if\\>")
114 ("else" "\\<if\\>" (sml-bolp))
115 ("of" "\\<case\\>")
116 ("d=" nil))
117 "Symbols that should behave somewhat like close parens.")
118
119 (defconst sml-agglomerate-re "\\<else[ \t]+if\\>"
120 "Regexp of compound symbols (pairs of symbols to be considered as one).")
121
122 (defvar sml-internal-syntax-table
123 (let ((st (make-syntax-table sml-mode-syntax-table)))
124 (modify-syntax-entry ?_ "w" st)
125 (modify-syntax-entry ?' "w" st)
126 (modify-syntax-entry ?. "w" st)
127 ;; treating `~' as a word constituent is not quite right, but
128 ;; close enough. Think about 12.3E~2 for example. Also `~' on its
129 ;; own *is* a nonfix symbol.
130 (modify-syntax-entry ?~ "w" st)
131 st)
132 "Syntax table used for internal sml-mode operation.")
133
134 ;;;
135 ;;; various macros
136 ;;;
137
138 (defmacro sml-with-ist (&rest r)
139 (let ((ost-sym (make-symbol "oldtable")))
140 `(let ((,ost-sym (syntax-table))
141 (case-fold-search nil)
142 (parse-sexp-lookup-properties t)
143 (parse-sexp-ignore-comments t))
144 (unwind-protect
145 (progn (set-syntax-table sml-internal-syntax-table) . ,r)
146 (set-syntax-table ,ost-sym)))))
147 (def-edebug-spec sml-with-ist t)
148
149 (defmacro sml-move-if (&rest body)
150 (let ((pt-sym (make-symbol "point"))
151 (res-sym (make-symbol "result")))
152 `(let ((,pt-sym (point))
153 (,res-sym ,(cons 'progn body)))
154 (unless ,res-sym (goto-char ,pt-sym))
155 ,res-sym)))
156 (def-edebug-spec sml-move-if t)
157
158 (defmacro sml-point-after (&rest body)
159 `(save-excursion
160 ,@body
161 (point)))
162 (def-edebug-spec sml-point-after t)
163
164 ;;
165
166 (defvar sml-op-prec
167 (sml-preproc-alist
168 '(("before" . 0)
169 ((":=" "o") . 3)
170 ((">" ">=" "<>" "<" "<=" "=") . 4)
171 (("::" "@") . 5)
172 (("+" "-" "^") . 6)
173 (("/" "*" "quot" "rem" "div" "mod") . 7)))
174 "Alist of SML infix operators and their precedence.")
175
176 (defconst sml-syntax-prec
177 (sml-preproc-alist
178 `((("in" "with") . 10)
179 ((";" ",") . 20)
180 (("=>" "d=" "=of") . (65 . 40))
181 ("|" . (47 . 30))
182 (("case" "of" "fn") . 45)
183 (("if" "then" "else" "while" "do" "raise") . 50)
184 ("handle" . 60)
185 ("orelse" . 70)
186 ("andalso" . 80)
187 ((":" ":>") . 90)
188 ("->" . 95)
189 (,(cons "end" sml-begin-syms) . 10000)))
190 "Alist of pseudo-precedence of syntactic elements.")
191
192 (defun sml-op-prec (op dir)
193 "Return the precedence of OP or nil if it's not an infix.
194 DIR should be set to BACK if you want to precedence w.r.t the left side
195 and to FORW for the precedence w.r.t the right side.
196 This assumes that we are `looking-at' the OP."
197 (when op
198 (let ((sprec (cdr (assoc op sml-syntax-prec))))
199 (cond
200 ((consp sprec) (if (eq dir 'back) (car sprec) (cdr sprec)))
201 (sprec sprec)
202 (t
203 (let ((prec (cdr (assoc op sml-op-prec))))
204 (when prec (+ prec 100))))))))
205
206 ;;
207
208 (defun sml-forward-spaces () (forward-comment 100000))
209 (defun sml-backward-spaces () (forward-comment -100000))
210
211
212 ;;
213 ;; moving forward around matching symbols
214 ;;
215
216 (defun sml-looking-back-at (re)
217 (save-excursion
218 (when (= 0 (skip-syntax-backward "w_")) (backward-char))
219 (looking-at re)))
220
221 (defun sml-find-match-forward (this match)
222 "Only works for word matches."
223 (let ((level 1)
224 (forward-sexp-function nil)
225 (either (concat this "\\|" match)))
226 (while (and (not (eobp)) (> level 0))
227 (forward-sexp 1)
228 (while (not (or (eobp) (sml-looking-back-at either)))
229 (condition-case () (forward-sexp 1) (error (forward-char 1))))
230 (setq level
231 (cond
232 ((sml-looking-back-at this) (1+ level))
233 ((sml-looking-back-at match) (1- level))
234 (t (error "Unbalanced")))))
235 t))
236
237 (defun sml-find-match-backward (this match)
238 (let ((level 1)
239 (forward-sexp-function nil)
240 (either (concat this "\\|" match)))
241 (while (> level 0)
242 (backward-sexp 1)
243 (while (not (or (bobp) (looking-at either)))
244 (condition-case () (backward-sexp 1) (error (backward-char 1))))
245 (setq level
246 (cond
247 ((looking-at this) (1+ level))
248 ((looking-at match) (1- level))
249 (t (error "Unbalanced")))))
250 t))
251
252 ;;;
253 ;;; Read a symbol, including the special "op <sym>" case
254 ;;;
255
256 (defmacro sml-move-read (&rest body)
257 (let ((pt-sym (make-symbol "point")))
258 `(let ((,pt-sym (point)))
259 ,@body
260 (when (/= (point) ,pt-sym)
261 (buffer-substring-no-properties (point) ,pt-sym)))))
262 (def-edebug-spec sml-move-read t)
263
264 (defun sml-poly-equal-p ()
265 ;; Figure out which kind of "=" this is.
266 ;; The idea is to look backward for the first occurrence of a token that
267 ;; requires a definitional "=" and then see if there's such a definitional
268 ;; equal between that token and ourselves (in which case we're not
269 ;; a definitional = ourselves).
270 ;; The "search for =" is naive and will match "=>" and "<=", but it turns
271 ;; out to be OK in practice because such tokens very rarely (if ever) appear
272 ;; between the =-starter and the corresponding definitional equal.
273 ;; One known problem case is code like:
274 ;; "functor foo (structure s : S) where type t = s.t ="
275 ;; where the "type t = s.t" is mistaken for a type definition.
276 (< (sml-point-after (re-search-backward sml-=-starter-re nil 'move))
277 (sml-point-after (re-search-backward "=" nil 'move))))
278
279 (defun sml-nested-of-p ()
280 (< (sml-point-after
281 (re-search-backward sml-non-nested-of-starter-re nil 'move))
282 (sml-point-after (re-search-backward "\\<case\\>" nil 'move))))
283
284 (defun sml-forward-sym-1 ()
285 (or (/= 0 (skip-syntax-forward "'w_"))
286 (/= 0 (skip-syntax-forward ".'"))))
287 (defun sml-forward-sym ()
288 (let ((sym (sml-move-read (sml-forward-sym-1))))
289 (cond
290 ((equal "op" sym)
291 (sml-forward-spaces)
292 (concat "op " (or (sml-move-read (sml-forward-sym-1)) "")))
293 ((equal sym "=")
294 (save-excursion
295 (sml-backward-sym-1)
296 (if (sml-poly-equal-p) "=" "d=")))
297 ((equal sym "of")
298 (save-excursion
299 (sml-backward-sym-1)
300 (if (sml-nested-of-p) "of" "=of")))
301 ;; ((equal sym "datatype")
302 ;; (save-excursion
303 ;; (sml-backward-sym-1)
304 ;; (sml-backward-spaces)
305 ;; (if (eq (preceding-char) ?=) "=datatype" sym)))
306 (t sym))))
307
308 (defun sml-backward-sym-1 ()
309 (or (/= 0 (skip-syntax-backward ".'"))
310 (/= 0 (skip-syntax-backward "'w_"))))
311 (defun sml-backward-sym ()
312 (let ((sym (sml-move-read (sml-backward-sym-1))))
313 (when sym
314 ;; FIXME: what should we do if `sym' = "op" ?
315 (let ((point (point)))
316 (sml-backward-spaces)
317 (if (equal "op" (sml-move-read (sml-backward-sym-1)))
318 (concat "op " sym)
319 (goto-char point)
320 (cond
321 ((string= sym "=") (if (sml-poly-equal-p) "=" "d="))
322 ((string= sym "of") (if (sml-nested-of-p) "of" "=of"))
323 ;; ((string= sym "datatype")
324 ;; (save-excursion (sml-backward-spaces)
325 ;; (if (eq (preceding-char) ?=) "=datatype" sym)))
326 (t sym)))))))
327
328
329 (defun sml-backward-sexp (prec)
330 "Move one sexp backward if possible, or one char else.
331 Returns t if the move indeed moved through one sexp and nil if not.
332 PREC is the precedence currently looked for."
333 (let ((parse-sexp-lookup-properties t)
334 (parse-sexp-ignore-comments t))
335 (sml-backward-spaces)
336 (let* ((op (sml-backward-sym))
337 (op-prec (sml-op-prec op 'back))
338 match)
339 (cond
340 ((not op)
341 (let ((point (point)))
342 (ignore-errors (let ((forward-sexp-function nil)) (backward-sexp 1)))
343 (if (/= point (point)) t (ignore-errors (backward-char 1)) nil)))
344 ;; stop as soon as precedence is smaller than `prec'
345 ((and prec op-prec (>= prec op-prec)) nil)
346 ;; special rules for nested constructs like if..then..else
347 ((and (or (not prec) (and prec op-prec))
348 (setq match (second (assoc op sml-close-paren))))
349 (sml-find-match-backward (concat "\\<" op "\\>") match))
350 ;; don't back over open-parens
351 ((assoc op sml-open-paren) nil)
352 ;; infix ops precedence
353 ((and prec op-prec) (< prec op-prec))
354 ;; [ prec = nil ] a new operator, let's skip the sexps until the next
355 (op-prec (while (sml-move-if (sml-backward-sexp op-prec))) t)
356 ;; special symbols indicating we're getting out of a nesting level
357 ((string-match sml-sexp-head-symbols-re op) nil)
358 ;; if the op was not alphanum, then we still have to do the backward-sexp
359 ;; this reproduces the usual backward-sexp, but it might be bogus
360 ;; in this case since !@$% is a perfectly fine symbol
361 (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec))
362
363 (defun sml-forward-sexp (prec)
364 "Moves one sexp forward if possible, or one char else.
365 Returns T if the move indeed moved through one sexp and NIL if not."
366 (let ((parse-sexp-lookup-properties t)
367 (parse-sexp-ignore-comments t))
368 (sml-forward-spaces)
369 (let* ((op (sml-forward-sym))
370 (op-prec (sml-op-prec op 'forw))
371 match)
372 (cond
373 ((not op)
374 (let ((point (point)))
375 (ignore-errors (let ((forward-sexp-function nil)) (forward-sexp 1)))
376 (if (/= point (point)) t (forward-char 1) nil)))
377 ;; stop as soon as precedence is smaller than `prec'
378 ((and prec op-prec (>= prec op-prec)) nil)
379 ;; special rules for nested constructs like if..then..else
380 ((and (or (not prec) (and prec op-prec))
381 (setq match (cdr (assoc op sml-open-paren))))
382 (sml-find-match-forward (first match) (second match)))
383 ;; don't forw over close-parens
384 ((assoc op sml-close-paren) nil)
385 ;; infix ops precedence
386 ((and prec op-prec) (< prec op-prec))
387 ;; [ prec = nil ] a new operator, let's skip the sexps until the next
388 (op-prec (while (sml-move-if (sml-forward-sexp op-prec))) t)
389 ;; special symbols indicating we're getting out of a nesting level
390 ((string-match sml-sexp-head-symbols-re op) nil)
391 ;; if the op was not alphanum, then we still have to do the backward-sexp
392 ;; this reproduces the usual backward-sexp, but it might be bogus
393 ;; in this case since !@$% is a perfectly fine symbol
394 (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec))
395
396 (defun sml-in-word-p ()
397 (and (eq ?w (char-syntax (or (char-before) ? )))
398 (eq ?w (char-syntax (or (char-after) ? )))))
399
400 (defun sml-user-backward-sexp (&optional count)
401 "Like `backward-sexp' but tailored to the SML syntax."
402 (interactive "p")
403 (unless count (setq count 1))
404 (sml-with-ist
405 (let ((point (point)))
406 (if (< count 0) (sml-user-forward-sexp (- count))
407 (when (sml-in-word-p) (forward-word 1))
408 (dotimes (i count)
409 (unless (sml-backward-sexp nil)
410 (goto-char point)
411 (error "Containing expression ends prematurely")))))))
412
413 (defun sml-user-forward-sexp (&optional count)
414 "Like `forward-sexp' but tailored to the SML syntax."
415 (interactive "p")
416 (unless count (setq count 1))
417 (sml-with-ist
418 (let ((point (point)))
419 (if (< count 0) (sml-user-backward-sexp (- count))
420 (when (sml-in-word-p) (backward-word 1))
421 (dotimes (i count)
422 (unless (sml-forward-sexp nil)
423 (goto-char point)
424 (error "Containing expression ends prematurely")))))))
425
426 ;;(defun sml-forward-thing ()
427 ;; (if (= ?w (char-syntax (char-after))) (forward-word 1) (forward-char 1)))
428
429 (defun sml-backward-arg () (sml-backward-sexp 1000))
430 (defun sml-forward-arg () (sml-forward-sexp 1000))
431
432 (provide 'sml-move)
433
434 (defvar sml-rightalign-and)
435 (defvar sml-indent-args)
436 (defvar sml-indent-level)
437
438 (defun sml-indent-line ()
439 "Indent current line of ML code."
440 (interactive)
441 (let ((savep (> (current-column) (current-indentation)))
442 (indent (max (or (ignore-errors (sml-calculate-indentation)) 0) 0)))
443 (if savep
444 (save-excursion (indent-line-to indent))
445 (indent-line-to indent))))
446
447 (defun sml-find-comment-indent ()
448 (save-excursion
449 (let ((depth 1))
450 (while (> depth 0)
451 (if (re-search-backward "(\\*\\|\\*)" nil t)
452 (cond
453 ;; FIXME: That's just a stop-gap.
454 ((eq (get-text-property (point) 'face) 'font-lock-string-face))
455 ((looking-at "*)") (incf depth))
456 ((looking-at comment-start-skip) (decf depth)))
457 (setq depth -1)))
458 (if (= depth 0)
459 (1+ (current-column))
460 nil))))
461
462 (defun sml-calculate-indentation ()
463 (save-excursion
464 (beginning-of-line) (skip-chars-forward "\t ")
465 (sml-with-ist
466 ;; Indentation for comments alone on a line, matches the
467 ;; proper indentation of the next line.
468 (when (looking-at "(\\*") (sml-forward-spaces))
469 (let (data
470 (sym (save-excursion (sml-forward-sym))))
471 (or
472 ;; Allow the user to override the indentation.
473 (when (looking-at (concat ".*" (regexp-quote comment-start)
474 "[ \t]*fixindent[ \t]*"
475 (regexp-quote comment-end)))
476 (current-indentation))
477
478 ;; Continued comment.
479 (and (looking-at "\\*") (sml-find-comment-indent))
480
481 ;; Continued string ? (Added 890113 lbn)
482 (and (looking-at "\\\\")
483 (or (save-excursion (forward-line -1)
484 (if (looking-at "[\t ]*\\\\")
485 (current-indentation)))
486 (save-excursion
487 (if (re-search-backward "[^\\\\]\"" nil t)
488 (1+ (current-column))
489 0))))
490
491 ;; Closing parens. Could be handled below with `sml-indent-relative'?
492 (and (looking-at "\\s)")
493 (save-excursion
494 (skip-syntax-forward ")")
495 (backward-sexp 1)
496 (if (sml-dangling-sym)
497 (sml-indent-default 'noindent)
498 (current-column))))
499
500 (and (setq data (assoc sym sml-close-paren))
501 (sml-indent-relative sym data))
502
503 (and (member sym sml-starters-syms)
504 (sml-indent-starter sym))
505
506 (and (string= sym "|") (sml-indent-pipe))
507
508 (sml-indent-arg)
509 (sml-indent-default))))))
510
511 (defsubst sml-bolp ()
512 (save-excursion (skip-chars-backward " \t|") (bolp)))
513
514 (defun sml-first-starter-p ()
515 "Non-nil if starter at point is immediately preceded by let/local/in/..."
516 (save-excursion
517 (let ((sym (unless (save-excursion (sml-backward-arg))
518 (sml-backward-spaces)
519 (sml-backward-sym))))
520 (if (member sym '(";" "d=")) (setq sym nil))
521 sym)))
522
523 (defun sml-indent-starter (orig-sym)
524 "Return the indentation to use for a symbol in `sml-starters-syms'.
525 Point should be just before the symbol ORIG-SYM and is not preserved."
526 (let ((sym (unless (save-excursion (sml-backward-arg))
527 (sml-backward-spaces)
528 (sml-backward-sym))))
529 (if (member sym '(";" "d=")) (setq sym nil))
530 (if sym (sml-get-sym-indent sym)
531 ;; FIXME: this can take a *long* time !!
532 (setq sym (sml-old-find-matching-starter sml-starters-syms))
533 (if (or (sml-first-starter-p)
534 ;; Don't align with `and' because it might be specially indented.
535 (and (or (equal orig-sym "and") (not (equal sym "and")))
536 (sml-bolp)))
537 (+ (current-column)
538 (if (and sml-rightalign-and (equal orig-sym "and"))
539 (- (length sym) 3) 0))
540 (sml-indent-starter orig-sym)))))
541
542 (defun sml-indent-relative (sym data)
543 (save-excursion
544 (sml-forward-sym) (sml-backward-sexp nil)
545 (unless (second data) (sml-backward-spaces) (sml-backward-sym))
546 (+ (or (cdr (assoc sym sml-symbol-indent)) 0)
547 (sml-delegated-indent))))
548
549 (defun sml-indent-pipe ()
550 (let ((sym (sml-old-find-matching-starter sml-pipeheads
551 (sml-op-prec "|" 'back))))
552 (when sym
553 (if (string= sym "|")
554 (if (sml-bolp) (current-column) (sml-indent-pipe))
555 (let ((pipe-indent (or (cdr (assoc "|" sml-symbol-indent)) -2)))
556 (when (or (member sym '("datatype" "abstype"))
557 (and (equal sym "and")
558 (save-excursion
559 (forward-word 1)
560 (not (sml-funname-of-and)))))
561 (re-search-forward "="))
562 (sml-forward-sym)
563 (sml-forward-spaces)
564 (+ pipe-indent (current-column)))))))
565
566 (defun sml-indent-arg ()
567 (and (save-excursion (ignore-errors (sml-forward-arg)))
568 ;;(not (looking-at sml-not-arg-re))
569 ;; looks like a function or an argument
570 (sml-move-if (sml-backward-arg))
571 ;; an argument
572 (if (save-excursion (not (sml-backward-arg)))
573 ;; a first argument
574 (+ (current-column) sml-indent-args)
575 ;; not a first arg
576 (while (and (/= (current-column) (current-indentation))
577 (sml-move-if (sml-backward-arg))))
578 (unless (save-excursion (sml-backward-arg))
579 ;; all earlier args are on the same line
580 (sml-forward-arg) (sml-forward-spaces))
581 (current-column))))
582
583 (defun sml-get-indent (data sym)
584 (let (d)
585 (cond
586 ((not (listp data)) data)
587 ((setq d (member sym data)) (cadr d))
588 ((and (consp data) (not (stringp (car data)))) (car data))
589 (t sml-indent-level))))
590
591 (defun sml-dangling-sym ()
592 "Non-nil if the symbol after point is dangling.
593 The symbol can be an SML symbol or an open-paren. \"Dangling\" means that
594 it is not on its own line but is the last element on that line."
595 (save-excursion
596 (and (not (sml-bolp))
597 (< (sml-point-after (end-of-line))
598 (sml-point-after (or (sml-forward-sym) (skip-syntax-forward "("))
599 (sml-forward-spaces))))))
600
601 (defun sml-delegated-indent ()
602 (if (sml-dangling-sym)
603 (sml-indent-default 'noindent)
604 (sml-move-if (backward-word 1)
605 (looking-at sml-agglomerate-re))
606 (current-column)))
607
608 (defun sml-get-sym-indent (sym &optional style)
609 "Find the indentation for the SYM we're `looking-at'.
610 If indentation is delegated, point will move to the start of the parent.
611 Optional argument STYLE is currently ignored."
612 (assert (equal sym (save-excursion (sml-forward-sym))))
613 (save-excursion
614 (let ((delegate (and (not (equal sym "end")) (assoc sym sml-close-paren)))
615 (head-sym sym))
616 (when (and delegate (not (eval (third delegate))))
617 ;;(sml-find-match-backward sym delegate)
618 (sml-forward-sym) (sml-backward-sexp nil)
619 (setq head-sym
620 (if (second delegate)
621 (save-excursion (sml-forward-sym))
622 (sml-backward-spaces) (sml-backward-sym))))
623
624 (let ((idata (assoc head-sym sml-indent-rule)))
625 (when idata
626 ;;(if (or style (not delegate))
627 ;; normal indentation
628 (let ((indent (sml-get-indent (cdr idata) sym)))
629 (when indent (+ (sml-delegated-indent) indent)))
630 ;; delgate indentation to the parent
631 ;;(sml-forward-sym) (sml-backward-sexp nil)
632 ;;(let* ((parent-sym (save-excursion (sml-forward-sym)))
633 ;; (parent-indent (cdr (assoc parent-sym sml-indent-starters))))
634 ;; check the special rules
635 ;;(+ (sml-delegated-indent)
636 ;; (or (sml-get-indent (cdr indent-data) 1 'strict)
637 ;; (sml-get-indent (cdr parent-indent) 1 'strict)
638 ;; (sml-get-indent (cdr indent-data) 0)
639 ;; (sml-get-indent (cdr parent-indent) 0))))))))
640 )))))
641
642 (defun sml-indent-default (&optional noindent)
643 (let* ((sym-after (save-excursion (sml-forward-sym)))
644 (_ (sml-backward-spaces))
645 (sym-before (sml-backward-sym))
646 (sym-indent (and sym-before (sml-get-sym-indent sym-before)))
647 (indent-after (or (cdr (assoc sym-after sml-symbol-indent)) 0)))
648 (when (equal sym-before "end")
649 ;; I don't understand what's really happening here, but when
650 ;; it's `end' clearly, we need to do something special.
651 (forward-word 1)
652 (setq sym-before nil sym-indent nil))
653 (cond
654 (sym-indent
655 ;; the previous sym is an indentation introducer: follow the rule
656 (if noindent
657 ;;(current-column)
658 sym-indent
659 (+ sym-indent indent-after)))
660 ;; If we're just after a hanging open paren.
661 ((and (eq (char-syntax (preceding-char)) ?\()
662 (save-excursion (backward-char) (sml-dangling-sym)))
663 (backward-char)
664 (sml-indent-default))
665 (t
666 ;; default-default
667 (let* ((prec-after (sml-op-prec sym-after 'back))
668 (prec (or (sml-op-prec sym-before 'back) prec-after 100)))
669 ;; go back until you hit a symbol that has a lower prec than the
670 ;; "current one", or until you backed over a sym that has the same prec
671 ;; but is at the beginning of a line.
672 (while (and (not (sml-bolp))
673 (while (sml-move-if (sml-backward-sexp (1- prec))))
674 (not (sml-bolp)))
675 (while (sml-move-if (sml-backward-sexp prec))))
676 (if noindent
677 ;; the `noindent' case does back over an introductory symbol
678 ;; such as `fun', ...
679 (progn
680 (sml-move-if
681 (sml-backward-spaces)
682 (member (sml-backward-sym) sml-starters-syms))
683 (current-column))
684 ;; Use `indent-after' for cases such as when , or ; should be
685 ;; outdented so that their following terms are aligned.
686 (+ (if (progn
687 (if (equal sym-after ";")
688 (sml-move-if
689 (sml-backward-spaces)
690 (member (sml-backward-sym) sml-starters-syms)))
691 (and sym-after (not (looking-at sym-after))))
692 indent-after 0)
693 (current-column))))))))
694
695
696 ;; maybe `|' should be set to word-syntax in our temp syntax table ?
697 (defun sml-current-indentation ()
698 (save-excursion
699 (beginning-of-line)
700 (skip-chars-forward " \t|")
701 (current-column)))
702
703
704 (defun sml-old-find-matching-starter (syms &optional prec)
705 (let (sym)
706 (ignore-errors
707 (while
708 (progn (sml-backward-sexp prec)
709 (setq sym (save-excursion (sml-forward-sym)))
710 (not (or (member sym syms) (bobp)))))
711 (if (member sym syms) sym))))
712
713 (defun sml-old-skip-siblings ()
714 (while (and (not (bobp)) (sml-backward-arg))
715 (sml-old-find-matching-starter sml-starters-syms))
716 (when (looking-at "in\\>\\|local\\>")
717 ;; Skip over `local...in' and continue.
718 (forward-word 1)
719 (sml-backward-sexp nil)
720 (sml-old-skip-siblings)))
721
722 (provide 'sml-oldindent)
723
724 ;;; sml-oldindent.el ends here