blob: b122c2f215fca2f612d0c671940e5711d4d1091e [file] [log] [blame]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00001import sys
2import os
3import string
4from Tkinter import *
Guido van Rossum2aeeb551998-10-12 21:01:37 +00005import tkMessageBox
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00006
Guido van Rossum2aeeb551998-10-12 21:01:37 +00007about_title = "About IDLE"
8about_text = """\
9IDLE 0.1
10
11A not totally unintegrated development environment for Python
12
13by Guido van Rossum
14"""
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000015
16class EditorWindow:
17
18 from Percolator import Percolator
19 from ColorDelegator import ColorDelegator
20 from UndoDelegator import UndoDelegator
21 from IOBinding import IOBinding
22 from SearchBinding import SearchBinding
23 from AutoIndent import AutoIndent
24 from AutoExpand import AutoExpand
25 import Bindings
Guido van Rossum2aeeb551998-10-12 21:01:37 +000026
27 about_title = about_title
28 about_text = about_text
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000029
30 def __init__(self, root, filename=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +000031 self.root = root
32 self.menubar = Menu(root)
33 self.top = top = Toplevel(root, menu=self.menubar)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000034 self.vbar = vbar = Scrollbar(top, name='vbar')
35 self.text = text = Text(top, name='text')
36
Guido van Rossum2aeeb551998-10-12 21:01:37 +000037 self.createmenubar()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000038 self.Bindings.apply_bindings(text)
39
40 self.top.protocol("WM_DELETE_WINDOW", self.close)
41 self.top.bind("<<close-window>>", self.close_event)
42 self.text.bind("<<center-insert>>", self.center_insert_event)
Guido van Rossume7b2e651998-10-12 23:56:08 +000043 self.text.bind("<<help>>", self.help_dialog)
44 self.text.bind("<<about-idle>>", self.about_dialog)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000045
46 vbar['command'] = text.yview
47 vbar.pack(side=RIGHT, fill=Y)
48
49 text['yscrollcommand'] = vbar.set
50 text['background'] = 'white'
51 if sys.platform[:3] == 'win':
52 text['font'] = ("lucida console", 8)
53 text.pack(side=LEFT, fill=BOTH, expand=1)
54 text.focus_set()
55
56 self.auto = auto = self.AutoIndent(text)
57 self.autoex = self.AutoExpand(text)
58 self.per = per = self.Percolator(text)
59 if self.ispythonsource(filename):
60 self.color = color = self.ColorDelegator(); per.insertfilter(color)
61 ##print "Initial colorizer"
62 else:
63 ##print "No initial colorizer"
64 self.color = None
65 self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
66 self.search = search = self.SearchBinding(undo)
67 self.io = io = self.IOBinding(undo)
68
69 undo.set_saved_change_hook(self.saved_change_hook)
70 io.set_filename_change_hook(self.filename_change_hook)
71
72 if filename:
73 if os.path.exists(filename):
74 io.loadfile(filename)
75 else:
76 io.set_filename(filename)
77
78 self.saved_change_hook()
79
Guido van Rossume7b2e651998-10-12 23:56:08 +000080 menu_specs = [
81 ("file", "File"),
82 ("edit", "Edit"),
83 ("help", "Help"),
84 ]
85
Guido van Rossum2aeeb551998-10-12 21:01:37 +000086 def createmenubar(self):
87 mbar = self.menubar
Guido van Rossume7b2e651998-10-12 23:56:08 +000088 self.menudict = mdict = {}
89 for name, label in self.menu_specs:
90 mdict[name] = menu = Menu(mbar, name=name)
91 mbar.add_cascade(label=label, menu=menu)
92 self.Bindings.fill_menus(self.text, mdict)
Guido van Rossum2aeeb551998-10-12 21:01:37 +000093
Guido van Rossume7b2e651998-10-12 23:56:08 +000094 def about_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +000095 tkMessageBox.showinfo(self.about_title, self.about_text,
96 master=self.text)
97
Guido van Rossume7b2e651998-10-12 23:56:08 +000098 def help_dialog(self, event=None):
Guido van Rossum2aeeb551998-10-12 21:01:37 +000099 from HelpWindow import HelpWindow
100 HelpWindow(root=self.root)
101
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000102 def gotoline(self, lineno):
103 if lineno is not None and lineno > 0:
104 self.text.mark_set("insert", "%d.0" % lineno)
105 self.text.tag_remove("sel", "1.0", "end")
106 self.text.tag_add("sel", "insert", "insert +1l")
107 self.center()
108
109 def ispythonsource(self, filename):
110 if not filename:
111 return 1
112 if os.path.normcase(filename[-3:]) == ".py":
113 return 1
114 try:
115 f = open(filename)
116 line = f.readline()
117 f.close()
118 except IOError:
119 return 0
120 return line[:2] == '#!' and string.find(line, 'python') >= 0
121
122 close_hook = None
123
124 def set_close_hook(self, close_hook):
125 self.close_hook = close_hook
126
127 def filename_change_hook(self):
128 self.saved_change_hook()
129 if self.ispythonsource(self.io.filename):
130 self.addcolorizer()
131 else:
132 self.rmcolorizer()
133
134 def addcolorizer(self):
135 if self.color:
136 return
137 ##print "Add colorizer"
138 self.per.removefilter(self.undo)
139 self.color = self.ColorDelegator()
140 self.per.insertfilter(self.color)
141 self.per.insertfilter(self.undo)
142
143 def rmcolorizer(self):
144 if not self.color:
145 return
146 ##print "Remove colorizer"
147 self.per.removefilter(self.undo)
148 self.per.removefilter(self.color)
149 self.color = None
150 self.per.insertfilter(self.undo)
151
152 def saved_change_hook(self):
153 if self.io.filename:
154 title = self.io.filename
155 else:
156 title = "(Untitled)"
157 if not self.undo.get_saved():
158 title = title + " *"
159 self.top.wm_title(title)
160
161 def center_insert_event(self, event):
162 self.center()
163
164 def center(self, mark="insert"):
165 insert = float(self.text.index(mark + " linestart"))
166 end = float(self.text.index("end"))
167 if insert > end-insert:
168 self.text.see("1.0")
169 else:
170 self.text.see("end")
171 self.text.see(mark)
172
173 def close_event(self, event):
174 self.close()
175
176 def close(self):
177 self.top.wm_deiconify()
178 self.top.tkraise()
179 reply = self.io.maybesave()
180 if reply != "cancel":
181 if self.color and self.color.colorizing:
182 self.color.close()
183 self.top.bell()
184 return "cancel"
185 if self.close_hook:
186 self.close_hook()
187 if self.color:
188 self.color.close() # Cancel colorization
189 self.top.destroy()
190 return reply
191
192
193def fixwordbreaks(root):
194 tk = root.tk
195 tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
196 tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
197 tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
198
199
200def test():
201 root = Tk()
202 fixwordbreaks(root)
203 root.withdraw()
204 if sys.argv[1:]:
205 filename = sys.argv[1]
206 else:
207 filename = None
208 edit = EditorWindow(root, filename)
209 edit.set_close_hook(root.quit)
210 root.mainloop()
211 root.destroy()
212
213if __name__ == '__main__':
214 test()