X Tutup
Skip to content

Commit bfa1327

Browse files
committed
Compile regular expressions only once
Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
1 parent e837c92 commit bfa1327

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

bpython/line.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,30 @@
55

66
import re
77

8+
current_word_re = re.compile(r'[\w_][\w0-9._]*[(]?')
9+
current_dict_key_re = re.compile(r'''[\w_][\w0-9._]*\[([\w0-9._(), '"]*)''')
10+
current_dict_re = re.compile(r'''([\w_][\w0-9._]*)\[([\w0-9._(), '"]*)''')
11+
current_string_re = re.compile(
12+
'''(?P<open>(?:""")|"|(?:''\')|')(?:((?P<closed>.+?)(?P=open))|(?P<unclosed>.+))''')
13+
current_object_re = re.compile(r'([\w_][\w0-9_]*)[.]')
14+
current_object_attribute_re = re.compile(r'([\w_][\w0-9_]*)[.]?')
15+
current_from_import_from_re = re.compile(r'from ([\w0-9_.]*)(?:\s+import\s+([\w0-9_]+[,]?\s*)+)*')
16+
current_from_import_import_re_1 = re.compile(r'from\s([\w0-9_.]*)\s+import')
17+
current_from_import_import_re_2 = re.compile(r'([\w0-9_]+)')
18+
current_from_import_import_re_3 = re.compile(r'[,][ ]([\w0-9_]*)')
19+
current_import_re_1 = re.compile(r'import')
20+
current_import_re_2 = re.compile(r'([\w0-9_.]+)')
21+
current_import_re_3 = re.compile(r'[,][ ]([\w0-9_.]*)')
22+
current_method_definition_name_re = re.compile("def\s+([a-zA-Z_][\w]*)")
23+
current_single_word_re = re.compile(r"(?<![.])\b([a-zA-Z_][\w]*)")
24+
current_string_literal_attr_re = re.compile(
25+
"('''" +
26+
r'''|"""|'|")((?:(?=([^"'\\]+|\\.|(?!\1)["']))\3)*)\1[.]([a-zA-Z_]?[\w]*)''')
27+
828
def current_word(cursor_offset, line):
929
"""the object.attribute.attribute just before or under the cursor"""
1030
pos = cursor_offset
11-
matches = list(re.finditer(r'[\w_][\w0-9._]*[(]?', line))
31+
matches = list(current_word_re.finditer(line))
1232
start = pos
1333
end = pos
1434
word = None
@@ -23,15 +43,15 @@ def current_word(cursor_offset, line):
2343

2444
def current_dict_key(cursor_offset, line):
2545
"""If in dictionary completion, return the current key"""
26-
matches = list(re.finditer(r'''[\w_][\w0-9._]*\[([\w0-9._(), '"]*)''', line))
46+
matches = list(current_dict_key_re.finditer(line))
2747
for m in matches:
2848
if m.start(1) <= cursor_offset and m.end(1) >= cursor_offset:
2949
return (m.start(1), m.end(1), m.group(1))
3050
return None
3151

