bpo-33679: IDLE: Re-enable color configuration for code context (GH-7199)
The difference from before is that the settings are now on the
Highlights tab instead of the Extensions tab and only change one theme
at a time instead of all themes. The default for light themes is black
on light gray, as before. The default for the IDLE Dark theme is white
on dark gray, which better fits the dark theme.
When one starts IDLE from a console and loads a custom theme without
definitions for 'context', one will see a warning message on the console.
To stop the warning, go to Options => Configure IDLE => Highlights,
select the custom theme if not selected already, select 'Code Context',
and select foreground and background colors.
(cherry picked from commit de6516264e
)
Co-authored-by: Cheryl Sabella <cheryl.sabella@gmail.com>
This commit is contained in:
parent
a42fe3c67c
commit
dd851d6019
|
@ -20,7 +20,7 @@ from idlelib.config import idleConf
|
||||||
BLOCKOPENERS = {"class", "def", "elif", "else", "except", "finally", "for",
|
BLOCKOPENERS = {"class", "def", "elif", "else", "except", "finally", "for",
|
||||||
"if", "try", "while", "with", "async"}
|
"if", "try", "while", "with", "async"}
|
||||||
UPDATEINTERVAL = 100 # millisec
|
UPDATEINTERVAL = 100 # millisec
|
||||||
FONTUPDATEINTERVAL = 1000 # millisec
|
CONFIGUPDATEINTERVAL = 1000 # millisec
|
||||||
|
|
||||||
|
|
||||||
def get_spaces_firstword(codeline, c=re.compile(r"^(\s*)(\w*)")):
|
def get_spaces_firstword(codeline, c=re.compile(r"^(\s*)(\w*)")):
|
||||||
|
@ -45,9 +45,6 @@ def get_line_info(codeline):
|
||||||
class CodeContext:
|
class CodeContext:
|
||||||
"Display block context above the edit window."
|
"Display block context above the edit window."
|
||||||
|
|
||||||
bgcolor = "LightGray"
|
|
||||||
fgcolor = "Black"
|
|
||||||
|
|
||||||
def __init__(self, editwin):
|
def __init__(self, editwin):
|
||||||
"""Initialize settings for context block.
|
"""Initialize settings for context block.
|
||||||
|
|
||||||
|
@ -69,22 +66,20 @@ class CodeContext:
|
||||||
self.editwin = editwin
|
self.editwin = editwin
|
||||||
self.text = editwin.text
|
self.text = editwin.text
|
||||||
self.textfont = self.text["font"]
|
self.textfont = self.text["font"]
|
||||||
|
self.contextcolors = CodeContext.colors
|
||||||
self.label = None
|
self.label = None
|
||||||
self.topvisible = 1
|
self.topvisible = 1
|
||||||
self.info = [(0, -1, "", False)]
|
self.info = [(0, -1, "", False)]
|
||||||
# Start two update cycles, one for context lines, one for font changes.
|
# Start two update cycles, one for context lines, one for font changes.
|
||||||
self.t1 = self.text.after(UPDATEINTERVAL, self.timer_event)
|
self.t1 = self.text.after(UPDATEINTERVAL, self.timer_event)
|
||||||
self.t2 = self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)
|
self.t2 = self.text.after(CONFIGUPDATEINTERVAL, self.config_timer_event)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def reload(cls):
|
def reload(cls):
|
||||||
"Load class variables from config."
|
"Load class variables from config."
|
||||||
cls.context_depth = idleConf.GetOption("extensions", "CodeContext",
|
cls.context_depth = idleConf.GetOption("extensions", "CodeContext",
|
||||||
"maxlines", type="int", default=15)
|
"maxlines", type="int", default=15)
|
||||||
## cls.bgcolor = idleConf.GetOption("extensions", "CodeContext",
|
cls.colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'context')
|
||||||
## "bgcolor", type="str", default="LightGray")
|
|
||||||
## cls.fgcolor = idleConf.GetOption("extensions", "CodeContext",
|
|
||||||
## "fgcolor", type="str", default="Black")
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"Cancel scheduled events."
|
"Cancel scheduled events."
|
||||||
|
@ -118,7 +113,8 @@ class CodeContext:
|
||||||
self.label = tkinter.Label(
|
self.label = tkinter.Label(
|
||||||
self.editwin.top, text="",
|
self.editwin.top, text="",
|
||||||
anchor=W, justify=LEFT, font=self.textfont,
|
anchor=W, justify=LEFT, font=self.textfont,
|
||||||
bg=self.bgcolor, fg=self.fgcolor,
|
bg=self.contextcolors['background'],
|
||||||
|
fg=self.contextcolors['foreground'],
|
||||||
width=1, # Don't request more than we get.
|
width=1, # Don't request more than we get.
|
||||||
padx=padx, border=border, relief=SUNKEN)
|
padx=padx, border=border, relief=SUNKEN)
|
||||||
# Pack the label widget before and above the text_frame widget,
|
# Pack the label widget before and above the text_frame widget,
|
||||||
|
@ -202,13 +198,17 @@ class CodeContext:
|
||||||
self.update_code_context()
|
self.update_code_context()
|
||||||
self.t1 = self.text.after(UPDATEINTERVAL, self.timer_event)
|
self.t1 = self.text.after(UPDATEINTERVAL, self.timer_event)
|
||||||
|
|
||||||
def font_timer_event(self):
|
def config_timer_event(self):
|
||||||
"Event on editor text widget triggered every FONTUPDATEINTERVAL ms."
|
"Event on editor text widget triggered every CONFIGUPDATEINTERVAL ms."
|
||||||
newtextfont = self.text["font"]
|
newtextfont = self.text["font"]
|
||||||
if self.label and newtextfont != self.textfont:
|
if (self.label and (newtextfont != self.textfont or
|
||||||
|
CodeContext.colors != self.contextcolors)):
|
||||||
self.textfont = newtextfont
|
self.textfont = newtextfont
|
||||||
|
self.contextcolors = CodeContext.colors
|
||||||
self.label["font"] = self.textfont
|
self.label["font"] = self.textfont
|
||||||
self.t2 = self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)
|
self.label['background'] = self.contextcolors['background']
|
||||||
|
self.label['foreground'] = self.contextcolors['foreground']
|
||||||
|
self.t2 = self.text.after(CONFIGUPDATEINTERVAL, self.config_timer_event)
|
||||||
|
|
||||||
|
|
||||||
CodeContext.reload()
|
CodeContext.reload()
|
||||||
|
|
|
@ -31,6 +31,8 @@ stderr-foreground= red
|
||||||
stderr-background= #ffffff
|
stderr-background= #ffffff
|
||||||
console-foreground= #770000
|
console-foreground= #770000
|
||||||
console-background= #ffffff
|
console-background= #ffffff
|
||||||
|
context-foreground= #000000
|
||||||
|
context-background= lightgray
|
||||||
|
|
||||||
[IDLE New]
|
[IDLE New]
|
||||||
normal-foreground= #000000
|
normal-foreground= #000000
|
||||||
|
@ -62,6 +64,8 @@ stderr-foreground= red
|
||||||
stderr-background= #ffffff
|
stderr-background= #ffffff
|
||||||
console-foreground= #770000
|
console-foreground= #770000
|
||||||
console-background= #ffffff
|
console-background= #ffffff
|
||||||
|
context-foreground= #000000
|
||||||
|
context-background= lightgray
|
||||||
|
|
||||||
[IDLE Dark]
|
[IDLE Dark]
|
||||||
comment-foreground = #dd0000
|
comment-foreground = #dd0000
|
||||||
|
@ -91,3 +95,5 @@ stdout-background = #002240
|
||||||
hit-foreground = #002240
|
hit-foreground = #002240
|
||||||
comment-background = #002240
|
comment-background = #002240
|
||||||
break-foreground = #FFFFFF
|
break-foreground = #FFFFFF
|
||||||
|
context-foreground= #ffffff
|
||||||
|
context-background= #454545
|
||||||
|
|
|
@ -360,6 +360,8 @@ class IdleConf:
|
||||||
'stderr-background':'#ffffff',
|
'stderr-background':'#ffffff',
|
||||||
'console-foreground':'#000000',
|
'console-foreground':'#000000',
|
||||||
'console-background':'#ffffff',
|
'console-background':'#ffffff',
|
||||||
|
'context-foreground':'#000000',
|
||||||
|
'context-background':'#ffffff',
|
||||||
}
|
}
|
||||||
for element in theme:
|
for element in theme:
|
||||||
if not cfgParser.has_option(themeName, element):
|
if not cfgParser.has_option(themeName, element):
|
||||||
|
|
|
@ -799,19 +799,20 @@ class HighPage(Frame):
|
||||||
"""
|
"""
|
||||||
self.theme_elements = {
|
self.theme_elements = {
|
||||||
'Normal Text': ('normal', '00'),
|
'Normal Text': ('normal', '00'),
|
||||||
'Python Keywords': ('keyword', '01'),
|
'Code Context': ('context', '01'),
|
||||||
'Python Definitions': ('definition', '02'),
|
'Python Keywords': ('keyword', '02'),
|
||||||
'Python Builtins': ('builtin', '03'),
|
'Python Definitions': ('definition', '03'),
|
||||||
'Python Comments': ('comment', '04'),
|
'Python Builtins': ('builtin', '04'),
|
||||||
'Python Strings': ('string', '05'),
|
'Python Comments': ('comment', '05'),
|
||||||
'Selected Text': ('hilite', '06'),
|
'Python Strings': ('string', '06'),
|
||||||
'Found Text': ('hit', '07'),
|
'Selected Text': ('hilite', '07'),
|
||||||
'Cursor': ('cursor', '08'),
|
'Found Text': ('hit', '08'),
|
||||||
'Editor Breakpoint': ('break', '09'),
|
'Cursor': ('cursor', '09'),
|
||||||
'Shell Normal Text': ('console', '10'),
|
'Editor Breakpoint': ('break', '10'),
|
||||||
'Shell Error Text': ('error', '11'),
|
'Shell Normal Text': ('console', '11'),
|
||||||
'Shell Stdout Text': ('stdout', '12'),
|
'Shell Error Text': ('error', '12'),
|
||||||
'Shell Stderr Text': ('stderr', '13'),
|
'Shell Stdout Text': ('stdout', '13'),
|
||||||
|
'Shell Stderr Text': ('stderr', '14'),
|
||||||
}
|
}
|
||||||
self.builtin_name = tracers.add(
|
self.builtin_name = tracers.add(
|
||||||
StringVar(self), self.var_changed_builtin_name)
|
StringVar(self), self.var_changed_builtin_name)
|
||||||
|
@ -842,6 +843,7 @@ class HighPage(Frame):
|
||||||
('\n', 'normal'),
|
('\n', 'normal'),
|
||||||
('#you can click here', 'comment'), ('\n', 'normal'),
|
('#you can click here', 'comment'), ('\n', 'normal'),
|
||||||
('#to choose items', 'comment'), ('\n', 'normal'),
|
('#to choose items', 'comment'), ('\n', 'normal'),
|
||||||
|
('code context section', 'context'), ('\n\n', 'normal'),
|
||||||
('def', 'keyword'), (' ', 'normal'),
|
('def', 'keyword'), (' ', 'normal'),
|
||||||
('func', 'definition'), ('(param):\n ', 'normal'),
|
('func', 'definition'), ('(param):\n ', 'normal'),
|
||||||
('"""string"""', 'string'), ('\n var0 = ', 'normal'),
|
('"""string"""', 'string'), ('\n var0 = ', 'normal'),
|
||||||
|
|
|
@ -110,6 +110,8 @@ class CodeContextTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_reload(self):
|
def test_reload(self):
|
||||||
codecontext.CodeContext.reload()
|
codecontext.CodeContext.reload()
|
||||||
|
self.assertEqual(self.cc.colors, {'background': 'lightgray',
|
||||||
|
'foreground': '#000000'})
|
||||||
self.assertEqual(self.cc.context_depth, 15)
|
self.assertEqual(self.cc.context_depth, 15)
|
||||||
|
|
||||||
def test_toggle_code_context_event(self):
|
def test_toggle_code_context_event(self):
|
||||||
|
@ -125,8 +127,8 @@ class CodeContextTest(unittest.TestCase):
|
||||||
eq(toggle(), 'break')
|
eq(toggle(), 'break')
|
||||||
self.assertIsNotNone(cc.label)
|
self.assertIsNotNone(cc.label)
|
||||||
eq(cc.label['font'], cc.textfont)
|
eq(cc.label['font'], cc.textfont)
|
||||||
eq(cc.label['fg'], cc.fgcolor)
|
eq(cc.label['fg'], cc.colors['foreground'])
|
||||||
eq(cc.label['bg'], cc.bgcolor)
|
eq(cc.label['bg'], cc.colors['background'])
|
||||||
eq(cc.label['text'], '')
|
eq(cc.label['text'], '')
|
||||||
|
|
||||||
# Toggle off.
|
# Toggle off.
|
||||||
|
@ -275,11 +277,13 @@ class CodeContextTest(unittest.TestCase):
|
||||||
self.cc.timer_event()
|
self.cc.timer_event()
|
||||||
mock_update.assert_called()
|
mock_update.assert_called()
|
||||||
|
|
||||||
def test_font_timer_event(self):
|
def test_config_timer_event(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
cc = self.cc
|
cc = self.cc
|
||||||
save_font = cc.text['font']
|
save_font = cc.text['font']
|
||||||
|
save_colors = codecontext.CodeContext.colors
|
||||||
test_font = 'FakeFont'
|
test_font = 'FakeFont'
|
||||||
|
test_colors = {'background': '#222222', 'foreground': '#ffff00'}
|
||||||
|
|
||||||
# Ensure code context is not active.
|
# Ensure code context is not active.
|
||||||
if cc.label:
|
if cc.label:
|
||||||
|
@ -287,24 +291,42 @@ class CodeContextTest(unittest.TestCase):
|
||||||
|
|
||||||
# Nothing updates on inactive code context.
|
# Nothing updates on inactive code context.
|
||||||
cc.text['font'] = test_font
|
cc.text['font'] = test_font
|
||||||
cc.font_timer_event()
|
codecontext.CodeContext.colors = test_colors
|
||||||
|
cc.config_timer_event()
|
||||||
eq(cc.textfont, save_font)
|
eq(cc.textfont, save_font)
|
||||||
|
eq(cc.contextcolors, save_colors)
|
||||||
|
|
||||||
# Activate code context, but no change to font.
|
# Activate code context, but no change to font or color.
|
||||||
cc.toggle_code_context_event()
|
cc.toggle_code_context_event()
|
||||||
cc.text['font'] = save_font
|
cc.text['font'] = save_font
|
||||||
cc.font_timer_event()
|
codecontext.CodeContext.colors = save_colors
|
||||||
|
cc.config_timer_event()
|
||||||
eq(cc.textfont, save_font)
|
eq(cc.textfont, save_font)
|
||||||
|
eq(cc.contextcolors, save_colors)
|
||||||
eq(cc.label['font'], save_font)
|
eq(cc.label['font'], save_font)
|
||||||
|
eq(cc.label['background'], save_colors['background'])
|
||||||
|
eq(cc.label['foreground'], save_colors['foreground'])
|
||||||
|
|
||||||
# Active code context, change font.
|
# Active code context, change font.
|
||||||
cc.text['font'] = test_font
|
cc.text['font'] = test_font
|
||||||
cc.font_timer_event()
|
cc.config_timer_event()
|
||||||
eq(cc.textfont, test_font)
|
eq(cc.textfont, test_font)
|
||||||
|
eq(cc.contextcolors, save_colors)
|
||||||
eq(cc.label['font'], test_font)
|
eq(cc.label['font'], test_font)
|
||||||
|
eq(cc.label['background'], save_colors['background'])
|
||||||
|
eq(cc.label['foreground'], save_colors['foreground'])
|
||||||
|
|
||||||
|
# Active code context, change color.
|
||||||
cc.text['font'] = save_font
|
cc.text['font'] = save_font
|
||||||
cc.font_timer_event()
|
codecontext.CodeContext.colors = test_colors
|
||||||
|
cc.config_timer_event()
|
||||||
|
eq(cc.textfont, save_font)
|
||||||
|
eq(cc.contextcolors, test_colors)
|
||||||
|
eq(cc.label['font'], save_font)
|
||||||
|
eq(cc.label['background'], test_colors['background'])
|
||||||
|
eq(cc.label['foreground'], test_colors['foreground'])
|
||||||
|
codecontext.CodeContext.colors = save_colors
|
||||||
|
cc.config_timer_event()
|
||||||
|
|
||||||
|
|
||||||
class HelperFunctionText(unittest.TestCase):
|
class HelperFunctionText(unittest.TestCase):
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
IDLE: Re-enable color configuration for Code Context.
|
||||||
|
The difference from before is that the settings are now on the
|
||||||
|
Highlights tab instead of the Extensions tab and only change one theme
|
||||||
|
at a time instead of all themes. The default for light themes is black
|
||||||
|
on light gray, as before. The default for the IDLE Dark theme is white
|
||||||
|
on dark gray, which better fits the dark theme.
|
||||||
|
|
||||||
|
When one starts IDLE from a console and loads a custom theme without
|
||||||
|
definitions for 'context', one will see a warning message on the console.
|
||||||
|
To stop the warning, go to Options => Configure IDLE => Highlights,
|
||||||
|
select the custom theme if not selected already, select 'Code Context',
|
||||||
|
and select foreground and background colors.
|
Loading…
Reference in New Issue