Tweak CodeContext.py docstrings, comments, and names.

This commit is contained in:
Kurt B. Kaiser 2005-10-03 19:26:03 +00:00
parent bee0d467a1
commit 0a1357930a
1 changed files with 57 additions and 51 deletions

View File

@ -1,13 +1,12 @@
"""CodeContext - Display the block context of code at top of edit window
"""CodeContext - Extension to display the block context above the edit window
Once code has scrolled off the top of the screen, it can be difficult
to determine which block you are in. This extension implements a pane
at the top of each IDLE edit window which provides block structure
hints. These hints are the lines which contain the block opening
keywords, e.g. 'if', for the enclosing block. The number of hint lines
is determined by the numlines variable in the CodeContext section of
config-extensions.def. Lines which do not open blocks are not shown in
the context hints pane.
Once code has scrolled off the top of a window, it can be difficult to
determine which block you are in. This extension implements a pane at the top
of each IDLE edit window which provides block structure hints. These hints are
the lines which contain the block opening keywords, e.g. 'if', for the
enclosing block. The number of hint lines is determined by the numlines
variable in the CodeContext section of config-extensions.def. Lines which do
not open blocks are not shown in the context hints pane.
"""
import Tkinter
@ -21,13 +20,14 @@ BLOCKOPENERS = Set(["class", "def", "elif", "else", "except", "finally", "for",
UPDATEINTERVAL = 100 # millisec
FONTUPDATEINTERVAL = 1000 # millisec
getspacesfirstword = lambda s, c=re.compile(r"^(\s*)(\w*)"): c.match(s).groups()
getspacesfirstword =\
lambda s, c=re.compile(r"^(\s*)(\w*)"): c.match(s).groups()
class CodeContext:
menudefs = [('options', [('!Code Conte_xt', '<<toggle-code-context>>')])]
numlines = idleConf.GetOption("extensions", "CodeContext",
"numlines", type="int", default=3)
context_depth = idleConf.GetOption("extensions", "CodeContext",
"numlines", type="int", default=3)
bgcolor = idleConf.GetOption("extensions", "CodeContext",
"bgcolor", type="str", default="LightGray")
fgcolor = idleConf.GetOption("extensions", "CodeContext",
@ -37,13 +37,13 @@ class CodeContext:
self.text = editwin.text
self.textfont = self.text["font"]
self.label = None
# self.info holds information about the context lines of line number
# self.lastfirstline. The information is a tuple of the line's
# indentation, the line's text and the keyword at the beginning of the
# line, as returned by get_line_info. At the beginning of the list
# there's a dummy line, which starts the "block" of the whole document.
# self.info is a list of (line number, indent level, line text, block
# keyword) tuples providing the block structure associated with
# self.topvisible (the linenumber of the line displayed at the top of
# the edit window). self.info[0] is initialized as a 'dummy' line which
# starts the toplevel 'block' of the module.
self.info = [(0, -1, "", False)]
self.lastfirstline = 1
self.topvisible = 1
visible = idleConf.GetOption("extensions", "CodeContext",
"visible", type="bool", default=False)
if visible:
@ -56,7 +56,7 @@ class CodeContext:
def toggle_code_context_event(self, event=None):
if not self.label:
self.label = Tkinter.Label(self.editwin.top,
text="\n" * (self.numlines - 1),
text="\n" * (self.context_depth - 1),
anchor="w", justify="left",
font=self.textfont,
bg=self.bgcolor, fg=self.fgcolor,
@ -77,6 +77,7 @@ class CodeContext:
If the line does not start a block, the keyword value is False.
The indentation of empty lines (or comment lines) is INFINITY.
"""
text = self.text.get("%d.0" % linenum, "%d.end" % linenum)
spaces, firstword = getspacesfirstword(text)
@ -87,64 +88,69 @@ class CodeContext:
indent = len(spaces)
return indent, text, opener
def interesting_lines(self, firstline, stopline=1, stopindent=0):
"""
Find the context lines, starting at firstline.
Will not return lines whose index is smaller than stopline or whose
indentation is smaller than stopindent.
stopline should always be >= 1, so the dummy block start will never
be returned (This function doesn't know what to do about it.)
Returns a list with the context lines, starting from the first (top),
and a number which all context lines above the inspected region should
have a smaller indentation than it.
def get_context(self, new_topvisible, stopline=1, stopindent=0):
"""Get context lines, starting at new_topvisible and working backwards.
Stop when stopline or stopindent is reached. Return a tuple of context
data and the indent level at the top of the region inspected.
"""
assert stopline > 0
lines = []
# The indentation level we are currently in:
lastindent = INFINITY
# For a line to be interesting, it must begin with a block opening
# keyword, and have less indentation than lastindent.
for line_index in xrange(firstline, stopline-1, -1):
indent, text, opener = self.get_line_info(line_index)
for linenum in xrange(new_topvisible, stopline-1, -1):
indent, text, opener = self.get_line_info(linenum)
if indent < lastindent:
lastindent = indent
if opener in ("else", "elif"):
# We also show the if statement
lastindent += 1
if opener and line_index < firstline and indent >= stopindent:
lines.append((line_index, indent, text, opener))
if opener and linenum < new_topvisible and indent >= stopindent:
lines.append((linenum, indent, text, opener))
if lastindent <= stopindent:
break
lines.reverse()
return lines, lastindent
def update_label(self):
"""Update the CodeContext label, if needed.
def update_code_context(self):
"""Update context information and lines visible in the context pane.
"""
firstline = int(self.text.index("@0,0").split('.')[0])
if self.lastfirstline == firstline:
new_topvisible = int(self.text.index("@0,0").split('.')[0])
if self.topvisible == new_topvisible: # haven't scrolled
return
if self.lastfirstline < firstline:
lines, lastindent = self.interesting_lines(firstline,
self.lastfirstline)
if self.topvisible < new_topvisible: # scroll down
lines, lastindent = self.get_context(new_topvisible,
self.topvisible)
# retain only context info applicable to the region
# between topvisible and new_topvisible:
while self.info[-1][1] >= lastindent:
del self.info[-1]
self.info.extend(lines)
else:
elif self.topvisible > new_topvisible: # scroll up
stopindent = self.info[-1][1] + 1
while self.info[-1][0] >= firstline:
# retain only context info associated
# with lines above new_topvisible:
while self.info[-1][0] >= new_topvisible:
stopindent = self.info[-1][1]
del self.info[-1]
lines, lastindent = self.interesting_lines(
firstline, self.info[-1][0]+1, stopindent)
self.info.extend(lines)
self.lastfirstline = firstline
lines = [""] * max(0, self.numlines - len(self.info)) + \
[x[2] for x in self.info[-self.numlines:]]
self.label["text"] = '\n'.join(lines)
lines, lastindent = self.get_context(new_topvisible,
self.info[-1][0]+1,
stopindent)
self.info.extend(lines)
self.topvisible = new_topvisible
# empty lines in context pane:
context_strings = [""] * max(0, self.context_depth - len(self.info))
# followed by the context hint lines:
context_strings += [x[2] for x in self.info[-self.context_depth:]]
self.label["text"] = '\n'.join(context_strings)
def timer_event(self):
if self.label:
self.update_label()
self.update_code_context()
self.text.after(UPDATEINTERVAL, self.timer_event)
def font_timer_event(self):