]> Cypherpunks repositories - gostls13.git/commitdiff
Update Emacs go-mode for new semicolon rule.
authorAustin Clements <aclements@csail.mit.edu>
Wed, 6 Jan 2010 00:50:36 +0000 (16:50 -0800)
committerRuss Cox <rsc@golang.org>
Wed, 6 Jan 2010 00:50:36 +0000 (16:50 -0800)
Fixes #415.

R=rsc
CC=golang-dev
https://golang.org/cl/183104

misc/emacs/go-mode.el

index 88198e3c4d45ce3da5a5be107deff5b3158abb18..f2dab59eb823e057aac083f07f3cff6c19b4dbdb 100644 (file)
     st)
   "Syntax table for Go mode.")
 
+(defvar go-mode-keywords
+  '("break"    "default"     "func"   "interface" "select"
+    "case"     "defer"       "go"     "map"       "struct"
+    "chan"     "else"        "goto"   "package"   "switch"
+    "const"    "fallthrough" "if"     "range"     "type"
+    "continue" "for"         "import" "return"    "var")
+  "All keywords in the Go language.  Used for font locking and
+some syntax analysis.")
+
 (defvar go-mode-font-lock-keywords
-  (let ((keywords '("import" "package"
-                    "var" "const" "type" "func"
-                    "struct" "interface"
-                    "chan" "map"
-                    "if" "else" "for" "switch" "select"
-                    "range" "case" "default"
-                    "return" "continue" "break" "fallthrough" "goto"
-                    "go" "defer"))
-        (builtins '("cap" "close" "closed" "len" "make" "new"
+  (let ((builtins '("cap" "close" "closed" "len" "make" "new"
                     "panic" "panicln" "print" "println"))
         (constants '("nil" "true" "false" "iota"))
         (type-name "\\s *\\(?:[*(]\\s *\\)*\\(?:\\w+\\s *\\.\\s *\\)?\\(\\w+\\)")
         )
-    `((,(regexp-opt keywords 'words) . font-lock-keyword-face)
+    `((,(regexp-opt go-mode-keywords 'words) . font-lock-keyword-face)
       (,(regexp-opt builtins 'words) . font-lock-builtin-face)
       (,(regexp-opt constants 'words) . font-lock-constant-face)
       ;; Function names in declarations
@@ -312,6 +313,37 @@ encountered the close character."
 ;; Indentation
 ;;
 
+(defvar go-mode-non-terminating-keywords-regexp
+  (let* ((kws go-mode-keywords)
+         (kws (remove "break" kws))
+         (kws (remove "continue" kws))
+         (kws (remove "fallthrough" kws))
+         (kws (remove "return" kws)))
+    (regexp-opt kws 'words))
+  "Regular expression matching all Go keywords that *do not*
+implicitly terminate a statement.")
+
+(defun go-mode-semicolon-p ()
+  "True iff point immediately follows either an explicit or
+implicit semicolon.  Point should immediately follow the last
+token on the line."
+
+  ;; #Semicolons
+  (case (char-before)
+    ((?\;) t)
+    ;; String literal
+    ((?' ?\" ?`) t)
+    ;; One of the operators and delimiters ++, --, ), ], or }
+    ((?+) (eq (char-before (1- (point))) ?+))
+    ((?-) (eq (char-before (1- (point))) ?-))
+    ((?\) ?\] ?\}) t)
+    ;; An identifier or one of the keywords break, continue,
+    ;; fallthrough, or return or a numeric literal
+    (otherwise
+     (save-excursion
+       (when (/= (skip-chars-backward "[:word:]_") 0)
+         (not (looking-at go-mode-non-terminating-keywords-regexp)))))))
+
 (defun go-mode-indentation ()
   "Compute the ideal indentation level of the current line.
 
@@ -335,25 +367,14 @@ indented one level."
         ;; Inside a multi-line string.  Don't mess with indentation.
         nil)
        (cs
-        ;; Inside a multi-line comment
+        ;; Inside a general comment
         (goto-char (car cs))
         (forward-char 1)
         (current-column))
-       ((not (go-mode-nesting))
-        ;; Top-level
-        (if (or (eolp)
-                (looking-at "\\<\\(import\\|package\\|const\\|var\\|type\\|func\\)\\>")
-                (looking-at "//\\|/\\*"))
-            0
-          ;; Continuation line
-          ;; XXX If you start typing a new continuation line, nothing
-          ;; will cause it to be indented.
-          tab-width))
        (t
-        ;; Neither top-level nor in a multi-line string or comment
+        ;; Not in a multi-line string or comment
         (let ((indent 0)
-              (inside-indenting-paren nil)
-              (current-line-closes-scope nil))
+              (inside-indenting-paren nil))
           ;; Count every enclosing brace, plus parens that follow
           ;; import, const, var, or type and indent according to
           ;; depth.  This simple rule does quite well, but also has a
@@ -377,28 +398,21 @@ indented one level."
                        (setq inside-indenting-paren t)))))
                 (setq first nil))))
 
-          (setq current-line-closes-scope
-                (case (char-after)
-                  ((?\} ?\)) t)
-                  (t nil)))
-
           ;; case, default, and labels are outdented 1 level
           (when (looking-at "\\<case\\>\\|\\<default\\>\\|\\w+\\s *:\\(\\S.\\|$\\)")
-            (decf indent tab-width)
-            ;; Lines with case, default, etc. also "close" the previous line's 
-            ;; scope, even when there is no semicolon. Don't treat them as
-            ;; continuation lines.
-            (setq current-line-closes-scope t))
+            (decf indent tab-width))
 
           ;; Continuation lines are indented 1 level
           (forward-comment (- (buffer-size)))
           (when (case (char-before)
-                  ((?\{ ?\} ?\; ?:)
-                   ;; Not a continuation line
+                  ((nil ?\{ ?:)
+                   ;; At the beginning of a block or the statement
+                   ;; following a label.
                    nil)
                   ((?\()
-                   ;; Usually a continuation line, unless this paren
-                   ;; counted towards our indentation already
+                   ;; Usually a continuation line in an expression,
+                   ;; unless this paren is part of a factored
+                   ;; declaration.
                    (not inside-indenting-paren))
                   ((?,)
                    ;; Could be inside a literal.  We're a little
@@ -411,10 +425,12 @@ indented one level."
                      (and depth
                           (not (eq (char-after (caar depth)) ?\{)))))
                   (t
-                   ;; Except when the current line closes the previous line's 
-                   ;; scope, anything else is a continuation line.
-                   (not current-line-closes-scope)))
+                   ;; We're in the middle of a block.  Did the
+                   ;; previous line end with an implicit or explicit
+                   ;; semicolon?
+                   (not (go-mode-semicolon-p))))
             (incf indent tab-width))
+
           (max indent 0)))))))
 
 (defun go-mode-indent-line ()