python-syntax icon indicating copy to clipboard operation
python-syntax copied to clipboard

Python 3.6 f-string literal support

Open achimnol opened this issue 9 years ago • 2 comments

Python 3.6 has reached its last beta where its features are frozen now. It introduces a new syntactic element: f-string literals. https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-pep498

In f-string literals, the content inside braces are treated as real Python expressions with optional format string after a colon character like in format() protocol. The expression expansion may be done inside the format string as well though. (See the examples in the above link.)

Let's add support for this.

achimnol avatar Nov 24 '16 04:11 achimnol

Trying to make a PR for this, but needs help! I'm not quite professional in vim syntax writing. 😞

syn region pythonFString   start=+[fF]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,@Spell
syn region pythonFString   start=+[fF]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,@Spell
syn region pythonFString   start=+[fF]"""+ end=+"""+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest2,pythonSpaceError,@Spell
syn region pythonFString   start=+[fF]'''+ end=+'''+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest,pythonSpaceError,@Spell
...
syn match pythonStrFormat "{{\|}}" contained containedin=pythonString,pythonRawString
syn match pythonStrFormat "{\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)\=\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\[\%(\d\+\|[^!:\}]\+\)\]\)*\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonString,pythonRawString
syn match pythonStrInterpFormat "{{\|}}" contained containedin=pythonFString
syn match pythonStrInterpFormat "{<any python expression>\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonFString
...
HiLink pythonFString            String
HiLink pythonStrInterpFormat    Special

I need to make Vim to treat above <any python expression> part like a just normal Python expression. The only rules for them are:

  • It should not contain the string terminating quote (e.g., if the current f-string has begun with a single quote, then the expressions may not contain single quote because it will break the Python parser.
  • As the content inside braces are limited to expressions, ~~colon and~~ exclamation mark can be used like previous string formatting mini-language. So I've copy-and-pasted the later part from the existing syntax. Update: colon may be used in parenthesized lambda expression, for example, f"{(lambda: 1)()}"

A nice test case would be something like f"{var} plain {expr1 if True or False else expr2} text {var!r} {dictob['key']:.2f} abc {123_34E+2:g} {(lambda: 1)()}". Somebody please help me to figure out how to do this! 😁

achimnol avatar Nov 25 '16 10:11 achimnol

This has been fixed over at the fork vim-python/python-syntax.

nfnty avatar Feb 18 '17 09:02 nfnty