comparison lisp/emacs-lisp/smie.el @ 108897:68586a267c40

* lisp/emacs-lisp/smie.el (smie-indent-offset-rule): Rename from smie-indent-offset-after. Add :prev case. Make a bit more generic. (smie-indent-virtual): Remove `virtual' arg. Update callers. (smie-indent-keyword): Add handling of open-paren keywords. (smie-indent-comment-continue): Don't assume comment-continue.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Mon, 07 Jun 2010 15:37:50 -0400
parents ca3bfaa18e56
children c7e85ff4bca6
comparison
equal deleted inserted replaced
108896:4a42850741ad 108897:68586a267c40
498 ;; structure Foo = 498 ;; structure Foo =
499 ;; struct ... end 499 ;; struct ... end
500 ;; I.e. the indentation after "=" depends on the parent ("structure") 500 ;; I.e. the indentation after "=" depends on the parent ("structure")
501 ;; as well as on the following token ("struct"). 501 ;; as well as on the following token ("struct").
502 "Rules of the following form. 502 "Rules of the following form.
503 \((:before . TOK) . OFFSET-RULES) how to indent TOK itself.
503 \(TOK . OFFSET-RULES) how to indent right after TOK. 504 \(TOK . OFFSET-RULES) how to indent right after TOK.
504 \((T1 . T2) . OFFSET) how to indent token T2 w.r.t T1. 505 \((T1 . T2) . OFFSET) how to indent token T2 w.r.t T1.
505 \((t . TOK) . OFFSET) how to indent TOK with respect to its parent. 506 \((t . TOK) . OFFSET) how to indent TOK with respect to its parent.
506 \(list-intro . TOKENS) declare TOKENS as being followed by what may look like 507 \(list-intro . TOKENS) declare TOKENS as being followed by what may look like
507 a funcall but is just a sequence of expressions. 508 a funcall but is just a sequence of expressions.
508 \(t . OFFSET) basic indentation step. 509 \(t . OFFSET) basic indentation step.
509 \(args . OFFSET) indentation of arguments. 510 \(args . OFFSET) indentation of arguments.
510 511
511 OFFSET-RULES is list of elements which can either be an integer (the offset to 512 OFFSET-RULES is a list of elements which can each either be:
512 use), or a cons of the form 513
513 \(:hanging . OFFSET-RULES) if TOK is hanging, use OFFSET-RULES. 514 \(:hanging . OFFSET-RULES) if TOK is hanging, use OFFSET-RULES.
514 \(:parent PARENT . OFFSET-RULES) if TOK's parent is PARENT, use OFFSET-RULES. 515 \(:parent PARENT . OFFSET-RULES) if TOK's parent is PARENT, use OFFSET-RULES.
515 \(:next TOKEN . OFFSET-RULES) if TOK is followed by TOKEN, use OFFSET-RULES. 516 \(:next TOKEN . OFFSET-RULES) if TOK is followed by TOKEN, use OFFSET-RULES.
516 A nil offset defaults to `smie-indent-basic'.") 517 \(:prev TOKEN . OFFSET-RULES) if TOK is preceded by TOKEN, use OFFSET-RULES.
518 a number the offset to use.
519 `point' align with the token.
520 `parent' align with the parent.
521
522 A nil offset for indentation after a token defaults to `smie-indent-basic'.")
517 523
518 (defun smie-indent-hanging-p () 524 (defun smie-indent-hanging-p ()
519 ;; A hanging keyword is one that's at the end of a line except it's not at 525 ;; A hanging keyword is one that's at the end of a line except it's not at
520 ;; the beginning of a line. 526 ;; the beginning of a line.
521 (and (save-excursion 527 (and (save-excursion
532 (defun smie-indent-offset (elem) 538 (defun smie-indent-offset (elem)
533 (or (cdr (assq elem smie-indent-rules)) 539 (or (cdr (assq elem smie-indent-rules))
534 (cdr (assq t smie-indent-rules)) 540 (cdr (assq t smie-indent-rules))
535 smie-indent-basic)) 541 smie-indent-basic))
536 542
537 (defun smie-indent-offset-after (tokinfo after) 543 (defun smie-indent-offset-rule (tokinfo &optional after)
538 ;; Presumes we're right before the token corresponding to `tokinfo' 544 "Apply the OFFSET-RULES in TOKINFO.
539 ;; and `after' is the position that we're trying to indent. 545 Point is expected to be right in front of the token corresponding to TOKINFO.
546 If computing the indentation after the token, then AFTER is the position
547 after the token."
540 (let ((rules (cdr tokinfo)) 548 (let ((rules (cdr tokinfo))
541 parent next offset) 549 parent next prev
550 offset)
542 (while (consp rules) 551 (while (consp rules)
543 (let ((rule (pop rules))) 552 (let ((rule (pop rules)))
544 (cond 553 (cond
545 ((not (consp rule)) (setq offset rule)) 554 ((not (consp rule)) (setq offset rule))
546 ;; Using this `:hanging' is often "wrong", in that the hangingness
547 ;; of a keyword should usually not affect the indentation of the
548 ;; immediately following expression, but rather should affect the
549 ;; virtual indentation of that keyword (which in turn will affect not
550 ;; only indentation of the immediately following expression, but also
551 ;; other dependent expressions).
552 ;; But there are cases where it's useful: you may want to use it to
553 ;; make the indentation inside parentheses different depending on the
554 ;; hangingness of the open-paren, but without affecting the
555 ;; indentation of the paren-close.
556 ((eq (car rule) :hanging) 555 ((eq (car rule) :hanging)
557 (when (smie-indent-hanging-p) 556 (when (smie-indent-hanging-p)
558 (setq rules (cdr rule)))) 557 (setq rules (cdr rule))))
558 ((eq (car rule) :prev)
559 (unless prev
560 (save-excursion
561 (setq prev (smie-indent-backward-token))))
562 (when (equal (car prev) (cadr rule))
563 (setq rules (cddr rule))))
559 ((eq (car rule) :next) 564 ((eq (car rule) :next)
560 (unless next 565 (unless next
566 (unless after
567 (error "Can't use :next in :before indentation rules"))
561 (save-excursion 568 (save-excursion
562 (goto-char after) 569 (goto-char after)
563 (setq next (funcall smie-forward-token-function)))) 570 (setq next (smie-indent-forward-token))))
564 (when (equal next (cadr rule)) 571 (when (equal (car next) (cadr rule))
565 (setq rules (cddr rule)))) 572 (setq rules (cddr rule))))
566 ((eq (car rule) :parent) 573 ((eq (car rule) :parent)
567 (unless parent 574 (unless parent
568 (save-excursion 575 (save-excursion
569 (goto-char after) 576 (if after (goto-char after))
570 (setq parent (smie-backward-sexp 'halfsexp)))) 577 (setq parent (smie-backward-sexp 'halfsexp))))
571 (when (equal (nth 2 parent) (cadr rule)) 578 (when (equal (nth 2 parent) (cadr rule))
572 (setq rules (cddr rule)))) 579 (setq rules (cddr rule))))
573 (t (error "Unknown rule %s for indentation after %s" 580 (t (error "Unknown rule %s for indentation of %s"
574 rule (car tokinfo)))))) 581 rule (car tokinfo))))))
575 (or offset (smie-indent-offset t)))) 582 offset))
576 583
577 (defun smie-indent-forward-token () 584 (defun smie-indent-forward-token ()
578 "Skip token forward and return it, along with its levels." 585 "Skip token forward and return it, along with its levels."
579 (let ((tok (funcall smie-forward-token-function))) 586 (let ((tok (funcall smie-forward-token-function)))
580 (cond 587 (cond
591 ;; 4 == Open paren syntax. 598 ;; 4 == Open paren syntax.
592 ((eq 4 (syntax-class (syntax-after (1- (point))))) 599 ((eq 4 (syntax-class (syntax-after (1- (point)))))
593 (forward-char -1) 600 (forward-char -1)
594 (list (buffer-substring (point) (1+ (point))) nil 0))))) 601 (list (buffer-substring (point) (1+ (point))) nil 0)))))
595 602
596 ;; FIXME: The `virtual' arg is fundamentally wrong: the virtual indent 603 (defun smie-indent-virtual ()
597 ;; of a position should not depend on the caller, since it leads to situations 604 ;; We used to take an optional arg (with value :not-hanging) to specify that
598 ;; where two dependent indentations get indented differently. 605 ;; we should only use (smie-indent-calculate) if we're looking at a hanging
599 (defun smie-indent-virtual (virtual) 606 ;; keyword. This was a bad idea, because the virtual indent of a position
607 ;; should not depend on the caller, since it leads to situations where two
608 ;; dependent indentations get indented differently.
600 "Compute the virtual indentation to use for point. 609 "Compute the virtual indentation to use for point.
601 This is used when we're not trying to indent point but just 610 This is used when we're not trying to indent point but just
602 need to compute the column at which point should be indented 611 need to compute the column at which point should be indented
603 in order to figure out the indentation of some other (further down) point. 612 in order to figure out the indentation of some other (further down) point."
604 VIRTUAL can take two different values:
605 - :bolp: means that the current indentation of point can be trusted
606 to be good only if it follows a line break.
607 - :not-hanging: means that the current indentation of point can be
608 trusted to be good except if the following token is hanging."
609 ;; Trust pre-existing indentation on other lines. 613 ;; Trust pre-existing indentation on other lines.
610 (assert virtual) 614 (if (smie-bolp) (current-column) (smie-indent-calculate)))
611 (if (if (eq virtual :not-hanging) (not (smie-indent-hanging-p)) (smie-bolp))
612 (current-column)
613 (smie-indent-calculate)))
614 615
615 (defun smie-indent-fixindent () 616 (defun smie-indent-fixindent ()
616 ;; Obey the `fixindent' special comment. 617 ;; Obey the `fixindent' special comment.
617 (and (smie-bolp) 618 (and (smie-bolp)
618 (save-excursion 619 (save-excursion
638 (while (not (zerop (skip-syntax-forward ")"))) 639 (while (not (zerop (skip-syntax-forward ")")))
639 (skip-chars-forward " \t")) 640 (skip-chars-forward " \t"))
640 (condition-case nil 641 (condition-case nil
641 (progn 642 (progn
642 (backward-sexp 1) 643 (backward-sexp 1)
643 (smie-indent-virtual :not-hanging)) 644 (smie-indent-virtual)) ;:not-hanging
644 (scan-error nil))))) 645 (scan-error nil)))))
645 646
646 (defun smie-indent-keyword () 647 (defun smie-indent-keyword ()
647 ;; Align closing token with the corresponding opening one. 648 ;; Align closing token with the corresponding opening one.
648 ;; (e.g. "of" with "case", or "in" with "let"). 649 ;; (e.g. "of" with "case", or "in" with "let").
649 ;; FIXME: This still looks too much like black magic!!
650 ;; FIXME: Rather than a bunch of rules like (PARENT . TOKEN), we
651 ;; want a single rule for TOKEN with different cases for each PARENT.
652 (save-excursion 650 (save-excursion
653 (let* ((pos (point)) 651 (let* ((pos (point))
654 (toklevels (smie-indent-forward-token)) 652 (toklevels (smie-indent-forward-token))
655 (token (pop toklevels))) 653 (token (pop toklevels)))
656 (when (car toklevels) 654 (if (null (car toklevels))
655 ;; Different case:
656 ;; - smie-bolp: "indent according to others".
657 ;; - common hanging: "indent according to others".
658 ;; - SML-let hanging: "indent like parent".
659 ;; - if-after-else: "indent-like parent".
660 ;; - middle-of-line: "trust current position".
661 (cond
662 ((null (cdr toklevels)) nil) ;Not a keyword.
663 ((smie-bolp)
664 ;; For an open-paren-like thingy at BOL, always indent only
665 ;; based on other rules (typically smie-indent-after-keyword).
666 nil)
667 (t
668 (let* ((tokinfo (or (assoc (cons :before token) smie-indent-rules)
669 ;; By default use point unless we're hanging.
670 (cons (cons :before token)
671 '((:hanging nil) point))))
672 (after (prog1 (point) (goto-char pos)))
673 (offset (smie-indent-offset-rule tokinfo)))
674 (cond
675 ((eq offset 'point) (current-column))
676 ((eq offset 'parent)
677 (let ((parent (smie-backward-sexp 'halfsexp)))
678 (if parent (goto-char (cadr parent))))
679 (smie-indent-virtual))
680 ((eq offset nil) nil)
681 (t (error "Unhandled offset %s in %s"
682 offset (cons :before token)))))))
683
684 ;; FIXME: This still looks too much like black magic!!
685 ;; FIXME: Rather than a bunch of rules like (PARENT . TOKEN), we
686 ;; want a single rule for TOKEN with different cases for each PARENT.
657 (let ((res (smie-backward-sexp 'halfsexp)) tmp) 687 (let ((res (smie-backward-sexp 'halfsexp)) tmp)
658 (cond 688 (cond
659 ((not (or (< (point) pos) 689 ((not (or (< (point) pos)
660 (and (cadr res) (< (cadr res) pos)))) 690 (and (cadr res) (< (cadr res) pos))))
661 ;; If we didn't move at all, that means we didn't really skip 691 ;; If we didn't move at all, that means we didn't really skip
667 ;; Don't use (smie-indent-virtual :not-hanging) here, because we 697 ;; Don't use (smie-indent-virtual :not-hanging) here, because we
668 ;; want to jump back over a sequence of same-level ops such as 698 ;; want to jump back over a sequence of same-level ops such as
669 ;; a -> b -> c 699 ;; a -> b -> c
670 ;; -> d 700 ;; -> d
671 ;; So as to align with the earliest appropriate place. 701 ;; So as to align with the earliest appropriate place.
672 (smie-indent-virtual :bolp)) 702 (smie-indent-virtual))
673 ((equal token (save-excursion 703 ((equal token (save-excursion
674 (funcall smie-backward-token-function))) 704 (funcall smie-backward-token-function)))
675 ;; in cases such as "fn x => fn y => fn z =>", 705 ;; in cases such as "fn x => fn y => fn z =>",
676 ;; jump back to the very first fn. 706 ;; jump back to the very first fn.
677 ;; FIXME: should we only do that for special tokens like "=>"? 707 ;; FIXME: should we only do that for special tokens like "=>"?
678 (smie-indent-virtual :bolp)) 708 (smie-indent-virtual))
679 ((setq tmp (assoc (cons (caddr res) token) 709 ((setq tmp (assoc (cons (caddr res) token)
680 smie-indent-rules)) 710 smie-indent-rules))
681 (goto-char (cadr res)) 711 (goto-char (cadr res))
682 (+ (cdr tmp) (smie-indent-virtual :not-hanging))) 712 (+ (cdr tmp) (smie-indent-virtual))) ;:not-hanging
683 ;; FIXME: The rules ((t . TOK) . OFFSET) either indent 713 ;; FIXME: The rules ((t . TOK) . OFFSET) either indent
684 ;; relative to "before the parent" or "after the parent", 714 ;; relative to "before the parent" or "after the parent",
685 ;; depending on details of the grammar. 715 ;; depending on details of the grammar.
686 ((null (car res)) 716 ((null (car res))
687 (assert (eq (point) (cadr res))) 717 (assert (eq (point) (cadr res)))
688 (goto-char (cadr res)) 718 (goto-char (cadr res))
689 (+ (or (cdr (assoc (cons t token) smie-indent-rules)) 0) 719 (+ (or (cdr (assoc (cons t token) smie-indent-rules)) 0)
690 (smie-indent-virtual :not-hanging))) 720 (smie-indent-virtual))) ;:not-hanging
691 ((smie-bolp) 721 ((and (= (point) pos) (smie-bolp))
722 ;; Since we started at BOL, we're not computing a virtual
723 ;; indentation, and we're still at the starting point, so the
724 ;; next (default) rule can't be used since it uses `current-column'
725 ;; which would cause. indentation to depend on itself.
726 ;; We could just return nil, but OTOH that's not good enough in
727 ;; some cases. Instead, we want to combine the offset-rules for
728 ;; the current token with the offset-rules of the previous one.
692 (+ (or (cdr (assoc (cons t token) smie-indent-rules)) 0) 729 (+ (or (cdr (assoc (cons t token) smie-indent-rules)) 0)
693 ;; FIXME: This is odd. Can't we make it use 730 ;; FIXME: This is odd. Can't we make it use
694 ;; smie-indent-(calculate|virtual) somehow? 731 ;; smie-indent-(calculate|virtual) somehow?
695 (smie-indent-after-keyword))) 732 (smie-indent-after-keyword)))
696 (t 733 (t
705 (skip-chars-forward " \t\r\n") 742 (skip-chars-forward " \t\r\n")
706 (smie-indent-calculate)))) 743 (smie-indent-calculate))))
707 744
708 (defun smie-indent-comment-continue () 745 (defun smie-indent-comment-continue ()
709 ;; indentation of comment-continue lines. 746 ;; indentation of comment-continue lines.
710 (let ((continue (comment-string-strip comment-continue t t))) 747 (let ((continue (and comment-continue
748 (comment-string-strip comment-continue t t))))
711 (and (< 0 (length continue)) 749 (and (< 0 (length continue))
712 (looking-at (regexp-quote continue)) (nth 4 (syntax-ppss)) 750 (looking-at (regexp-quote continue)) (nth 4 (syntax-ppss))
713 (let ((ppss (syntax-ppss))) 751 (let ((ppss (syntax-ppss)))
714 (save-excursion 752 (save-excursion
715 (forward-line -1) 753 (forward-line -1)
731 ;; (if (and tokinfo (null toklevel)) 769 ;; (if (and tokinfo (null toklevel))
732 ;; (error "Token %S has indent rule but has no parsing info" tok)) 770 ;; (error "Token %S has indent rule but has no parsing info" tok))
733 (when toklevel 771 (when toklevel
734 (let ((offset 772 (let ((offset
735 (cond 773 (cond
736 (tokinfo (smie-indent-offset-after tokinfo pos)) 774 (tokinfo (or (smie-indent-offset-rule tokinfo pos)
775 (smie-indent-offset t)))
737 ;; The default indentation after a keyword/operator 776 ;; The default indentation after a keyword/operator
738 ;; is 0 for infix and t for prefix. 777 ;; is 0 for infix and t for prefix.
739 ;; Using the BNF syntax, we could come up with 778 ;; Using the BNF syntax, we could come up with
740 ;; better defaults, but we only have the 779 ;; better defaults, but we only have the
741 ;; precedence levels here. 780 ;; precedence levels here.
742 ((null (cadr toklevel)) (smie-indent-offset t)) 781 ((null (cadr toklevel)) (smie-indent-offset t))
743 (t 0)))) 782 (t 0))))
744 ;; For indentation after "(let" in SML-mode, we end up accumulating 783 ;; For indentation after "(let" in SML-mode, we end up accumulating
745 ;; the offset of "(" and the offset of "let", so we use `min' to try 784 ;; the offset of "(" and the offset of "let", so we use `min' to try
746 ;; and get it right either way. 785 ;; and get it right either way.
747 (+ (min (smie-indent-virtual :bolp) (current-column)) offset)))))) 786 (+ (min (smie-indent-virtual) (current-column)) offset))))))
748 787
749 (defun smie-indent-exps () 788 (defun smie-indent-exps ()
750 ;; Indentation of sequences of simple expressions without 789 ;; Indentation of sequences of simple expressions without
751 ;; intervening keywords or operators. E.g. "a b c" or "g (balbla) f". 790 ;; intervening keywords or operators. E.g. "a b c" or "g (balbla) f".
752 ;; Can be a list of expressions or a function call. 791 ;; Can be a list of expressions or a function call.
791 (current-column)) 830 (current-column))
792 (positions 831 (positions
793 ;; We're the first arg. 832 ;; We're the first arg.
794 (goto-char (car positions)) 833 (goto-char (car positions))
795 (+ (smie-indent-offset 'args) 834 (+ (smie-indent-offset 'args)
796 ;; We used to use (smie-indent-virtual :bolp), but that 835 ;; We used to use (smie-indent-virtual), but that
797 ;; doesn't seem right since it might then indent args less than 836 ;; doesn't seem right since it might then indent args less than
798 ;; the function itself. 837 ;; the function itself.
799 (current-column))))))) 838 (current-column)))))))
800 839
801 (defvar smie-indent-functions 840 (defvar smie-indent-functions