blob: cea3fcd3a90467f83d8bee1fb42c8c08b989b558 [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
Guido van Rossumd6e87131999-03-10 05:18:02 +000022#$ event <<open-path-browser>>
23
Guido van Rossum504b0bf1999-01-02 21:28:54 +000024#$ event <<close-window>>
25#$ unix <Control-x><Control-0>
26#$ unix <Control-x><Key-0>
27#$ win <Alt-F4>
28
29# Edit menu
30
31#$ event <<Copy>>
32#$ win <Control-c>
33#$ unix <Alt-w>
34
35#$ event <<Cut>>
36#$ win <Control-x>
37#$ unix <Control-w>
38
39#$ event <<Paste>>
40#$ win <Control-v>
41#$ unix <Control-y>
42
43#$ event <<select-all>>
44#$ win <Alt-a>
45#$ unix <Alt-a>
46
47# Help menu
48
49#$ event <<help>>
50#$ win <F1>
51#$ unix <F1>
52
53#$ event <<about-idle>>
54
55# Events without menu entries
56
57#$ event <<remove-selection>>
58#$ win <Escape>
59
60#$ event <<center-insert>>
61#$ win <Control-l>
62#$ unix <Control-l>
63
64#$ event <<do-nothing>>
65#$ unix <Control-x>
66
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000067
Guido van Rossum2aeeb551998-10-12 21:01:37 +000068about_title = "About IDLE"
69about_text = """\
Guido van Rossum504b0bf1999-01-02 21:28:54 +000070IDLE %s
Guido van Rossum2aeeb551998-10-12 21:01:37 +000071
Guido van Rossum504b0bf1999-01-02 21:28:54 +000072An Integrated DeveLopment Environment for Python
Guido van Rossum2aeeb551998-10-12 21:01:37 +000073
74by Guido van Rossum
Guido van Rossum504b0bf1999-01-02 21:28:54 +000075""" % idlever.IDLE_VERSION
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000076
77class EditorWindow:
78
79 from Percolator import Percolator
80 from ColorDelegator import ColorDelegator
81 from UndoDelegator import UndoDelegator
82 from IOBinding import IOBinding
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000083 import Bindings
Guido van Rossum504b0bf1999-01-02 21:28:54 +000084 from Tkinter import Toplevel
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000085
Guido van Rossum504b0bf1999-01-02 21:28:54 +000086 about_title = about_title
87 about_text = about_text
88
Guido van Rossumb7ebb831999-01-28 22:24:30 +000089 vars = {}
90
Guido van Rossum504b0bf1999-01-02 21:28:54 +000091 def __init__(self, flist=None, filename=None, key=None, root=None):
92 self.flist = flist
93 root = root or flist.root
Guido van Rossum2aeeb551998-10-12 21:01:37 +000094 self.root = root
Guido van Rossumb7ebb831999-01-28 22:24:30 +000095 if flist:
96 self.vars = flist.vars
Guido van Rossum2aeeb551998-10-12 21:01:37 +000097 self.menubar = Menu(root)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000098 self.top = top = self.Toplevel(root, menu=self.menubar)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000099 self.vbar = vbar = Scrollbar(top, name='vbar')
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000100 self.text = text = Text(top, name='text', padx=5,
101 background="white", wrap="none")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000102
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000103 self.createmenubar()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000104 self.apply_bindings()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000105
106 self.top.protocol("WM_DELETE_WINDOW", self.close)
107 self.top.bind("<<close-window>>", self.close_event)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000108 text.bind("<<center-insert>>", self.center_insert_event)
109 text.bind("<<help>>", self.help_dialog)
110 text.bind("<<about-idle>>", self.about_dialog)
111 text.bind("<<open-module>>", self.open_module)
112 text.bind("<<do-nothing>>", lambda event: "break")
113 text.bind("<<select-all>>", self.select_all)
114 text.bind("<<remove-selection>>", self.remove_selection)
115 text.bind("<3>", self.right_menu_event)
116 if flist:
117 flist.inversedict[self] = key
118 if key:
119 flist.dict[key] = self
120 text.bind("<<open-new-window>>", self.flist.new_callback)
121 text.bind("<<close-all-windows>>", self.flist.close_all_callback)
122 text.bind("<<open-class-browser>>", self.open_class_browser)
Guido van Rossumd6e87131999-03-10 05:18:02 +0000123 text.bind("<<open-path-browser>>", self.open_path_browser)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000124
125 vbar['command'] = text.yview
126 vbar.pack(side=RIGHT, fill=Y)
127
128 text['yscrollcommand'] = vbar.set
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000129 if sys.platform[:3] == 'win':
130 text['font'] = ("lucida console", 8)
131 text.pack(side=LEFT, fill=BOTH, expand=1)
132 text.focus_set()
133
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000134 self.per = per = self.Percolator(text)
135 if self.ispythonsource(filename):
136 self.color = color = self.ColorDelegator(); per.insertfilter(color)
137 ##print "Initial colorizer"
138 else:
139 ##print "No initial colorizer"
140 self.color = None
141 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000142 self.io = io = self.IOBinding(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000143
144 undo.set_saved_change_hook(self.saved_change_hook)
145 io.set_filename_change_hook(self.filename_change_hook)
146
147 if filename:
148 if os.path.exists(filename):
149 io.loadfile(filename)
150 else:
151 io.set_filename(filename)
152
153 self.saved_change_hook()
154
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000155 self.load_extensions()
156
157 menu = self.menudict.get('windows')
158 if menu:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000159 end = menu.index("end")
160 if end is None:
161 end = -1
162 if end >= 0:
163 menu.add_separator()
164 end = end + 1
165 self.wmenu_end = end
Guido van Rossumc4f752f1999-02-17 17:20:50 +0000166 WindowList.register_callback(self.postwindowsmenu)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000167
168 def wakeup(self):
Guido van Rossum36911a11999-01-18 15:18:57 +0000169 if self.top.wm_state() == "iconic":
170 self.top.wm_deiconify()
171 else:
172 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000173 self.text.focus_set()
174
Guido van Rossume7b2e651998-10-12 23:56:08 +0000175 menu_specs = [
Guido van Rossumb5eed031998-11-27 03:19:07 +0000176 ("file", "_File"),
177 ("edit", "_Edit"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000178 ("windows", "_Windows"),
Guido van Rossumb5eed031998-11-27 03:19:07 +0000179 ("help", "_Help"),
Guido van Rossume7b2e651998-10-12 23:56:08 +0000180 ]
181
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000182 def createmenubar(self):
183 mbar = self.menubar
Guido van Rossum07ec8961999-01-28 22:02:47 +0000184 self.menudict = menudict = {}
Guido van Rossume7b2e651998-10-12 23:56:08 +0000185 for name, label in self.menu_specs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000186 underline, label = prepstr(label)
187 menudict[name] = menu = Menu(mbar, name=name)
Guido van Rossumb5eed031998-11-27 03:19:07 +0000188 mbar.add_cascade(label=label, menu=menu, underline=underline)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000189 self.fill_menus()
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000190
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000191 def postwindowsmenu(self):
192 # Only called when Windows menu exists
Guido van Rossum07ec8961999-01-28 22:02:47 +0000193 # XXX Actually, this Just-In-Time updating interferes
194 # XXX badly with the tear-off feature. It would be better
195 # XXX to update all Windows menus whenever the list of windows
196 # XXX changes.
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000197 menu = self.menudict['windows']
198 end = menu.index("end")
199 if end is None:
200 end = -1
201 if end > self.wmenu_end:
202 menu.delete(self.wmenu_end+1, end)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000203 WindowList.add_windows_to_menu(menu)
204
205 rmenu = None
206
207 def right_menu_event(self, event):
208 self.text.tag_remove("sel", "1.0", "end")
209 self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
210 if not self.rmenu:
211 self.make_rmenu()
212 rmenu = self.rmenu
213 self.event = event
214 iswin = sys.platform[:3] == 'win'
215 if iswin:
216 self.text.config(cursor="arrow")
217 rmenu.tk_popup(event.x_root, event.y_root)
218 if iswin:
219 self.text.config(cursor="ibeam")
220
221 rmenu_specs = [
222 # ("Label", "<<virtual-event>>"), ...
223 ("Close", "<<close-window>>"), # Example
224 ]
225
226 def make_rmenu(self):
227 rmenu = Menu(self.text, tearoff=0)
228 for label, eventname in self.rmenu_specs:
229 def command(text=self.text, eventname=eventname):
230 text.event_generate(eventname)
231 rmenu.add_command(label=label, command=command)
232 self.rmenu = rmenu
233
Guido van Rossume7b2e651998-10-12 23:56:08 +0000234 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000235 tkMessageBox.showinfo(self.about_title, self.about_text,
236 master=self.text)
237
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000238 helpfile = "help.txt"
239
Guido van Rossume7b2e651998-10-12 23:56:08 +0000240 def help_dialog(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000241 helpfile = self.helpfile
242 if not os.path.exists(helpfile):
243 base = os.path.basename(self.helpfile)
244 for dir in sys.path:
245 fullname = os.path.join(dir, base)
246 if os.path.exists(fullname):
247 helpfile = fullname
248 break
249 if self.flist:
250 self.flist.open(helpfile)
251 else:
252 self.io.loadfile(helpfile)
253
254 def select_all(self, event=None):
255 self.text.tag_add("sel", "1.0", "end-1c")
256 self.text.mark_set("insert", "1.0")
257 self.text.see("insert")
258 return "break"
259
260 def remove_selection(self, event=None):
261 self.text.tag_remove("sel", "1.0", "end")
262 self.text.see("insert")
263
Guido van Rossumb3418881998-10-13 03:45:15 +0000264 def open_module(self, event=None):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000265 # XXX Shouldn't this be in IOBinding or in FileList?
Guido van Rossumb3418881998-10-13 03:45:15 +0000266 try:
267 name = self.text.get("sel.first", "sel.last")
268 except TclError:
269 name = ""
270 else:
271 name = string.strip(name)
272 if not name:
273 name = tkSimpleDialog.askstring("Module",
Guido van Rossume1dedc01998-10-16 16:09:57 +0000274 "Enter the name of a Python module\n"
275 "to search on sys.path and open:",
Guido van Rossumb3418881998-10-13 03:45:15 +0000276 parent=self.text)
277 if name:
278 name = string.strip(name)
279 if not name:
280 return
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000281 # XXX Ought to support package syntax
282 # XXX Ought to insert current file's directory in front of path
Guido van Rossumb3418881998-10-13 03:45:15 +0000283 try:
284 (f, file, (suffix, mode, type)) = imp.find_module(name)
285 except ImportError, msg:
286 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
287 return
288 if type != imp.PY_SOURCE:
289 tkMessageBox.showerror("Unsupported type",
290 "%s is not a source module" % name, parent=self.text)
291 return
292 if f:
293 f.close()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000294 if self.flist:
295 self.flist.open(file)
296 else:
297 self.io.loadfile(file)
298
299 def open_class_browser(self, event=None):
300 filename = self.io.filename
301 if not filename:
302 tkMessageBox.showerror(
303 "No filename",
304 "This buffer has no associated filename",
305 master=self.text)
306 return None
307 head, tail = os.path.split(filename)
308 base, ext = os.path.splitext(tail)
309 import pyclbr
310 if pyclbr._modules.has_key(base):
311 del pyclbr._modules[base]
Guido van Rossum245ddc41999-01-11 14:51:32 +0000312 save_cursor = self.text["cursor"]
313 self.text["cursor"] = "watch"
314 self.text.update_idletasks()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000315 import ClassBrowser
316 ClassBrowser.ClassBrowser(self.flist, base, [head])
Guido van Rossum245ddc41999-01-11 14:51:32 +0000317 self.text["cursor"] = save_cursor
Guido van Rossumd6e87131999-03-10 05:18:02 +0000318
319 def open_path_browser(self, event=None):
320 import PathBrowser
321 PathBrowser.PathBrowser(self.flist)
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000322
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000323 def gotoline(self, lineno):
324 if lineno is not None and lineno > 0:
325 self.text.mark_set("insert", "%d.0" % lineno)
326 self.text.tag_remove("sel", "1.0", "end")
327 self.text.tag_add("sel", "insert", "insert +1l")
328 self.center()
329
330 def ispythonsource(self, filename):
331 if not filename:
332 return 1
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000333 base, ext = os.path.splitext(os.path.basename(filename))
334 if os.path.normcase(ext) in (".py", ".pyw"):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000335 return 1
336 try:
337 f = open(filename)
338 line = f.readline()
339 f.close()
340 except IOError:
341 return 0
342 return line[:2] == '#!' and string.find(line, 'python') >= 0
343
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000344 def close_hook(self):
345 if self.flist:
346 self.flist.close_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000347
348 def set_close_hook(self, close_hook):
349 self.close_hook = close_hook
350
351 def filename_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000352 if self.flist:
353 self.flist.filename_changed_edit(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000354 self.saved_change_hook()
355 if self.ispythonsource(self.io.filename):
356 self.addcolorizer()
357 else:
358 self.rmcolorizer()
359
360 def addcolorizer(self):
361 if self.color:
362 return
363 ##print "Add colorizer"
364 self.per.removefilter(self.undo)
365 self.color = self.ColorDelegator()
366 self.per.insertfilter(self.color)
367 self.per.insertfilter(self.undo)
368
369 def rmcolorizer(self):
370 if not self.color:
371 return
372 ##print "Remove colorizer"
373 self.per.removefilter(self.undo)
374 self.per.removefilter(self.color)
375 self.color = None
376 self.per.insertfilter(self.undo)
377
378 def saved_change_hook(self):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000379 short = self.short_title()
380 long = self.long_title()
381 if short and long:
382 title = short + " - " + long
383 elif short:
384 title = short
385 elif long:
386 title = long
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000387 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000388 title = "Untitled"
389 icon = short or long or title
390 if not self.get_saved():
391 title = "*%s*" % title
392 icon = "*%s" % icon
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000393 self.top.wm_title(title)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000394 self.top.wm_iconname(icon)
395
396 def get_saved(self):
397 return self.undo.get_saved()
398
399 def set_saved(self, flag):
400 self.undo.set_saved(flag)
401
402 def reset_undo(self):
403 self.undo.reset_undo()
404
405 def short_title(self):
406 filename = self.io.filename
407 if filename:
408 filename = os.path.basename(filename)
409 return filename
410
411 def long_title(self):
412 return self.io.filename or ""
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000413
414 def center_insert_event(self, event):
415 self.center()
416
417 def center(self, mark="insert"):
Guido van Rossum245ddc41999-01-11 14:51:32 +0000418 text = self.text
419 top, bot = self.getwindowlines()
420 lineno = self.getlineno(mark)
421 height = bot - top
422 newtop = max(1, lineno - height/2)
423 text.yview(float(newtop))
424
425 def getwindowlines(self):
426 text = self.text
427 top = self.getlineno("@0,0")
428 bot = self.getlineno("@0,65535")
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000429 if top == bot and text.winfo_height() == 1:
430 # Geometry manager hasn't run yet
Guido van Rossum245ddc41999-01-11 14:51:32 +0000431 height = int(text['height'])
432 bot = top + height - 1
433 return top, bot
434
435 def getlineno(self, mark="insert"):
436 text = self.text
437 return int(float(text.index(mark)))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000438
439 def close_event(self, event):
440 self.close()
441
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000442 def maybesave(self):
443 if self.io:
444 return self.io.maybesave()
445
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000446 def close(self):
447 self.top.wm_deiconify()
448 self.top.tkraise()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000449 reply = self.maybesave()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000450 if reply != "cancel":
Guido van Rossumc4f752f1999-02-17 17:20:50 +0000451 WindowList.unregister_callback(self.postwindowsmenu)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000452 if self.close_hook:
453 self.close_hook()
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000454 colorizing = 0
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000455 if self.color:
Guido van Rossum5051f4f1999-01-12 22:09:57 +0000456 colorizing = self.color.colorizing
457 doh = colorizing and self.top
458 self.color.close(doh) # Cancel colorization
459 if not colorizing:
460 self.top.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000461 return reply
462
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000463 def load_extensions(self):
464 self.extensions = {}
465 self.load_standard_extensions()
466
467 def load_standard_extensions(self):
468 for name in self.get_standard_extension_names():
469 try:
470 self.load_extension(name)
471 except:
472 print "Failed to load extension", `name`
473 import traceback
474 traceback.print_exc()
475
476 def get_standard_extension_names(self):
477 import extend
478 return extend.standard
479
480 def load_extension(self, name):
481 mod = __import__(name)
482 cls = getattr(mod, name)
483 ins = cls(self)
484 self.extensions[name] = ins
485 kdnames = ["keydefs"]
486 if sys.platform == 'win32':
487 kdnames.append("windows_keydefs")
488 elif sys.platform == 'mac':
489 kdnames.append("mac_keydefs")
490 else:
491 kdnames.append("unix_keydefs")
492 keydefs = {}
493 for kdname in kdnames:
494 if hasattr(ins, kdname):
495 keydefs.update(getattr(ins, kdname))
496 if keydefs:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000497 self.apply_bindings(keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000498 for vevent in keydefs.keys():
499 methodname = string.replace(vevent, "-", "_")
500 while methodname[:1] == '<':
501 methodname = methodname[1:]
502 while methodname[-1:] == '>':
503 methodname = methodname[:-1]
504 methodname = methodname + "_event"
505 if hasattr(ins, methodname):
506 self.text.bind(vevent, getattr(ins, methodname))
507 if hasattr(ins, "menudefs"):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000508 self.fill_menus(ins.menudefs, keydefs)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000509 return ins
510
Guido van Rossum07ec8961999-01-28 22:02:47 +0000511 def apply_bindings(self, keydefs=None):
512 if keydefs is None:
513 keydefs = self.Bindings.default_keydefs
514 text = self.text
515 text.keydefs = keydefs
516 for event, keylist in keydefs.items():
517 if keylist:
518 apply(text.event_add, (event,) + tuple(keylist))
519
520 def fill_menus(self, defs=None, keydefs=None):
521 # Fill the menus.
522 # Menus that are absent or None in self.menudict are ignored.
523 if defs is None:
524 defs = self.Bindings.menudefs
525 if keydefs is None:
526 keydefs = self.Bindings.default_keydefs
527 menudict = self.menudict
528 text = self.text
529 for mname, itemlist in defs:
530 menu = menudict.get(mname)
531 if not menu:
532 continue
533 for item in itemlist:
534 if not item:
535 menu.add_separator()
536 else:
537 label, event = item
538 checkbutton = (label[:1] == '!')
539 if checkbutton:
540 label = label[1:]
541 underline, label = prepstr(label)
542 accelerator = get_accelerator(keydefs, event)
543 def command(text=text, event=event):
544 text.event_generate(event)
545 if checkbutton:
546 var = self.getrawvar(event, BooleanVar)
547 menu.add_checkbutton(label=label, underline=underline,
548 command=command, accelerator=accelerator,
549 variable=var)
550 else:
551 menu.add_command(label=label, underline=underline,
552 command=command, accelerator=accelerator)
553
554 def getvar(self, name):
555 var = self.getrawvar(name)
556 if var:
557 return var.get()
558
559 def setvar(self, name, value, vartype=None):
560 var = self.getrawvar(name, vartype)
561 if var:
562 var.set(value)
563
564 def getrawvar(self, name, vartype=None):
Guido van Rossumb7ebb831999-01-28 22:24:30 +0000565 var = self.vars.get(name)
566 if not var and vartype:
567 self.vars[name] = var = vartype(self.text)
568 return var
Guido van Rossum07ec8961999-01-28 22:02:47 +0000569
570
571def prepstr(s):
572 # Helper to extract the underscore from a string,
573 # e.g. prepstr("Co_py") returns (2, "Copy").
574 i = string.find(s, '_')
575 if i >= 0:
576 s = s[:i] + s[i+1:]
577 return i, s
578
579
580keynames = {
581 'bracketleft': '[',
582 'bracketright': ']',
583 'slash': '/',
584}
585
586def get_accelerator(keydefs, event):
587 keylist = keydefs.get(event)
588 if not keylist:
589 return ""
590 s = keylist[0]
591 s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
592 s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
593 s = re.sub("Key-", "", s)
594 s = re.sub("Control-", "Ctrl-", s)
595 s = re.sub("-", "+", s)
596 s = re.sub("><", " ", s)
597 s = re.sub("<", "", s)
598 s = re.sub(">", "", s)
599 return s
600
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000601
602def fixwordbreaks(root):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000603 # Make sure that Tk's double-click and next/previous word
604 # operations use our definition of a word (i.e. an identifier)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000605 tk = root.tk
606 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
607 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
608 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
609
610
611def test():
612 root = Tk()
613 fixwordbreaks(root)
614 root.withdraw()
615 if sys.argv[1:]:
616 filename = sys.argv[1]
617 else:
618 filename = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000619 edit = EditorWindow(root=root, filename=filename)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000620 edit.set_close_hook(root.quit)
621 root.mainloop()
622 root.destroy()
623
624if __name__ == '__main__':
625 test()