blob: 977be6bf029584bdefc3ecb64e9f58234d62e606 [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",
114 "Module name:",
115 parent=self.text)
116 if name:
117 name = string.strip(name)
118 if not name:
119 return
120 try:
121 (f, file, (suffix, mode, type)) = imp.find_module(name)
122 except ImportError, msg:
123 tkMessageBox.showerror("Import error", str(msg), parent=self.text)
124 return
125 if type != imp.PY_SOURCE:
126 tkMessageBox.showerror("Unsupported type",
127 "%s is not a source module" % name, parent=self.text)
128 return
129 if f:
130 f.close()
131 self.flist.open(file, self)
Guido van Rossum2aeeb551998-10-12 21:01:37 +0000132
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000133 def gotoline(self, lineno):
134 if lineno is not None and lineno > 0:
135 self.text.mark_set("insert", "%d.0" % lineno)
136 self.text.tag_remove("sel", "1.0", "end")
137 self.text.tag_add("sel", "insert", "insert +1l")
138 self.center()
139
140 def ispythonsource(self, filename):
141 if not filename:
142 return 1
143 if os.path.normcase(filename[-3:]) == ".py":
144 return 1
145 try:
146 f = open(filename)
147 line = f.readline()
148 f.close()
149 except IOError:
150 return 0
151 return line[:2] == '#!' and string.find(line, 'python') >= 0
152
153 close_hook = None
154
155 def set_close_hook(self, close_hook):
156 self.close_hook = close_hook
157
158 def filename_change_hook(self):
159 self.saved_change_hook()
160 if self.ispythonsource(self.io.filename):
161 self.addcolorizer()
162 else:
163 self.rmcolorizer()
164
165 def addcolorizer(self):
166 if self.color:
167 return
168 ##print "Add colorizer"
169 self.per.removefilter(self.undo)
170 self.color = self.ColorDelegator()
171 self.per.insertfilter(self.color)
172 self.per.insertfilter(self.undo)
173
174 def rmcolorizer(self):
175 if not self.color:
176 return
177 ##print "Remove colorizer"
178 self.per.removefilter(self.undo)
179 self.per.removefilter(self.color)
180 self.color = None
181 self.per.insertfilter(self.undo)
182
183 def saved_change_hook(self):
184 if self.io.filename:
185 title = self.io.filename
186 else:
187 title = "(Untitled)"
188 if not self.undo.get_saved():
189 title = title + " *"
190 self.top.wm_title(title)
191
192 def center_insert_event(self, event):
193 self.center()
194
195 def center(self, mark="insert"):
196 insert = float(self.text.index(mark + " linestart"))
197 end = float(self.text.index("end"))
198 if insert > end-insert:
199 self.text.see("1.0")
200 else:
201 self.text.see("end")
202 self.text.see(mark)
203
204 def close_event(self, event):
205 self.close()
206
207 def close(self):
208 self.top.wm_deiconify()
209 self.top.tkraise()
210 reply = self.io.maybesave()
211 if reply != "cancel":
212 if self.color and self.color.colorizing:
213 self.color.close()
214 self.top.bell()
215 return "cancel"
216 if self.close_hook:
217 self.close_hook()
218 if self.color:
219 self.color.close() # Cancel colorization
220 self.top.destroy()
221 return reply
222
223
224def fixwordbreaks(root):
225 tk = root.tk
226 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
227 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
228 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
229
230
231def test():
232 root = Tk()
233 fixwordbreaks(root)
234 root.withdraw()
235 if sys.argv[1:]:
236 filename = sys.argv[1]
237 else:
238 filename = None
239 edit = EditorWindow(root, filename)
240 edit.set_close_hook(root.quit)
241 root.mainloop()
242 root.destroy()
243
244if __name__ == '__main__':
245 test()