aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2010-11-26 16:33:21 -0500
committerStefan Monnier2010-11-26 16:33:21 -0500
commit09ffa822f8c0ff82d7a277d1bc673cc0831010b6 (patch)
tree0840bfa1c9abeba2a86b88a32e6ecb2bb767781c
parentafde451abef73d7b4b21af427c48621dedc60f4b (diff)
downloademacs-09ffa822f8c0ff82d7a277d1bc673cc0831010b6.tar.gz
emacs-09ffa822f8c0ff82d7a277d1bc673cc0831010b6.zip
* emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
of :smie-open/close-alist. (smie-next-sexp): Make it accept a "start token" as argument. (smie-indent-keyword): Be careful not to misidentify tokens that span more than one line, as empty lines. Add argument `token'.
-rw-r--r--lisp/ChangeLog8
-rw-r--r--lisp/emacs-lisp/smie.el120
2 files changed, 74 insertions, 54 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 1b35c13377c..3ac8fd7a270 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,11 @@
12010-11-26 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
4 of :smie-open/close-alist.
5 (smie-next-sexp): Make it accept a "start token" as argument.
6 (smie-indent-keyword): Be careful not to misidentify tokens that span
7 more than one line, as empty lines. Add argument `token'.
8
12010-11-26 Kenichi Handa <handa@m17n.org> 92010-11-26 Kenichi Handa <handa@m17n.org>
2 10
3 * mail/rmailmm.el (rmail-mime-insert-multipart): For unsupported 11 * mail/rmailmm.el (rmail-mime-insert-multipart): For unsupported
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index 179e0a9f094..a7021b3cf7b 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -76,8 +76,6 @@
76 76
77;; TODO & BUGS: 77;; TODO & BUGS:
78;; 78;;
79;; - FIXME: I think the behavior on empty lines is wrong. It shouldn't
80;; look at the next token on subsequent lines.
81;; - Using the structural information SMIE gives us, it should be possible to 79;; - Using the structural information SMIE gives us, it should be possible to
82;; implement a `smie-align' command that would automatically figure out what 80;; implement a `smie-align' command that would automatically figure out what
83;; there is to align and how to do it (something like: align the token of 81;; there is to align and how to do it (something like: align the token of
@@ -470,7 +468,7 @@ PREC2 is a table as returned by `smie-precs->prec2' or
470 (to (cdar eqs))) 468 (to (cdar eqs)))
471 (setq eqs (cdr eqs)) 469 (setq eqs (cdr eqs))
472 (if (eq to from) 470 (if (eq to from)
473 nil ;Nothing to do. 471 nil ;Nothing to do.
474 (dolist (other-eq eqs) 472 (dolist (other-eq eqs)
475 (if (eq from (cdr other-eq)) (setcdr other-eq to)) 473 (if (eq from (cdr other-eq)) (setcdr other-eq to))
476 (when (eq from (car other-eq)) 474 (when (eq from (car other-eq))
@@ -523,24 +521,23 @@ PREC2 is a table as returned by `smie-precs->prec2' or
523 (setcar (car eq) (cadr eq)) 521 (setcar (car eq) (cadr eq))
524 ;; (smie-check-grammar table prec2 'step2) 522 ;; (smie-check-grammar table prec2 'step2)
525 ) 523 )
526 ;; Finally, fill in the remaining vars (which only appeared on the 524 ;; Finally, fill in the remaining vars (which did not appear on the
527 ;; right side of the < constraints). 525 ;; left side of any < constraint).
528 (let ((classification-table (gethash :smie-open/close-alist prec2))) 526 (dolist (x table)
529 (dolist (x table) 527 (unless (nth 1 x)
530 ;; When both sides are nil, it means this operator binds very 528 (setf (nth 1 x) i)
531 ;; very tight, but it's still just an operator, so we give it 529 (incf i)) ;See other (incf i) above.
532 ;; the highest precedence. 530 (unless (nth 2 x)
533 ;; OTOH if only one side is nil, it usually means it's like an 531 (setf (nth 2 x) i)
534 ;; open-paren, which is very important for indentation purposes, 532 (incf i)))) ;See other (incf i) above.
535 ;; so we keep it nil if so, to make it easier to recognize. 533 ;; Mark closers and openers.
536 (unless (or (nth 1 x) 534 (dolist (x (gethash :smie-open/close-alist prec2))
537 (eq 'opener (cdr (assoc (car x) classification-table)))) 535 (let* ((token (car x))
538 (setf (nth 1 x) i) 536 (cons (case (cdr x)
539 (incf i)) ;See other (incf i) above. 537 (closer (cddr (assoc token table)))
540 (unless (or (nth 2 x) 538 (opener (cdr (assoc token table))))))
541 (eq 'closer (cdr (assoc (car x) classification-table)))) 539 (assert (numberp (car cons)))
542 (setf (nth 2 x) i) 540 (setf (car cons) (list (car cons)))))
543 (incf i))))) ;See other (incf i) above.
544 (let ((ca (gethash :smie-closer-alist prec2))) 541 (let ((ca (gethash :smie-closer-alist prec2)))
545 (when ca (push (cons :smie-closer-alist ca) table))) 542 (when ca (push (cons :smie-closer-alist ca) table)))
546 ;; (smie-check-grammar table prec2 'step3) 543 ;; (smie-check-grammar table prec2 'step3)
@@ -611,6 +608,8 @@ OP-FORW is the accessor to the forward level of the level data.
611OP-BACK is the accessor to the backward level of the level data. 608OP-BACK is the accessor to the backward level of the level data.
612HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the 609HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
613first token we see is an operator, skip over its left-hand-side argument. 610first token we see is an operator, skip over its left-hand-side argument.
611HALFSEXP can also be a token, in which case it means to parse as if
612we had just successfully passed this token.
614Possible return values: 613Possible return values:
615 (FORW-LEVEL POS TOKEN): we couldn't skip TOKEN because its back-level 614 (FORW-LEVEL POS TOKEN): we couldn't skip TOKEN because its back-level
616 is too high. FORW-LEVEL is the forw-level of TOKEN, 615 is too high. FORW-LEVEL is the forw-level of TOKEN,
@@ -619,7 +618,10 @@ Possible return values:
619 (nil POS TOKEN): we skipped over a paren-like pair. 618 (nil POS TOKEN): we skipped over a paren-like pair.
620 nil: we skipped over an identifier, matched parentheses, ..." 619 nil: we skipped over an identifier, matched parentheses, ..."
621 (catch 'return 620 (catch 'return
622 (let ((levels ())) 621 (let ((levels
622 (if (stringp halfsexp)
623 (prog1 (list (cdr (assoc halfsexp smie-grammar)))
624 (setq halfsexp nil)))))
623 (while 625 (while
624 (let* ((pos (point)) 626 (let* ((pos (point))
625 (token (funcall next-token)) 627 (token (funcall next-token))
@@ -697,6 +699,8 @@ Possible return values:
697 "Skip over one sexp. 699 "Skip over one sexp.
698HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the 700HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
699first token we see is an operator, skip over its left-hand-side argument. 701first token we see is an operator, skip over its left-hand-side argument.
702HALFSEXP can also be a token, in which case we should skip the text
703assuming it is the left-hand-side argument of that token.
700Possible return values: 704Possible return values:
701 (LEFT-LEVEL POS TOKEN): we couldn't skip TOKEN because its right-level 705 (LEFT-LEVEL POS TOKEN): we couldn't skip TOKEN because its right-level
702 is too high. LEFT-LEVEL is the left-level of TOKEN, 706 is too high. LEFT-LEVEL is the left-level of TOKEN,
@@ -714,7 +718,9 @@ Possible return values:
714(defun smie-forward-sexp (&optional halfsexp) 718(defun smie-forward-sexp (&optional halfsexp)
715 "Skip over one sexp. 719 "Skip over one sexp.
716HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the 720HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
717first token we see is an operator, skip over its left-hand-side argument. 721first token we see is an operator, skip over its right-hand-side argument.
722HALFSEXP can also be a token, in which case we should skip the text
723assuming it is the right-hand-side argument of that token.
718Possible return values: 724Possible return values:
719 (RIGHT-LEVEL POS TOKEN): we couldn't skip TOKEN because its left-level 725 (RIGHT-LEVEL POS TOKEN): we couldn't skip TOKEN because its left-level
720 is too high. RIGHT-LEVEL is the right-level of TOKEN, 726 is too high. RIGHT-LEVEL is the right-level of TOKEN,
@@ -791,7 +797,7 @@ Possible return values:
791 (push (car other) found)))))) 797 (push (car other) found))))))
792 (cond 798 (cond
793 ((null found) (error "No known closer for opener %s" open)) 799 ((null found) (error "No known closer for opener %s" open))
794 ;; FIXME: what should we do if there are various closers? 800 ;; What should we do if there are various closers?
795 (t (car found)))))))))) 801 (t (car found))))))))))
796 (unless (save-excursion (skip-chars-backward " \t") (bolp)) 802 (unless (save-excursion (skip-chars-backward " \t") (bolp))
797 (newline)) 803 (newline))
@@ -1094,9 +1100,6 @@ Only meaningful when called from within `smie-rules-function'."
1094 ;; line, in which case we want to align it with its enclosing parent. 1100 ;; line, in which case we want to align it with its enclosing parent.
1095 (cond 1101 (cond
1096 ((and (eq method :before) (smie-rule-bolp) (not (smie-rule-sibling-p))) 1102 ((and (eq method :before) (smie-rule-bolp) (not (smie-rule-sibling-p)))
1097 ;; FIXME: Rather than consult the number of spaces, we could *set* the
1098 ;; number of spaces so as to align the separator with the close-paren
1099 ;; while aligning the content with the rest.
1100 (let ((parent-col (cdr (smie-rule-parent))) 1103 (let ((parent-col (cdr (smie-rule-parent)))
1101 (parent-pos-col ;FIXME: we knew this when computing smie--parent. 1104 (parent-pos-col ;FIXME: we knew this when computing smie--parent.
1102 (save-excursion 1105 (save-excursion
@@ -1225,39 +1228,48 @@ in order to figure out the indentation of some other (further down) point."
1225 (smie-indent-virtual)) ;:not-hanging 1228 (smie-indent-virtual)) ;:not-hanging
1226 (scan-error nil))))) 1229 (scan-error nil)))))
1227 1230
1228(defun smie-indent-keyword () 1231(defun smie-indent-keyword (&optional token)
1229 ;; Align closing token with the corresponding opening one. 1232 "Indent point based on the token that follows it immediately.
1230 ;; (e.g. "of" with "case", or "in" with "let"). 1233If TOKEN is non-nil, assume that that is the token that follows point.
1234Returns either a column number or nil if it considers that indentation
1235should not be computed on the basis of the following token."
1231 (save-excursion 1236 (save-excursion
1232 (let* ((pos (point)) 1237 (let* ((pos (point))
1233 (toklevels (smie-indent-forward-token)) 1238 (toklevels
1234 (token (pop toklevels))) 1239 (if token
1240 (assoc token smie-grammar)
1241 (let* ((res (smie-indent-forward-token)))
1242 ;; Ignore tokens on subsequent lines.
1243 (if (and (< pos (line-beginning-position))
1244 ;; Make sure `token' also *starts* on another line.
1245 (save-excursion
1246 (smie-indent-backward-token)
1247 (< pos (line-beginning-position))))
1248 nil
1249 (goto-char pos)
1250 res)))))
1251 (setq token (pop toklevels))
1235 (cond 1252 (cond
1236 ((< pos (line-beginning-position)) 1253 ((null (cdr toklevels)) nil) ;Not a keyword.
1237 ;; The token we just read is actually not on the line where we started.
1238 nil)
1239 ((not (numberp (car toklevels))) 1254 ((not (numberp (car toklevels)))
1240 (save-excursion 1255 ;; Different cases:
1241 (goto-char pos) 1256 ;; - smie-indent--bolp: "indent according to others".
1242 ;; Different cases: 1257 ;; - common hanging: "indent according to others".
1243 ;; - smie-indent--bolp: "indent according to others". 1258 ;; - SML-let hanging: "indent like parent".
1244 ;; - common hanging: "indent according to others". 1259 ;; - if-after-else: "indent-like parent".
1245 ;; - SML-let hanging: "indent like parent". 1260 ;; - middle-of-line: "trust current position".
1246 ;; - if-after-else: "indent-like parent". 1261 (cond
1247 ;; - middle-of-line: "trust current position". 1262 ((smie-indent--rule :before token))
1248 (cond 1263 ((smie-indent--bolp) ;I.e. non-virtual indent.
1249 ((null (cdr toklevels)) nil) ;Not a keyword. 1264 ;; For an open-paren-like thingy at BOL, always indent only
1250 ((smie-indent--rule :before token)) 1265 ;; based on other rules (typically smie-indent-after-keyword).
1251 ((smie-indent--bolp) ;I.e. non-virtual indent. 1266 nil)
1252 ;; For an open-paren-like thingy at BOL, always indent only 1267 (t
1253 ;; based on other rules (typically smie-indent-after-keyword). 1268 ;; By default use point unless we're hanging.
1254 nil) 1269 (unless (smie-indent--hanging-p) (current-column)))))
1255 (t
1256 ;; By default use point unless we're hanging.
1257 (unless (smie-indent--hanging-p) (current-column))))))
1258 (t 1270 (t
1259 ;; FIXME: This still looks too much like black magic!! 1271 ;; FIXME: This still looks too much like black magic!!
1260 (let* ((parent (smie-backward-sexp 'halfsexp))) 1272 (let* ((parent (smie-backward-sexp token)))
1261 ;; Different behaviors: 1273 ;; Different behaviors:
1262 ;; - align with parent. 1274 ;; - align with parent.
1263 ;; - parent + offset. 1275 ;; - parent + offset.