home *** CD-ROM | disk | FTP | other *** search
/ Freelog 33 / Freelog033.iso / Progr / Python-2.2.1.exe / COLORDELEGATOR.PY < prev    next >
Encoding:
Python Source  |  2001-03-22  |  9.0 KB  |  248 lines

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