5 from Delegator
import Delegator
6 from IdleConf
import idleconf
8 #$ event <<toggle-auto-coloring>>
10 #$ unix <Control-slash>
16 return "(?P<%s>" % name
+ "|".join(list) + ")"
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"])
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
)
32 class ColorDelegator(Delegator
):
35 Delegator
.__init
__(self
)
40 def setdelegate(self
, delegate
):
41 if self
.delegate
is not None:
42 self
.unbind("<<toggle-auto-coloring>>")
43 Delegator
.setdelegate(self
, delegate
)
44 if delegate
is not None:
46 self
.bind("<<toggle-auto-coloring>>", self
.toggle_colorize_event
)
47 self
.notify_range("1.0", "end")
49 def config_colors(self
):
50 for tag
, cnf
in self
.tagdefs
.items():
52 apply(self
.tag_configure
, (tag
,), cnf
)
55 cconf
= idleconf
.getsection('Colors')
58 "COMMENT": cconf
.getcolor("comment"),
59 "KEYWORD": cconf
.getcolor("keyword"),
60 "STRING": cconf
.getcolor("string"),
61 "DEFINITION": cconf
.getcolor("definition"),
62 "SYNC": cconf
.getcolor("sync"),
63 "TODO": cconf
.getcolor("todo"),
64 "BREAK": cconf
.getcolor("break"),
65 # The following is used by ReplaceDialog:
66 "hit": cconf
.getcolor("hit"),
69 def insert(self
, index
, chars
, tags
=None):
70 index
= self
.index(index
)
71 self
.delegate
.insert(index
, chars
, tags
)
72 self
.notify_range(index
, index
+ "+%dc" % len(chars
))
74 def delete(self
, index1
, index2
=None):
75 index1
= self
.index(index1
)
76 self
.delegate
.delete(index1
, index2
)
77 self
.notify_range(index1
)
83 def notify_range(self
, index1
, index2
=None):
84 self
.tag_add("TODO", index1
, index2
)
86 if DEBUG
: print "colorizing already scheduled"
89 self
.stop_colorizing
= 1
90 if DEBUG
: print "stop colorizing"
91 if self
.allow_colorizing
:
92 if DEBUG
: print "schedule colorizing"
93 self
.after_id
= self
.after(1, self
.recolorize
)
95 close_when_done
= None # Window to be closed when done colorizing
97 def close(self
, close_when_done
=None):
99 after_id
= self
.after_id
101 if DEBUG
: print "cancel scheduled recolorizer"
102 self
.after_cancel(after_id
)
103 self
.allow_colorizing
= 0
104 self
.stop_colorizing
= 1
106 if not self
.colorizing
:
107 close_when_done
.destroy()
109 self
.close_when_done
= close_when_done
111 def toggle_colorize_event(self
, event
):
113 after_id
= self
.after_id
115 if DEBUG
: print "cancel scheduled recolorizer"
116 self
.after_cancel(after_id
)
117 if self
.allow_colorizing
and self
.colorizing
:
118 if DEBUG
: print "stop colorizing"
119 self
.stop_colorizing
= 1
120 self
.allow_colorizing
= not self
.allow_colorizing
121 if self
.allow_colorizing
and not self
.colorizing
:
122 self
.after_id
= self
.after(1, self
.recolorize
)
124 print "auto colorizing turned", self
.allow_colorizing
and "on" or "off"
127 def recolorize(self
):
129 if not self
.delegate
:
130 if DEBUG
: print "no delegate"
132 if not self
.allow_colorizing
:
133 if DEBUG
: print "auto colorizing is off"
136 if DEBUG
: print "already colorizing"
139 self
.stop_colorizing
= 0
141 if DEBUG
: print "colorizing..."
143 self
.recolorize_main()
145 if DEBUG
: print "%.3f seconds" % (t1
-t0
)
148 if self
.allow_colorizing
and self
.tag_nextrange("TODO", "1.0"):
149 if DEBUG
: print "reschedule colorizing"
150 self
.after_id
= self
.after(1, self
.recolorize
)
151 if self
.close_when_done
:
152 top
= self
.close_when_done
153 self
.close_when_done
= None
156 def recolorize_main(self
):
159 item
= self
.tag_nextrange("TODO", next
)
163 self
.tag_remove("SYNC", head
, tail
)
164 item
= self
.tag_prevrange("SYNC", head
)
176 next
= self
.index(mark
+ "+%d lines linestart" %
178 lines_to_get
= min(lines_to_get
* 2, 100)
179 ok
= "SYNC" in self
.tag_names(next
+ "-1c")
180 line
= self
.get(mark
, next
)
181 ##print head, "get", mark, next, "->", `line`
184 for tag
in self
.tagdefs
.keys():
185 self
.tag_remove(tag
, mark
, next
)
187 m
= self
.prog
.search(chars
)
189 for key
, value
in m
.groupdict().items():
195 if value
in ("def", "class"):
196 m1
= self
.idprog
.match(chars
, b
)
199 self
.tag_add("DEFINITION",
202 elif value
== "import":
203 # color all the "as" words on same line;
204 # cheap approximation to the truth
206 m1
= self
.asprog
.match(chars
, b
)
210 self
.tag_add("KEYWORD",
213 m
= self
.prog
.search(chars
, m
.end())
214 if "SYNC" in self
.tag_names(next
+ "-1c"):
220 # We're in an inconsistent state, and the call to
221 # update may tell us to stop. It may also change
222 # the correct value for "next" (since this is a
223 # line.col string, not a true mark). So leave a
224 # crumb telling the next invocation to resume here
225 # in case update tells us to leave.
226 self
.tag_add("TODO", next
)
228 if self
.stop_colorizing
:
229 if DEBUG
: print "colorizing stopped"
234 from Percolator
import Percolator
236 root
.wm_protocol("WM_DELETE_WINDOW", root
.quit
)
237 text
= Text(background
="white")
238 text
.pack(expand
=1, fill
="both")
245 if __name__
== "__main__":