blob: 9436903fe1dde25f613c2e36473aa2f5b6a8ae31 [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
Guido van Rossumc4f752f1999-02-17 17:20:50 +000010import WindowList
Guido van Rossum504b0bf1999-01-02 21:28:54 +000011
12# File menu
13
14#$ event <<open-module>>
15#$ win <Alt-m>
16#$ unix <Control-x><Control-m>
17
18#$ event <<open-class-browser>>
19#$ win <Alt-c>
20#$ unix <Control-x><Control-b>
21
22#$ event <<close-window>>
23#$ unix <Control-x><Control-0>
24#$ unix <Control-x><Key-0>
25#$ win <Alt-F4>
26
27# Edit menu
28
29#$ event <<Copy>>
30#$ win <Control-c>
31#$ unix <Alt-w>
32
33#$ event <<Cut>>
34#$ win <Control-x>
35#$ unix <Control-w>
36
37#$ event <<Paste>>
38#$ win <Control-v>
39#$ unix <Control-y>
40
41#$ event <<select-all>>
42#$ win <Alt-a>
43#$ unix <Alt-a>
44
45# Help menu
46
47#$ event <<help>>
48#$ win <F1>
49#$ unix <F1>
50
51#$ event <<about-idle>>
52
53# Events without menu entries
54
55#$ event <<remove-selection>>
56#$ win <Escape>
57
58#$ event <<center-insert>>
59#$ win <Control-l>
60#$ unix <Control-l>
61
62#$ event <<do-nothing>>
63#$ unix <Control-x>
64
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000065
Guido van Rossum2aeeb551998-10-12 21:01:37 +000066about_title = "About IDLE"
67about_text = """\
Guido van Rossum504b0bf1999-01-02 21:28:54 +000068IDLE %s
Guido van Rossum2aeeb551998-10-12 21:01:37 +000069
Guido van Rossum504b0bf1999-01-02 21:28:54 +000070An Integrated DeveLopment Environment for Python
Guido van Rossum2aeeb551998-10-12 21:01:37 +000071
72by Guido van Rossum
Guido van Rossum504b0bf1999-01-02 21:28:54 +000073""" % idlever.IDLE_VERSION
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000074
75class EditorWindow:
76
77 from Percolator import Percolator
78 from ColorDelegator import ColorDelegator
79 from UndoDelegator import UndoDelegator
80 from IOBinding import IOBinding
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000081 import Bindings
Guido van Rossum504b0bf1999-01-02 21:28:54 +000082 from Tkinter import Toplevel
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000083
Guido van Rossum504b0bf1999-01-02 21:28:54 +000084 about_title = about_title
85 about_text = about_text
86
Guido van Rossumb7ebb831999-01-28 22:24:30 +000087 vars = {}
88
Guido van Rossum504b0bf1999-01-02 21:28:54 +000089 def __init__(self, flist=None, filename=None, key=None, root=None):
90 self.flist = flist
91 root = root or flist.root
Guido van Rossum2aeeb551998-10-12 21:01:37 +000092 self.root = root
Guido van Rossumb7ebb831999-01-28 22:24:30 +000093 if flist:
94 self.vars = flist.vars
Guido van Rossum2aeeb551998-10-12 21:01:37 +000095 self.menubar = Menu(root)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000096 self.top = top = self.Toplevel(root, menu=self.menubar)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000097 self.vbar = vbar = Scrollbar(top, name='vbar')
Guido van Rossum504b0bf1999-01-02 21:28:54 +000098 self.text = text = Text(top, name='text', padx=5,
99 background="white", wrap="none")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000100
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000101 self.createmenubar()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000102 self.apply_bindings()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000103
104 self.top.protocol("WM_DELETE_WINDOW", self.close)
105 self.top.bind("<<close-window>>", self.close_event)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000106 text.bind("<<center-insert>>", self.center_insert_event)
107 text.bind("<<help>>", self.help_dialog)
108 text.bind("<<about-idle>>", self.about_dialog)
109 text.bind("<<open-module>>", self.open_module)
110 text.bind("<<do-nothing>>", lambda event: "break")
111 text.bind("<<select-all>>", self.select_all)
112 text.bind("<<remove-selection>>", self.remove_selection)
113 text.bind("<3>", self.right_menu_event)
114 if flist:
115 flist.inversedict[self] = key
116 if key:
117 flist.dict[key] = self
118 text.bind("<<open-new-window>>", self.flist.new_callback)
119 text.bind("<<close-all-windows>>", self.flist.close_all_callback)
120 text.bind("<<open-class-browser>>", self.open_class_browser)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000121
122 vbar['command'] = text.yview
123 vbar.pack(side=RIGHT, fill=Y)
124
125 text['yscrollcommand'] = vbar.set
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000126 if sys.platform[:3] == 'win':
127 text['font'] = ("lucida console", 8)
128 text.pack(side=LEFT, fill=BOTH, expand=1)
129 text.focus_set()
130
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000131 self.per = per = self.Percolator(text)
132 if self.ispythonsource(filename):
133 self.color = color = self.ColorDelegator(); per.insertfilter(color)
134 ##print "Initial colorizer"
135 else:
136 ##print "No initial colorizer"
137 self.color = None
138 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000139 self.io = io = self.IOBinding(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000140
141 undo.set_saved_change_hook(self.saved_change_hook)
142 io.set_filename_change_hook(self.filename_change_hook)
143
144 if filename:
145 if os.path.exists(filename):
146 io.loadfile(filename)
147 else:
148 io.set_filename(filename)
149
150 self.saved_change_hook()
151
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000152 self.load_extensions()
153
154 menu = self.menudict.get('windows')
155 if menu:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000156 end = menu.index("end")
157 if end is None:
158 end = -1
159 if end >= 0:
160 menu.add_separator()
161 end = end + 1
162 self.wmenu_end = end
Guido van Rossumc4f752f1999-02-17 17:20:50 +0000163 WindowList.register_callback(self.postwindowsmenu)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000164
165 def wakeup(self):
Guido van Rossum36911a11999-01-18 15:18:57 +0000166 if self.top.wm_state() == "iconic":
167 self.top.wm_deiconify()
168 else:
169 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000170 self.text.focus_set()
171
Guido van Rossume7b2e651998-10-12 23:56:08 +0000172 menu_specs = [
Guido van Rossumb5eed031998-11-27 03:19:07 +0000173 ("file", "_File"),
174 ("edit", "_Edit"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000175 ("windows", "_Windows"),
Guido van Rossumb5eed031998-11-27 03:19:07 +0000176 ("help", "_Help"),
Guido van Rossume7b2e651998-10-12 23:56:08 +0000177 ]
178
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000179 def createmenubar(self):
180 mbar = self.menubar
Guido van Rossum07ec8961999-01-28 22:02:47 +0000181 self.menudict = menudict = {}
Guido van Rossume7b2e651998-10-12 23:56:08 +0000182 for name, label in self.menu_specs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000183 underline, label = prepstr(label)
184 menudict[name] = menu = Menu(mbar, name=name)
Guido van Rossumb5eed031998-11-27 03:19:07 +0000185 mbar.add_cascade(label=label, menu=menu, underline=underline)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000186 self.fill_menus()
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000187
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000188 def postwindowsmenu(self):
189 # Only called when Windows menu exists
Guido van Rossum07ec8961999-01-28 22:02:47 +0000190 # XXX Actually, this Just-In-Time updating interferes
191 # XXX badly with the tear-off feature. It would be better
192 # XXX to update all Windows menus whenever the list of windows
193 # XXX changes.
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000194 menu = self.menudict['windows']
195 end = menu.index("end")
196 if end is None:
197 end = -1
198 if end > self.wmenu_end:
199 menu.delete(self.wmenu_end+1, end)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000200 WindowList.add_windows_to_menu(menu)
201
202 rmenu = None
203
204 def right_menu_event(self, event):
205 self.text.tag_remove("sel", "1.0", "end")
206 self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
207 if not self.rmenu:
208 self.make_rmenu()
209 rmenu = self.rmenu
210 self.event = event
211 iswin = sys.platform[:3] == 'win'
212 if iswin:
213 self.text.config(cursor="arrow")
214 rmenu.tk_popup(event.x_root, event.y_root)
215 if iswin:
216 self.text.config(cursor="ibeam")
217
218 rmenu_specs = [
219 # ("Label", "<<virtual-event>>"), ...
220 ("Close", "<<close-window>>"), # Example
221 ]
222
223 def make_rmenu(self):
224 rmenu = Menu(self.text, tearoff=0)
225 for label, eventname in self.rmenu_specs:
226 def command(text=self.text, eventname=eventname):
227 text.event_generate(eventname)
228 rmenu.add_command(label=label, command=command)
229 self.rmenu = rmenu
230
Guido van Rossume7b2e651998-10-12 23:56:08 +0000231 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000232 tkMessageBox.showinfo(self.about_title, self.about_text,
233 master=self.text)
234
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000235 helpfile = "help.txt"
236
Guido van Rossume7b2e651998-10-12 23:56:08 +0000237 def help_dialog(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000238 helpfile = self.helpfile
239 if not os.path.exists(helpfile):
240 base = os.path.basename(self.helpfile)
241 for dir in sys.path:
242 fullname = os.path.join(dir, base)
243 if os.path.exists(fullname):
244 helpfile = fullname
245 break
246 if self.flist:
247 self.flist.open(helpfile)
248 else:
249 self.io.loadfile(helpfile)
250
251 def select_all(self, event=None):
252 self.text.tag_add("sel", "1.0", "end-1c")
253 self.text.mark_set("insert", "1.0")
254 self.text.see("insert")
255 return "break"
256
257 def remove_selection(self, event=None):
258 self.text.tag_remove("sel", "1.0", "end")
259 self.text.see("insert")
260
Guido van Rossumb3418881998-10-13 03:45:15 +0000261 def open_module(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000262 # XXX Shouldn't this be in IOBinding or in FileList?
Guido van Rossumb3418881998-10-13 03:45:15 +0000263 try:
264 name = self.text.get("sel.first", "sel.last")
265 except TclError:
266 name = ""
267 else:
268 name = string.strip(name)
269 if not name:
270 name = tkSimpleDialog.askstring("Module",
Guido van Rossume1dedc01998-10-16 16:09:57 +0000271 "Enter the name of a Python module\n"
272 "to search on sys.path and open:",
Guido van Rossumb3418881998-10-13 03:45:15 +0000273 parent=self.text)
274 if name:
275 name = string.strip(name)
276 if not name:
277 return
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000278 # XXX Ought to support package syntax
279 # XXX Ought to insert current file's directory in front of path
Guido van Rossumb3418881998-10-13 03:45:15 +0000280 try:
281 (f, file, (suffix, mode, type)) = imp.find_module(name)
282 except ImportError, msg:
283 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
284 return
285 if type != imp.PY_SOURCE:
286 tkMessageBox.showerror("Unsupported type",
287 "%s is not a source module" % name, parent=self.text)
288 return
289 if f:
290 f.close()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000291 if self.flist:
292 self.flist.open(file)
293 else:
294 self.io.loadfile(file)
295
296 def open_class_browser(self, event=None):
297 filename = self.io.filename
298 if not filename:
299 tkMessageBox.showerror(
300 "No filename",
301 "This buffer has no associated filename",
302 master=self.text)
303 return None
304 head, tail = os.path.split(filename)
305 base, ext = os.path.splitext(tail)
306 import pyclbr
307 if pyclbr._modules.has_key(base):
308 del pyclbr._modules[base]
Guido van Rossum245ddc41999-01-11 14:51:32 +0000309 save_cursor = self.text["cursor"]
310 self.text["cursor"] = "watch"
311 self.text.update_idletasks()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000312 import ClassBrowser
313 ClassBrowser.ClassBrowser(self.flist, base, [head])
Guido van Rossum245ddc41999-01-11 14:51:32 +0000314 self.text["cursor"] = save_cursor
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000315
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000316 def gotoline(self, lineno):
317 if lineno is not None and lineno > 0:
318 self.text.mark_set("insert", "%d.0" % lineno)
319 self.text.tag_remove("sel", "1.0", "end")
320 self.text.tag_add("sel", "insert", "insert +1l")
321 self.center()
322
323 def ispythonsource(self, filename):
324 if not filename:
325 return 1
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000326 base, ext = os.path.splitext(os.path.basename(filename))
327 if os.path.normcase(ext) in (".py", ".pyw"):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000328 return 1
329 try:
330 f = open(filename)
331 line = f.readline()
332 f.close()
333 except IOError:
334 return 0
335 return line[:2] == '#!' and string.find(line, 'python') >= 0
336
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000337 def close_hook(self):
338 if self.flist:
339 self.flist.close_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000340
341 def set_close_hook(self, close_hook):
342 self.close_hook = close_hook
343
344 def filename_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000345 if self.flist:
346 self.flist.filename_changed_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000347 self.saved_change_hook()
348 if self.ispythonsource(self.io.filename):
349 self.addcolorizer()
350 else:
351 self.rmcolorizer()
352
353 def addcolorizer(self):
354 if self.color:
355 return
356 ##print "Add colorizer"
357 self.per.removefilter(self.undo)
358 self.color = self.ColorDelegator()
359 self.per.insertfilter(self.color)
360 self.per.insertfilter(self.undo)
361
362 def rmcolorizer(self):
363 if not self.color:
364 return
365 ##print "Remove colorizer"
366 self.per.removefilter(self.undo)
367 self.per.removefilter(self.color)
368 self.color = None
369 self.per.insertfilter(self.undo)
370
371 def saved_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000372 short = self.short_title()
373 long = self.long_title()
374 if short and long:
375 title = short + " - " + long
376 elif short:
377 title = short
378 elif long:
379 title = long
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000380 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000381 title = "Untitled"
382 icon = short or long or title
383 if not self.get_saved():
384 title = "*%s*" % title
385 icon = "*%s" % icon
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000386 self.top.wm_title(title)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000387 self.top.wm_iconname(icon)
388
389 def get_saved(self):
390 return self.undo.get_saved()
391
392 def set_saved(self, flag):
393 self.undo.set_saved(flag)
394
395 def reset_undo(self):
396 self.undo.reset_undo()
397
398 def short_title(self):
399 filename = self.io.filename
400 if filename:
401 filename = os.path.basename(filename)
402 return filename
403
404 def long_title(self):
405 return self.io.filename or ""
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000406
407 def center_insert_event(self, event):
408 self.center()
409
410 def center(self, mark="insert"):
Guido van Rossum245ddc41999-01-11 14:51:32 +0000411 text = self.text
412 top, bot = self.getwindowlines()
413 lineno = self.getlineno(mark)
414 height = bot - top
415 newtop = max(1, lineno - height/2)
416 text.yview(float(newtop))
417
418 def getwindowlines(self):
419 text = self.text
420 top = self.getlineno("@0,0")
421 bot = self.getlineno("@0,65535")
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000422 if top == bot and text.winfo_height() == 1:
423 # Geometry manager hasn't run yet
Guido van Rossum245ddc41999-01-11 14:51:32 +0000424 height = int(text['height'])
425 bot = top + height - 1
426 return top, bot
427
428 def getlineno(self, mark="insert"):
429 text = self.text
430 return int(float(text.index(mark)))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000431
432 def close_event(self, event):
433 self.close()
434
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000435 def maybesave(self):
436 if self.io:
437 return self.io.maybesave()
438
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000439 def close(self):
440 self.top.wm_deiconify()
441 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000442 reply = self.maybesave()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000443 if reply != "cancel":
Guido van Rossumc4f752f1999-02-17 17:20:50 +0000444 WindowList.unregister_callback(self.postwindowsmenu)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000445 if self.close_hook:
446 self.close_hook()
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000447 colorizing = 0
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000448 if self.color:
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000449 colorizing = self.color.colorizing
450 doh = colorizing and self.top
451 self.color.close(doh) # Cancel colorization
452 if not colorizing:
453 self.top.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000454 return reply
455
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000456 def load_extensions(self):
457 self.extensions = {}
458 self.load_standard_extensions()
459
460 def load_standard_extensions(self):
461 for name in self.get_standard_extension_names():
462 try:
463 self.load_extension(name)
464 except:
465 print "Failed to load extension", `name`
466 import traceback
467 traceback.print_exc()
468
469 def get_standard_extension_names(self):
470 import extend
471 return extend.standard
472
473 def load_extension(self, name):
474 mod = __import__(name)
475 cls = getattr(mod, name)
476 ins = cls(self)
477 self.extensions[name] = ins
478 kdnames = ["keydefs"]
479 if sys.platform == 'win32':
480 kdnames.append("windows_keydefs")
481 elif sys.platform == 'mac':
482 kdnames.append("mac_keydefs")
483 else:
484 kdnames.append("unix_keydefs")
485 keydefs = {}
486 for kdname in kdnames:
487 if hasattr(ins, kdname):
488 keydefs.update(getattr(ins, kdname))
489 if keydefs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000490 self.apply_bindings(keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000491 for vevent in keydefs.keys():
492 methodname = string.replace(vevent, "-", "_")
493 while methodname[:1] == '<':
494 methodname = methodname[1:]
495 while methodname[-1:] == '>':
496 methodname = methodname[:-1]
497 methodname = methodname + "_event"
498 if hasattr(ins, methodname):
499 self.text.bind(vevent, getattr(ins, methodname))
500 if hasattr(ins, "menudefs"):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000501 self.fill_menus(ins.menudefs, keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000502 return ins
503
Guido van Rossum07ec8961999-01-28 22:02:47 +0000504 def apply_bindings(self, keydefs=None):
505 if keydefs is None:
506 keydefs = self.Bindings.default_keydefs
507 text = self.text
508 text.keydefs = keydefs
509 for event, keylist in keydefs.items():
510 if keylist:
511 apply(text.event_add, (event,) + tuple(keylist))
512
513 def fill_menus(self, defs=None, keydefs=None):
514 # Fill the menus.
515 # Menus that are absent or None in self.menudict are ignored.
516 if defs is None:
517 defs = self.Bindings.menudefs
518 if keydefs is None:
519 keydefs = self.Bindings.default_keydefs
520 menudict = self.menudict
521 text = self.text
522 for mname, itemlist in defs:
523 menu = menudict.get(mname)
524 if not menu:
525 continue
526 for item in itemlist:
527 if not item:
528 menu.add_separator()
529 else:
530 label, event = item
531 checkbutton = (label[:1] == '!')
532 if checkbutton:
533 label = label[1:]
534 underline, label = prepstr(label)
535 accelerator = get_accelerator(keydefs, event)
536 def command(text=text, event=event):
537 text.event_generate(event)
538 if checkbutton:
539 var = self.getrawvar(event, BooleanVar)
540 menu.add_checkbutton(label=label, underline=underline,
541 command=command, accelerator=accelerator,
542 variable=var)
543 else:
544 menu.add_command(label=label, underline=underline,
545 command=command, accelerator=accelerator)
546
547 def getvar(self, name):
548 var = self.getrawvar(name)
549 if var:
550 return var.get()
551
552 def setvar(self, name, value, vartype=None):
553 var = self.getrawvar(name, vartype)
554 if var:
555 var.set(value)
556
557 def getrawvar(self, name, vartype=None):
Guido van Rossumb7ebb831999-01-28 22:24:30 +0000558 var = self.vars.get(name)
559 if not var and vartype:
560 self.vars[name] = var = vartype(self.text)
561 return var
Guido van Rossum07ec8961999-01-28 22:02:47 +0000562
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()