1998-10-10 15:48:31 -03:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import string
|
1998-10-13 00:45:15 -03:00
|
|
|
import imp
|
1998-10-10 15:48:31 -03:00
|
|
|
from Tkinter import *
|
1998-10-13 00:45:15 -03:00
|
|
|
import tkSimpleDialog
|
1998-10-12 18:01:37 -03:00
|
|
|
import tkMessageBox
|
1998-10-10 15:48:31 -03:00
|
|
|
|
1998-10-12 18:01:37 -03:00
|
|
|
about_title = "About IDLE"
|
|
|
|
about_text = """\
|
|
|
|
IDLE 0.1
|
|
|
|
|
|
|
|
A not totally unintegrated development environment for Python
|
|
|
|
|
|
|
|
by Guido van Rossum
|
|
|
|
"""
|
1998-10-10 15:48:31 -03:00
|
|
|
|
|
|
|
class EditorWindow:
|
|
|
|
|
|
|
|
from Percolator import Percolator
|
|
|
|
from ColorDelegator import ColorDelegator
|
|
|
|
from UndoDelegator import UndoDelegator
|
|
|
|
from IOBinding import IOBinding
|
|
|
|
from SearchBinding import SearchBinding
|
|
|
|
from AutoIndent import AutoIndent
|
|
|
|
from AutoExpand import AutoExpand
|
|
|
|
import Bindings
|
1998-10-12 18:01:37 -03:00
|
|
|
|
|
|
|
about_title = about_title
|
|
|
|
about_text = about_text
|
1998-10-10 15:48:31 -03:00
|
|
|
|
|
|
|
def __init__(self, root, filename=None):
|
1998-10-12 18:01:37 -03:00
|
|
|
self.root = root
|
|
|
|
self.menubar = Menu(root)
|
|
|
|
self.top = top = Toplevel(root, menu=self.menubar)
|
1998-10-10 15:48:31 -03:00
|
|
|
self.vbar = vbar = Scrollbar(top, name='vbar')
|
|
|
|
self.text = text = Text(top, name='text')
|
|
|
|
|
1998-10-12 18:01:37 -03:00
|
|
|
self.createmenubar()
|
1998-10-10 15:48:31 -03:00
|
|
|
self.Bindings.apply_bindings(text)
|
|
|
|
|
|
|
|
self.top.protocol("WM_DELETE_WINDOW", self.close)
|
|
|
|
self.top.bind("<<close-window>>", self.close_event)
|
|
|
|
self.text.bind("<<center-insert>>", self.center_insert_event)
|
1998-10-12 20:56:08 -03:00
|
|
|
self.text.bind("<<help>>", self.help_dialog)
|
|
|
|
self.text.bind("<<about-idle>>", self.about_dialog)
|
1998-10-13 00:45:15 -03:00
|
|
|
self.text.bind("<<open-module>>", self.open_module)
|
1998-10-16 17:08:34 -03:00
|
|
|
self.text.bind("<<do-nothing>>", lambda event: "break")
|
1998-10-10 15:48:31 -03:00
|
|
|
|
|
|
|
vbar['command'] = text.yview
|
|
|
|
vbar.pack(side=RIGHT, fill=Y)
|
|
|
|
|
|
|
|
text['yscrollcommand'] = vbar.set
|
|
|
|
text['background'] = 'white'
|
|
|
|
if sys.platform[:3] == 'win':
|
|
|
|
text['font'] = ("lucida console", 8)
|
|
|
|
text.pack(side=LEFT, fill=BOTH, expand=1)
|
|
|
|
text.focus_set()
|
|
|
|
|
|
|
|
self.auto = auto = self.AutoIndent(text)
|
|
|
|
self.autoex = self.AutoExpand(text)
|
|
|
|
self.per = per = self.Percolator(text)
|
|
|
|
if self.ispythonsource(filename):
|
|
|
|
self.color = color = self.ColorDelegator(); per.insertfilter(color)
|
|
|
|
##print "Initial colorizer"
|
|
|
|
else:
|
|
|
|
##print "No initial colorizer"
|
|
|
|
self.color = None
|
|
|
|
self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
|
|
|
|
self.search = search = self.SearchBinding(undo)
|
|
|
|
self.io = io = self.IOBinding(undo)
|
|
|
|
|
|
|
|
undo.set_saved_change_hook(self.saved_change_hook)
|
|
|
|
io.set_filename_change_hook(self.filename_change_hook)
|
|
|
|
|
|
|
|
if filename:
|
|
|
|
if os.path.exists(filename):
|
|
|
|
io.loadfile(filename)
|
|
|
|
else:
|
|
|
|
io.set_filename(filename)
|
|
|
|
|
|
|
|
self.saved_change_hook()
|
|
|
|
|
1998-10-12 20:56:08 -03:00
|
|
|
menu_specs = [
|
1998-11-26 23:19:07 -04:00
|
|
|
("file", "_File"),
|
|
|
|
("edit", "_Edit"),
|
|
|
|
("help", "_Help"),
|
1998-10-12 20:56:08 -03:00
|
|
|
]
|
|
|
|
|
1998-10-12 18:01:37 -03:00
|
|
|
def createmenubar(self):
|
|
|
|
mbar = self.menubar
|
1998-10-12 20:56:08 -03:00
|
|
|
self.menudict = mdict = {}
|
|
|
|
for name, label in self.menu_specs:
|
1998-11-26 23:19:07 -04:00
|
|
|
underline, label = self.Bindings.prepstr(label)
|
1998-10-12 20:56:08 -03:00
|
|
|
mdict[name] = menu = Menu(mbar, name=name)
|
1998-11-26 23:19:07 -04:00
|
|
|
mbar.add_cascade(label=label, menu=menu, underline=underline)
|
1998-10-12 20:56:08 -03:00
|
|
|
self.Bindings.fill_menus(self.text, mdict)
|
1998-10-12 18:01:37 -03:00
|
|
|
|
1998-10-12 20:56:08 -03:00
|
|
|
def about_dialog(self, event=None):
|
1998-10-12 18:01:37 -03:00
|
|
|
tkMessageBox.showinfo(self.about_title, self.about_text,
|
|
|
|
master=self.text)
|
|
|
|
|
1998-10-12 20:56:08 -03:00
|
|
|
def help_dialog(self, event=None):
|
1998-10-12 18:01:37 -03:00
|
|
|
from HelpWindow import HelpWindow
|
|
|
|
HelpWindow(root=self.root)
|
1998-10-13 00:45:15 -03:00
|
|
|
|
|
|
|
def open_module(self, event=None):
|
|
|
|
try:
|
|
|
|
name = self.text.get("sel.first", "sel.last")
|
|
|
|
except TclError:
|
|
|
|
name = ""
|
|
|
|
else:
|
|
|
|
name = string.strip(name)
|
|
|
|
if not name:
|
|
|
|
name = tkSimpleDialog.askstring("Module",
|
1998-10-16 13:09:57 -03:00
|
|
|
"Enter the name of a Python module\n"
|
|
|
|
"to search on sys.path and open:",
|
1998-10-13 00:45:15 -03:00
|
|
|
parent=self.text)
|
|
|
|
if name:
|
|
|
|
name = string.strip(name)
|
|
|
|
if not name:
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
(f, file, (suffix, mode, type)) = imp.find_module(name)
|
|
|
|
except ImportError, msg:
|
|
|
|
tkMessageBox.showerror("Import error", str(msg), parent=self.text)
|
|
|
|
return
|
|
|
|
if type != imp.PY_SOURCE:
|
|
|
|
tkMessageBox.showerror("Unsupported type",
|
|
|
|
"%s is not a source module" % name, parent=self.text)
|
|
|
|
return
|
|
|
|
if f:
|
|
|
|
f.close()
|
|
|
|
self.flist.open(file, self)
|
1998-10-12 18:01:37 -03:00
|
|
|
|
1998-10-10 15:48:31 -03:00
|
|
|
def gotoline(self, lineno):
|
|
|
|
if lineno is not None and lineno > 0:
|
|
|
|
self.text.mark_set("insert", "%d.0" % lineno)
|
|
|
|
self.text.tag_remove("sel", "1.0", "end")
|
|
|
|
self.text.tag_add("sel", "insert", "insert +1l")
|
|
|
|
self.center()
|
|
|
|
|
|
|
|
def ispythonsource(self, filename):
|
|
|
|
if not filename:
|
|
|
|
return 1
|
|
|
|
if os.path.normcase(filename[-3:]) == ".py":
|
|
|
|
return 1
|
|
|
|
try:
|
|
|
|
f = open(filename)
|
|
|
|
line = f.readline()
|
|
|
|
f.close()
|
|
|
|
except IOError:
|
|
|
|
return 0
|
|
|
|
return line[:2] == '#!' and string.find(line, 'python') >= 0
|
|
|
|
|
|
|
|
close_hook = None
|
|
|
|
|
|
|
|
def set_close_hook(self, close_hook):
|
|
|
|
self.close_hook = close_hook
|
|
|
|
|
|
|
|
def filename_change_hook(self):
|
|
|
|
self.saved_change_hook()
|
|
|
|
if self.ispythonsource(self.io.filename):
|
|
|
|
self.addcolorizer()
|
|
|
|
else:
|
|
|
|
self.rmcolorizer()
|
|
|
|
|
|
|
|
def addcolorizer(self):
|
|
|
|
if self.color:
|
|
|
|
return
|
|
|
|
##print "Add colorizer"
|
|
|
|
self.per.removefilter(self.undo)
|
|
|
|
self.color = self.ColorDelegator()
|
|
|
|
self.per.insertfilter(self.color)
|
|
|
|
self.per.insertfilter(self.undo)
|
|
|
|
|
|
|
|
def rmcolorizer(self):
|
|
|
|
if not self.color:
|
|
|
|
return
|
|
|
|
##print "Remove colorizer"
|
|
|
|
self.per.removefilter(self.undo)
|
|
|
|
self.per.removefilter(self.color)
|
|
|
|
self.color = None
|
|
|
|
self.per.insertfilter(self.undo)
|
|
|
|
|
|
|
|
def saved_change_hook(self):
|
|
|
|
if self.io.filename:
|
|
|
|
title = self.io.filename
|
|
|
|
else:
|
|
|
|
title = "(Untitled)"
|
|
|
|
if not self.undo.get_saved():
|
|
|
|
title = title + " *"
|
|
|
|
self.top.wm_title(title)
|
|
|
|
|
|
|
|
def center_insert_event(self, event):
|
|
|
|
self.center()
|
|
|
|
|
|
|
|
def center(self, mark="insert"):
|
|
|
|
insert = float(self.text.index(mark + " linestart"))
|
|
|
|
end = float(self.text.index("end"))
|
|
|
|
if insert > end-insert:
|
|
|
|
self.text.see("1.0")
|
|
|
|
else:
|
|
|
|
self.text.see("end")
|
|
|
|
self.text.see(mark)
|
|
|
|
|
|
|
|
def close_event(self, event):
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.top.wm_deiconify()
|
|
|
|
self.top.tkraise()
|
|
|
|
reply = self.io.maybesave()
|
|
|
|
if reply != "cancel":
|
|
|
|
if self.color and self.color.colorizing:
|
|
|
|
self.color.close()
|
|
|
|
self.top.bell()
|
|
|
|
return "cancel"
|
|
|
|
if self.close_hook:
|
|
|
|
self.close_hook()
|
|
|
|
if self.color:
|
|
|
|
self.color.close() # Cancel colorization
|
|
|
|
self.top.destroy()
|
|
|
|
return reply
|
|
|
|
|
|
|
|
|
|
|
|
def fixwordbreaks(root):
|
|
|
|
tk = root.tk
|
|
|
|
tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
|
|
|
|
tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
|
|
|
|
tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
|
|
|
|
|
|
|
|
|
|
|
|
def test():
|
|
|
|
root = Tk()
|
|
|
|
fixwordbreaks(root)
|
|
|
|
root.withdraw()
|
|
|
|
if sys.argv[1:]:
|
|
|
|
filename = sys.argv[1]
|
|
|
|
else:
|
|
|
|
filename = None
|
|
|
|
edit = EditorWindow(root, filename)
|
|
|
|
edit.set_close_hook(root.quit)
|
|
|
|
root.mainloop()
|
|
|
|
root.destroy()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
test()
|