ยปCore Development>Code coverage>Lib/idlelib/colorizer.py

Python code coverage for Lib/idlelib/colorizer.py

#countcontent
1n/aimport builtins
2n/aimport keyword
3n/aimport re
4n/aimport time
5n/a
6n/afrom idlelib.config import idleConf
7n/afrom idlelib.delegator import Delegator
8n/a
9n/aDEBUG = False
10n/a
11n/adef any(name, alternates):
12n/a "Return a named group pattern matching list of alternates."
13n/a return "(?P<%s>" % name + "|".join(alternates) + ")"
14n/a
15n/adef make_pat():
16n/a kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
17n/a builtinlist = [str(name) for name in dir(builtins)
18n/a if not name.startswith('_') and \
19n/a name not in keyword.kwlist]
20n/a # self.file = open("file") :
21n/a # 1st 'file' colorized normal, 2nd as builtin, 3rd as string
22n/a builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
23n/a comment = any("COMMENT", [r"#[^\n]*"])
24n/a stringprefix = r"(?i:\br|u|f|fr|rf|b|br|rb)?"
25n/a sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
26n/a dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
27n/a sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
28n/a dq3string = stringprefix + r'"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
29n/a string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
30n/a return kw + "|" + builtin + "|" + comment + "|" + string +\
31n/a "|" + any("SYNC", [r"\n"])
32n/a
33n/aprog = re.compile(make_pat(), re.S)
34n/aidprog = re.compile(r"\s+(\w+)", re.S)
35n/a
36n/adef color_config(text): # Called from htest, Editor, and Turtle Demo.
37n/a '''Set color opitons of Text widget.
38n/a
39n/a Should be called whenever ColorDelegator is called.
40n/a '''
41n/a # Not automatic because ColorDelegator does not know 'text'.
42n/a theme = idleConf.CurrentTheme()
43n/a normal_colors = idleConf.GetHighlight(theme, 'normal')
44n/a cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
45n/a select_colors = idleConf.GetHighlight(theme, 'hilite')
46n/a text.config(
47n/a foreground=normal_colors['foreground'],
48n/a background=normal_colors['background'],
49n/a insertbackground=cursor_color,
50n/a selectforeground=select_colors['foreground'],
51n/a selectbackground=select_colors['background'],
52n/a inactiveselectbackground=select_colors['background'], # new in 8.5
53n/a )
54n/a
55n/aclass ColorDelegator(Delegator):
56n/a
57n/a def __init__(self):
58n/a Delegator.__init__(self)
59n/a self.prog = prog
60n/a self.idprog = idprog
61n/a self.LoadTagDefs()
62n/a
63n/a def setdelegate(self, delegate):
64n/a if self.delegate is not None:
65n/a self.unbind("<<toggle-auto-coloring>>")
66n/a Delegator.setdelegate(self, delegate)
67n/a if delegate is not None:
68n/a self.config_colors()
69n/a self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
70n/a self.notify_range("1.0", "end")
71n/a else:
72n/a # No delegate - stop any colorizing
73n/a self.stop_colorizing = True
74n/a self.allow_colorizing = False
75n/a
76n/a def config_colors(self):
77n/a for tag, cnf in self.tagdefs.items():
78n/a if cnf:
79n/a self.tag_configure(tag, **cnf)
80n/a self.tag_raise('sel')
81n/a
82n/a def LoadTagDefs(self):
83n/a theme = idleConf.CurrentTheme()
84n/a self.tagdefs = {
85n/a "COMMENT": idleConf.GetHighlight(theme, "comment"),
86n/a "KEYWORD": idleConf.GetHighlight(theme, "keyword"),
87n/a "BUILTIN": idleConf.GetHighlight(theme, "builtin"),
88n/a "STRING": idleConf.GetHighlight(theme, "string"),
89n/a "DEFINITION": idleConf.GetHighlight(theme, "definition"),
90n/a "SYNC": {'background':None,'foreground':None},
91n/a "TODO": {'background':None,'foreground':None},
92n/a "ERROR": idleConf.GetHighlight(theme, "error"),
93n/a # The following is used by ReplaceDialog:
94n/a "hit": idleConf.GetHighlight(theme, "hit"),
95n/a }
96n/a
97n/a if DEBUG: print('tagdefs',self.tagdefs)
98n/a
99n/a def insert(self, index, chars, tags=None):
100n/a index = self.index(index)
101n/a self.delegate.insert(index, chars, tags)
102n/a self.notify_range(index, index + "+%dc" % len(chars))
103n/a
104n/a def delete(self, index1, index2=None):
105n/a index1 = self.index(index1)
106n/a self.delegate.delete(index1, index2)
107n/a self.notify_range(index1)
108n/a
109n/a after_id = None
110n/a allow_colorizing = True
111n/a colorizing = False
112n/a
113n/a def notify_range(self, index1, index2=None):
114n/a self.tag_add("TODO", index1, index2)
115n/a if self.after_id:
116n/a if DEBUG: print("colorizing already scheduled")
117n/a return
118n/a if self.colorizing:
119n/a self.stop_colorizing = True
120n/a if DEBUG: print("stop colorizing")
121n/a if self.allow_colorizing:
122n/a if DEBUG: print("schedule colorizing")
123n/a self.after_id = self.after(1, self.recolorize)
124n/a
125n/a close_when_done = None # Window to be closed when done colorizing
126n/a
127n/a def close(self, close_when_done=None):
128n/a if self.after_id:
129n/a after_id = self.after_id
130n/a self.after_id = None
131n/a if DEBUG: print("cancel scheduled recolorizer")
132n/a self.after_cancel(after_id)
133n/a self.allow_colorizing = False
134n/a self.stop_colorizing = True
135n/a if close_when_done:
136n/a if not self.colorizing:
137n/a close_when_done.destroy()
138n/a else:
139n/a self.close_when_done = close_when_done
140n/a
141n/a def toggle_colorize_event(self, event):
142n/a if self.after_id:
143n/a after_id = self.after_id
144n/a self.after_id = None
145n/a if DEBUG: print("cancel scheduled recolorizer")
146n/a self.after_cancel(after_id)
147n/a if self.allow_colorizing and self.colorizing:
148n/a if DEBUG: print("stop colorizing")
149n/a self.stop_colorizing = True
150n/a self.allow_colorizing = not self.allow_colorizing
151n/a if self.allow_colorizing and not self.colorizing:
152n/a self.after_id = self.after(1, self.recolorize)
153n/a if DEBUG:
154n/a print("auto colorizing turned",\
155n/a self.allow_colorizing and "on" or "off")
156n/a return "break"
157n/a
158n/a def recolorize(self):
159n/a self.after_id = None
160n/a if not self.delegate:
161n/a if DEBUG: print("no delegate")
162n/a return
163n/a if not self.allow_colorizing:
164n/a if DEBUG: print("auto colorizing is off")
165n/a return
166n/a if self.colorizing:
167n/a if DEBUG: print("already colorizing")
168n/a return
169n/a try:
170n/a self.stop_colorizing = False
171n/a self.colorizing = True
172n/a if DEBUG: print("colorizing...")
173n/a t0 = time.perf_counter()
174n/a self.recolorize_main()
175n/a t1 = time.perf_counter()
176n/a if DEBUG: print("%.3f seconds" % (t1-t0))
177n/a finally:
178n/a self.colorizing = False
179n/a if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
180n/a if DEBUG: print("reschedule colorizing")
181n/a self.after_id = self.after(1, self.recolorize)
182n/a if self.close_when_done:
183n/a top = self.close_when_done
184n/a self.close_when_done = None
185n/a top.destroy()
186n/a
187n/a def recolorize_main(self):
188n/a next = "1.0"
189n/a while True:
190n/a item = self.tag_nextrange("TODO", next)
191n/a if not item:
192n/a break
193n/a head, tail = item
194n/a self.tag_remove("SYNC", head, tail)
195n/a item = self.tag_prevrange("SYNC", head)
196n/a if item:
197n/a head = item[1]
198n/a else:
199n/a head = "1.0"
200n/a
201n/a chars = ""
202n/a next = head
203n/a lines_to_get = 1
204n/a ok = False
205n/a while not ok:
206n/a mark = next
207n/a next = self.index(mark + "+%d lines linestart" %
208n/a lines_to_get)
209n/a lines_to_get = min(lines_to_get * 2, 100)
210n/a ok = "SYNC" in self.tag_names(next + "-1c")
211n/a line = self.get(mark, next)
212n/a ##print head, "get", mark, next, "->", repr(line)
213n/a if not line:
214n/a return
215n/a for tag in self.tagdefs:
216n/a self.tag_remove(tag, mark, next)
217n/a chars = chars + line
218n/a m = self.prog.search(chars)
219n/a while m:
220n/a for key, value in m.groupdict().items():
221n/a if value:
222n/a a, b = m.span(key)
223n/a self.tag_add(key,
224n/a head + "+%dc" % a,
225n/a head + "+%dc" % b)
226n/a if value in ("def", "class"):
227n/a m1 = self.idprog.match(chars, b)
228n/a if m1:
229n/a a, b = m1.span(1)
230n/a self.tag_add("DEFINITION",
231n/a head + "+%dc" % a,
232n/a head + "+%dc" % b)
233n/a m = self.prog.search(chars, m.end())
234n/a if "SYNC" in self.tag_names(next + "-1c"):
235n/a head = next
236n/a chars = ""
237n/a else:
238n/a ok = False
239n/a if not ok:
240n/a # We're in an inconsistent state, and the call to
241n/a # update may tell us to stop. It may also change
242n/a # the correct value for "next" (since this is a
243n/a # line.col string, not a true mark). So leave a
244n/a # crumb telling the next invocation to resume here
245n/a # in case update tells us to leave.
246n/a self.tag_add("TODO", next)
247n/a self.update()
248n/a if self.stop_colorizing:
249n/a if DEBUG: print("colorizing stopped")
250n/a return
251n/a
252n/a def removecolors(self):
253n/a for tag in self.tagdefs:
254n/a self.tag_remove(tag, "1.0", "end")
255n/a
256n/a
257n/adef _color_delegator(parent): # htest #
258n/a from tkinter import Toplevel, Text
259n/a from idlelib.percolator import Percolator
260n/a
261n/a top = Toplevel(parent)
262n/a top.title("Test ColorDelegator")
263n/a x, y = map(int, parent.geometry().split('+')[1:])
264n/a top.geometry("700x250+%d+%d" % (x + 20, y + 175))
265n/a source = ("# Following has syntax errors\n"
266n/a "if True: then int 1\nelif False: print 0\nelse: float(None)\n"
267n/a "if iF + If + IF: 'keywork matching must respect case'\n"
268n/a "# All valid prefixes for unicode and byte strings should be colored\n"
269n/a "'x', '''x''', \"x\", \"\"\"x\"\"\"\n"
270n/a "r'x', u'x', R'x', U'x', f'x', F'x', ur'is invalid'\n"
271n/a "fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n"
272n/a "b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n")
273n/a text = Text(top, background="white")
274n/a text.pack(expand=1, fill="both")
275n/a text.insert("insert", source)
276n/a text.focus_set()
277n/a
278n/a color_config(text)
279n/a p = Percolator(text)
280n/a d = ColorDelegator()
281n/a p.insertfilter(d)
282n/a
283n/aif __name__ == "__main__":
284n/a import unittest
285n/a unittest.main('idlelib.idle_test.test_colorizer',
286n/a verbosity=2, exit=False)
287n/a
288n/a from idlelib.idle_test.htest import run
289n/a run(_color_delegator)