blob: 1b9db06d1806fffd07d821ba13ad7e4d5e7eac37 [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 Rossum3b4ca0d1998-10-10 18:48:31 +000048
49 vbar['command'] = text.yview
50 vbar.pack(side=RIGHT, fill=Y)
51
52 text['yscrollcommand'] = vbar.set
53 text['background'] = 'white'
54 if sys.platform[:3] == 'win':
55 text['font'] = ("lucida console", 8)
56 text.pack(side=LEFT, fill=BOTH, expand=1)
57 text.focus_set()
58
59 self.auto = auto = self.AutoIndent(text)
60 self.autoex = self.AutoExpand(text)
61 self.per = per = self.Percolator(text)
62 if self.ispythonsource(filename):
63 self.color = color = self.ColorDelegator(); per.insertfilter(color)
64 ##print "Initial colorizer"
65 else:
66 ##print "No initial colorizer"
67 self.color = None
68 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
69 self.search = search = self.SearchBinding(undo)
70 self.io = io = self.IOBinding(undo)
71
72 undo.set_saved_change_hook(self.saved_change_hook)
73 io.set_filename_change_hook(self.filename_change_hook)
74
75 if filename:
76 if os.path.exists(filename):
77 io.loadfile(filename)
78 else:
79 io.set_filename(filename)
80
81 self.saved_change_hook()
82
Guido van Rossume7b2e651998-10-12 23:56:08 +000083 menu_specs = [
84 ("file", "File"),
85 ("edit", "Edit"),
86 ("help", "Help"),
87 ]
88
Guido van Rossum2aeeb551998-10-12 21:01:37 +000089 def createmenubar(self):
90 mbar = self.menubar
Guido van Rossume7b2e651998-10-12 23:56:08 +000091 self.menudict = mdict = {}
92 for name, label in self.menu_specs:
93 mdict[name] = menu = Menu(mbar, name=name)
94 mbar.add_cascade(label=label, menu=menu)
95 self.Bindings.fill_menus(self.text, mdict)
Guido van Rossum2aeeb551998-10-12 21:01:37 +000096
Guido van Rossume7b2e651998-10-12 23:56:08 +000097 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +000098 tkMessageBox.showinfo(self.about_title, self.about_text,
99 master=self.text)
100
Guido van Rossume7b2e651998-10-12 23:56:08 +0000101 def help_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000102 from HelpWindow import HelpWindow
103 HelpWindow(root=self.root)
Guido van Rossumb3418881998-10-13 03:45:15 +0000104
105 def open_module(self, event=None):
106 try:
107 name = self.text.get("sel.first", "sel.last")
108 except TclError:
109 name = ""
110 else:
111 name = string.strip(name)
112 if not name:
113 name = tkSimpleDialog.askstring("Module",
Guido van Rossume1dedc01998-10-16 16:09:57 +0000114 "Enter the name of a Python module\n"
115 "to search on sys.path and open:",
Guido van Rossumb3418881998-10-13 03:45:15 +0000116 parent=self.text)
117 if name:
118 name = string.strip(name)
119 if not name:
120 return
121 try:
122 (f, file, (suffix, mode, type)) = imp.find_module(name)
123 except ImportError, msg:
124 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
125 return
126 if type != imp.PY_SOURCE:
127 tkMessageBox.showerror("Unsupported type",
128 "%s is not a source module" % name, parent=self.text)
129 return
130 if f:
131 f.close()
132 self.flist.open(file, self)
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000133
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000134 def gotoline(self, lineno):
135 if lineno is not None and lineno > 0:
136 self.text.mark_set("insert", "%d.0" % lineno)
137 self.text.tag_remove("sel", "1.0", "end")
138 self.text.tag_add("sel", "insert", "insert +1l")
139 self.center()
140
141 def ispythonsource(self, filename):
142 if not filename:
143 return 1
144 if os.path.normcase(filename[-3:]) == ".py":
145 return 1
146 try:
147 f = open(filename)
148 line = f.readline()
149 f.close()
150 except IOError:
151 return 0
152 return line[:2] == '#!' and string.find(line, 'python') >= 0
153
154 close_hook = None
155
156 def set_close_hook(self, close_hook):
157 self.close_hook = close_hook
158
159 def filename_change_hook(self):
160 self.saved_change_hook()
161 if self.ispythonsource(self.io.filename):
162 self.addcolorizer()
163 else:
164 self.rmcolorizer()
165
166 def addcolorizer(self):
167 if self.color:
168 return
169 ##print "Add colorizer"
170 self.per.removefilter(self.undo)
171 self.color = self.ColorDelegator()
172 self.per.insertfilter(self.color)
173 self.per.insertfilter(self.undo)
174
175 def rmcolorizer(self):
176 if not self.color:
177 return
178 ##print "Remove colorizer"
179 self.per.removefilter(self.undo)
180 self.per.removefilter(self.color)
181 self.color = None
182 self.per.insertfilter(self.undo)
183
184 def saved_change_hook(self):
185 if self.io.filename:
186 title = self.io.filename
187 else:
188 title = "(Untitled)"
189 if not self.undo.get_saved():
190 title = title + " *"
191 self.top.wm_title(title)
192
193 def center_insert_event(self, event):
194 self.center()
195
196 def center(self, mark="insert"):
197 insert = float(self.text.index(mark + " linestart"))
198 end = float(self.text.index("end"))
199 if insert > end-insert:
200 self.text.see("1.0")
201 else:
202 self.text.see("end")
203 self.text.see(mark)
204
205 def close_event(self, event):
206 self.close()
207
208 def close(self):
209 self.top.wm_deiconify()
210 self.top.tkraise()
211 reply = self.io.maybesave()
212 if reply != "cancel":
213 if self.color and self.color.colorizing:
214 self.color.close()
215 self.top.bell()
216 return "cancel"
217 if self.close_hook:
218 self.close_hook()
219 if self.color:
220 self.color.close() # Cancel colorization
221 self.top.destroy()
222 return reply
223
224
225def fixwordbreaks(root):
226 tk = root.tk
227 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
228 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
229 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
230
231
232def test():
233 root = Tk()
234 fixwordbreaks(root)
235 root.withdraw()
236 if sys.argv[1:]:
237 filename = sys.argv[1]
238 else:
239 filename = None
240 edit = EditorWindow(root, filename)
241 edit.set_close_hook(root.quit)
242 root.mainloop()
243 root.destroy()
244
245if __name__ == '__main__':
246 test()