bpo-33642: IDLE: Use variable number of lines in CodeContext. (GH-7106)

Instead of displaying a fixed number of lines, some blank, Code Context
now displays the variable number of actual context lines.  When there
are no context lines, it shows a single blank line to indicate that the
feature is turned on.

The Code Context configuration option is changed from 'numlines'
(default 3) to 'maxlines' (default 15) to avoid possible interference
between user settings for the old and new versions of Code Context.
This commit is contained in:
Cheryl Sabella 2018-06-01 19:23:00 -04:00 committed by Terry Jan Reedy
parent 6854e803b7
commit 29996a1c4e
6 changed files with 40 additions and 29 deletions

View File

@ -4,7 +4,7 @@ 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
enclosing block. The number of hint lines is determined by the maxlines
variable in the codecontext section of config-extensions.def. Lines which do
not open blocks are not shown in the context hints pane.
@ -80,7 +80,7 @@ class CodeContext:
def reload(cls):
"Load class variables from config."
cls.context_depth = idleConf.GetOption("extensions", "CodeContext",
"numlines", type="int", default=3)
"maxlines", type="int", default=15)
## cls.bgcolor = idleConf.GetOption("extensions", "CodeContext",
## "bgcolor", type="str", default="LightGray")
## cls.fgcolor = idleConf.GetOption("extensions", "CodeContext",
@ -116,7 +116,7 @@ class CodeContext:
padx += widget.tk.getint(widget.cget('padx'))
border += widget.tk.getint(widget.cget('border'))
self.label = tkinter.Label(
self.editwin.top, text="\n" * (self.context_depth - 1),
self.editwin.top, text="",
anchor=W, justify=LEFT, font=self.textfont,
bg=self.bgcolor, fg=self.fgcolor,
width=1, # Don't request more than we get.
@ -191,11 +191,10 @@ class CodeContext:
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)
# Last context_depth context lines.
context_strings = [x[2] for x in self.info[-self.context_depth:]]
showfirst = 0 if context_strings[0] else 1
self.label["text"] = '\n'.join(context_strings[showfirst:])
def timer_event(self):
"Event on editor text widget triggered every UPDATEINTERVAL ms."

View File

@ -7,10 +7,7 @@
popupwait= 2000
[CodeContext]
numlines= 3
visible= False
bgcolor= LightGray
fgcolor= Black
maxlines= 15
[FormatParagraph]
max-width= 72

View File

