blob: 24b62dcbaabb4334b7e402c4833c9fea2b3b4e2d [file] [log] [blame]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00001import sys
2import os
3import string
Guido van Rossumb3418881998-10-13 03:45:15 +00004import imp
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00005from Tkinter import *
Guido van Rossumb3418881998-10-13 03:45:15 +00006import tkSimpleDialog
Guido van Rossum2aeeb551998-10-12 21:01:37 +00007import tkMessageBox
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00008
Guido van Rossum2aeeb551998-10-12 21:01:37 +00009about_title = "About IDLE"
10about_text = """\
11IDLE 0.1
12
13A not totally unintegrated development environment for Python
14
15by Guido van Rossum
16"""
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000017
18class EditorWindow:
19
20 from Percolator import Percolator
21 from ColorDelegator import ColorDelegator
22 from UndoDelegator import UndoDelegator
23 from IOBinding import IOBinding
24 from SearchBinding import SearchBinding
25 from AutoIndent import AutoIndent
26 from AutoExpand import AutoExpand
27 import Bindings
Guido van Rossum2aeeb551998-10-12 21:01:37 +000028
29 about_title = about_title
30 about_text = about_text
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000031
32 def __init__(self, root, filename=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +000033 self.root = root
34 self.menubar = Menu(root)
35 self.top = top = Toplevel(root, menu=self.menubar)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000036 self.vbar = vbar = Scrollbar(top, name='vbar')
37 self.text = text = Text(top, name='text')
38
Guido van Rossum2aeeb551998-10-12 21:01:37 +000039 self.createmenubar()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000040 self.Bindings.apply_bindings(text)
41
42 self.top.protocol("WM_DELETE_WINDOW", self.close)
43 self.top.bind("<<close-window>>", self.close_event)
44 self.text.bind("<<center-insert>>", self.center_insert_event)
Guido van Rossume7b2e651998-10-12 23:56:08 +000045 self.text.bind("<<help>>", self.help_dialog)
46 self.text.bind("<<about-idle>>", self.about_dialog)
Guido van Rossumb3418881998-10-13 03:45:15 +000047 self.text.bind("<<open-module>>", self.open_module)
Guido van Rossumbaf53b41998-10-16 20:08:34 +000048 self.text.bind("<<do-nothing>>", lambda event: "break")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000049
50 vbar['command'] = text.yview
51 vbar.pack(side=RIGHT, fill=Y)
52
53 text['yscrollcommand'] = vbar.set
54 text['background'] = 'white'
55 if sys.platform[:3] == 'win':
56 text['font'] = ("lucida console", 8)
57 text.pack(side=LEFT, fill=BOTH, expand=1)
58 text.focus_set()
59
60 self.auto = auto = self.AutoIndent(text)
61 self.autoex = self.AutoExpand(text)
62 self.per = per = self.Percolator(text)
63 if self.ispythonsource(filename):
64 self.color = color = self.ColorDelegator(); per.insertfilter(color)
65 ##print "Initial colorizer"
66 else:
67 ##print "No initial colorizer"
68 self.color = None
69 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
70 self.search = search = self.SearchBinding(undo)
71 self.io = io = self.IOBinding(undo)
72
73 undo.set_saved_change_hook(self.saved_change_hook)
74 io.set_filename_change_hook(self.filename_change_hook)
75
76 if filename:
77 if os.path.exists(filename):
78 io.loadfile(filename)
79 else:
80 io.set_filename(filename)
81
82 self.saved_change_hook()
83
Guido van Rossume7b2e651998-10-12 23:56:08 +000084 menu_specs = [
Guido van Rossumb5eed031998-11-27 03:19:07 +000085 ("file", "_File"),
86 ("edit", "_Edit"),
87 ("help", "_Help"),
Guido van Rossume7b2e651998-10-12 23:56:08 +000088 ]
89
Guido van Rossum2aeeb551998-10-12 21:01:37 +000090 def createmenubar(self):
91 mbar = self.menubar
Guido van Rossume7b2e651998-10-12 23:56:08 +000092 self.menudict = mdict = {}
93 for name, label in self.menu_specs:
Guido van Rossumb5eed031998-11-27 03:19:07 +000094 underline, label = self.Bindings.prepstr(label)
Guido van Rossume7b2e651998-10-12 23:56:08 +000095 mdict[name] = menu = Menu(mbar, name=name)
Guido van Rossumb5eed031998-11-27 03:19:07 +000096 mbar.add_cascade(label=label, menu=menu, underline=underline)
Guido van Rossume7b2e651998-10-12 23:56:08 +000097 self.Bindings.fill_menus(self.text, mdict)
Guido van Rossum2aeeb551998-10-12 21:01:37 +000098
Guido van Rossume7b2e651998-10-12 23:56:08 +000099 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000100 tkMessageBox.showinfo(self.about_title, self.about_text,
101 master=self.text)
102
Guido van Rossume7b2e651998-10-12 23:56:08 +0000103 def help_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000104 from HelpWindow import HelpWindow
105 HelpWindow(root=self.root)
Guido van Rossumb3418881998-10-13 03:45:15 +0000106
107 def open_module(self, event=None):
108 try:
109 name = self.text.get("sel.first", "sel.last")
110 except TclError:
111 name = ""
112 else:
113 name = string.strip(name)
114 if not name:
115 name = tkSimpleDialog.askstring("Module",
Guido van Rossume1dedc01998-10-16 16:09:57 +0000116 "Enter the name of a Python module\n"
117 "to search on sys.path and open:",
Guido van Rossumb3418881998-10-13 03:45:15 +0000118 parent=self.text)
119 if name:
120 name = string.strip(name)
121 if not name:
122 return
123 try:
124 (f, file, (suffix, mode, type)) = imp.find_module(name)
125 except ImportError, msg:
126 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
127 return
128 if type != imp.PY_SOURCE:
129 tkMessageBox.showerror("Unsupported type",
130 "%s is not a source module" % name, parent=self.text)
131 return
132 if f:
133 f.close()
134 self.flist.open(file, self)
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000135
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000136 def gotoline(self, lineno):
137 if lineno is not None and lineno > 0:
138 self.text.mark_set("insert", "%d.0" % lineno)
139 self.text.tag_remove("sel", "1.0", "end")
140 self.text.tag_add("sel", "insert", "insert +1l")
141 self.center()
142
143 def ispythonsource(self, filename):
144 if not filename:
145 return 1
146 if os.path.normcase(filename[-3:]) == ".py":
147 return 1
148 try:
149 f = open(filename)
150 line = f.readline()
151 f.close()
152 except IOError:
153 return 0
154 return line[:2] == '#!' and string.find(line, 'python') >= 0
155
156 close_hook = None
157
158 def set_close_hook(self, close_hook):
159 self.close_hook = close_hook
160
161 def filename_change_hook(self):
162 self.saved_change_hook()
163 if self.ispythonsource(self.io.filename):
164 self.addcolorizer()
165 else:
166 self.rmcolorizer()
167
168 def addcolorizer(self):
169 if self.color:
170 return
171 ##print "Add colorizer"
172 self.per.removefilter(self.undo)
173 self.color = self.ColorDelegator()
174 self.per.insertfilter(self.color)
175 self.per.insertfilter(self.undo)
176
177 def rmcolorizer(self):
178 if not self.color:
179 return
180 ##print "Remove colorizer"
181 self.per.removefilter(self.undo)
182 self.per.removefilter(self.color)
183 self.color = None
184 self.per.insertfilter(self.undo)
185
186 def saved_change_hook(self):
187 if self.io.filename:
188 title = self.io.filename
189 else:
190 title = "(Untitled)"
191 if not self.undo.get_saved():
192 title = title + " *"
193 self.top.wm_title(title)
194
195 def center_insert_event(self, event):
196 self.center()
197
198 def center(self, mark="insert"):
199 insert = float(self.text.index(mark + " linestart"))
200 end = float(self.text.index("end"))
201 if insert > end-insert:
202 self.text.see("1.0")
203 else:
204 self.text.see("end")
205 self.text.see(mark)
206
207 def close_event(self, event):
208 self.close()
209
210 def close(self):
211 self.top.wm_deiconify()
212 self.top.tkraise()
213 reply = self.io.maybesave()
214 if reply != "cancel":
215 if self.color and self.color.colorizing:
216 self.color.close()
217 self.top.bell()
218 return "cancel"
219 if self.close_hook:
220 self.close_hook()
221 if self.color:
222 self.color.close() # Cancel colorization
223 self.top.destroy()
224 return reply
225
226
227def fixwordbreaks(root):
228 tk = root.tk
229 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
230 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
231 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
232
233
234def test():
235 root = Tk()
236 fixwordbreaks(root)
237 root.withdraw()
238 if sys.argv[1:]:
239 filename = sys.argv[1]
240 else:
241 filename = None
242 edit = EditorWindow(root, filename)
243 edit.set_close_hook(root.quit)
244 root.mainloop()
245 root.destroy()
246
247if __name__ == '__main__':
248 test()