Subject: Properly indent Python PEP634 match/case blocks

From: Lele Gaifax <[email-masked]>
Date: Sun, 22 May 2022 11:03:22 +0200

Hi,

PEP634, introduced in Python 3.10, added two new keywords, "match"
and "case". Commit 139042eb8629e6fd49b2c3002a8fc4d1aabd174d added them to the
font-lock machinery, but missed the opportunity to configure them as
block-starter as well.

The attached patch does that, adding also two simple indentation tests.

All the best,
ciao, lele.
>From 49730d01dbf3a72c29d5c881e5b5ae1fc55c71ec Mon Sep 17 00:00:00 2001
From: Lele Gaifax <[email-masked]>
Date: Sun, 22 May 2022 10:44:31 +0200
Subject: [PATCH] Properly indent Python PEP634 match/case blocks

Python 3.10 introduced the "structural pattern matching" syntax, and
commit 139042eb8629e6fd49b2c3002a8fc4d1aabd174d told font-lock about the
new keywords. This adds them also as block-start statements, to enable
proper indentation of such blocks.

* lisp/progmodes/python.el (python-rx): Add "match" and "case" as
block-start keywords.
* test/lisp/progmodes/python-tests.el (python-indent-after-match-block,
python-indent-after-case-block): New tests to verify indentation of
"match" and "case" blocks.
---
 lisp/progmodes/python.el            |  2 ++
 test/lisp/progmodes/python-tests.el | 25 +++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 0761aaebdc..94297d4ea5 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -362,6 +362,8 @@ python-rx
   `(rx-let ((block-start       (seq symbol-start
                                     (or "def" "class" "if" "elif" "else" "try"
                                         "except" "finally" "for" "while" "with"
+                                        ;; Python 3.10+ PEP634
+                                        "match" "case"
                                         ;; Python 3.5+ PEP492
                                         (and "async" (+ space)
                                              (or "def" "for" "with")))
diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el
index ee7b66610a..a3f778bbbe 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -1516,6 +1516,31 @@ python-virt-bin
      (should (string= (buffer-substring-no-properties (point-min) (point-max))
                       expected)))))
 
+(ert-deftest python-indent-after-match-block ()
+  "Test PEP634 match."
+  (python-tests-with-temp-buffer
+   "
+match foo:
+"
+   (should (eq (car (python-indent-context)) :no-indent))
+   (should (= (python-indent-calculate-indentation) 0))
+   (goto-char (point-max))
+   (should (eq (car (python-indent-context)) :after-block-start))
+   (should (= (python-indent-calculate-indentation) 4))))
+
+(ert-deftest python-indent-after-case-block ()
+  "Test PEP634 case."
+  (python-tests-with-temp-buffer
+   "
+match foo:
+    case 1:
+"
+   (should (eq (car (python-indent-context)) :no-indent))
+   (should (= (python-indent-calculate-indentation) 0))
+   (goto-char (point-max))
+   (should (eq (car (python-indent-context)) :after-block-start))
+   (should (= (python-indent-calculate-indentation) 8))))
+
 
 ;;; Filling
 
-- 
2.36.1

-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
[email-masked]  |                 -- Fortunato Depero, 1929.