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

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

[nongnu] elpa/zig-mode 3778fb5 030/104: Make indentation more nuanced (a


From: ELPA Syncer
Subject: [nongnu] elpa/zig-mode 3778fb5 030/104: Make indentation more nuanced (and add more tests for it)
Date: Sun, 29 Aug 2021 11:36:57 -0400 (EDT)

branch: elpa/zig-mode
commit 3778fb55ca675f1eaa5cc85f941ef952a2daa5f4
Author: Matthew D. Steele <mdsteele@alum.mit.edu>
Commit: Matthew D. Steele <mdsteele@alum.mit.edu>

    Make indentation more nuanced (and add more tests for it)
---
 README.md   | 18 ++++++++++-----
 tests.el    | 56 ++++++++++++++++++++++++++++++++++++++++++++++
 zig-mode.el | 74 +++++++++++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 124 insertions(+), 24 deletions(-)

diff --git a/README.md b/README.md
index be2ab54..28b851c 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,22 @@
 # zig-mode
-Syntax highlighting for the [Zig programming language](http://ziglang.org) in 
Emacs.
+
+Syntax highlighting and automatic indentation for the
+[Zig programming language](http://ziglang.org) in Emacs.  Requires Emacs 24 or
+later.
 
 ## Installation
-Simply install the `zig-mode` package via 
[MELPA](https://melpa.org/#/getting-started).
+
+[![MELPA](https://melpa.org/packages/zig-mode-badge.svg)](https://melpa.org/#/zig-mode)
+
+Simply install the `zig-mode` package via
+[MELPA](https://melpa.org/#/getting-started).
 
 Alternatively, you can `git clone` the `zig-mode` repository somewhere
 (e.g. under your `~/.emacs.d/`), then add the following to your `.emacs` file:
 
 ```elisp
-(add-to-list 'load-path "~/path/to/your/zig-mode/")
-(autoload 'zig-mode "zig-mode" nil t)
-(add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode))
+(unless (version< emacs-version "24")
+  (add-to-list 'load-path "~/path/to/your/zig-mode/")
+  (autoload 'zig-mode "zig-mode" nil t)
+  (add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)))
 ```
diff --git a/tests.el b/tests.el
index f5f7fb2..304103e 100644
--- a/tests.el
+++ b/tests.el
@@ -103,6 +103,29 @@ const python =
 ;;===========================================================================;;
 ;; Indentation tests
 
+(defun zig-test-indent-line (line-number original expected-line)
+  (with-temp-buffer
+    (zig-mode)
+    (insert original)
+    (goto-line line-number)
+    (indent-for-tab-command)
+    (let* ((current-line (thing-at-point 'line t))
+           (stripped-line (replace-regexp-in-string "\n\\'" "" current-line)))
+      (should (equal expected-line stripped-line)))))
+
+(ert-deftest test-indent-from-current-block ()
+  (zig-test-indent-line
+   6
+   "
+{
+  // Normally, zig-mode indents to 4, but suppose
+  // someone indented this part to 2 for some reason.
+  {
+    // This line should get indented to 6, not 8.
+  }
+}"
+   "      // This line should get indented to 6, not 8."))
+
 (defun zig-test-indent-region (original expected)
   (with-temp-buffer
     (zig-mode)
@@ -231,4 +254,37 @@ const msg = []u8{'h', 'e', 'l', 'l', 'o',
 const msg = []u8{'h', 'e', 'l', 'l', 'o',
                  'w', 'o', 'r', 'l', 'd'};"))
 
+(ert-deftest test-indent-paren-block ()
+  (zig-test-indent-region
+   "
+const foo = (
+some_very_long + expression_that_is * set_off_in_parens
+);"
+   "
+const foo = (
+    some_very_long + expression_that_is * set_off_in_parens
+);"))
+
+(ert-deftest test-indent-double-paren-block ()
+  (zig-test-indent-region
+   "
+const foo = ((
+this_expression_is + set_off_in_double_parens * for_some_reason
+));"
+   "
+const foo = ((
+    this_expression_is + set_off_in_double_parens * for_some_reason
+));"))
+
+(ert-deftest test-indent-with-comment-after-open-brace ()
+  (zig-test-indent-region
+   "
+if (false) { // This comment shouldn't mess anything up.
+launchTheMissiles();
+}"
+   "
+if (false) { // This comment shouldn't mess anything up.
+    launchTheMissiles();
+}"))
+
 ;;===========================================================================;;
diff --git a/zig-mode.el b/zig-mode.el
index 2a3a737..f78080a 100644
--- a/zig-mode.el
+++ b/zig-mode.el
@@ -1,6 +1,6 @@
 ;;; zig-mode.el --- A major mode for the Zig programming language -*- 
lexical-binding: t -*-
 
-;; Version: 0.0.7
+;; Version: 0.0.8
 ;; Author: Andrea Orru <andreaorru1991@gmail.com>, Andrew Kelley 
<superjoe30@gmail.com>
 ;; Keywords: zig, languages
 ;; Package-Requires: ((emacs "24"))
@@ -110,6 +110,9 @@
     ;; Other constants
     "null" "undefined" "this"))
 
+(defconst zig-electric-indent-chars
+  '( ?\; ?, ?) ?] ?} ))
+
 (defgroup zig-mode nil
   "Support for Zig code."
   :link '(url-link "https://ziglang.org/";)
@@ -151,7 +154,6 @@
              ("fn"    . font-lock-function-name-face)))))
 
 (defun zig-paren-nesting-level () (nth 0 (syntax-ppss)))
-(defun zig-prev-open-paren-pos () (car (last (nth 9 (syntax-ppss)))))
 (defun zig-currently-in-str () (nth 3 (syntax-ppss)))
 (defun zig-start-of-current-str-or-comment () (nth 8 (syntax-ppss)))
 
@@ -167,27 +169,57 @@
 
 (defun zig-mode-indent-line ()
   (interactive)
+  ;; First, calculate the column that this line should be indented to.
   (let ((indent-col
          (save-excursion
            (back-to-indentation)
-           (let ((paren-level
-                  (let ((level (zig-paren-nesting-level)))
-                    (if (looking-at "[]})]") (1- level) level))))
-             (+ (if (<= paren-level 0)
-                    0
-                  (or (save-excursion
-                        (goto-char (1+ (zig-prev-open-paren-pos)))
-                        (and (not (looking-at "\n"))
-                             (current-column)))
-                      (* zig-indent-offset paren-level)))
-                (if (and
-                     (not (looking-at ";"))
+           (let* (;; paren-level: How many sets of parens (or other delimiters)
+                  ;;   we're within, except that if this line closes the
+                  ;;   innermost set(s) (e.g. the line is just "}"), then we
+                  ;;   don't count those set(s).
+                  (paren-level
+                   (save-excursion
+                     (while (looking-at "[]})]") (forward-char))
+                     (zig-paren-nesting-level)))
+                  ;; prev-block-indent-col: If we're within delimiters, this is
+                  ;; the column to which the start of that block is indented
+                  ;; (if we're not, this is just zero).
+                  (prev-block-indent-col
+                   (if (<= paren-level 0) 0
                      (save-excursion
-                       (zig-skip-backwards-past-whitespace-and-comments)
-                       (when (> (point) 1)
-                         (backward-char)
-                         (not (looking-at "[,;([{}]")))))
-                     zig-indent-offset 0))))))
+                       (while (>= (zig-paren-nesting-level) paren-level)
+                         (backward-up-list)
+                         (back-to-indentation))
+                       (current-column))))
+                  ;; base-indent-col: The column to which a complete expression
+                  ;;   on this line should be indented.
+                  (base-indent-col
+                   (if (<= paren-level 0)
+                       prev-block-indent-col
+                     (or (save-excursion
+                           (backward-up-list)
+                           (forward-char)
+                           (and (not (looking-at " *\\(//[^\n]*\\)?\n"))
+                                (current-column)))
+                         (+ prev-block-indent-col zig-indent-offset))))
+                  ;; is-expr-continutation: True if this line continues an
+                  ;; expression from the previous line, false otherwise.
+                  (is-expr-continutation
+                   (and
+                    (not (looking-at "[]});]"))
+                    (save-excursion
+                      (zig-skip-backwards-past-whitespace-and-comments)
+                      (when (> (point) 1)
+                        (backward-char)
+                        (not (looking-at "[,;([{}]")))))))
+             ;; Now we can calculate indent-col:
+             (if is-expr-continutation
+                 (+ base-indent-col zig-indent-offset)
+               base-indent-col)))))
+    ;; If point is within the indentation whitespace, move it to the end of the
+    ;; new indentation whitespace (which is what the indent-line-to function
+    ;; always does).  Otherwise, we don't want point to move, so we use a
+    ;; save-excursion.
     (if (<= (current-column) (current-indentation))
         (indent-line-to indent-col)
       (save-excursion (indent-line-to indent-col)))))
@@ -256,6 +288,10 @@
   "A major mode for the Zig programming language."
   (setq-local comment-start "// ")
   (setq-local comment-end "")
+  (setq-local electric-indent-chars
+              (append zig-electric-indent-chars
+                      (and (boundp 'electric-indent-chars)
+                           electric-indent-chars)))
   (setq-local indent-line-function 'zig-mode-indent-line)
   (setq-local indent-tabs-mode nil)  ; Zig forbids tab characters.
   (setq-local syntax-propertize-function 'zig-syntax-propertize)



reply via email to

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