mirror of
https://github.com/python/cpython.git
synced 2025-10-21 17:04:17 +00:00

in the stdlib and changed each of them to use "open" instead. At this time there are no other known occurrences that can be safely changed (in Lib and all subdirectories thereof).
263 lines
9.9 KiB
Python
263 lines
9.9 KiB
Python
import time
|
|
import re
|
|
import keyword
|
|
import __builtin__
|
|
from Tkinter import *
|
|
from Delegator import Delegator
|
|
from configHandler import idleConf
|
|
|
|
DEBUG = False
|
|
|
|
def any(name, alternates):
|
|
"Return a named group pattern matching list of alternates."
|
|
return "(?P<%s>" % name + "|".join(alternates) + ")"
|
|
|
|
def make_pat():
|
|
kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
|
|
builtinlist = [str(name) for name in dir(__builtin__)
|
|
if not name.startswith('_')]
|
|
# self.file = open("file") :
|
|
# 1st 'file' colorized normal, 2nd as builtin, 3rd as string
|
|
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
|
|
comment = any("COMMENT", [r"#[^\n]*"])
|
|
sqstring = r"(\b[rRuU])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
|
|
dqstring = r'(\b[rRuU])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
|
|
sq3string = r"(\b[rRuU])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
|
|
dq3string = r'(\b[rRuU])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
|
|
string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
|
|
return kw + "|" + builtin + "|" + comment + "|" + string +\
|
|
"|" + any("SYNC", [r"\n"])
|
|
|
|
prog = re.compile(make_pat(), re.S)
|
|
idprog = re.compile(r"\s+(\w+)", re.S)
|
|
asprog = re.compile(r".*?\b(as)\b")
|
|
|
|
class ColorDelegator(Delegator):
|
|
|
|
def __init__(self):
|
|
Delegator.__init__(self)
|
|
self.prog = prog
|
|
self.idprog = idprog
|
|
self.asprog = asprog
|
|
self.LoadTagDefs()
|
|
|
|
def setdelegate(self, delegate):
|
|
if self.delegate is not None:
|
|
self.unbind("<<toggle-auto-coloring>>")
|
|
Delegator.setdelegate(self, delegate)
|
|
if delegate is not None:
|
|
self.config_colors()
|
|
self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
|
|
self.notify_range("1.0", "end")
|
|
|
|
def config_colors(self):
|
|
for tag, cnf in self.tagdefs.items():
|
|
if cnf:
|
|
self.tag_configure(tag, **cnf)
|
|
self.tag_raise('sel')
|
|
|
|
def LoadTagDefs(self):
|
|
theme = idleConf.GetOption('main','Theme','name')
|
|
self.tagdefs = {
|
|
"COMMENT": idleConf.GetHighlight(theme, "comment"),
|
|
"KEYWORD": idleConf.GetHighlight(theme, "keyword"),
|
|
"BUILTIN": idleConf.GetHighlight(theme, "builtin"),
|
|
"STRING": idleConf.GetHighlight(theme, "string"),
|
|
"DEFINITION": idleConf.GetHighlight(theme, "definition"),
|
|
"SYNC": {'background':None,'foreground':None},
|
|
"TODO": {'background':None,'foreground':None},
|
|
"BREAK": idleConf.GetHighlight(theme, "break"),
|
|
"ERROR": idleConf.GetHighlight(theme, "error"),
|
|
# The following is used by ReplaceDialog:
|
|
"hit": idleConf.GetHighlight(theme, "hit"),
|
|
}
|
|
|
|
if DEBUG: print 'tagdefs',self.tagdefs
|
|
|
|
def insert(self, index, chars, tags=None):
|
|
index = self.index(index)
|
|
self.delegate.insert(index, chars, tags)
|
|
self.notify_range(index, index + "+%dc" % len(chars))
|
|
|
|
def delete(self, index1, index2=None):
|
|
index1 = self.index(index1)
|
|
self.delegate.delete(index1, index2)
|
|
self.notify_range(index1)
|
|
|
|
after_id = None
|
|
allow_colorizing = True
|
|
colorizing = False
|
|
|
|
def notify_range(self, index1, index2=None):
|
|
self.tag_add("TODO", index1, index2)
|
|
if self.after_id:
|
|
if DEBUG: print "colorizing already scheduled"
|
|
return
|
|
if self.colorizing:
|
|
self.stop_colorizing = True
|
|
if DEBUG: print "stop colorizing"
|
|
if self.allow_colorizing:
|
|
if DEBUG: print "schedule colorizing"
|
|
self.after_id = self.after(1, self.recolorize)
|
|
|
|
close_when_done = None # Window to be closed when done colorizing
|
|
|
|
def close(self, close_when_done=None):
|
|
if self.after_id:
|
|
after_id = self.after_id
|
|
self.after_id = None
|
|
if DEBUG: print "cancel scheduled recolorizer"
|
|
self.after_cancel(after_id)
|
|
self.allow_colorizing = False
|
|
self.stop_colorizing = True
|
|
if close_when_done:
|
|
if not self.colorizing:
|
|
close_when_done.destroy()
|
|
else:
|
|
self.close_when_done = close_when_done
|
|
|
|
def toggle_colorize_event(self, event):
|
|
if self.after_id:
|
|
after_id = self.after_id
|
|
self.after_id = None
|
|
if DEBUG: print "cancel scheduled recolorizer"
|
|
self.after_cancel(after_id)
|
|
if self.allow_colorizing and self.colorizing:
|
|
if DEBUG: print "stop colorizing"
|
|
self.stop_colorizing = True
|
|
self.allow_colorizing = not self.allow_colorizing
|
|
if self.allow_colorizing and not self.colorizing:
|
|
self.after_id = self.after(1, self.recolorize)
|
|
if DEBUG:
|
|
print "auto colorizing turned",\
|
|
self.allow_colorizing and "on" or "off"
|
|
return "break"
|
|
|
|
def recolorize(self):
|
|
self.after_id = None
|
|
if not self.delegate:
|
|
if DEBUG: print "no delegate"
|
|
return
|
|
if not self.allow_colorizing:
|
|
if DEBUG: print "auto colorizing is off"
|
|
return
|
|
if self.colorizing:
|
|
if DEBUG: print "already colorizing"
|
|
return
|
|
try:
|
|
self.stop_colorizing = False
|
|
self.colorizing = True
|
|
if DEBUG: print "colorizing..."
|
|
t0 = time.clock()
|
|
self.recolorize_main()
|
|
t1 = time.clock()
|
|
if DEBUG: print "%.3f seconds" % (t1-t0)
|
|
finally:
|
|
self.colorizing = False
|
|
if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
|
|
if DEBUG: print "reschedule colorizing"
|
|
self.after_id = self.after(1, self.recolorize)
|
|
if self.close_when_done:
|
|
top = self.close_when_done
|
|
self.close_when_done = None
|
|
top.destroy()
|
|
|
|
def recolorize_main(self):
|
|
next = "1.0"
|
|
while True:
|
|
item = self.tag_nextrange("TODO", next)
|
|
if not item:
|
|
break
|
|
head, tail = item
|
|
self.tag_remove("SYNC", head, tail)
|
|
item = self.tag_prevrange("SYNC", head)
|
|
if item:
|
|
head = item[1]
|
|
else:
|
|
head = "1.0"
|
|
|
|
chars = ""
|
|
next = head
|
|
lines_to_get = 1
|
|
ok = False
|
|
while not ok:
|
|
mark = next
|
|
next = self.index(mark + "+%d lines linestart" %
|
|
lines_to_get)
|
|
lines_to_get = min(lines_to_get * 2, 100)
|
|
ok = "SYNC" in self.tag_names(next + "-1c")
|
|
line = self.get(mark, next)
|
|
##print head, "get", mark, next, "->", repr(line)
|
|
if not line:
|
|
return
|
|
for tag in self.tagdefs.keys():
|
|
self.tag_remove(tag, mark, next)
|
|
chars = chars + line
|
|
m = self.prog.search(chars)
|
|
while m:
|
|
for key, value in m.groupdict().items():
|
|
if value:
|
|
a, b = m.span(key)
|
|
self.tag_add(key,
|
|
head + "+%dc" % a,
|
|
head + "+%dc" % b)
|
|
if value in ("def", "class"):
|
|
m1 = self.idprog.match(chars, b)
|
|
if m1:
|
|
a, b = m1.span(1)
|
|
self.tag_add("DEFINITION",
|
|
head + "+%dc" % a,
|
|
head + "+%dc" % b)
|
|
elif value == "import":
|
|
# color all the "as" words on same line, except
|
|
# if in a comment; cheap approximation to the
|
|
# truth
|
|
if '#' in chars:
|
|
endpos = chars.index('#')
|
|
else:
|
|
endpos = len(chars)
|
|
while True:
|
|
m1 = self.asprog.match(chars, b, endpos)
|
|
if not m1:
|
|
break
|
|
a, b = m1.span(1)
|
|
self.tag_add("KEYWORD",
|
|
head + "+%dc" % a,
|
|
head + "+%dc" % b)
|
|
m = self.prog.search(chars, m.end())
|
|
if "SYNC" in self.tag_names(next + "-1c"):
|
|
head = next
|
|
chars = ""
|
|
else:
|
|
ok = False
|
|
if not ok:
|
|
# We're in an inconsistent state, and the call to
|
|
# update may tell us to stop. It may also change
|
|
# the correct value for "next" (since this is a
|
|
# line.col string, not a true mark). So leave a
|
|
# crumb telling the next invocation to resume here
|
|
# in case update tells us to leave.
|
|
self.tag_add("TODO", next)
|
|
self.update()
|
|
if self.stop_colorizing:
|
|
if DEBUG: print "colorizing stopped"
|
|
return
|
|
|
|
def removecolors(self):
|
|
for tag in self.tagdefs.keys():
|
|
self.tag_remove(tag, "1.0", "end")
|
|
|
|
def main():
|
|
from Percolator import Percolator
|
|
root = Tk()
|
|
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
|
|
text = Text(background="white")
|
|
text.pack(expand=1, fill="both")
|
|
text.focus_set()
|
|
p = Percolator(text)
|
|
d = ColorDelegator()
|
|
p.insertfilter(d)
|
|
root.mainloop()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|