changeset 111603:c901fac3b428

* lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule): Use smie-indent-virtual when indenting relative to an opener. (smie-rule-separator): Use smie-rule-parent. (smie-indent-keyword): Consult rules, even for openers at bol. (smie-indent-comment-close): Try to align closer's content.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Thu, 11 Nov 2010 00:08:25 -0500
parents f44b93254721
children 149090e9b891
files lisp/ChangeLog lisp/emacs-lisp/smie.el
diffstat 2 files changed, 59 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Wed Nov 10 19:48:46 2010 -0800
+++ b/lisp/ChangeLog	Thu Nov 11 00:08:25 2010 -0500
@@ -1,3 +1,11 @@
+2010-11-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+	* emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
+	Use smie-indent-virtual when indenting relative to an opener.
+	(smie-rule-separator): Use smie-rule-parent.
+	(smie-indent-keyword): Consult rules, even for openers at bol.
+	(smie-indent-comment-close): Try to align closer's content.
+
 2010-11-11  Glenn Morris  <rgm@gnu.org>
 
 	* ls-lisp.el (ls-lisp-dired-ignore-case): Make it an obsolete alias.
--- a/lisp/emacs-lisp/smie.el	Wed Nov 10 19:48:46 2010 -0800
+++ b/lisp/emacs-lisp/smie.el	Thu Nov 11 00:08:25 2010 -0500
@@ -63,6 +63,17 @@
 ;; Since then, some of that code has been beaten into submission, but the
 ;; smie-indent-keyword is still pretty obscure.
 
+;; Conflict resolution:
+;;
+;; - One source of conflicts is when you have:
+;;     (exp ("IF" exp "ELSE" exp "END") ("CASE" cases "END"))
+;;     (cases (cases "ELSE" insts) ...)
+;;   The IF-rule implies ELSE=END and the CASE-rule implies ELSE>END.
+;;   FIXME: we could try to resolve such conflicts automatically by changing
+;;   the way BNF rules such as the IF-rule is handled.  I.e. rather than
+;;   IF=ELSE and ELSE=END, we could turn them into IF<ELSE and ELSE>END
+;;   and IF=END,
+
 ;;; Code:
 
 ;; FIXME: I think the behavior on empty lines is wrong.  It shouldn't
@@ -155,6 +166,11 @@
 
 (put 'smie-bnf->prec2 'pure t)
 (defun smie-bnf->prec2 (bnf &rest precs)
+  ;; FIXME: Add repetition operator like (repeat <separator> <elems>).
+  ;; Maybe also add (or <elem1> <elem2>...) for things like
+  ;; (exp (exp (or "+" "*" "=" ..) exp)).
+  ;; Basically, make it EBNF (except for the specification of a separator in
+  ;; the repetition).
   (let ((nts (mapcar 'car bnf))         ;Non-terminals
         (first-ops-table ())
         (last-ops-table ())
@@ -613,7 +629,7 @@
                     ;; It is the last element, let's stop here.
                     (throw 'return (list nil (point) token)))
                    ;; If the new operator is not the last in the BNF rule,
-                   ;; ans is not associative, it's one of the inner operators
+                   ;; and is not associative, it's one of the inner operators
                    ;; (like the "in" in "let .. in .. end"), so keep looking.
                    ((not (smie--associative-p toklevels))
                     (push toklevels levels))
@@ -969,8 +985,14 @@
     (goto-char (cadr (smie-indent--parent)))
     (cons 'column
           (+ (or offset 0)
-             (if (smie-indent--hanging-p)
-                 (smie-indent-virtual) (current-column))))))  
+             ;; Use smie-indent-virtual when indenting relative to an opener:
+             ;; this will also by default use current-column unless
+             ;; that opener is hanging, but will additionally consult
+             ;; rules-function, so it gives it a chance to tweak
+             ;; indentation (e.g. by forcing indentation relative to
+             ;; its own parent, as in fn a => fn b => fn c =>).
+             (if (or (null (car smie--parent)) (smie-indent--hanging-p))
+                 (smie-indent-virtual) (current-column))))))
 
 (defvar smie-rule-separator-outdent 2)
 
@@ -1030,11 +1052,7 @@
     ;; FIXME: Rather than consult the number of spaces, we could *set* the
     ;; number of spaces so as to align the separator with the close-paren
     ;; while aligning the content with the rest.
-    (let ((parent-col
-           (save-excursion
-             (goto-char (cadr smie--parent))
-             (if (smie-indent--hanging-p)
-                 (smie-indent-virtual) (current-column))))
+    (let ((parent-col (cdr (smie-rule-parent)))
           (parent-pos-col     ;FIXME: we knew this when computing smie--parent.
            (save-excursion
              (goto-char (cadr smie--parent))
@@ -1083,7 +1101,16 @@
         (+ offset
            (if (null base-pos) 0
              (goto-char base-pos)
-             (if (smie-indent--hanging-p)
+             ;; Use smie-indent-virtual when indenting relative to an opener:
+             ;; this will also by default use current-column unless
+             ;; that opener is hanging, but will additionally consult
+             ;; rules-function, so it gives it a chance to tweak indentation
+             ;; (e.g. by forcing indentation relative to its own parent, as in
+             ;; fn a => fn b => fn c =>).
+             ;; When parent==nil it doesn't matter because the only case
+             ;; where it's really used is when the base-pos is hanging anyway.
+             (if (or (and parent (null (car parent)))
+                     (smie-indent--hanging-p))
                  (smie-indent-virtual) (current-column)))))
        (t (error "Unknown indentation offset %s" offset))))))
 
@@ -1171,12 +1198,11 @@
             ;; - middle-of-line: "trust current position".
             (cond
              ((null (cdr toklevels)) nil) ;Not a keyword.
-             ((smie-indent--bolp)
+             ((smie-indent--rule :before token))
+             ((smie-indent--bolp)       ;I.e. non-virtual indent.
               ;; For an open-paren-like thingy at BOL, always indent only
               ;; based on other rules (typically smie-indent-after-keyword).
               nil)
-             ;; We're only ever here for virtual-indent.
-             ((smie-indent--rule :before token))
              (t
               ;; By default use point unless we're hanging.
               (unless (smie-indent--hanging-p) (current-column)))))
@@ -1298,10 +1324,19 @@
        comment-end-skip
        (not (looking-at " \t*$"))       ;Not just a \n comment-closer.
        (looking-at comment-end-skip)
-       (nth 4 (syntax-ppss))
-       (save-excursion
-         (goto-char (nth 8 (syntax-ppss)))
-         (current-column))))
+       (let ((end (match-string 0)))
+         (and (nth 4 (syntax-ppss))
+              (save-excursion
+                (goto-char (nth 8 (syntax-ppss)))
+                (and (looking-at comment-start-skip)
+                     (let ((start (match-string 0)))
+                       ;; Align the common substring between starter
+                       ;; and ender, if possible.
+                       (if (string-match "\\(.+\\).*\n\\(.*?\\)\\1"
+                                         (concat start "\n" end))
+                           (+ (current-column) (match-beginning 0)
+                              (- (match-beginning 2) (match-end 2)))
+                         (current-column)))))))))
 
 (defun smie-indent-comment-inside ()
   (and (nth 4 (syntax-ppss))