| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | import time | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import keyword | 
					
						
							|  |  |  | from Tkinter import * | 
					
						
							|  |  |  | from Delegator import Delegator | 
					
						
							| 
									
										
										
										
											2001-11-03 05:07:28 +00:00
										 |  |  | from configHandler import idleConf | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #$ event <<toggle-auto-coloring>> | 
					
						
							|  |  |  | #$ win <Control-slash> | 
					
						
							|  |  |  | #$ unix <Control-slash> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  | DEBUG = 0 | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def any(name, list): | 
					
						
							| 
									
										
										
										
											2002-09-15 22:09:16 +00:00
										 |  |  |     return "(?P<%s>" % name + "|".join(list) + ")" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def make_pat(): | 
					
						
							|  |  |  |     kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b" | 
					
						
							|  |  |  |     comment = any("COMMENT", [r"#[^\n]*"]) | 
					
						
							|  |  |  |     sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?" | 
					
						
							|  |  |  |     dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?' | 
					
						
							|  |  |  |     sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" | 
					
						
							|  |  |  |     dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?' | 
					
						
							|  |  |  |     string = any("STRING", [sq3string, dq3string, sqstring, dqstring]) | 
					
						
							|  |  |  |     return kw + "|" + comment + "|" + string + "|" + any("SYNC", [r"\n"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | prog = re.compile(make_pat(), re.S) | 
					
						
							|  |  |  | idprog = re.compile(r"\s+(\w+)", re.S) | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  | asprog = re.compile(r".*?\b(as)\b", re.S) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ColorDelegator(Delegator): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         Delegator.__init__(self) | 
					
						
							|  |  |  |         self.prog = prog | 
					
						
							|  |  |  |         self.idprog = idprog | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |         self.asprog = asprog | 
					
						
							| 
									
										
										
										
											2002-03-02 07:16:21 +00:00
										 |  |  |         self.LoadTagDefs() | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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: | 
					
						
							|  |  |  |                 apply(self.tag_configure, (tag,), cnf) | 
					
						
							|  |  |  |         self.tag_raise('sel') | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-02 07:16:21 +00:00
										 |  |  |     def LoadTagDefs(self): | 
					
						
							|  |  |  |         theme = idleConf.GetOption('main','Theme','name') | 
					
						
							|  |  |  |         self.tagdefs = { | 
					
						
							|  |  |  |             "COMMENT": idleConf.GetHighlight(theme, "comment"), | 
					
						
							|  |  |  |             "KEYWORD": idleConf.GetHighlight(theme, "keyword"), | 
					
						
							|  |  |  |             "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"), | 
					
						
							| 
									
										
										
										
											2002-12-17 21:16:12 +00:00
										 |  |  |             "ERROR": idleConf.GetHighlight(theme, "error"), | 
					
						
							| 
									
										
										
										
											2002-03-02 07:16:21 +00:00
										 |  |  |             # The following is used by ReplaceDialog: | 
					
						
							|  |  |  |             "hit": idleConf.GetHighlight(theme, "hit"), | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-03 14:54:25 +00:00
										 |  |  |     if DEBUG: print 'tagdefs',tagdefs | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 = 1 | 
					
						
							|  |  |  |     colorizing = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def notify_range(self, index1, index2=None): | 
					
						
							|  |  |  |         self.tag_add("TODO", index1, index2) | 
					
						
							|  |  |  |         if self.after_id: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "colorizing already scheduled" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         if self.colorizing: | 
					
						
							|  |  |  |             self.stop_colorizing = 1 | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "stop colorizing" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         if self.allow_colorizing: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "schedule colorizing" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "cancel scheduled recolorizer" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             self.after_cancel(after_id) | 
					
						
							|  |  |  |         self.allow_colorizing = 0 | 
					
						
							|  |  |  |         self.stop_colorizing = 1 | 
					
						
							|  |  |  |         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 | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "cancel scheduled recolorizer" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             self.after_cancel(after_id) | 
					
						
							|  |  |  |         if self.allow_colorizing and self.colorizing: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "stop colorizing" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             self.stop_colorizing = 1 | 
					
						
							|  |  |  |         self.allow_colorizing = not self.allow_colorizing | 
					
						
							|  |  |  |         if self.allow_colorizing and not self.colorizing: | 
					
						
							|  |  |  |             self.after_id = self.after(1, self.recolorize) | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |         if DEBUG: | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             print "auto colorizing turned", self.allow_colorizing and "on" or "off" | 
					
						
							|  |  |  |         return "break" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def recolorize(self): | 
					
						
							|  |  |  |         self.after_id = None | 
					
						
							|  |  |  |         if not self.delegate: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "no delegate" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         if not self.allow_colorizing: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "auto colorizing is off" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         if self.colorizing: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "already colorizing" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.stop_colorizing = 0 | 
					
						
							|  |  |  |             self.colorizing = 1 | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "colorizing..." | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             t0 = time.clock() | 
					
						
							|  |  |  |             self.recolorize_main() | 
					
						
							|  |  |  |             t1 = time.clock() | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "%.3f seconds" % (t1-t0) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             self.colorizing = 0 | 
					
						
							|  |  |  |         if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"): | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |             if DEBUG: print "reschedule colorizing" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             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 1: | 
					
						
							|  |  |  |             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 = 0 | 
					
						
							|  |  |  |             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, "->", `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) | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |                             elif value == "import": | 
					
						
							|  |  |  |                                 # color all the "as" words on same line; | 
					
						
							|  |  |  |                                 # cheap approximation to the truth | 
					
						
							|  |  |  |                                 while 1: | 
					
						
							|  |  |  |                                     m1 = self.asprog.match(chars, b) | 
					
						
							|  |  |  |                                     if not m1: | 
					
						
							|  |  |  |                                         break | 
					
						
							|  |  |  |                                     a, b = m1.span(1) | 
					
						
							|  |  |  |                                     self.tag_add("KEYWORD", | 
					
						
							|  |  |  |                                                  head + "+%dc" % a, | 
					
						
							|  |  |  |                                                  head + "+%dc" % b) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |                     m = self.prog.search(chars, m.end()) | 
					
						
							|  |  |  |                 if "SYNC" in self.tag_names(next + "-1c"): | 
					
						
							|  |  |  |                     head = next | 
					
						
							|  |  |  |                     chars = "" | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     ok = 0 | 
					
						
							|  |  |  |                 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: | 
					
						
							| 
									
										
										
										
											2001-07-13 00:04:24 +00:00
										 |  |  |                     if DEBUG: print "colorizing stopped" | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |                     return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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() |