diff options
| author | Dario Gjorgjevski | 2020-12-21 05:40:38 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2020-12-21 05:41:07 +0100 |
| commit | b2ce94fa5eecee0afd0e6237956cfb2b02b8bb0b (patch) | |
| tree | 259b491dcc5f87cfff344e168a54d467eb2939a2 | |
| parent | 759ec257699d734de2ba733bcc204745500b9b23 (diff) | |
| download | emacs-b2ce94fa5eecee0afd0e6237956cfb2b02b8bb0b.tar.gz emacs-b2ce94fa5eecee0afd0e6237956cfb2b02b8bb0b.zip | |
Make python-mode fontify more assignment statements
* lisp/progmodes/python.el (python-font-lock-assignment-matcher): New
function to match assignment statements.
(python-rx): Add `assignment-target' and `grouped-assignment-target'.
(python-font-lock-keywords-maximum-decoration): Add new matchers
(bug#45341).
| -rw-r--r-- | lisp/progmodes/python.el | 96 |
1 files changed, 69 insertions, 27 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index d58b32f3c3c..50bb841111f 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -394,6 +394,12 @@ This variant of `rx' supports common Python named REGEXPS." | |||
| 394 | (any ?' ?\") "__main__" (any ?' ?\") | 394 | (any ?' ?\") "__main__" (any ?' ?\") |
| 395 | (* space) ?:)) | 395 | (* space) ?:)) |
| 396 | (symbol-name (seq (any letter ?_) (* (any word ?_)))) | 396 | (symbol-name (seq (any letter ?_) (* (any word ?_)))) |
| 397 | (assignment-target (seq (? ?*) | ||
| 398 | (* symbol-name ?.) symbol-name | ||
| 399 | (? ?\[ (+ (not ?\])) ?\]))) | ||
| 400 | (grouped-assignment-target (seq (? ?*) | ||
| 401 | (* symbol-name ?.) (group symbol-name) | ||
| 402 | (? ?\[ (+ (not ?\])) ?\]))) | ||
| 397 | (open-paren (or "{" "[" "(")) | 403 | (open-paren (or "{" "[" "(")) |
| 398 | (close-paren (or "}" "]" ")")) | 404 | (close-paren (or "}" "]" ")")) |
| 399 | (simple-operator (any ?+ ?- ?/ ?& ?^ ?~ ?| ?* ?< ?> ?= ?%)) | 405 | (simple-operator (any ?+ ?- ?/ ?& ?^ ?~ ?| ?* ?< ?> ?= ?%)) |
| @@ -605,6 +611,18 @@ This is the medium decoration level, including everything in | |||
| 605 | `python-font-lock-keywords-level-1', as well as keywords and | 611 | `python-font-lock-keywords-level-1', as well as keywords and |
| 606 | builtins.") | 612 | builtins.") |
| 607 | 613 | ||
| 614 | (defun python-font-lock-assignment-matcher (regexp) | ||
| 615 | "Font lock matcher for assignments based on REGEXP. | ||
| 616 | Return nil if REGEXP matched within a `paren' context (to avoid, | ||
| 617 | e.g., default values for arguments or passing arguments by name | ||
| 618 | being treated as assignments) or is followed by an '=' sign (to | ||
| 619 | avoid '==' being treated as an assignment." | ||
| 620 | (lambda (limit) | ||
| 621 | (let ((res (re-search-forward regexp limit t))) | ||
| 622 | (unless (or (python-syntax-context 'paren) | ||
| 623 | (equal (char-after (point)) ?=)) | ||
| 624 | res)))) | ||
| 625 | |||
| 608 | (defvar python-font-lock-keywords-maximum-decoration | 626 | (defvar python-font-lock-keywords-maximum-decoration |
| 609 | `((python--font-lock-f-strings) | 627 | `((python--font-lock-f-strings) |
| 610 | ,@python-font-lock-keywords-level-2 | 628 | ,@python-font-lock-keywords-level-2 |
| @@ -652,33 +670,57 @@ builtins.") | |||
| 652 | ) | 670 | ) |
| 653 | symbol-end) | 671 | symbol-end) |
| 654 | . font-lock-type-face) | 672 | . font-lock-type-face) |
| 655 | ;; assignments | 673 | ;; multiple assignment |
| 656 | ;; support for a = b = c = 5 | 674 | ;; (note that type hints are not allowed for multiple assignments) |
| 657 | (,(lambda (limit) | 675 | ;; a, b, c = 1, 2, 3 |
| 658 | (let ((re (python-rx (group symbol-name) | 676 | ;; a, *b, c = 1, 2, 3, 4, 5 |
| 659 | ;; subscript, like "[5]" | 677 | ;; [a, b] = (1, 2) |
| 660 | (? ?\[ (+ (not ?\])) ?\]) (* space) | 678 | ;; (l[1], l[2]) = (10, 11) |
| 661 | ;; type hint, like ": int" or ": Mapping[int, str]" | 679 | ;; (a, b, c, *d) = *x, y = 5, 6, 7, 8, 9 |
| 662 | (? ?: (* space) (+ not-simple-operator) (* space)) | 680 | ;; (a,) = 'foo' |
| 663 | assignment-operator)) | 681 | ;; (*a,) = ['foo', 'bar', 'baz'] |
| 664 | (res nil)) | 682 | ;; d.x, d.y[0], *d.z = 'a', 'b', 'c', 'd', 'e' |
| 665 | (while (and (setq res (re-search-forward re limit t)) | 683 | ;; and variants thereof |
| 666 | (or (python-syntax-context 'paren) | 684 | ;; the cases |
| 667 | (equal (char-after (point)) ?=)))) | 685 | ;; (a) = 5 |
| 668 | res)) | 686 | ;; [a] = 5 |
| 669 | (1 font-lock-variable-name-face nil nil)) | 687 | ;; [*a] = 5, 6 |
| 670 | ;; support for a, b, c = (1, 2, 3) | 688 | ;; are handled separately below |
| 671 | (,(lambda (limit) | 689 | (,(python-font-lock-assignment-matcher |
| 672 | (let ((re (python-rx (group symbol-name) (* space) | 690 | (python-rx (? (or "[" "(") (* space)) |
| 673 | (* ?, (* space) symbol-name (* space)) | 691 | grouped-assignment-target (* space) ?, (* space) |
| 674 | ?, (* space) symbol-name (* space) | 692 | (* assignment-target (* space) ?, (* space)) |
| 675 | assignment-operator)) | 693 | (? assignment-target (* space)) |
| 676 | (res nil)) | 694 | (? ?, (* space)) |
| 677 | (while (and (setq res (re-search-forward re limit t)) | 695 | (? (or ")" "]") (* space)) |
| 678 | (goto-char (match-end 1)) | 696 | (group assignment-operator))) |
| 679 | (python-syntax-context 'paren))) | 697 | (1 font-lock-variable-name-face) |
| 680 | res)) | 698 | (,(python-rx grouped-assignment-target) |
| 681 | (1 font-lock-variable-name-face nil nil))) | 699 | (progn |
| 700 | (goto-char (match-end 1)) ; go back after the first symbol | ||
| 701 | (match-beginning 2)) ; limit the search until the assignment | ||
| 702 | nil | ||
| 703 | (1 font-lock-variable-name-face))) | ||
| 704 | ;; single assignment with type hints, e.g. | ||
| 705 | ;; a: int = 5 | ||
| 706 | ;; b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo') | ||
| 707 | ;; c: Collection = {1, 2, 3} | ||
| 708 | ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} | ||
| 709 | (,(python-font-lock-assignment-matcher | ||
| 710 | (python-rx grouped-assignment-target (* space) | ||
| 711 | (? ?: (* space) (+ not-simple-operator) (* space)) | ||
| 712 | assignment-operator)) | ||
| 713 | (1 font-lock-variable-name-face)) | ||
| 714 | ;; special cases | ||
| 715 | ;; (a) = 5 | ||
| 716 | ;; [a] = 5 | ||
| 717 | ;; [*a] = 5, 6 | ||
| 718 | (,(python-font-lock-assignment-matcher | ||
| 719 | (python-rx (or "[" "(") (* space) | ||
| 720 | grouped-assignment-target (* space) | ||
| 721 | (or ")" "]") (* space) | ||
| 722 | assignment-operator)) | ||
| 723 | (1 font-lock-variable-name-face))) | ||
| 682 | "Font lock keywords to use in python-mode for maximum decoration. | 724 | "Font lock keywords to use in python-mode for maximum decoration. |
| 683 | 725 | ||
| 684 | This decoration level includes everything in | 726 | This decoration level includes everything in |