3252
def current_dict(cursor_offset, line):
3353
"""If in dictionary completion, return the dict that should be used"""
34-
matches = list(re.finditer(r'''([\w_][\w0-9._]*)\[([\w0-9._(), '"]*)''', line))
54+
matches = list(current_dict_re.finditer(line))
3555
for m in matches:
3656
if m.start(2) <= cursor_offset and m.end(2) >= cursor_offset:
3757
return (m.start(1), m.end(1), m.group(1))
@@ -42,7 +62,7 @@ def current_string(cursor_offset, line):
4262
4363
Weaker than bpython.Repl's current_string, because that checks that a string is a string
4464
based on previous lines in the buffer"""
45-
for m in re.finditer('''(?P<open>(?:""")|"|(?:''\')|')(?:((?P<closed>.+?)(?P=open))|(?P<unclosed>.+))''', line):
65+
for m in current_string_re.finditer(line):
4666
i = 3 if m.group(3) else 4
4767
if m.start(i) <= cursor_offset and m.end(i) >= cursor_offset:
4868
return m.start(i), m.end(i), m.group(i)
@@ -53,7 +73,7 @@ def current_object(cursor_offset, line):
5373
match = current_word(cursor_offset, line)
5474
if match is None: return None
5575
start, end, word = match
56-
matches = list(re.finditer(r'([\w_][\w0-9_]*)[.]', word))
76+
matches = list(current_object_re.finditer(word))
5777
s = ''
5878
for m in matches:
5979
if m.end(1) + start < cursor_offset:
@@ -69,7 +89,7 @@ def current_object_attribute(cursor_offset, line):
6989
match = current_word(cursor_offset, line)
7090
if match is None: return None
7191
start, end, word = match
72-
matches = list(re.finditer(r'([\w_][\w0-9_]*)[.]?', word))
92+
matches = list(current_object_attribute_re.finditer(word))
7393
for m in matches[1:]:
7494
if m.start(1) + start <= cursor_offset and m.end(1) + start >= cursor_offset:
7595
return m.start(1) + start, m.end(1) + start, m.group(1)
@@ -85,7 +105,7 @@ def current_from_import_from(cursor_offset, line):
85105
tokens = line.split()
86106
if not ('from' in tokens or 'import' in tokens):
87107
return None
88-
matches = list(re.finditer(r'from ([\w0-9_.]*)(?:\s+import\s+([\w0-9_]+[,]?\s*)+)*', line))
108+
matches = list(current_from_import_from_re.finditer(line))
89109
for m in matches:
90110
if ((m.start(1) < cursor_offset and m.end(1) >= cursor_offset) or
91111
(m.start(2) < cursor_offset and m.end(2) >= cursor_offset)):
@@ -97,13 +117,13 @@ def current_from_import_import(cursor_offset, line):
97117
98118
returns None if cursor not in or just after one of these words
99119
"""
100-
baseline = re.search(r'from\s([\w0-9_.]*)\s+import', line)
120+
baseline = current_from_import_import_re_1.search(line)
101121
if baseline is None:
102122
return None
103-
match1 = re.search(r'([\w0-9_]+)', line[baseline.end():])
123+
match1 = current_from_import_import_re_2.search(line[baseline.end():])
104124
if match1 is None:
105125
return None
106-
matches = list(re.finditer(r'[,][ ]([\w0-9_]*)', line[baseline.end():]))
126+
matches = list(current_from_import_import_re_3.finditer(line[baseline.end():]))
107127
for m in [match1] + matches:
108128
start = baseline.end() + m.start(1)
109129
end = baseline.end() + m.end(1)
@@ -113,13 +133,13 @@ def current_from_import_import(cursor_offset, line):
113133

114134
def current_import(cursor_offset, line):
115135
#TODO allow for multiple as's
116-
baseline = re.search(r'import', line)
136+
baseline = current_import_re_1.search(line)
117137
if baseline is None:
118138
return None
119-
match1 = re.search(r'([\w0-9_.]+)', line[baseline.end():])
139+
match1 = current_import_re_2.search(line[baseline.end():])
120140
if match1 is None:
121141
return None
122-
matches = list(re.finditer(r'[,][ ]([\w0-9_.]*)', line[baseline.end():]))
142+
matches = list(current_import_re_3.finditer(line[baseline.end():]))
123143
for m in [match1] + matches:
124144
start = baseline.end() + m.start(1)
125145
end = baseline.end() + m.end(1)
@@ -128,15 +148,15 @@ def current_import(cursor_offset, line):
128148

129149
def current_method_definition_name(cursor_offset, line):
130150
"""The name of a method being defined"""
131-
matches = re.finditer("def\s+([a-zA-Z_][\w]*)", line)
151+
matches = current_method_definition_name_re.finditer(line)
132152
for m in matches:
133153
if (m.start(1) <= cursor_offset and m.end(1) >= cursor_offset):
134154
return m.start(1), m.end(1), m.group(1)
135155
return None
136156

137157
def current_single_word(cursor_offset, line):
138158
"""the un-dotted word just before or under the cursor"""
139-
matches = re.finditer(r"(?<![.])\b([a-zA-Z_][\w]*)", line)
159+
matches = current_single_word_re.finditer(line)
140160
for m in matches:
141161
if (m.start(1) <= cursor_offset and m.end(1) >= cursor_offset):
142162
return m.start(1), m.end(1), m.group(1)
@@ -152,7 +172,7 @@ def current_dotted_attribute(cursor_offset, line):
152172

153173
def current_string_literal_attr(cursor_offset, line):
154174
"""The attribute following a string literal"""
155-
matches = re.finditer("('''" + r'''|"""|'|")((?:(?=([^"'\\]+|\\.|(?!\1)["']))\3)*)\1[.]([a-zA-Z_]?[\w]*)''', line)
175+
matches = current_string_literal_attr_re.finditer(line)
156176
for m in matches:
157177
if (m.start(4) <= cursor_offset and m.end(4) >= cursor_offset):
158178
return m.start(4), m.end(4), m.group(4)

0 commit comments

Comments
 (0)
X Tutup