home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 14 / hacker14.iso / programacao / pythonwin / python.exe / COLORDELEGATOR.PY < prev    next >
Encoding:
Python Source  |  2003-07-09  |  9.3 KB  |  251 lines

  1. import time
  2. import re
  3. import keyword
  4. from Tkinter import *
  5. from Delegator import Delegator
  6. from configHandler import idleConf
  7.  
  8. #$ event <<toggle-auto-coloring>>
  9. #$ win <Control-slash>
  10. #$ unix <Control-slash>
  11.  
  12. DEBUG = 0
  13.  
  14.  
  15. def any(name, list):
  16.     return "(?P<%s>" % name + "|".join(list) + ")"
  17.  
  18. def make_pat():
  19.     kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
  20.     comment = any("COMMENT", [r"#[^\n]*"])
  21.     sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
  22.     dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
  23.     sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
  24.     dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
  25.     string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
  26.     return kw + "|" + comment + "|" + string + "|" + any("SYNC", [r"\n"])
  27.  
  28. prog = re.compile(make_pat(), re.S)
  29. idprog = re.compile(r"\s+(\w+)", re.S)
  30. asprog = re.compile(r".*?\b(as)\b", re.S)
  31.  
  32. class ColorDelegator(Delegator):
  33.  
  34.     def __init__(self):
  35.         Delegator.__init__(self)
  36.         self.prog = prog
  37.         self.idprog = idprog
  38.         self.asprog = asprog
  39.         self.LoadTagDefs()
  40.  
  41.     def setdelegate(self, delegate):
  42.         if self.delegate is not None:
  43.             self.unbind("<<toggle-auto-coloring>>")
  44.         Delegator.setdelegate(self, delegate)
  45.         if delegate is not None:
  46.             self.config_colors()
  47.             self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
  48.             self.notify_range("1.0", "end")
  49.  
  50.     def config_colors(self):
  51.         for tag, cnf in self.tagdefs.items():
  52.             if cnf:
  53.                 self.tag_configure(tag, **cnf)
  54.         self.tag_raise('sel')
  55.  
  56.     def LoadTagDefs(self):
  57.         theme = idleConf.GetOption('main','Theme','name')
  58.         self.tagdefs = {
  59.             "COMMENT": idleConf.GetHighlight(theme, "comment"),
  60.             "KEYWORD": idleConf.GetHighlight(theme, "keyword"),
  61.             "STRING": idleConf.GetHighlight(theme, "string"),
  62.             "DEFINITION": idleConf.GetHighlight(theme, "definition"),
  63.             "SYNC": {'background':None,'foreground':None},
  64.             "TODO": {'background':None,'foreground':None},
  65.             "BREAK": idleConf.GetHighlight(theme, "break"),
  66.             "ERROR": idleConf.GetHighlight(theme, "error"),
  67.             # The following is used by ReplaceDialog:
  68.             "hit": idleConf.GetHighlight(theme, "hit"),
  69.             }
  70.  
  71.     if DEBUG: print 'tagdefs',tagdefs
  72.  
  73.     def insert(self, index, chars, tags=None):
  74.         index = self.index(index)
  75.         self.delegate.insert(index, chars, tags)
  76.         self.notify_range(index, index + "+%dc" % len(chars))
  77.  
  78.     def delete(self, index1, index2=None):
  79.         index1 = self.index(index1)
  80.         self.delegate.delete(index1, index2)
  81.         self.notify_range(index1)
  82.  
  83.     after_id = None
  84.     allow_colorizing = 1
  85.     colorizing = 0
  86.  
  87.     def notify_range(self, index1, index2=None):
  88.         self.tag_add("TODO", index1, index2)
  89.         if self.after_id:
  90.             if DEBUG: print "colorizing already scheduled"
  91.             return
  92.         if self.colorizing:
  93.             self.stop_colorizing = 1
  94.             if DEBUG: print "stop colorizing"
  95.         if self.allow_colorizing:
  96.             if DEBUG: print "schedule colorizing"
  97.             self.after_id = self.after(1, self.recolorize)
  98.  
  99.     close_when_done = None # Window to be closed when done colorizing
  100.  
  101.     def close(self, close_when_done=None):
  102.         if self.after_id:
  103.             after_id = self.after_id
  104.             self.after_id = None
  105.             if DEBUG: print "cancel scheduled recolorizer"
  106.             self.after_cancel(after_id)
  107.         self.allow_colorizing = 0
  108.         self.stop_colorizing = 1
  109.         if close_when_done:
  110.             if not self.colorizing:
  111.                 close_when_done.destroy()
  112.             else:
  113.                 self.close_when_done = close_when_done
  114.  
  115.     def toggle_colorize_event(self, event):
  116.         if self.after_id:
  117.             after_id = self.after_id
  118.             self.after_id = None
  119.             if DEBUG: print "cancel scheduled recolorizer"
  120.             self.after_cancel(after_id)
  121.         if self.allow_colorizing and self.colorizing:
  122.             if DEBUG: print "stop colorizing"
  123.             self.stop_colorizing = 1
  124.         self.allow_colorizing = not self.allow_colorizing
  125.         if self.allow_colorizing and not self.colorizing:
  126.             self.after_id = self.after(1, self.recolorize)
  127.         if DEBUG:
  128.             print "auto colorizing turned", self.allow_colorizing and "on" or "off"
  129.         return "break"
  130.  
  131.     def recolorize(self):
  132.         self.after_id = None
  133.         if not self.delegate:
  134.             if DEBUG: print "no delegate"
  135.             return
  136.         if not self.allow_colorizing:
  137.             if DEBUG: print "auto colorizing is off"
  138.             return
  139.         if self.colorizing:
  140.             if DEBUG: print "already colorizing"
  141.             return
  142.         try:
  143.             self.stop_colorizing = 0
  144.             self.colorizing = 1
  145.             if DEBUG: print "colorizing..."
  146.             t0 = time.clock()
  147.             self.recolorize_main()
  148.             t1 = time.clock()
  149.             if DEBUG: print "%.3f seconds" % (t1-t0)
  150.         finally:
  151.             self.colorizing = 0
  152.         if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
  153.             if DEBUG: print "reschedule colorizing"
  154.             self.after_id = self.after(1, self.recolorize)
  155.         if self.close_when_done:
  156.             top = self.close_when_done
  157.             self.close_when_done = None
  158.             top.destroy()
  159.  
  160.     def recolorize_main(self):
  161.         next = "1.0"
  162.         while 1:
  163.             item = self.tag_nextrange("TODO", next)
  164.             if not item:
  165.                 break
  166.             head, tail = item
  167.             self.tag_remove("SYNC", head, tail)
  168.             item = self.tag_prevrange("SYNC", head)
  169.             if item:
  170.                 head = item[1]
  171.             else:
  172.                 head = "1.0"
  173.  
  174.             chars = ""
  175.             next = head
  176.             lines_to_get = 1
  177.             ok = 0
  178.             while not ok:
  179.                 mark = next
  180.                 next = self.index(mark + "+%d lines linestart" %
  181.                                          lines_to_get)
  182.                 lines_to_get = min(lines_to_get * 2, 100)
  183.                 ok = "SYNC" in self.tag_names(next + "-1c")
  184.                 line = self.get(mark, next)
  185.                 ##print head, "get", mark, next, "->", `line`
  186.                 if not line:
  187.                     return
  188.                 for tag in self.tagdefs.keys():
  189.                     self.tag_remove(tag, mark, next)
  190.                 chars = chars + line
  191.                 m = self.prog.search(chars)
  192.                 while m:
  193.                     for key, value in m.groupdict().items():
  194.                         if value:
  195.                             a, b = m.span(key)
  196.                             self.tag_add(key,
  197.                                          head + "+%dc" % a,
  198.                                          head + "+%dc" % b)
  199.                             if value in ("def", "class"):
  200.                                 m1 = self.idprog.match(chars, b)
  201.                                 if m1:
  202.                                     a, b = m1.span(1)
  203.                                     self.tag_add("DEFINITION",
  204.                                                  head + "+%dc" % a,
  205.                                                  head + "+%dc" % b)
  206.                             elif value == "import":
  207.                                 # color all the "as" words on same line;
  208.                                 # cheap approximation to the truth
  209.                                 while 1:
  210.                                     m1 = self.asprog.match(chars, b)
  211.                                     if not m1:
  212.                                         break
  213.                                     a, b = m1.span(1)
  214.                                     self.tag_add("KEYWORD",
  215.                                                  head + "+%dc" % a,
  216.                                                  head + "+%dc" % b)
  217.                     m = self.prog.search(chars, m.end())
  218.                 if "SYNC" in self.tag_names(next + "-1c"):
  219.                     head = next
  220.                     chars = ""
  221.                 else:
  222.                     ok = 0
  223.                 if not ok:
  224.                     # We're in an inconsistent state, and the call to
  225.                     # update may tell us to stop.  It may also change
  226.                     # the correct value for "next" (since this is a
  227.                     # line.col string, not a true mark).  So leave a
  228.                     # crumb telling the next invocation to resume here
  229.                     # in case update tells us to leave.
  230.                     self.tag_add("TODO", next)
  231.                 self.update()
  232.                 if self.stop_colorizing:
  233.                     if DEBUG: print "colorizing stopped"
  234.                     return
  235.  
  236.  
  237. def main():
  238.     from Percolator import Percolator
  239.     root = Tk()
  240.     root.wm_protocol("WM_DELETE_WINDOW", root.quit)
  241.     text = Text(background="white")
  242.     text.pack(expand=1, fill="both")
  243.     text.focus_set()
  244.     p = Percolator(text)
  245.     d = ColorDelegator()
  246.     p.insertfilter(d)
  247.     root.mainloop()
  248.  
  249. if __name__ == "__main__":
  250.     main()
  251.