emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/smalltalk-mode 59a96de: * smalltalk-mode.el: Let SMIE i


From: Stefan Monnier
Subject: [elpa] externals/smalltalk-mode 59a96de: * smalltalk-mode.el: Let SMIE indent class and method definitions
Date: Mon, 15 Apr 2019 17:09:36 -0400 (EDT)

branch: externals/smalltalk-mode
commit 59a96de4beee4afea879fdeda626c8b00411a715
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    * smalltalk-mode.el: Let SMIE indent class and method definitions
    
    * indent-test.st: Add some pragmas and some ; indentation tests.
    
    (smalltalk--smie-grammar): Add `id` so smie-rules are consulted for
    ":before id".
    (smalltalk--smie-id-re): Allow . for namespaces.
    (smalltalk--smie-symbol-re): New variable.
    (smalltalk--smie-forward-token, smalltalk--smie-backward-token):
    Recognize the < and > "parentheses".
    Return "id" for plain identifiers.  Recognize symbol literals.
    Recognize "^" as well.
    (smalltalk--smie-exp-p, smalltalk--smie-begin-def): New functions.
    (smalltalk--smie-rules): Add new rules for method/class definitions
    and for `;`.
---
 indent-test.st    |   7 +++-
 smalltalk-mode.el | 122 +++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 114 insertions(+), 15 deletions(-)

