font-lock-string-face)
font-lock-comment-face))
+(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))
+ (or (< (point-min) spos)
+ (not (memq (char-syntax (char-before spos)) '(?w ?_))))))))
+
+(defun python--font-lock-f-strings (limit)
+ "Mark {...} holes as being code.
+Remove the (presumably `font-lock-string-face') `face' property from
+the {...} holes that appear within f-strings."
+ ;; FIXME: This will fail to properly highlight strings appearing
+ ;; within the {...} of an f-string.
+ ;; We could presumably fix it by running
+ ;; `font-lock-fontify-syntactically-region' (as is done in
+ ;; `sm-c--cpp-fontify-syntactically', for example) after removing
+ ;; the `face' property, but I'm not sure it's worth the effort and
+ ;; the risks.
+ (let ((ppss (syntax-ppss)))
+ (while
+ (progn
+ (while (and (not (python--f-string-p ppss))
+ (re-search-forward "\\<f['\"]" limit 'move))
+ (setq ppss (syntax-ppss)))
+ (< (point) limit))
+ (cl-assert (python--f-string-p ppss))
+ (let ((send (save-excursion
+ (goto-char (nth 8 ppss))
+ (condition-case nil
+ (progn (let ((forward-sexp-function nil))
+ (forward-sexp 1))
+ (min limit (1- (point))))
+ (scan-error limit)))))
+ (while (re-search-forward "{" send t)
+ (if (eq ?\{ (char-after))
+ (forward-char 1) ;Just skip over {{
+ (let ((beg (match-beginning 0))
+ (end (condition-case nil
+ (progn (up-list 1) (min send (point)))
+ (scan-error send))))
+ (goto-char end)
+ (put-text-property beg end 'face nil))))
+ (goto-char (min limit (1+ send)))
+ (setq ppss (syntax-ppss))))))
+
(defvar python-font-lock-keywords-level-1
`((,(rx symbol-start "def" (1+ space) (group (1+ (or word ?_))))
(1 font-lock-function-name-face))
builtins.")
(defvar python-font-lock-keywords-maximum-decoration
- `(,@python-font-lock-keywords-level-2
+ `((python--font-lock-f-strings)
+ ,@python-font-lock-keywords-level-2
;; Constants
(,(rx symbol-start
(or
;; copyright, license, credits, quit and exit are added by the site
;; module and they are not intended to be used in programs
"copyright" "credits" "exit" "license" "quit")
- symbol-end) . font-lock-constant-face)
+ symbol-end)
+ . font-lock-constant-face)
;; Decorators.
(,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_))
(0+ "." (1+ (or word ?_)))))
;; OS specific
"VMSError" "WindowsError"
)
- symbol-end) . font-lock-type-face)
+ symbol-end)
+ . font-lock-type-face)
;; assignments
;; support for a = b = c = 5
(,(lambda (limit)