Skip to content

Commit

Permalink
bpo-35689: IDLE: Add docstrings and unittests for colorizer.py (GH-11472
Browse files Browse the repository at this point in the history
)

(cherry picked from commit ee0f927)

Co-authored-by: Cheryl Sabella <cheryl.sabella@gmail.com>
  • Loading branch information
miss-islington and csabella committed Feb 19, 2019
1 parent 3129432 commit 99e9c36
Show file tree
Hide file tree
Showing 4 changed files with 408 additions and 16 deletions.
2 changes: 2 additions & 0 deletions Lib/idlelib/NEWS.txt
Expand Up @@ -3,6 +3,8 @@ Released on 2019-??-??
======================================


bpo-35689: Add docstrings and tests for colorizer.

bpo-35833: Revise IDLE doc for control codes sent to Shell.
Add a code example block.

Expand Down
63 changes: 57 additions & 6 deletions Lib/idlelib/colorizer.py
Expand Up @@ -53,6 +53,21 @@ def color_config(text):


class ColorDelegator(Delegator):
"""Delegator for syntax highlighting (text coloring).
Class variables:
after_id: Identifier for scheduled after event.
allow_colorizing: Boolean toggle for applying colorizing.
colorizing: Boolean flag when colorizing is in process.
stop_colorizing: Boolean flag to end an active colorizing
process.
close_when_done: Widget to destroy after colorizing process
completes (doesn't seem to be used by IDLE).
Instance variables:
delegate: Delegator below this one in the stack, meaning the
one this one delegates to.
"""

def __init__(self):
Delegator.__init__(self)
Expand All @@ -61,6 +76,16 @@ def __init__(self):
self.LoadTagDefs()

def setdelegate(self, delegate):
"""Set the delegate for this instance.
A delegate is an instance of a Delegator class and each
delegate points to the next delegator in the stack. This
allows multiple delegators to be chained together for a
widget. The bottom delegate for a colorizer is a Text
widget.
If there is a delegate, also start the colorizing process.
"""
if self.delegate is not None:
self.unbind("<<toggle-auto-coloring>>")
Delegator.setdelegate(self, delegate)
Expand All @@ -69,17 +94,18 @@ def setdelegate(self, delegate):
self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
self.notify_range("1.0", "end")
else:
# No delegate - stop any colorizing
# No delegate - stop any colorizing.
self.stop_colorizing = True
self.allow_colorizing = False

def config_colors(self):
"Configure text widget tags with colors from tagdefs."
for tag, cnf in self.tagdefs.items():
if cnf:
self.tag_configure(tag, **cnf)
self.tag_configure(tag, **cnf)
self.tag_raise('sel')

def LoadTagDefs(self):
"Create dictionary of tag names to text colors."
theme = idleConf.CurrentTheme()
self.tagdefs = {
"COMMENT": idleConf.GetHighlight(theme, "comment"),
Expand All @@ -97,20 +123,24 @@ def LoadTagDefs(self):
if DEBUG: print('tagdefs',self.tagdefs)

def insert(self, index, chars, tags=None):
"Insert chars into widget at index and mark for colorizing."
index = self.index(index)
self.delegate.insert(index, chars, tags)
self.notify_range(index, index + "+%dc" % len(chars))

def delete(self, index1, index2=None):
"Delete chars between indexes and mark for colorizing."
index1 = self.index(index1)
self.delegate.delete(index1, index2)
self.notify_range(index1)

after_id = None
allow_colorizing = True
stop_colorizing = False
colorizing = False

def notify_range(self, index1, index2=None):
"Mark text changes for processing and restart colorizing, if active."
self.tag_add("TODO", index1, index2)
if self.after_id:
if DEBUG: print("colorizing already scheduled")
Expand All @@ -121,8 +151,9 @@ def notify_range(self, index1, index2=None):
if self.allow_colorizing:
if DEBUG: print("schedule colorizing")
self.after_id = self.after(1, self.recolorize)
return

close_when_done = None # Window to be closed when done colorizing
close_when_done = None # Window to be closed when done colorizing.

def close(self, close_when_done=None):
if self.after_id:
Expand All @@ -138,7 +169,14 @@ def close(self, close_when_done=None):
else:
self.close_when_done = close_when_done

def toggle_colorize_event(self, event):
def toggle_colorize_event(self, event=None):
"""Toggle colorizing on and off.
When toggling off, if colorizing is scheduled or is in
process, it will be cancelled and/or stopped.
When toggling on, colorizing will be scheduled.
"""
if self.after_id:
after_id = self.after_id
self.after_id = None
Expand All @@ -156,6 +194,17 @@ def toggle_colorize_event(self, event):
return "break"

def recolorize(self):
"""Timer event (every 1ms) to colorize text.
Colorizing is only attempted when the text widget exists,
when colorizing is toggled on, and when the colorizing
process is not already running.
After colorizing is complete, some cleanup is done to
make sure that all the text has been colorized and to close
the window if the close event had been called while the
process was running.
"""
self.after_id = None
if not self.delegate:
if DEBUG: print("no delegate")
Expand Down Expand Up @@ -185,6 +234,7 @@ def recolorize(self):
top.destroy()

def recolorize_main(self):
"Evaluate text and apply colorizing tags."
next = "1.0"
while True:
item = self.tag_nextrange("TODO", next)
Expand Down Expand Up @@ -250,6 +300,7 @@ def recolorize_main(self):
return

def removecolors(self):
"Remove all colorizing tags."
for tag in self.tagdefs:
self.tag_remove(tag, "1.0", "end")

Expand All @@ -273,7 +324,7 @@ def _color_delegator(parent): # htest #
"'x', '''x''', \"x\", \"\"\"x\"\"\"\n"
"r'x', u'x', R'x', U'x', f'x', F'x'\n"
"fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n"
"b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n"
"b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x', rB'x',Rb'x',RB'x'\n"
"# Invalid combinations of legal characters should be half colored.\n"
"ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'\n"
)
Expand Down

0 comments on commit 99e9c36

Please sign in to comment.