diff --git a/indent-test.st b/indent-test.st
index d5ecf1a..3a3753d 100644
--- a/indent-test.st
+++ b/indent-test.st
@@ -61,11 +61,16 @@ Kernel.PackageContainer subclass: StarPackageFile [
     | name |
 
     StarPackageFile class >> on: aFile [
+        <category: ('file things')>
+        <other: (3 > 4)>
        ^self new file: aFile; yourself
     ]
 
     StarPackageFile class >> on: aFile name: aString [
-       ^self new file: aFile; name: aString; yourself
+        <category: ('file things')>
+       ^self new file: aFile;
+              name: aString;
+              yourself
     ]
 
     baseDirectoriesFor: aPackage [
diff --git a/smalltalk-mode.el b/smalltalk-mode.el
index bb0861a..4582bb2 100644
--- a/smalltalk-mode.el
+++ b/smalltalk-mode.el
@@ -219,6 +219,7 @@
     `(eval '(if (fboundp ',sym) ,exp))))
 
 (defun smalltalk--pragma-start-p (pos)
+  "Return non-nil if the `<' at point starts a pragma."
   ;; I think in practice it's not disastrous if we fail to mark some pragmas,
   ;; whereas if we mistakenly mark a binary `<' as an open-paren, this
   ;; can throw things off pretty badly, so when in doubt presume it's just
@@ -234,6 +235,7 @@
 
 
 (defun smalltalk--pragma-end-p (pos)
+  "Return non-nil if the `>' at point ends a pragma."
   (save-excursion
     (let ((ppss (syntax-ppss pos)))
       (and (nth 1 ppss)
@@ -284,7 +286,7 @@ The SMIE support is currently experimental 
work-in-progress.")
   (when (fboundp 'smie-bnf->prec2)
     (smie-prec2->grammar
      (smie-bnf->prec2
-      '((id)
+      '((id ("id"))
         (blockbody (id "|" exp)         ;Block with args
                    (exp))               ;Block without args
         (exp ("|-open" id "|" exp)      ;Local var declaration
@@ -292,6 +294,7 @@ The SMIE support is currently experimental 
work-in-progress.")
              ("^" exp)                  ;Return
              (exp "bin-sel" exp)
              (exp "kw-sel" exp)
+             (id)
              ("<" id ">")              ;Meta info like `comment' and `category'
              (exp "!" exp)             ;GNU Smalltalk extension
              (id ":=" exp)             ;Assignment
@@ -301,7 +304,17 @@ The SMIE support is currently experimental 
work-in-progress.")
         (assoc ";") (assoc "kw-sel" "bin-sel"))))))
 
 (defconst smalltalk--smie-id-re
-  (concat "\\(:\\)?" smalltalk-name-regexp "\\(:\\)?"))
+  (concat "\\(:\\)?" smalltalk-name-regexp
+          "\\(?:\\." smalltalk-name-regexp "\\)*"
+          "\\(:\\)?"))
+
+(defconst smalltalk--smie-symbol-re
+  (concat "#\\(?:" smalltalk-binsel
+          "\\|\\(?:"
+          smalltalk-name-regexp
+          "\\(?:\\(?::" smalltalk-name-regexp "\\)*:"
+          "\\|\\(?:\\." smalltalk-name-regexp "\\)*"
+          "\\)\\)\\)"))
 
 (defun smalltalk--smie-|-kind ()
   ;; FIXME: Probably too naive a heuristic.
@@ -314,11 +327,14 @@ The SMIE support is currently experimental 
work-in-progress.")
 (defun smalltalk--smie-forward-token ()
   (forward-comment (point-max))
   (cond
+   ((looking-at "\\s(\\|\\s)") "")
+   ;; Symbol literals are easy to lex when going forward.
+   ((looking-at smalltalk--smie-symbol-re) "lit-symbol")
    ((looking-at smalltalk--smie-id-re)
     (goto-char (match-end 0))
     (cond
      ((match-beginning 2) "kw-sel")
-     (t (match-string 0))))
+     (t "id")))
    ((looking-at smalltalk-binsel)
     (goto-char (match-end 0))
     (or (match-string 1) "bin-sel"))
@@ -326,7 +342,7 @@ The SMIE support is currently experimental 
work-in-progress.")
     (let ((pos (match-end 0)))
       (prog1 (smalltalk--smie-|-kind)
         (goto-char pos))))
-   ((looking-at "[;.!]")
+   ((looking-at "[;.!^]")
     (goto-char (match-end 0))
     (match-string 0))
    (t (smie-default-forward-token))))
@@ -334,32 +350,101 @@ The SMIE support is currently experimental 
work-in-progress.")
 (defun smalltalk--smie-backward-token ()
   (forward-comment (- (point)))
   (cond
+   ((looking-back "\\s(\\|\\s)" (1- (point))) "")
    ((and (eq (char-before) ?:)
          (memq (char-syntax (or (char-before (1- (point))) ?\ )) '(?w ?_)))
     (forward-char -1)
-    (skip-chars-backward smalltalk-name-chars)
-    (skip-chars-forward "0-9_")         ;Maybe we skipped too much!
-    "kw-sel")
+    (skip-chars-backward "[:alnum:]_")
+    (skip-chars-forward "0-9_.")         ;Maybe we skipped too much!
+    (if (and (eq (char-before) ?:)
+             (looking-back smalltalk--smie-symbol-re 
(line-beginning-position)))
+        (progn
+         (goto-char (match-beginning 0))
+         "lit-symbol")
+      "kw-sel"))
    ((memq (char-syntax (preceding-char)) '(?w ?_))
-    (let ((end (point)))
-      (skip-chars-backward smalltalk-name-chars)
-      (skip-chars-forward "0-9_")       ;Maybe we skipped too much!
-      (buffer-substring (point) end)))
-   ((looking-back smalltalk--smie-id-re (- (point) 2) t)
+    (skip-chars-backward "[:alnum:]_.")
+    (skip-chars-forward "0-9_.")       ;Maybe we skipped too much!
+    (if (eq (char-before) ?#)
+        (progn
+          (forward-char -1)
+          "lit-symbol")
+      "id"))
+   ((looking-back smalltalk-binsel (- (point) 2) t)
     (goto-char (match-beginning 0))
-    (or (match-string 1) "bin-sel"))
+    (if (eq (char-before) ?#)
+        (progn
+          (forward-char -1)
+          "lit-symbol")
+      (or (match-string 1) "bin-sel")))
    ((eq ?| (char-before))
     (forward-char -1)
     (smalltalk--smie-|-kind))
-   ((memql (char-before) '(?\; ?\. ?!))
+   ((memql (char-before) '(?\; ?\. ?^ ?!))
     (forward-char -1)
     (buffer-substring (point) (1+ (point))))
    (t (smie-default-backward-token))))
 
+(defun smalltalk--smie-exp-p ()
+  "Return non-nil if the thing at point is allowed to be an /expr/."
+  (save-excursion
+    (pcase (smalltalk--smie-backward-token)
+      ((or `"bin-sel" `"kw-sel" ":=" `"." `"^" `"!" "|")
+       t)
+      ((or `"|-open" `";" `"lit-symbol") nil)
+      ;;`""' means we bumped into a paren or a string.
+      (`"" (looking-back "\\s(" (1- (point))))
+      (_
+       ;; Presumably a plain `id', which is either a reference to a variable,
+       ;; or a unary selector.  In either case we can't be just an /expr/.
+       nil))))
+
+(defun smalltalk--smie-begin-def ()
+  (let ((pos nil))
+    (while (member (smalltalk--smie-backward-token)
+                   '("bin-sel" "kw-sel" "id"))
+      (setq pos (point)))
+    (goto-char pos)))
+
 (defun smalltalk--smie-rules (method arg)
   (pcase (cons method arg)
     (`(:elem . basic) smalltalk-indent-amount)
     (`(:after . "|") 0)
+    (`(:after . ">") 0)                 ;Indentation after a pragma.
+    (`(:after . ";")
+     (save-excursion
+       (forward-char 1)
+       (let ((parent (smie-backward-sexp 'halfsexp)))
+         ;; We do:
+         ;;
+        ;;     ^self new file: aFile;
+         ;;           fooselector name: aString;
+         ;;           yourself
+         ;;
+         ;; but I wonder if we shouldn't instead try to do:
+         ;;
+        ;;     ^self new file: aFile;
+         ;;               fooselector name: aString;
+         ;;                           yourself
+         (pcase (nth 2 parent)
+           (`";" nil)
+           (_ (forward-sexp 1) (forward-comment 1)
+              `(column . ,(current-column)))))))
+    ((and `(:before . ,(or `"kw-sel" `"bin-sel" `"id"))
+          (guard (and (smie-rule-bolp)
+                      (save-excursion
+                        (forward-comment (- (point)))
+                        (when (eq (char-before) ?\])
+                          (forward-sexp -1)
+                          (not (smalltalk--smie-exp-p)))))))
+     ;; Looks like a definition following another.
+     ;; FIXME: While this seems to indent class/method definitions acceptably,
+     ;; the underlying parsing of them is still wrong, as visible when
+     ;; trying to navigate with sexp movement commands :-(
+     (save-excursion
+       (forward-sexp -1)
+       (smalltalk--smie-begin-def)
+       `(column . ,(current-column))))
     (`(:before . "kw-sel")
      (let ((pos (point))
            (kw-len (and (looking-at smalltalk--smie-id-re)
@@ -380,6 +465,15 @@ The SMIE support is currently experimental 
work-in-progress.")
                (when (< (point) pos)
                  (let ((c (current-column)))
                    `(column . ,(+ c smalltalk-indent-amount)))))))))))
+    (`(:before . "[")
+     (if (smalltalk--smie-exp-p)
+         ;; Just a block.
+         nil
+       ;; We're not a block, so presumably some class/method definition.
+       ;; Find the beginning of that definition.
+       (save-excursion
+         (smalltalk--smie-begin-def)
+         `(column . ,(current-column)))))
     ))
 
 ;;;; ---[ Interactive functions ]---------------------------------------



reply via email to

[Prev in Thread] Current Thread [Next in Thread]