10

I am using python-mode which colors the parameters.

When I concatinate strings the variable color is represented as different:

On the other hand, if I use fstring, the variable is not represented as different color:

str

Please note that, if I enter non-existing variable, python-mode detects it:

enter image description here

[Q] Is there any way to give a color to variables inside a fstring under python-mode?

Drew
  • 75,699
  • 9
  • 109
  • 225
alper
  • 1,238
  • 11
  • 30

1 Answers1

11

I think this will do it for Emacs versions < 27.1

(require 'python)

(setq python-font-lock-keywords
      (append python-font-lock-keywords
          '(;; this is the full string.
        ;; group 1 is the quote type and a closing quote is matched
        ;; group 2 is the string part
        ("f\\(['\"]\\{1,3\\}\\)\\(.+?\\)\\1"
         ;; these are the {keywords}
         ("{[^}]*?}"
          ;; Pre-match form
          (progn (goto-char (match-beginning 0)) (match-end 0))
          ;; Post-match form
          (goto-char (match-end 0))
          ;; face for this match
          (0 font-lock-variable-name-face t))))))

For later versions replace python-font-lock-keywords with python-font-lock-keywords-maximum-decoration.

I think this works on all strings now, including multiline ones (that seems to be a tricky one in general though). I left the {} in the highlight, they get replaced and that made sense to me.

Here is what it looks like for me: enter image description here

font lock is hard!

The two other posts I looked at related to this are:

  1. Repeated regex capture for font-lock

  2. Python mode - custom syntax highlighting.

dshepherd
  • 1,281
  • 6
  • 18
John Kitchin
  • 11,555
  • 1
  • 19
  • 41
  • It works perfect (I pasted into `.emacs` file) but when I use it few other `python-mode` colorings are gone, is there any way to use it but keep the `python-mode` colorings as well? Such as comments color was red but become white again. Also strings inside `""` was green but become white. – alper Jan 30 '20 at 01:12
  • Please see the color change for the strings inside `""` => https://gist.github.com/avatar-lavventura/5af25ccc3de7e07b537fce2f14c6aac2 @John Kitchin – alper Jan 30 '20 at 08:45
  • 1
    I think with the new version you can get rid of the font-lock-keywords-only setting, then this works for everything but mulitline f-strings. see teh new picture above. – John Kitchin Jan 30 '20 at 12:39
  • This may be challenging by what if I have `dict` inside a string, ex: `f"received: {jobInfo["received"]}"` //`received` string is seen as a invalid syntac on `python-mode` – alper Jan 31 '20 at 11:52
  • 1
    That probably is invalid. You can't use the same kind of quotes for the dictionary key here. Try f'received {jobInfo["received"]}' instead. – John Kitchin Jan 31 '20 at 12:23
  • Coloring get confused if multiple strings (`""`) or fstrings (`f""`) on the same line. Example: `["bash", f"{PATH}/check.sh", jobKey.replace("=", "", 1)]` or `[f"hello", f"world"]` (second `f` is not detected as keyword)@John Kitchin – alper Feb 06 '20 at 12:55
  • I don't see that, {PATH} is the only keyword in that example, and it is highlighted correctly for me. The second example has no keywords in it, and both are just plain strings. – John Kitchin Feb 06 '20 at 13:26
  • Please see, I tried to show it on the screenshot of what I am having: https://gist.github.com/avatar-lavventura/5af25ccc3de7e07b537fce2f14c6aac2#gistcomment-3168317 – alper Feb 06 '20 at 13:39
  • When I have a example like this (starting, ending, or middle of the string having `\n`), `print(f"Downloading => {key} \n")` ; variable(key) deos not show up with a different color, do you have the similar output? @John Kitchin – alper Feb 16 '20 at 08:03
  • yes I see that too. the \n seems to break it, but I don't know why. `"f\\(['\"]\\{1,3\\}\\)\\(.+?\\)\\1"` also seems to work, but I have not checked it against all your other test cases. – John Kitchin Feb 16 '20 at 15:35
  • Thank you, I was just curious about it maybe `\n` is a defines as specific symbol on python-mode or emacs – alper Feb 16 '20 at 17:40
  • \n is just a newline character. I don't know why it doesn't get matched though by `[^\\1]` which should match any character that is not the opening quote. – John Kitchin Feb 16 '20 at 18:20
  • Should we ask it as a question, which seems like an interesting case? – alper Feb 16 '20 at 21:16
  • 1
    I asked it at https://emacs.stackexchange.com/questions/55586/regexp-for-matching-quoted-strings-that-may-have-control-characters-in-them – John Kitchin Feb 17 '20 at 13:35
  • Thanks and appreciated your help @John Kitchin – alper Feb 17 '20 at 13:41
  • 1
    There are some interesting approaches and explanations in the answers to the new question. I have updated this answer so it works with \n in it, but there may be a more robust answer that leverages syntax described at https://emacs.stackexchange.com/questions/55586/regexp-for-matching-quoted-strings-that-may-have-control-characters-in-them. It will take some work to make that also do what is done here though. – John Kitchin Feb 17 '20 at 22:04
  • If you prefer not to highlight the `{`: change `"{[^}]*?}"` to `"{\\([^}]*?\\)}"` and change `(0 font-lock-variable-name-face t)` to `(1 font-lock-variable-name-face t)` – dshepherd Jun 28 '20 at 12:46
  • 1
    In `GNU Emacs 27.1` seems like it does not work :-( – alper Sep 22 '20 at 18:04
  • Yeah this breaks almost all python font locking in emacs 27.1 :( – dshepherd Nov 23 '20 at 12:03
  • The fix seems to be to replace `python-font-lock-keywords` with `python-font-lock-keywords-maximum-decoration`. – dshepherd Nov 23 '20 at 12:16
  • Would it be working in `GNU Emacs 27.1` ? If yes, that would be awesome. Only replacing `python-font-lock-keywords` with `python-font-lock-keywords-maximum-decoration` would be enough? seems like it didn't have any affect @John Kitchin – alper Mar 09 '21 at 22:23
  • @JohnKitchin Sorry for pretty late comment. In some cases I have to use `{{` or `}}` to add curly brakets into the string (https://stackoverflow.com/a/68254078/2402577). But the coloring get confused. Would it be possible to handle those cases as well? Example color: https://gist.github.com/avatar-lavventura/27bcfb5df8b9d243fa8bf4b7928d2254#gistcomment-3817024 – alper Jul 18 '21 at 10:11