PyXR

c:\python24\lib \ idlelib \ ColorDelegator.py



0001 import time
0002 import re
0003 import keyword
0004 import __builtin__
0005 from Tkinter import *
0006 from Delegator import Delegator
0007 from configHandler import idleConf
0008 
0009 DEBUG = False
0010 
0011 def any(name, list):
0012     return "(?P<%s>" % name + "|".join(list) + ")"
0013 
0014 def make_pat():
0015     kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
0016     builtinlist = [str(name) for name in dir(__builtin__)
0017                                         if not name.startswith('_')]
0018     # self.file = file("file") :
0019     # 1st 'file' colorized normal, 2nd as builtin, 3rd as comment
0020     builtin = r"([^.'\"\\]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
0021     comment = any("COMMENT", [r"#[^\n]*"])
0022     sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
0023     dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
0024     sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
0025     dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
0026     string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
0027     return kw + "|" + builtin + "|" + comment + "|" + string +\
0028            "|" + any("SYNC", [r"\n"])
0029 
0030 prog = re.compile(make_pat(), re.S)
0031 idprog = re.compile(r"\s+(\w+)", re.S)
0032 asprog = re.compile(r".*?\b(as)\b", re.S)
0033 
0034 class ColorDelegator(Delegator):
0035 
0036     def __init__(self):
0037         Delegator.__init__(self)
0038         self.prog = prog
0039         self.idprog = idprog
0040         self.asprog = asprog
0041         self.LoadTagDefs()
0042 
0043     def setdelegate(self, delegate):
0044         if self.delegate is not None:
0045             self.unbind("<<toggle-auto-coloring>>")
0046         Delegator.setdelegate(self, delegate)
0047         if delegate is not None:
0048             self.config_colors()
0049             self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
0050             self.notify_range("1.0", "end")
0051 
0052     def config_colors(self):
0053         for tag, cnf in self.tagdefs.items():
0054             if cnf:
0055                 self.tag_configure(tag, **cnf)
0056         self.tag_raise('sel')
0057 
0058     def LoadTagDefs(self):
0059         theme = idleConf.GetOption('main','Theme','name')
0060         self.tagdefs = {
0061             "COMMENT": idleConf.GetHighlight(theme, "comment"),
0062             "KEYWORD": idleConf.GetHighlight(theme, "keyword"),
0063             "BUILTIN": idleConf.GetHighlight(theme, "builtin"),
0064             "STRING": idleConf.GetHighlight(theme, "string"),
0065             "DEFINITION": idleConf.GetHighlight(theme, "definition"),
0066             "SYNC": {'background':None,'foreground':None},
0067             "TODO": {'background':None,'foreground':None},
0068             "BREAK": idleConf.GetHighlight(theme, "break"),
0069             "ERROR": idleConf.GetHighlight(theme, "error"),
0070             # The following is used by ReplaceDialog:
0071             "hit": idleConf.GetHighlight(theme, "hit"),
0072             }
0073 
0074         if DEBUG: print 'tagdefs',self.tagdefs
0075 
0076     def insert(self, index, chars, tags=None):
0077         index = self.index(index)
0078         self.delegate.insert(index, chars, tags)
0079         self.notify_range(index, index + "+%dc" % len(chars))
0080 
0081     def delete(self, index1, index2=None):
0082         index1 = self.index(index1)
0083         self.delegate.delete(index1, index2)
0084         self.notify_range(index1)
0085 
0086     after_id = None
0087     allow_colorizing = True
0088     colorizing = False
0089 
0090     def notify_range(self, index1, index2=None):
0091         self.tag_add("TODO", index1, index2)
0092         if self.after_id:
0093             if DEBUG: print "colorizing already scheduled"
0094             return
0095         if self.colorizing:
0096             self.stop_colorizing = True
0097             if DEBUG: print "stop colorizing"
0098         if self.allow_colorizing:
0099             if DEBUG: print "schedule colorizing"
0100             self.after_id = self.after(1, self.recolorize)
0101 
0102     close_when_done = None # Window to be closed when done colorizing
0103 
0104     def close(self, close_when_done=None):
0105         if self.after_id:
0106             after_id = self.after_id
0107             self.after_id = None
0108             if DEBUG: print "cancel scheduled recolorizer"
0109             self.after_cancel(after_id)
0110         self.allow_colorizing = False
0111         self.stop_colorizing = True
0112         if close_when_done:
0113             if not self.colorizing:
0114                 close_when_done.destroy()
0115             else:
0116                 self.close_when_done = close_when_done
0117 
0118     def toggle_colorize_event(self, event):
0119         if self.after_id:
0120             after_id = self.after_id
0121             self.after_id = None
0122             if DEBUG: print "cancel scheduled recolorizer"
0123             self.after_cancel(after_id)
0124         if self.allow_colorizing and self.colorizing:
0125             if DEBUG: print "stop colorizing"
0126             self.stop_colorizing = True
0127         self.allow_colorizing = not self.allow_colorizing
0128         if self.allow_colorizing and not self.colorizing:
0129             self.after_id = self.after(1, self.recolorize)
0130         if DEBUG:
0131             print "auto colorizing turned",\
0132                   self.allow_colorizing and "on" or "off"
0133         return "break"
0134 
0135     def recolorize(self):
0136         self.after_id = None
0137         if not self.delegate:
0138             if DEBUG: print "no delegate"
0139             return
0140         if not self.allow_colorizing:
0141             if DEBUG: print "auto colorizing is off"
0142             return
0143         if self.colorizing:
0144             if DEBUG: print "already colorizing"
0145             return
0146         try:
0147             self.stop_colorizing = False
0148             self.colorizing = True
0149             if DEBUG: print "colorizing..."
0150             t0 = time.clock()
0151             self.recolorize_main()
0152             t1 = time.clock()
0153             if DEBUG: print "%.3f seconds" % (t1-t0)
0154         finally:
0155             self.colorizing = False
0156         if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
0157             if DEBUG: print "reschedule colorizing"
0158             self.after_id = self.after(1, self.recolorize)
0159         if self.close_when_done:
0160             top = self.close_when_done
0161             self.close_when_done = None
0162             top.destroy()
0163 
0164     def recolorize_main(self):
0165         next = "1.0"
0166         while True:
0167             item = self.tag_nextrange("TODO", next)
0168             if not item:
0169                 break
0170             head, tail = item
0171             self.tag_remove("SYNC", head, tail)
0172             item = self.tag_prevrange("SYNC", head)
0173             if item:
0174                 head = item[1]
0175             else:
0176                 head = "1.0"
0177 
0178             chars = ""
0179             next = head
0180             lines_to_get = 1
0181             ok = False
0182             while not ok:
0183                 mark = next
0184                 next = self.index(mark + "+%d lines linestart" %
0185                                          lines_to_get)
0186                 lines_to_get = min(lines_to_get * 2, 100)
0187                 ok = "SYNC" in self.tag_names(next + "-1c")
0188                 line = self.get(mark, next)
0189                 ##print head, "get", mark, next, "->", repr(line)
0190                 if not line:
0191                     return
0192                 for tag in self.tagdefs.keys():
0193                     self.tag_remove(tag, mark, next)
0194                 chars = chars + line
0195                 m = self.prog.search(chars)
0196                 while m:
0197                     for key, value in m.groupdict().items():
0198                         if value:
0199                             a, b = m.span(key)
0200                             self.tag_add(key,
0201                                          head + "+%dc" % a,
0202                                          head + "+%dc" % b)
0203                             if value in ("def", "class"):
0204                                 m1 = self.idprog.match(chars, b)
0205                                 if m1:
0206                                     a, b = m1.span(1)
0207                                     self.tag_add("DEFINITION",
0208                                                  head + "+%dc" % a,
0209                                                  head + "+%dc" % b)
0210                             elif value == "import":
0211                                 # color all the "as" words on same line;
0212                                 # cheap approximation to the truth
0213                                 while True:
0214                                     m1 = self.asprog.match(chars, b)
0215                                     if not m1:
0216                                         break
0217                                     a, b = m1.span(1)
0218                                     self.tag_add("KEYWORD",
0219                                                  head + "+%dc" % a,
0220                                                  head + "+%dc" % b)
0221                     m = self.prog.search(chars, m.end())
0222                 if "SYNC" in self.tag_names(next + "-1c"):
0223                     head = next
0224                     chars = ""
0225                 else:
0226                     ok = False
0227                 if not ok:
0228                     # We're in an inconsistent state, and the call to
0229                     # update may tell us to stop.  It may also change
0230                     # the correct value for "next" (since this is a
0231                     # line.col string, not a true mark).  So leave a
0232                     # crumb telling the next invocation to resume here
0233                     # in case update tells us to leave.
0234                     self.tag_add("TODO", next)
0235                 self.update()
0236                 if self.stop_colorizing:
0237                     if DEBUG: print "colorizing stopped"
0238                     return
0239 
0240 
0241 def main():
0242     from Percolator import Percolator
0243     root = Tk()
0244     root.wm_protocol("WM_DELETE_WINDOW", root.quit)
0245     text = Text(background="white")
0246     text.pack(expand=1, fill="both")
0247     text.focus_set()
0248     p = Percolator(text)
0249     d = ColorDelegator()
0250     p.insertfilter(d)
0251     root.mainloop()
0252 
0253 if __name__ == "__main__":
0254     main()
0255 

Generated by PyXR 0.9.4
SourceForge.net Logo