aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorYuan Fu2025-09-20 23:36:23 -0700
committerYuan Fu2025-09-22 16:41:06 -0700
commit7b8c17d52704548ff2d2ea706247b1cf52de7d36 (patch)
tree87aaf440eb76dec53091d6550fee603de7d70fd7 /lisp/progmodes/python.el
parent192a0e177305e896d9e0ebc098be1e4cbb63eece (diff)
downloademacs-7b8c17d52704548ff2d2ea706247b1cf52de7d36.tar.gz
emacs-7b8c17d52704548ff2d2ea706247b1cf52de7d36.zip
Fix python-ts-mode font-lock breakage by grammar change (bug#79457)
* lisp/progmodes/python.el (python--treesit-fontify-string): Use new algorithm.
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el67
1 files changed, 37 insertions, 30 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index e5cc3b0078b..22a4e2c2e5d 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1092,36 +1092,43 @@ NODE is the string node. Do not fontify the initial f for
1092f-strings. OVERRIDE is the override flag described in 1092f-strings. OVERRIDE is the override flag described in
1093`treesit-font-lock-rules'. START and END mark the region to be 1093`treesit-font-lock-rules'. START and END mark the region to be
1094fontified." 1094fontified."
1095 (let* ((maybe-expression (treesit-node-parent node)) 1095 ;; Criteria for docstring: go up the parse tree until top-level or a
1096 (grandparent (treesit-node-parent 1096 ;; node under function/class, at each level, the node is the first
1097 (treesit-node-parent 1097 ;; child (excluding comments). This condition also rules out negative
1098 maybe-expression))) 1098 ;; cases like
1099 (maybe-defun grandparent) 1099 ;;
1100 (face (if (and (or (member (treesit-node-type maybe-defun) 1100 ;; def function():
1101 '("function_definition" 1101 ;; return "some string"
1102 "class_definition")) 1102 ;;
1103 ;; If the grandparent is null, meaning the 1103 ;; And it recognizes for BOF docstrings, and allows comments before
1104 ;; string is top-level, and the string has 1104 ;; the docstring.
1105 ;; no node or only comment preceding it, 1105 ;;
1106 ;; it's a BOF docstring. 1106 ;; Older grammar has function_definition -> block -> expression_statement -> string
1107 (and (null grandparent) 1107 ;; Newer grammar has function_definition -> block -> string
1108 (cl-loop 1108 ;; This algorithm works for both.
1109 for prev = (treesit-node-prev-sibling 1109 (let* ((cursor node)
1110 maybe-expression) 1110 (face (catch 'break
1111 then (treesit-node-prev-sibling prev) 1111 (while t
1112 while prev 1112 (let ((parent (treesit-node-parent cursor))
1113 if (not (equal (treesit-node-type prev) 1113 (cursor-idx (treesit-node-index cursor)))
1114 "comment")) 1114 (when (null parent)
1115 return nil 1115 (throw 'break 'font-lock-doc-face))
1116 finally return t))) 1116
1117 ;; This check filters out this case: 1117 (when (and (member (treesit-node-type parent)
1118 ;; def function(): 1118 '("function_definition"
1119 ;; return "some string" 1119 "class_definition"))
1120 (equal (treesit-node-type maybe-expression) 1120 (equal (treesit-node-field-name-for-child
1121 "expression_statement")) 1121 parent cursor-idx)
1122 'font-lock-doc-face 1122 "body"))
1123 'font-lock-string-face)) 1123 (throw 'break 'font-lock-doc-face))
1124 1124
1125 (let ((idx 0))
1126 (while (< idx cursor-idx)
1127 (unless (equal (treesit-node-type
1128 (treesit-node-child parent idx))
1129 "comment")
1130 (throw 'break 'font-lock-string-face))))
1131 (setq cursor parent)))))
1125 (ignore-interpolation 1132 (ignore-interpolation
1126 (not (seq-some 1133 (not (seq-some
1127 (lambda (feats) (memq 'string-interpolation feats)) 1134 (lambda (feats) (memq 'string-interpolation feats))