emacs-diffs
[Top][All Lists]
Advanced

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

master c44908c059: Fix Python highlighting of some assignment statements


From: Lars Ingebrigtsen
Subject: master c44908c059: Fix Python highlighting of some assignment statements
Date: Mon, 16 May 2022 09:43:05 -0400 (EDT)

branch: master
commit c44908c0593a2c3aab6468144643ccd003084afa
Author: kobarity <kobarity@gmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Fix Python highlighting of some assignment statements
    
    * lisp/progmodes/python.el (python-rx): Limit not-simple-operator
    to a single line (bug#51362).
---
 lisp/progmodes/python.el            |  18 ++--
 test/lisp/progmodes/python-tests.el | 160 ++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 9 deletions(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index cb4be10f5c..ca744b1cfd 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -394,7 +394,7 @@ This variant of `rx' supports common Python named REGEXPS."
             (open-paren        (or "{" "[" "("))
             (close-paren       (or "}" "]" ")"))
             (simple-operator   (any ?+ ?- ?/ ?& ?^ ?~ ?| ?* ?< ?> ?= ?%))
-            (not-simple-operator (not simple-operator))
+            (not-simple-operator (not (or simple-operator ?\n)))
             (operator          (or "==" ">=" "is" "not"
                                    "**" "//" "<<" ">>" "<=" "!="
                                    "+" "-" "/" "&" "^" "~" "|" "*" "<" ">"
@@ -603,15 +603,15 @@ builtins.")
 
 (defun python-font-lock-assignment-matcher (regexp)
   "Font lock matcher for assignments based on REGEXP.
-Return nil if REGEXP matched within a `paren' context (to avoid,
-e.g., default values for arguments or passing arguments by name
-being treated as assignments) or is followed by an '=' sign (to
-avoid '==' being treated as an assignment."
+Search for next occurrence if REGEXP matched within a `paren'
+context (to avoid, e.g., default values for arguments or passing
+arguments by name being treated as assignments) or is followed by
+an '=' sign (to avoid '==' being treated as an assignment."
   (lambda (limit)
-    (let ((res (re-search-forward regexp limit t)))
-      (unless (or (python-syntax-context 'paren)
-                  (equal (char-after (point)) ?=))
-        res))))
+    (cl-loop while (re-search-forward regexp limit t)
+             unless (or (python-syntax-context 'paren)
+                        (equal (char-after) ?=))
+               return t)))
 
 (defvar python-font-lock-keywords-maximum-decoration
   `((python--font-lock-f-strings)
diff --git a/test/lisp/progmodes/python-tests.el 
b/test/lisp/progmodes/python-tests.el
index 01b233cc42..98b55a5f8b 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -95,6 +95,19 @@ STRING, it is skipped so the next STRING occurrence is 
selected."
         found-point
       (and restore-point (goto-char starting-point)))))
 
