Skip to content

Commit a69c2b6

Browse files
RunDevelopmentmAAdhaTTah
authored andcommitted
Improvements to Python F-strings and string prefixes (#1642)
This PR adds support for [string interpolation](https://www.python.org/dev/peps/pep-0498/) (aka. f-strings) and makes the [string prefixes](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals) part of the string. Resolves #1636. ### Known issues Assumes that strings inside the interpolation expression are 'nice'. So strings with unfortunate numbers of curley braces will cause incorrect highlighting: E.g.: `f"{'}'}"`.
1 parent 5b6ad70 commit a69c2b6

File tree

5 files changed

+188
-9
lines changed

5 files changed

+188
-9
lines changed

components/prism-python.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,36 @@ Prism.languages.python = {
33
pattern: /(^|[^\\])#.*/,
44
lookbehind: true
55
},
6+
'string-interpolation': {
7+
pattern: /(?:f|rf|fr)(?:("""|''')[\s\S]+?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
8+
greedy: true,
9+
inside: {
10+
'interpolation': {
11+
// "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
12+
pattern: /((?:^|[^{])(?:{{)*){(?!{)(?:[^{}]|{(?!{)(?:[^{}]|{(?!{)(?:[^{}])+})+})+}/,
13+
lookbehind: true,
14+
inside: {
15+
'format-spec': {
16+
pattern: /(:)[^:(){}]+(?=}$)/,
17+
lookbehind: true
18+
},
19+
'conversion-option': {
20+
pattern: /![sra](?=[:}]$)/,
21+
alias: 'punctuation'
22+
},
23+
rest: null
24+
}
25+
},
26+
'string': /[\s\S]+/
27+
}
28+
},
629
'triple-quoted-string': {
7-
pattern: /("""|''')[\s\S]+?\1/,
30+
pattern: /(?:[rub]|rb|br)?("""|''')[\s\S]+?\1/i,
831
greedy: true,
932
alias: 'string'
1033
},
1134
'string': {
12-
pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
35+
pattern: /(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
1336
greedy: true
1437
},
1538
'function': {
@@ -35,3 +58,5 @@ Prism.languages.python = {
3558
'operator': /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
3659
'punctuation': /[{}[\];(),.:]/
3760
};
61+
62+
Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python;

components/prism-python.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/prism-python.html

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,5 @@ <h2>Known failures</h2>
5757
If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug.
5858
</p>
5959

60-
<h3>Triple-quoted strings with what look like strings inside</h3>
61-
<pre><code>def antique(string):
62-
"""Replace anachronistic Latin "j" with "i"."""
63-
return string.replace("j", "i").replace("J", "I")
64-
</code></pre>
60+
<h3>Interpolation expressions containing strings with <code>{</code> or <code>}</code></h3>
61+
<pre><code>f"{'}'}"</code></pre>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
f'The value is {value}.'
2+
3+
f"The value is {'4'}."
4+
5+
f'input={value!s:#06x}'
6+
7+
f'{{{4*10}}}'
8+
9+
fr'x={4*10}\n'
10+
11+
f'''{x
12+
+1}'''
13+
14+
f'mapping is { {a:b for (a, b) in ((1, 2), (3, 4))} }'
15+
16+
f'{(lambda x: x*2)(3)}'
17+
18+
----------------------------------------------------
19+
20+
[
21+
["string-interpolation", [
22+
["string", "f'The value is "],
23+
["interpolation", [
24+
["punctuation", "{"],
25+
"value",
26+
["punctuation", "}"]
27+
]],
28+
["string", ".'"]
29+
]],
30+
31+
["string-interpolation", [
32+
["string", "f\"The value is "],
33+
["interpolation", [
34+
["punctuation", "{"],
35+
["string", "'4'"],
36+
["punctuation", "}"]
37+
]],
38+
["string", ".\""]
39+
]],
40+
41+
["string-interpolation", [
42+
["string", "f'input="],
43+
["interpolation", [
44+
["punctuation", "{"],
45+
"value",
46+
["conversion-option", "!s"],
47+
["punctuation", ":"],
48+
["format-spec", "#06x"],
49+
["punctuation", "}"]
50+
]],
51+
["string", "'"]
52+
]],
53+
54+
["string-interpolation", [
55+
["string", "f'{{"],
56+
["interpolation", [
57+
["punctuation", "{"],
58+
["number", "4"],
59+
["operator", "*"],
60+
["number", "10"],
61+
["punctuation", "}"]
62+
]],
63+
["string", "}}'"]
64+
]],
65+
66+
["string-interpolation", [
67+
["string", "fr'x="],
68+
["interpolation", [
69+
["punctuation", "{"],
70+
["number", "4"],
71+
["operator", "*"],
72+
["number", "10"],
73+
["punctuation", "}"]
74+
]],
75+
["string", "\\n'"]
76+
]],
77+
78+
["string-interpolation", [
79+
["string", "f'''"],
80+
["interpolation", [
81+
["punctuation", "{"],
82+
"x\r\n",
83+
["operator", "+"],
84+
["number", "1"],
85+
["punctuation", "}"]
86+
]],
87+
["string", "'''"]
88+
]],
89+
90+
["string-interpolation", [
91+
["string", "f'mapping is "],
92+
["interpolation", [
93+
["punctuation", "{"],
94+
["punctuation", "{"],
95+
"a",
96+
["punctuation", ":"],
97+
"b ",
98+
["keyword", "for"],
99+
["punctuation", "("],
100+
"a",
101+
["punctuation", ","],
102+
" b",
103+
["punctuation", ")"],
104+
["keyword", "in"],
105+
["punctuation", "("],
106+
["punctuation", "("],
107+
["number", "1"],
108+
["punctuation", ","],
109+
["number", "2"],
110+
["punctuation", ")"],
111+
["punctuation", ","],
112+
["punctuation", "("],
113+
["number", "3"],
114+
["punctuation", ","],
115+
["number", "4"],
116+
["punctuation", ")"],
117+
["punctuation", ")"],
118+
["punctuation", "}"],
119+
["punctuation", "}"]
120+
]],
121+
["string", "'"]
122+
]],
123+
124+
["string-interpolation", [
125+
["string", "f'"],
126+
["interpolation", [
127+
["punctuation", "{"],
128+
["punctuation", "("],
129+
["keyword", "lambda"],
130+
" x",
131+
["punctuation", ":"],
132+
" x",
133+
["operator", "*"],
134+
["number", "2"],
135+
["punctuation", ")"],
136+
["punctuation", "("],
137+
["number", "3"],
138+
["punctuation", ")"],
139+
["punctuation", "}"]
140+
]],
141+
["string", "'"]
142+
]]
143+
]
144+
145+
----------------------------------------------------
146+
147+
Checks for string interpolation.

tests/languages/python/string_feature.test

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@
44
'fo\'obar'
55
"fo\" # comment obar"
66

7+
r"\n"
8+
b'foo'
9+
rb"foo\n"
10+
u"foo"
11+
712
----------------------------------------------------
813

914
[
1015
["string", "\"\""],
1116
["string", "\"fo\\\"obar\""],
1217
["string", "''"],
1318
["string", "'fo\\'obar'"],
14-
["string", "\"fo\\\" # comment obar\""]
19+
["string", "\"fo\\\" # comment obar\""],
20+
21+
["string", "r\"\\n\""],
22+
["string", "b'foo'"],
23+
["string", "rb\"foo\\n\""],
24+
["string", "u\"foo\""]
1525
]
1626

1727
----------------------------------------------------

0 commit comments

Comments
 (0)