blob: 17f23ca3a25aa7f35b597d6e4fad5acb6f8cd96b [file] [log] [blame]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00001import sys
2import os
3import string
Guido van Rossum07ec8961999-01-28 22:02:47 +00004import re
Guido van Rossumb3418881998-10-13 03:45:15 +00005import imp
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00006from Tkinter import *
Guido van Rossumb3418881998-10-13 03:45:15 +00007import tkSimpleDialog
Guido van Rossum2aeeb551998-10-12 21:01:37 +00008import tkMessageBox
Guido van Rossum504b0bf1999-01-02 21:28:54 +00009import idlever
10
11# File menu
12
13#$ event <<open-module>>
14#$ win <Alt-m>
15#$ unix <Control-x><Control-m>
16
17#$ event <<open-class-browser>>
18#$ win <Alt-c>
19#$ unix <Control-x><Control-b>
20
21#$ event <<close-window>>
22#$ unix <Control-x><Control-0>
23#$ unix <Control-x><Key-0>
24#$ win <Alt-F4>
25
26# Edit menu
27
28#$ event <<Copy>>
29#$ win <Control-c>
30#$ unix <Alt-w>
31
32#$ event <<Cut>>
33#$ win <Control-x>
34#$ unix <Control-w>
35
36#$ event <<Paste>>
37#$ win <Control-v>
38#$ unix <Control-y>
39
40#$ event <<select-all>>
41#$ win <Alt-a>
42#$ unix <Alt-a>
43
44# Help menu
45
46#$ event <<help>>
47#$ win <F1>
48#$ unix <F1>
49
50#$ event <<about-idle>>
51
52# Events without menu entries
53
54#$ event <<remove-selection>>
55#$ win <Escape>
56
57#$ event <<center-insert>>
58#$ win <Control-l>
59#$ unix <Control-l>
60
61#$ event <<do-nothing>>
62#$ unix <Control-x>
63
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000064
Guido van Rossum2aeeb551998-10-12 21:01:37 +000065about_title = "About IDLE"
66about_text = """\
Guido van Rossum504b0bf1999-01-02 21:28:54 +000067IDLE %s
Guido van Rossum2aeeb551998-10-12 21:01:37 +000068
Guido van Rossum504b0bf1999-01-02 21:28:54 +000069An Integrated DeveLopment Environment for Python
Guido van Rossum2aeeb551998-10-12 21:01:37 +000070
71by Guido van Rossum
Guido van Rossum504b0bf1999-01-02 21:28:54 +000072""" % idlever.IDLE_VERSION
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000073
74class EditorWindow:
75
76 from Percolator import Percolator
77 from ColorDelegator import ColorDelegator
78 from UndoDelegator import UndoDelegator
79 from IOBinding import IOBinding
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000080 import Bindings
Guido van Rossum504b0bf1999-01-02 21:28:54 +000081 from Tkinter import Toplevel
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000082
Guido van Rossum504b0bf1999-01-02 21:28:54 +000083 about_title = about_title
84 about_text = about_text
85
86 def __init__(self, flist=None, filename=None, key=None, root=None):
87 self.flist = flist
88 root = root or flist.root
Guido van Rossum2aeeb551998-10-12 21:01:37 +000089 self.root = root
90 self.menubar = Menu(root)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000091 self.top = top = self.Toplevel(root, menu=self.menubar)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000092 self.vbar = vbar = Scrollbar(top, name='vbar')
Guido van Rossum504b0bf1999-01-02 21:28:54 +000093 self.text = text = Text(top, name='text', padx=5,
94 background="white", wrap="none")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000095
Guido van Rossum2aeeb551998-10-12 21:01:37 +000096 self.createmenubar()
Guido van Rossum07ec8961999-01-28 22:02:47 +000097 self.apply_bindings()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000098
99 self.top.protocol("WM_DELETE_WINDOW", self.close)
100 self.top.bind("<<close-window>>", self.close_event)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000101 text.bind("<<center-insert>>", self.center_insert_event)
102 text.bind("<<help>>", self.help_dialog)
103 text.bind("<<about-idle>>", self.about_dialog)
104 text.bind("<<open-module>>", self.open_module)
105 text.bind("<<do-nothing>>", lambda event: "break")
106 text.bind("<<select-all>>", self.select_all)
107 text.bind("<<remove-selection>>", self.remove_selection)
108 text.bind("<3>", self.right_menu_event)
109 if flist:
110 flist.inversedict[self] = key
111 if key:
112 flist.dict[key] = self
113 text.bind("<<open-new-window>>", self.flist.new_callback)
114 text.bind("<<close-all-windows>>", self.flist.close_all_callback)
115 text.bind("<<open-class-browser>>", self.open_class_browser)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000116
117 vbar['command'] = text.yview
118 vbar.pack(side=RIGHT, fill=Y)
119
120 text['yscrollcommand'] = vbar.set
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000121 if sys.platform[:3] == 'win':
122 text['font'] = ("lucida console", 8)
123 text.pack(side=LEFT, fill=BOTH, expand=1)
124 text.focus_set()
125
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000126 self.per = per = self.Percolator(text)
127 if self.ispythonsource(filename):
128 self.color = color = self.ColorDelegator(); per.insertfilter(color)
129 ##print "Initial colorizer"
130 else:
131 ##print "No initial colorizer"
132 self.color = None
133 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000134 self.io = io = self.IOBinding(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000135
136 undo.set_saved_change_hook(self.saved_change_hook)
137 io.set_filename_change_hook(self.filename_change_hook)
138
139 if filename:
140 if os.path.exists(filename):
141 io.loadfile(filename)
142 else:
143 io.set_filename(filename)
144
145 self.saved_change_hook()
146
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000147 self.load_extensions()
148
149 menu = self.menudict.get('windows')
150 if menu:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000151 end = menu.index("end")
152 if end is None:
153 end = -1
154 if end >= 0:
155 menu.add_separator()
156 end = end + 1
157 self.wmenu_end = end
158 menu.configure(postcommand=self.postwindowsmenu)
159
160 def wakeup(self):
Guido van Rossum36911a11999-01-18 15:18:57 +0000161 if self.top.wm_state() == "iconic":
162 self.top.wm_deiconify()
163 else:
164 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000165 self.text.focus_set()
166
Guido van Rossume7b2e651998-10-12 23:56:08 +0000167 menu_specs = [
Guido van Rossumb5eed031998-11-27 03:19:07 +0000168 ("file", "_File"),
169 ("edit", "_Edit"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000170 ("windows", "_Windows"),
Guido van Rossumb5eed031998-11-27 03:19:07 +0000171 ("help", "_Help"),
Guido van Rossume7b2e651998-10-12 23:56:08 +0000172 ]
173
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000174 def createmenubar(self):
175 mbar = self.menubar
Guido van Rossum07ec8961999-01-28 22:02:47 +0000176 self.menudict = menudict = {}
Guido van Rossume7b2e651998-10-12 23:56:08 +0000177 for name, label in self.menu_specs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000178 underline, label = prepstr(label)
179 menudict[name] = menu = Menu(mbar, name=name)
Guido van Rossumb5eed031998-11-27 03:19:07 +0000180 mbar.add_cascade(label=label, menu=menu, underline=underline)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000181 self.fill_menus()
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000182
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000183 def postwindowsmenu(self):
184 # Only called when Windows menu exists
Guido van Rossum07ec8961999-01-28 22:02:47 +0000185 # XXX Actually, this Just-In-Time updating interferes
186 # XXX badly with the tear-off feature. It would be better
187 # XXX to update all Windows menus whenever the list of windows
188 # XXX changes.
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000189 menu = self.menudict['windows']
190 end = menu.index("end")
191 if end is None:
192 end = -1
193 if end > self.wmenu_end:
194 menu.delete(self.wmenu_end+1, end)
195 import WindowList
196 WindowList.add_windows_to_menu(menu)
197
198 rmenu = None
199
200 def right_menu_event(self, event):
201 self.text.tag_remove("sel", "1.0", "end")
202 self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
203 if not self.rmenu:
204 self.make_rmenu()
205 rmenu = self.rmenu
206 self.event = event
207 iswin = sys.platform[:3] == 'win'
208 if iswin:
209 self.text.config(cursor="arrow")
210 rmenu.tk_popup(event.x_root, event.y_root)
211 if iswin:
212 self.text.config(cursor="ibeam")
213
214 rmenu_specs = [
215 # ("Label", "<<virtual-event>>"), ...
216 ("Close", "<<close-window>>"), # Example
217 ]
218
219 def make_rmenu(self):
220 rmenu = Menu(self.text, tearoff=0)
221 for label, eventname in self.rmenu_specs:
222 def command(text=self.text, eventname=eventname):
223 text.event_generate(eventname)
224 rmenu.add_command(label=label, command=command)
225 self.rmenu = rmenu
226
Guido van Rossume7b2e651998-10-12 23:56:08 +0000227 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000228 tkMessageBox.showinfo(self.about_title, self.about_text,
229 master=self.text)
230
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000231 helpfile = "help.txt"
232
Guido van Rossume7b2e651998-10-12 23:56:08 +0000233 def help_dialog(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000234 helpfile = self.helpfile
235 if not os.path.exists(helpfile):
236 base = os.path.basename(self.helpfile)
237 for dir in sys.path:
238 fullname = os.path.join(dir, base)
239 if os.path.exists(fullname):
240 helpfile = fullname
241 break
242 if self.flist:
243 self.flist.open(helpfile)
244 else:
245 self.io.loadfile(helpfile)
246
247 def select_all(self, event=None):
248 self.text.tag_add("sel", "1.0", "end-1c")
249 self.text.mark_set("insert", "1.0")
250 self.text.see("insert")
251 return "break"
252
253 def remove_selection(self, event=None):
254 self.text.tag_remove("sel", "1.0", "end")
255 self.text.see("insert")
256
Guido van Rossumb3418881998-10-13 03:45:15 +0000257 def open_module(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000258 # XXX Shouldn't this be in IOBinding or in FileList?
Guido van Rossumb3418881998-10-13 03:45:15 +0000259 try:
260 name = self.text.get("sel.first", "sel.last")
261 except TclError:
262 name = ""
263 else:
264 name = string.strip(name)
265 if not name:
266 name = tkSimpleDialog.askstring("Module",
Guido van Rossume1dedc01998-10-16 16:09:57 +0000267 "Enter the name of a Python module\n"
268 "to search on sys.path and open:",
Guido van Rossumb3418881998-10-13 03:45:15 +0000269 parent=self.text)
270 if name:
271 name = string.strip(name)
272 if not name:
273 return
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000274 # XXX Ought to support package syntax
275 # XXX Ought to insert current file's directory in front of path
Guido van Rossumb3418881998-10-13 03:45:15 +0000276 try:
277 (f, file, (suffix, mode, type)) = imp.find_module(name)
278 except ImportError, msg:
279 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
280 return
281 if type != imp.PY_SOURCE:
282 tkMessageBox.showerror("Unsupported type",
283 "%s is not a source module" % name, parent=self.text)
284 return
285 if f:
286 f.close()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000287 if self.flist:
288 self.flist.open(file)
289 else:
290 self.io.loadfile(file)
291
292 def open_class_browser(self, event=None):
293 filename = self.io.filename
294 if not filename:
295 tkMessageBox.showerror(
296 "No filename",
297 "This buffer has no associated filename",
298 master=self.text)
299 return None
300 head, tail = os.path.split(filename)
301 base, ext = os.path.splitext(tail)
302 import pyclbr
303 if pyclbr._modules.has_key(base):
304 del pyclbr._modules[base]
Guido van Rossum245ddc41999-01-11 14:51:32 +0000305 save_cursor = self.text["cursor"]
306 self.text["cursor"] = "watch"
307 self.text.update_idletasks()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000308 import ClassBrowser
309 ClassBrowser.ClassBrowser(self.flist, base, [head])
Guido van Rossum245ddc41999-01-11 14:51:32 +0000310 self.text["cursor"] = save_cursor
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000311
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000312 def gotoline(self, lineno):
313 if lineno is not None and lineno > 0:
314 self.text.mark_set("insert", "%d.0" % lineno)
315 self.text.tag_remove("sel", "1.0", "end")
316 self.text.tag_add("sel", "insert", "insert +1l")
317 self.center()
318
319 def ispythonsource(self, filename):
320 if not filename:
321 return 1
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000322 base, ext = os.path.splitext(os.path.basename(filename))
323 if os.path.normcase(ext) in (".py", ".pyw"):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000324 return 1
325 try:
326 f = open(filename)
327 line = f.readline()
328 f.close()
329 except IOError:
330 return 0
331 return line[:2] == '#!' and string.find(line, 'python') >= 0
332
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000333 def close_hook(self):
334 if self.flist:
335 self.flist.close_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000336
337 def set_close_hook(self, close_hook):
338 self.close_hook = close_hook
339
340 def filename_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000341 if self.flist:
342 self.flist.filename_changed_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000343 self.saved_change_hook()
344 if self.ispythonsource(self.io.filename):
345 self.addcolorizer()
346 else:
347 self.rmcolorizer()
348
349 def addcolorizer(self):
350 if self.color:
351 return
352 ##print "Add colorizer"
353 self.per.removefilter(self.undo)
354 self.color = self.ColorDelegator()
355 self.per.insertfilter(self.color)
356 self.per.insertfilter(self.undo)
357
358 def rmcolorizer(self):
359 if not self.color:
360 return
361 ##print "Remove colorizer"
362 self.per.removefilter(self.undo)
363 self.per.removefilter(self.color)
364 self.color = None
365 self.per.insertfilter(self.undo)
366
367 def saved_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000368 short = self.short_title()
369 long = self.long_title()
370 if short and long:
371 title = short + " - " + long
372 elif short:
373 title = short
374 elif long:
375 title = long
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000376 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000377 title = "Untitled"
378 icon = short or long or title
379 if not self.get_saved():
380 title = "*%s*" % title
381 icon = "*%s" % icon
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000382 self.top.wm_title(title)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000383 self.top.wm_iconname(icon)
384
385 def get_saved(self):
386 return self.undo.get_saved()
387
388 def set_saved(self, flag):
389 self.undo.set_saved(flag)
390
391 def reset_undo(self):
392 self.undo.reset_undo()
393
394 def short_title(self):
395 filename = self.io.filename
396 if filename:
397 filename = os.path.basename(filename)
398 return filename
399
400 def long_title(self):
401 return self.io.filename or ""
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000402
403 def center_insert_event(self, event):
404 self.center()
405
406 def center(self, mark="insert"):
Guido van Rossum245ddc41999-01-11 14:51:32 +0000407 text = self.text
408 top, bot = self.getwindowlines()
409 lineno = self.getlineno(mark)
410 height = bot - top
411 newtop = max(1, lineno - height/2)
412 text.yview(float(newtop))
413
414 def getwindowlines(self):
415 text = self.text
416 top = self.getlineno("@0,0")
417 bot = self.getlineno("@0,65535")
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000418 if top == bot and text.winfo_height() == 1:
419 # Geometry manager hasn't run yet
Guido van Rossum245ddc41999-01-11 14:51:32 +0000420 height = int(text['height'])
421 bot = top + height - 1
422 return top, bot
423
424 def getlineno(self, mark="insert"):
425 text = self.text
426 return int(float(text.index(mark)))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000427
428 def close_event(self, event):
429 self.close()
430
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000431 def maybesave(self):
432 if self.io:
433 return self.io.maybesave()
434
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000435 def close(self):
436 self.top.wm_deiconify()
437 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000438 reply = self.maybesave()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000439 if reply != "cancel":
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000440 if self.close_hook:
441 self.close_hook()
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000442 colorizing = 0
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000443 if self.color:
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000444 colorizing = self.color.colorizing
445 doh = colorizing and self.top
446 self.color.close(doh) # Cancel colorization
447 if not colorizing:
448 self.top.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000449 return reply
450
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000451 def load_extensions(self):
452 self.extensions = {}
453 self.load_standard_extensions()
454
455 def load_standard_extensions(self):
456 for name in self.get_standard_extension_names():
457 try:
458 self.load_extension(name)
459 except:
460 print "Failed to load extension", `name`
461 import traceback
462 traceback.print_exc()
463
464 def get_standard_extension_names(self):
465 import extend
466 return extend.standard
467
468 def load_extension(self, name):
469 mod = __import__(name)
470 cls = getattr(mod, name)
471 ins = cls(self)
472 self.extensions[name] = ins
473 kdnames = ["keydefs"]
474 if sys.platform == 'win32':
475 kdnames.append("windows_keydefs")
476 elif sys.platform == 'mac':
477 kdnames.append("mac_keydefs")
478 else:
479 kdnames.append("unix_keydefs")
480 keydefs = {}
481 for kdname in kdnames:
482 if hasattr(ins, kdname):
483 keydefs.update(getattr(ins, kdname))
484 if keydefs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000485 self.apply_bindings(keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000486 for vevent in keydefs.keys():
487 methodname = string.replace(vevent, "-", "_")
488 while methodname[:1] == '<':
489 methodname = methodname[1:]
490 while methodname[-1:] == '>':
491 methodname = methodname[:-1]
492 methodname = methodname + "_event"
493 if hasattr(ins, methodname):
494 self.text.bind(vevent, getattr(ins, methodname))
495 if hasattr(ins, "menudefs"):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000496 self.fill_menus(ins.menudefs, keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000497 return ins
498
Guido van Rossum07ec8961999-01-28 22:02:47 +0000499 def apply_bindings(self, keydefs=None):
500 if keydefs is None:
501 keydefs = self.Bindings.default_keydefs
502 text = self.text
503 text.keydefs = keydefs
504 for event, keylist in keydefs.items():
505 if keylist:
506 apply(text.event_add, (event,) + tuple(keylist))
507
508 def fill_menus(self, defs=None, keydefs=None):
509 # Fill the menus.
510 # Menus that are absent or None in self.menudict are ignored.
511 if defs is None:
512 defs = self.Bindings.menudefs
513 if keydefs is None:
514 keydefs = self.Bindings.default_keydefs
515 menudict = self.menudict
516 text = self.text
517 for mname, itemlist in defs:
518 menu = menudict.get(mname)
519 if not menu:
520 continue
521 for item in itemlist:
522 if not item:
523 menu.add_separator()
524 else:
525 label, event = item
526 checkbutton = (label[:1] == '!')
527 if checkbutton:
528 label = label[1:]
529 underline, label = prepstr(label)
530 accelerator = get_accelerator(keydefs, event)
531 def command(text=text, event=event):
532 text.event_generate(event)
533 if checkbutton:
534 var = self.getrawvar(event, BooleanVar)
535 menu.add_checkbutton(label=label, underline=underline,
536 command=command, accelerator=accelerator,
537 variable=var)
538 else:
539 menu.add_command(label=label, underline=underline,
540 command=command, accelerator=accelerator)
541
542 def getvar(self, name):
543 var = self.getrawvar(name)
544 if var:
545 return var.get()
546
547 def setvar(self, name, value, vartype=None):
548 var = self.getrawvar(name, vartype)
549 if var:
550 var.set(value)
551
552 def getrawvar(self, name, vartype=None):
553 key = ".VARS."
554 vars = self.menudict.get(key)
555 if not vars and vartype:
556 self.menudict[key] = vars = {}
557 if vars is not None:
558 var = vars.get(name)
559 if not var and vartype:
560 vars[name] = var = vartype(self.text)
561 return var
562
563
564def prepstr(s):
565 # Helper to extract the underscore from a string,
566 # e.g. prepstr("Co_py") returns (2, "Copy").
567 i = string.find(s, '_')
568 if i >= 0:
569 s = s[:i] + s[i+1:]
570 return i, s
571
572
573keynames = {
574 'bracketleft': '[',
575 'bracketright': ']',
576 'slash': '/',
577}
578
579def get_accelerator(keydefs, event):
580 keylist = keydefs.get(event)
581 if not keylist:
582 return ""
583 s = keylist[0]
584 s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
585 s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
586 s = re.sub("Key-", "", s)
587 s = re.sub("Control-", "Ctrl-", s)
588 s = re.sub("-", "+", s)
589 s = re.sub("><", " ", s)
590 s = re.sub("<", "", s)
591 s = re.sub(">", "", s)
592 return s
593
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000594
595def fixwordbreaks(root):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000596 # Make sure that Tk's double-click and next/previous word
597 # operations use our definition of a word (i.e. an identifier)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000598 tk = root.tk
599 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
600 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
601 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
602
603
604def test():
605 root = Tk()
606 fixwordbreaks(root)
607 root.withdraw()
608 if sys.argv[1:]:
609 filename = sys.argv[1]
610 else:
611 filename = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000612 edit = EditorWindow(root=root, filename=filename)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000613 edit.set_close_hook(root.quit)
614 root.mainloop()
615 root.destroy()
616
617if __name__ == '__main__':
618 test()