+(defun python-tests-assert-faces (content faces)
+  "Assert that font faces for CONTENT are equal to FACES."
+  (python-tests-with-temp-buffer content
+    (font-lock-ensure nil nil)
+    (should (equal faces (python-tests-get-buffer-faces)))))
+
+(defun python-tests-get-buffer-faces ()
+  "Return a list of (position . face) for each face change positions."
+  (cl-loop for pos = (point-min)
+           then (next-single-property-change pos 'face)
+           while pos
+           collect (cons pos (get-text-property pos 'face))))
+
 (defun python-tests-self-insert (char-or-str)
   "Call `self-insert-command' for chars in CHAR-OR-STR."
   (let ((chars
@@ -201,6 +214,153 @@ aliqua."
     (should (string= (buffer-string) "\"\""))
     (should (null (nth 3 (syntax-ppss))))))
 
+(ert-deftest python-font-lock-assignment-statement-1 ()
+  (python-tests-assert-faces
+   "a, b, c = 1, 2, 3"
+   '((1 . font-lock-variable-name-face) (2)
+     (4 . font-lock-variable-name-face) (5)
+     (7 . font-lock-variable-name-face) (8))))
+
+(ert-deftest python-font-lock-assignment-statement-2 ()
+  (python-tests-assert-faces
+   "a, *b, c = 1, 2, 3, 4, 5"
+   '((1 . font-lock-variable-name-face) (2)
+     (5 . font-lock-variable-name-face) (6)
+     (8 . font-lock-variable-name-face) (9))))
+
+(ert-deftest python-font-lock-assignment-statement-3 ()
+  (python-tests-assert-faces
+   "[a, b] = (1, 2)"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (5 . font-lock-variable-name-face) (6))))
+
+(ert-deftest python-font-lock-assignment-statement-4 ()
+  (python-tests-assert-faces
+   "(l[1], l[2]) = (10, 11)"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (8 . font-lock-variable-name-face) (9))))
+
+(ert-deftest python-font-lock-assignment-statement-5 ()
+  (python-tests-assert-faces
+   "(a, b, c, *d) = *x, y = 5, 6, 7, 8, 9"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (5 . font-lock-variable-name-face) (6)
+     (8 . font-lock-variable-name-face) (9)
+     (12 . font-lock-variable-name-face) (13)
+     (18 . font-lock-variable-name-face) (19)
+     (21 . font-lock-variable-name-face) (22))))
+
+(ert-deftest python-font-lock-assignment-statement-6 ()
+  (python-tests-assert-faces
+   "(a,) = 'foo',"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (8 . font-lock-string-face) (13))))
+
+(ert-deftest python-font-lock-assignment-statement-7 ()
+  (python-tests-assert-faces
+   "(*a,) = ['foo', 'bar', 'baz']"
+   '((1)
+     (3 . font-lock-variable-name-face) (4)
+     (10 . font-lock-string-face) (15)
+     (17 . font-lock-string-face) (22)
+     (24 . font-lock-string-face) (29))))
+
+(ert-deftest python-font-lock-assignment-statement-8 ()
+  (python-tests-assert-faces
+   "d = D('a', ['b'], 'c')"
+   '((1 . font-lock-variable-name-face) (2)
+     (7 . font-lock-string-face) (10)
+     (13 . font-lock-string-face) (16)
+     (19 . font-lock-string-face) (22))))
+
+(ert-deftest python-font-lock-assignment-statement-9 ()
+  (python-tests-assert-faces
+   "d.x, d.y[0], *d.z = 'a', 'b', 'c', 'd', 'e'"
+   '((1)
+     (3 . font-lock-variable-name-face) (4)
+     (8 . font-lock-variable-name-face) (9)
+     (17 . font-lock-variable-name-face) (18)
+     (21 . font-lock-string-face) (24)
+     (26 . font-lock-string-face) (29)
+     (31 . font-lock-string-face) (34)
+     (36 . font-lock-string-face) (39)
+     (41 . font-lock-string-face))))
+
+(ert-deftest python-font-lock-assignment-statement-10 ()
+  (python-tests-assert-faces
+   "a: int = 5"
+   '((1 . font-lock-variable-name-face) (2)
+     (4 . font-lock-builtin-face) (7))))
+
+(ert-deftest python-font-lock-assignment-statement-11 ()
+  (python-tests-assert-faces
+   "b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo')"
+   '((1 . font-lock-variable-name-face) (2)
+     (19 . font-lock-builtin-face) (22)
+     (40 . font-lock-builtin-face) (43)
+     (46 . font-lock-builtin-face) (49)
+     (55 . font-lock-constant-face) (59)
+     (61 . font-lock-string-face) (66))))
+
+(ert-deftest python-font-lock-assignment-statement-12 ()
+  (python-tests-assert-faces
+   "c: Collection = {1, 2, 3}"
+   '((1 . font-lock-variable-name-face) (2))))
+
+(ert-deftest python-font-lock-assignment-statement-13 ()
+  (python-tests-assert-faces
+   "d: Mapping[int, str] = {1: 'bar', 2: 'baz'}"
+   '((1 . font-lock-variable-name-face) (2)
+     (12 . font-lock-builtin-face) (15)
+     (17 . font-lock-builtin-face) (20)
+     (28 . font-lock-string-face) (33)
+     (38 . font-lock-string-face) (43))))
+
+(ert-deftest python-font-lock-assignment-statement-14 ()
+  (python-tests-assert-faces
+   "(a) = 5; (b) = 6"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (11 . font-lock-variable-name-face) (12))))
+
+(ert-deftest python-font-lock-assignment-statement-15 ()
+  (python-tests-assert-faces
+   "[a] = 5,; [b] = 6,"
+   '((1)
+     (2 . font-lock-variable-name-face) (3)
+     (12 . font-lock-variable-name-face) (13))))
+
+(ert-deftest python-font-lock-assignment-statement-16 ()
+  (python-tests-assert-faces
+   "[*a] = 5, 6; [*b] = 7, 8"
+   '((1)
+     (3 . font-lock-variable-name-face) (4)
+     (16 . font-lock-variable-name-face) (17))))
+
+(ert-deftest python-font-lock-assignment-statement-17 ()
+  (python-tests-assert-faces
+   "CustomInt = int
+
+def f(x: CustomInt) -> CustomInt:
+    y = x + 1
+    ys: Sequence[CustomInt] = [y, y + 1]
+    res: CustomInt = sum(ys) + 1
+    return res
+"
+   '((1 . font-lock-variable-name-face) (10)
+     (13 . font-lock-builtin-face) (16)
+     (18 . font-lock-keyword-face) (21)
+     (22 . font-lock-function-name-face) (23)
+     (56 . font-lock-variable-name-face) (57)
+     (70 . font-lock-variable-name-face) (72)
+     (111 . font-lock-variable-name-face) (114)
+     (128 . font-lock-builtin-face) (131)
+     (144 . font-lock-keyword-face) (150))))
+
 
 ;;; Indentation
 



reply via email to

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