Subject: Re: Python f-string font-lock logic is incomplete

From: Laurence Warne <[email-masked]>
Date: Sat, 30 Jul 2022 15:58:00 +0100

Hi, I've attached a patch which looks good to me locally using the above
examples and others.

In addition to the above, mixed capitalizations are also covered:
https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
.

Thanks!
From 9335081156142bf06ab0f1b77192bf446f1d6b3a Mon Sep 17 00:00:00 2001
From: lWarne <[email-masked]>
Date: Sat, 30 Jul 2022 13:22:18 +0100
Subject: [PATCH] Apply syntax highlighting for all python f-strings

Apply syntax highlighting to all Python formatted string literals
(Bug#56757), including multiline strings and formatted strings also
having the raw string prefix ("r") either following or preceding "f".

* lisp/progmodes/python.el (python--f-string-p, python--font-lock-f-strings):
Edit functions to use a regular expression matching all f-strings.
---
 lisp/progmodes/python.el | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index b8fc7d4c54..87a849aaf3 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -493,11 +493,22 @@ python-font-lock-syntactic-face-function
         font-lock-string-face)
     font-lock-comment-face))
 
+(defconst python--f-string-start-regexp
+  (rx bow
+      (or "f" "F" "fr" "Fr" "fR" "FR" "rf" "rF" "Rf" "RF")
+      (or "\"" "\"\"\"" "'" "'''"))
+  "A regular expression matching the beginning of an f-string.
+
+See URL `https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals'.")
+
 (defun python--f-string-p (ppss)
   "Return non-nil if the pos where PPSS was found is inside an f-string."
   (and (nth 3 ppss)
-       (let ((spos (1- (nth 8 ppss))))
-         (and (memq (char-after spos) '(?f ?F))
+       (let* ((spos (1- (nth 8 ppss)))
+              (before-quote
+               (buffer-substring-no-properties (max (- spos 4) (point-min))
+                                               (min (+ spos 2) (point-max)))))
+         (and (string-match-p python--f-string-start-regexp before-quote)
               (or (< (point-min) spos)
                   (not (memq (char-syntax (char-before spos)) '(?w ?_))))))))
 
@@ -516,7 +527,7 @@ python--font-lock-f-strings
     (while
         (progn
           (while (and (not (python--f-string-p ppss))
-                      (re-search-forward "\\<f['\"]" limit 'move))
+                      (re-search-forward python--f-string-start-regexp limit 'move))
             (setq ppss (syntax-ppss)))
           (< (point) limit))
       (cl-assert (python--f-string-p ppss))
-- 
2.30.2