23
23
FONTUPDATEINTERVAL = 1000 # millisec
24
24
25
25
26
- def getspacesfirstword (s , c = re .compile (r"^(\s*)(\w*)" )):
27
- "Extract the beginning whitespace and first word from s."
28
- return c .match (s ).groups ()
26
+ def get_spaces_firstword (codeline , c = re .compile (r"^(\s*)(\w*)" )):
27
+ "Extract the beginning whitespace and first word from codeline."
28
+ return c .match (codeline ).groups ()
29
+
30
+
31
+ def get_line_info (codeline ):
32
+ """Return tuple of (line indent value, codeline, block start keyword).
33
+
34
+ The indentation of empty lines (or comment lines) is INFINITY.
35
+ If the line does not start a block, the keyword value is False.
36
+ """
37
+ spaces , firstword = get_spaces_firstword (codeline )
38
+ indent = len (spaces )
39
+ if len (codeline ) == indent or codeline [indent ] == '#' :
40
+ indent = INFINITY
41
+ opener = firstword in BLOCKOPENERS and firstword
42
+ return indent , codeline , opener
29
43
30
44
31
45
class CodeContext :
@@ -42,15 +56,15 @@ def __init__(self, editwin):
42
56
self.textfont is the editor window font.
43
57
44
58
self.label displays the code context text above the editor text.
45
- Initially None it is toggled via <<toggle-code-context>>.
59
+ Initially None, it is toggled via <<toggle-code-context>>.
46
60
self.topvisible is the number of the top text line displayed.
47
61
self.info is a list of (line number, indent level, line text,
48
62
block keyword) tuples for the block structure above topvisible.
49
- s self.info[0] is initialized a 'dummy' line which
50
- # starts the toplevel 'block' of the module.
63
+ self.info[0] is initialized with a 'dummy' line which
64
+ starts the toplevel 'block' of the module.
51
65
52
66
self.t1 and self.t2 are two timer events on the editor text widget to
53
- monitor for changes to the context text or editor font.
67
+ monitor for changes to the context text or editor font.
54
68
"""
55
69
self .editwin = editwin
56
70
self .text = editwin .text
@@ -94,45 +108,28 @@ def toggle_code_context_event(self, event=None):
94
108
# All values are passed through getint(), since some
95
109
# values may be pixel objects, which can't simply be added to ints.
96
110
widgets = self .editwin .text , self .editwin .text_frame
97
- # Calculate the required vertical padding
111
+ # Calculate the required horizontal padding and border width.
98
112
padx = 0
113
+ border = 0
99
114
for widget in widgets :
100
115
padx += widget .tk .getint (widget .pack_info ()['padx' ])
101
116
padx += widget .tk .getint (widget .cget ('padx' ))
102
- # Calculate the required border width
103
- border = 0
104
- for widget in widgets :
105
117
border += widget .tk .getint (widget .cget ('border' ))
106
118
self .label = tkinter .Label (
107
119
self .editwin .top , text = "\n " * (self .context_depth - 1 ),
108
120
anchor = W , justify = LEFT , font = self .textfont ,
109
121
bg = self .bgcolor , fg = self .fgcolor ,
110
- width = 1 , #don 't request more than we get
122
+ width = 1 , # Don 't request more than we get.
111
123
padx = padx , border = border , relief = SUNKEN )
112
124
# Pack the label widget before and above the text_frame widget,
113
- # thus ensuring that it will appear directly above text_frame
125
+ # thus ensuring that it will appear directly above text_frame.
114
126
self .label .pack (side = TOP , fill = X , expand = False ,
115
127
before = self .editwin .text_frame )
116
128
else :
117
129
self .label .destroy ()
118
130
self .label = None
119
131
return "break"
120
132
121
- def get_line_info (self , linenum ):
122
- """Return tuple of (line indent value, text, and block start keyword).
123
-
124
- If the line does not start a block, the keyword value is False.
125
- The indentation of empty lines (or comment lines) is INFINITY.
126
- """
127
- text = self .text .get ("%d.0" % linenum , "%d.end" % linenum )
128
- spaces , firstword = getspacesfirstword (text )
129
- opener = firstword in BLOCKOPENERS and firstword
130
- if len (text ) == len (spaces ) or text [len (spaces )] == '#' :
131
- indent = INFINITY
132
- else :
133
- indent = len (spaces )
134
- return indent , text , opener
135
-
136
133
def get_context (self , new_topvisible , stopline = 1 , stopindent = 0 ):
137
134
"""Return a list of block line tuples and the 'last' indent.
138
135
@@ -144,16 +141,17 @@ def get_context(self, new_topvisible, stopline=1, stopindent=0):
144
141
"""
145
142
assert stopline > 0
146
143
lines = []
147
- # The indentation level we are currently in:
144
+ # The indentation level we are currently in.
148
145
lastindent = INFINITY
149
146
# For a line to be interesting, it must begin with a block opening
150
147
# keyword, and have less indentation than lastindent.
151
148
for linenum in range (new_topvisible , stopline - 1 , - 1 ):
152
- indent , text , opener = self .get_line_info (linenum )
149
+ codeline = self .text .get (f'{ linenum } .0' , f'{ linenum } .end' )
150
+ indent , text , opener = get_line_info (codeline )
153
151
if indent < lastindent :
154
152
lastindent = indent
155
153
if opener in ("else" , "elif" ):
156
- # We also show the if statement
154
+ # Also show the if statement.
157
155
lastindent += 1
158
156
if opener and linenum < new_topvisible and indent >= stopindent :
159
157
lines .append ((linenum , indent , text , opener ))
@@ -172,19 +170,19 @@ def update_code_context(self):
172
170
the context label.
173
171
"""
174
172
new_topvisible = int (self .text .index ("@0,0" ).split ('.' )[0 ])
175
- if self .topvisible == new_topvisible : # haven 't scrolled
173
+ if self .topvisible == new_topvisible : # Haven 't scrolled.
176
174
return
177
- if self .topvisible < new_topvisible : # scroll down
175
+ if self .topvisible < new_topvisible : # Scroll down.
178
176
lines , lastindent = self .get_context (new_topvisible ,
179
177
self .topvisible )
180
- # retain only context info applicable to the region
181
- # between topvisible and new_topvisible:
178
+ # Retain only context info applicable to the region
179
+ # between topvisible and new_topvisible.
182
180
while self .info [- 1 ][1 ] >= lastindent :
183
181
del self .info [- 1 ]
184
- else : # self.topvisible > new_topvisible: # scroll up
182
+ else : # self.topvisible > new_topvisible: # Scroll up.
185
183
stopindent = self .info [- 1 ][1 ] + 1
186
- # retain only context info associated
187
- # with lines above new_topvisible:
184
+ # Retain only context info associated
185
+ # with lines above new_topvisible.
188
186
while self .info [- 1 ][0 ] >= new_topvisible :
189
187
stopindent = self .info [- 1 ][1 ]
190
188
del self .info [- 1 ]
@@ -193,9 +191,9 @@ def update_code_context(self):
193
191
stopindent )
194
192
self .info .extend (lines )
195
193
self .topvisible = new_topvisible
196
- # empty lines in context pane:
194
+ # Empty lines in context pane.
197
195
context_strings = ["" ] * max (0 , self .context_depth - len (self .info ))
198
- # followed by the context hint lines:
196
+ # Followed by the context hint lines.
199
197
context_strings += [x [2 ] for x in self .info [- self .context_depth :]]
200
198
self .label ["text" ] = '\n ' .join (context_strings )
201
199
0 commit comments