@ -1843,7 +1843,7 @@ class GenPage(Frame):
self.format_width = tracers.add(
StringVar(self), ('extensions', 'FormatParagraph', 'max-width'))
self.context_lines = tracers.add(
StringVar(self), ('extensions', 'CodeContext', 'numlines'))
StringVar(self), ('extensions', 'CodeContext', 'maxlines'))
# Create widgets:
# Section frames.
@ -1910,7 +1910,7 @@ class GenPage(Frame):
frame_format, textvariable=self.format_width, width=4)
frame_context = Frame(frame_editor, borderwidth=0)
context_title = Label(frame_context, text='Context Lines :')
context_title = Label(frame_context, text='Max Context Lines :')
self.context_int = Entry(
frame_context, textvariable=self.context_lines, width=3)
@ -2012,7 +2012,7 @@ class GenPage(Frame):
self.format_width.set(idleConf.GetOption(
'extensions', 'FormatParagraph', 'max-width', type='int'))
self.context_lines.set(idleConf.GetOption(
'extensions', 'CodeContext', 'numlines', type='int'))
'extensions', 'CodeContext', 'maxlines', type='int'))
# Set additional help sources.
self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
@ -2204,6 +2204,9 @@ ParenMatch: Style indicates what is highlighted when closer is entered:
'opener' - opener '({[' corresponding to closer; 'parens' - both chars;
'expression' (default) - also everything in between. Flash-delay is how
long to highlight if cursor is not moved (0 means forever).
CodeContext: Maxlines is the maximum number of code context lines to
display when Code Context is turned on for an editor window.
'''
}

View File

@ -110,7 +110,7 @@ class CodeContextTest(unittest.TestCase):
def test_reload(self):
codecontext.CodeContext.reload()
self.assertEqual(self.cc.context_depth, 3)
self.assertEqual(self.cc.context_depth, 15)
def test_toggle_code_context_event(self):
eq = self.assertEqual
@ -127,7 +127,7 @@ class CodeContextTest(unittest.TestCase):
eq(cc.label['font'], cc.textfont)
eq(cc.label['fg'], cc.fgcolor)
eq(cc.label['bg'], cc.bgcolor)
eq(cc.label['text'], '\n' * 2)
eq(cc.label['text'], '')
# Toggle off.
eq(toggle(), 'break')
@ -193,24 +193,26 @@ class CodeContextTest(unittest.TestCase):
eq(cc.info, [(0, -1, '', False)])
eq(cc.topvisible, 1)
# Scroll down to line 1.
cc.text.yview(1)
cc.update_code_context()
eq(cc.info, [(0, -1, '', False)])
eq(cc.topvisible, 2)
eq(cc.label['text'], '')
# Scroll down to line 2.
cc.text.yview(2)
cc.update_code_context()
eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
eq(cc.topvisible, 3)
# context_depth is 3 so it pads with blank lines.
eq(cc.label['text'], '\n'
'\n'
'class C1():')
eq(cc.label['text'], 'class C1():')
# Scroll down to line 3. Since it's a comment, nothing changes.
cc.text.yview(3)
cc.update_code_context()
eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
eq(cc.topvisible, 4)
eq(cc.label['text'], '\n'
'\n'
'class C1():')
eq(cc.label['text'], 'class C1():')
# Scroll down to line 4.
cc.text.yview(4)
@ -219,8 +221,7 @@ class CodeContextTest(unittest.TestCase):
(2, 0, 'class C1():', 'class'),
(4, 4, ' def __init__(self, a, b):', 'def')])
eq(cc.topvisible, 5)
eq(cc.label['text'], '\n'
'class C1():\n'
eq(cc.label['text'], 'class C1():\n'
' def __init__(self, a, b):')
# Scroll down to line 11. Last 'def' is removed.
@ -232,7 +233,8 @@ class CodeContextTest(unittest.TestCase):
(8, 8, ' if a > b:', 'if'),
(10, 8, ' elif a < b:', 'elif')])
eq(cc.topvisible, 12)
eq(cc.label['text'], ' def compare(self):\n'
eq(cc.label['text'], 'class C1():\n'
' def compare(self):\n'
' if a > b:\n'
' elif a < b:')
@ -245,7 +247,8 @@ class CodeContextTest(unittest.TestCase):
(8, 8, ' if a > b:', 'if'),
(10, 8, ' elif a < b:', 'elif')])
eq(cc.topvisible, 12)
eq(cc.label['text'], ' def compare(self):\n'
eq(cc.label['text'], 'class C1():\n'
' def compare(self):\n'
' if a > b:\n'
' elif a < b:')

View File

@ -1170,7 +1170,7 @@ class GenPageTest(unittest.TestCase):
def test_context(self):
self.page.context_int.delete(0, 'end')
self.page.context_int.insert(0, '1')
self.assertEqual(extpage, {'CodeContext': {'numlines': '1'}})
self.assertEqual(extpage, {'CodeContext': {'maxlines': '1'}})
def test_source_selected(self):
d = self.page

View File

@ -0,0 +1,9 @@
IDLE: Only display actual code context lines.
Instead of displaying a fixed number of lines, some blank, Code Context
now displays the variable number of actual context lines. When there
are no context lines, it shows a single blank line to indicate that the
feature is turned on.
The Code Context configuration option is changed from 'numlines'
(default 3) to 'maxlines' (default 15) to avoid possible interference
between user settings for the old and new versions of Code Context.