mirror of
https://github.com/python/cpython.git
synced 2025-08-29 21:25:01 +00:00
Initial revision
This commit is contained in:
parent
33a6da9971
commit
7aced17437
73 changed files with 12383 additions and 0 deletions
749
Lib/idlelib/EditorWindow.py
Normal file
749
Lib/idlelib/EditorWindow.py
Normal file
|
@ -0,0 +1,749 @@
|
|||
# changes by dscherer@cmu.edu
|
||||
# - created format and run menus
|
||||
# - added silly advice dialog (apologies to Douglas Adams)
|
||||
# - made Python Documentation work on Windows (requires win32api to
|
||||
# do a ShellExecute(); other ways of starting a web browser are awkward)
|
||||
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import re
|
||||
import imp
|
||||
from Tkinter import *
|
||||
import tkSimpleDialog
|
||||
import tkMessageBox
|
||||
import idlever
|
||||
import WindowList
|
||||
from IdleConf import idleconf
|
||||
|
||||
# The default tab setting for a Text widget, in average-width characters.
|
||||
TK_TABWIDTH_DEFAULT = 8
|
||||
|
||||
# File menu
|
||||
|
||||
#$ event <<open-module>>
|
||||
#$ win <Alt-m>
|
||||
#$ unix <Control-x><Control-m>
|
||||
|
||||
#$ event <<open-class-browser>>
|
||||
#$ win <Alt-c>
|
||||
#$ unix <Control-x><Control-b>
|
||||
|
||||
#$ event <<open-path-browser>>
|
||||
|
||||
#$ event <<close-window>>
|
||||
#$ unix <Control-x><Control-0>
|
||||
#$ unix <Control-x><Key-0>
|
||||
#$ win <Alt-F4>
|
||||
|
||||
# Edit menu
|
||||
|
||||
#$ event <<Copy>>
|
||||
#$ win <Control-c>
|
||||
#$ unix <Alt-w>
|
||||
|
||||
#$ event <<Cut>>
|
||||
#$ win <Control-x>
|
||||
#$ unix <Control-w>
|
||||
|
||||
#$ event <<Paste>>
|
||||
#$ win <Control-v>
|
||||
#$ unix <Control-y>
|
||||
|
||||
#$ event <<select-all>>
|
||||
#$ win <Alt-a>
|
||||
#$ unix <Alt-a>
|
||||
|
||||
# Help menu
|
||||
|
||||
#$ event <<help>>
|
||||
#$ win <F1>
|
||||
#$ unix <F1>
|
||||
|
||||
#$ event <<about-idle>>
|
||||
|
||||
# Events without menu entries
|
||||
|
||||
#$ event <<remove-selection>>
|
||||
#$ win <Escape>
|
||||
|
||||
#$ event <<center-insert>>
|
||||
#$ win <Control-l>
|
||||
#$ unix <Control-l>
|
||||
|
||||
#$ event <<do-nothing>>
|
||||
#$ unix <Control-x>
|
||||
|
||||
|
||||
about_title = "About IDLE"
|
||||
about_text = """\
|
||||
IDLE %s
|
||||
|
||||
An Integrated DeveLopment Environment for Python
|
||||
|
||||
by Guido van Rossum
|
||||
|
||||
This version of IDLE has been modified by David Scherer
|
||||
(dscherer@cmu.edu). See readme.txt for details.
|
||||
""" % idlever.IDLE_VERSION
|
||||
|
||||
class EditorWindow:
|
||||
|
||||
from Percolator import Percolator
|
||||
from ColorDelegator import ColorDelegator
|
||||
from UndoDelegator import UndoDelegator
|
||||
from IOBinding import IOBinding
|
||||
import Bindings
|
||||
from Tkinter import Toplevel
|
||||
from MultiStatusBar import MultiStatusBar
|
||||
|
||||
about_title = about_title
|
||||
about_text = about_text
|
||||
|
||||
vars = {}
|
||||
|
||||
def __init__(self, flist=None, filename=None, key=None, root=None):
|
||||
edconf = idleconf.getsection('EditorWindow')
|
||||
coconf = idleconf.getsection('Colors')
|
||||
self.flist = flist
|
||||
root = root or flist.root
|
||||
self.root = root
|
||||
if flist:
|
||||
self.vars = flist.vars
|
||||
self.menubar = Menu(root)
|
||||
self.top = top = self.Toplevel(root, menu=self.menubar)
|
||||
self.vbar = vbar = Scrollbar(top, name='vbar')
|
||||
self.text_frame = text_frame = Frame(top)
|
||||
self.text = text = Text(text_frame, name='text', padx=5,
|
||||
foreground=coconf.getdef('normal-foreground'),
|
||||
background=coconf.getdef('normal-background'),
|
||||
highlightcolor=coconf.getdef('hilite-foreground'),
|
||||
highlightbackground=coconf.getdef('hilite-background'),
|
||||
insertbackground=coconf.getdef('cursor-background'),
|
||||
width=edconf.getint('width'),
|
||||
height=edconf.getint('height'),
|
||||
wrap="none")
|
||||
|
||||
self.createmenubar()
|
||||
self.apply_bindings()
|
||||
|
||||
self.top.protocol("WM_DELETE_WINDOW", self.close)
|
||||
self.top.bind("<<close-window>>", self.close_event)
|
||||
text.bind("<<center-insert>>", self.center_insert_event)
|
||||
text.bind("<<help>>", self.help_dialog)
|
||||
text.bind("<<good-advice>>", self.good_advice)
|
||||
text.bind("<<python-docs>>", self.python_docs)
|
||||
text.bind("<<about-idle>>", self.about_dialog)
|
||||
text.bind("<<open-module>>", self.open_module)
|
||||
text.bind("<<do-nothing>>", lambda event: "break")
|
||||
text.bind("<<select-all>>", self.select_all)
|
||||
text.bind("<<remove-selection>>", self.remove_selection)
|
||||
text.bind("<3>", self.right_menu_event)
|
||||
if flist:
|
||||
flist.inversedict[self] = key
|
||||
if key:
|
||||
flist.dict[key] = self
|
||||
text.bind("<<open-new-window>>", self.flist.new_callback)
|
||||
text.bind("<<close-all-windows>>", self.flist.close_all_callback)
|
||||
text.bind("<<open-class-browser>>", self.open_class_browser)
|
||||
text.bind("<<open-path-browser>>", self.open_path_browser)
|
||||
|
||||
vbar['command'] = text.yview
|
||||
vbar.pack(side=RIGHT, fill=Y)
|
||||
|
||||
text['yscrollcommand'] = vbar.set
|
||||
text['font'] = edconf.get('font-name'), edconf.get('font-size')
|
||||
text_frame.pack(side=LEFT, fill=BOTH, expand=1)
|
||||
text.pack(side=TOP, fill=BOTH, expand=1)
|
||||
text.focus_set()
|
||||
|
||||
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.io = io = self.IOBinding(self)
|
||||
|
||||
text.undo_block_start = undo.undo_block_start
|
||||
text.undo_block_stop = undo.undo_block_stop
|
||||
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()
|
||||
|
||||
self.load_extensions()
|
||||
|
||||
menu = self.menudict.get('windows')
|
||||
if menu:
|
||||
end = menu.index("end")
|
||||
if end is None:
|
||||
end = -1
|
||||
if end >= 0:
|
||||
menu.add_separator()
|
||||
end = end + 1
|
||||
self.wmenu_end = end
|
||||
WindowList.register_callback(self.postwindowsmenu)
|
||||
|
||||
# Some abstractions so IDLE extensions are cross-IDE
|
||||
self.askyesno = tkMessageBox.askyesno
|
||||
self.askinteger = tkSimpleDialog.askinteger
|
||||
self.showerror = tkMessageBox.showerror
|
||||
|
||||
if self.extensions.has_key('AutoIndent'):
|
||||
self.extensions['AutoIndent'].set_indentation_params(
|
||||
self.ispythonsource(filename))
|
||||
self.set_status_bar()
|
||||
|
||||
def set_status_bar(self):
|
||||
self.status_bar = self.MultiStatusBar(self.text_frame)
|
||||
self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
|
||||
self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
|
||||
self.status_bar.pack(side=BOTTOM, fill=X)
|
||||
self.text.bind('<KeyRelease>', self.set_line_and_column)
|
||||
self.text.bind('<ButtonRelease>', self.set_line_and_column)
|
||||
self.text.after_idle(self.set_line_and_column)
|
||||
|
||||
def set_line_and_column(self, event=None):
|
||||
line, column = string.split(self.text.index(INSERT), '.')
|
||||
self.status_bar.set_label('column', 'Col: %s' % column)
|
||||
self.status_bar.set_label('line', 'Ln: %s' % line)
|
||||
|
||||
def wakeup(self):
|
||||
if self.top.wm_state() == "iconic":
|
||||
self.top.wm_deiconify()
|
||||
else:
|
||||
self.top.tkraise()
|
||||
self.text.focus_set()
|
||||
|
||||
menu_specs = [
|
||||
("file", "_File"),
|
||||
("edit", "_Edit"),
|
||||
("format", "F_ormat"),
|
||||
("run", "_Run"),
|
||||
("windows", "_Windows"),
|
||||
("help", "_Help"),
|
||||
]
|
||||
|
||||
def createmenubar(self):
|
||||
mbar = self.menubar
|
||||
self.menudict = menudict = {}
|
||||
for name, label in self.menu_specs:
|
||||
underline, label = prepstr(label)
|
||||
menudict[name] = menu = Menu(mbar, name=name)
|
||||
mbar.add_cascade(label=label, menu=menu, underline=underline)
|
||||
self.fill_menus()
|
||||
|
||||
def postwindowsmenu(self):
|
||||
# Only called when Windows menu exists
|
||||
# XXX Actually, this Just-In-Time updating interferes badly
|
||||
# XXX with the tear-off feature. It would be better to update
|
||||
# XXX all Windows menus whenever the list of windows changes.
|
||||
menu = self.menudict['windows']
|
||||
end = menu.index("end")
|
||||
if end is None:
|
||||
end = -1
|
||||
if end > self.wmenu_end:
|
||||
menu.delete(self.wmenu_end+1, end)
|
||||
WindowList.add_windows_to_menu(menu)
|
||||
|
||||
rmenu = None
|
||||
|
||||
def right_menu_event(self, event):
|
||||
self.text.tag_remove("sel", "1.0", "end")
|
||||
self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
|
||||
if not self.rmenu:
|
||||
self.make_rmenu()
|
||||
rmenu = self.rmenu
|
||||
self.event = event
|
||||
iswin = sys.platform[:3] == 'win'
|
||||
if iswin:
|
||||
self.text.config(cursor="arrow")
|
||||
rmenu.tk_popup(event.x_root, event.y_root)
|
||||
if iswin:
|
||||
self.text.config(cursor="ibeam")
|
||||
|
||||
rmenu_specs = [
|
||||
# ("Label", "<<virtual-event>>"), ...
|
||||
("Close", "<<close-window>>"), # Example
|
||||
]
|
||||
|
||||
def make_rmenu(self):
|
||||
rmenu = Menu(self.text, tearoff=0)
|
||||
for label, eventname in self.rmenu_specs:
|
||||
def command(text=self.text, eventname=eventname):
|
||||
text.event_generate(eventname)
|
||||
rmenu.add_command(label=label, command=command)
|
||||
self.rmenu = rmenu
|
||||
|
||||
def about_dialog(self, event=None):
|
||||
tkMessageBox.showinfo(self.about_title, self.about_text,
|
||||
master=self.text)
|
||||
|
||||
helpfile = "help.txt"
|
||||
|
||||
def good_advice(self, event=None):
|
||||
tkMessageBox.showinfo('Advice', "Don't Panic!", master=self.text)
|
||||
|
||||
def help_dialog(self, event=None):
|
||||
try:
|
||||
helpfile = os.path.join(os.path.dirname(__file__), self.helpfile)
|
||||
except NameError:
|
||||
helpfile = self.helpfile
|
||||
if self.flist:
|
||||
self.flist.open(helpfile)
|
||||
else:
|
||||
self.io.loadfile(helpfile)
|
||||
|
||||
help_viewer = "netscape -remote 'openurl(%(url)s)' 2>/dev/null || " \
|
||||
"netscape %(url)s &"
|
||||
help_url = "http://www.python.org/doc/current/"
|
||||
|
||||
def python_docs(self, event=None):
|
||||
if sys.platform=='win32':
|
||||
try:
|
||||
import win32api
|
||||
import ExecBinding
|
||||
doc = os.path.join( os.path.dirname( ExecBinding.pyth_exe ), "doc", "index.html" )
|
||||
win32api.ShellExecute(0, None, doc, None, sys.path[0], 1)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
cmd = self.help_viewer % {"url": self.help_url}
|
||||
os.system(cmd)
|
||||
|
||||
def select_all(self, event=None):
|
||||
self.text.tag_add("sel", "1.0", "end-1c")
|
||||
self.text.mark_set("insert", "1.0")
|
||||
self.text.see("insert")
|
||||
return "break"
|
||||
|
||||
def remove_selection(self, event=None):
|
||||
self.text.tag_remove("sel", "1.0", "end")
|
||||
self.text.see("insert")
|
||||
|
||||
def open_module(self, event=None):
|
||||
# XXX Shouldn't this be in IOBinding or in FileList?
|
||||
try:
|
||||
name = self.text.get("sel.first", "sel.last")
|
||||
except TclError:
|
||||
name = ""
|
||||
else:
|
||||
name = string.strip(name)
|
||||
if not name:
|
||||
name = tkSimpleDialog.askstring("Module",
|
||||
"Enter the name of a Python module\n"
|
||||
"to search on sys.path and open:",
|
||||
parent=self.text)
|
||||
if name:
|
||||
name = string.strip(name)
|
||||
if not name:
|
||||
return
|
||||
# XXX Ought to support package syntax
|
||||
# XXX Ought to insert current file's directory in front of path
|
||||
try:
|
||||
(f, file, (suffix, mode, type)) = imp.find_module(name)
|
||||
except (NameError, 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()
|
||||
if self.flist:
|
||||
self.flist.open(file)
|
||||
else:
|
||||
self.io.loadfile(file)
|
||||
|
||||
def open_class_browser(self, event=None):
|
||||
filename = self.io.filename
|
||||
if not filename:
|
||||
tkMessageBox.showerror(
|
||||
"No filename",
|
||||
"This buffer has no associated filename",
|
||||
master=self.text)
|
||||
self.text.focus_set()
|
||||
return None
|
||||
head, tail = os.path.split(filename)
|
||||
base, ext = os.path.splitext(tail)
|
||||
import ClassBrowser
|
||||
ClassBrowser.ClassBrowser(self.flist, base, [head])
|
||||
|
||||
def open_path_browser(self, event=None):
|
||||
import PathBrowser
|
||||
PathBrowser.PathBrowser(self.flist)
|
||||
|
||||
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
|
||||
base, ext = os.path.splitext(os.path.basename(filename))
|
||||
if os.path.normcase(ext) in (".py", ".pyw"):
|
||||
return 1
|
||||
try:
|
||||
f = open(filename)
|
||||
line = f.readline()
|
||||
f.close()
|
||||
except IOError:
|
||||
return 0
|
||||
return line[:2] == '#!' and string.find(line, 'python') >= 0
|
||||
|
||||
def close_hook(self):
|
||||
if self.flist:
|
||||
self.flist.close_edit(self)
|
||||
|
||||
def set_close_hook(self, close_hook):
|
||||
self.close_hook = close_hook
|
||||
|
||||
def filename_change_hook(self):
|
||||
if self.flist:
|
||||
self.flist.filename_changed_edit(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):
|
||||
short = self.short_title()
|
||||
long = self.long_title()
|
||||
if short and long:
|
||||
title = short + " - " + long
|
||||
elif short:
|
||||
title = short
|
||||
elif long:
|
||||
title = long
|
||||
else:
|
||||
title = "Untitled"
|
||||
icon = short or long or title
|
||||
if not self.get_saved():
|
||||
title = "*%s*" % title
|
||||
icon = "*%s" % icon
|
||||
self.top.wm_title(title)
|
||||
self.top.wm_iconname(icon)
|
||||
|
||||
def get_saved(self):
|
||||
return self.undo.get_saved()
|
||||
|
||||
def set_saved(self, flag):
|
||||
self.undo.set_saved(flag)
|
||||
|
||||
def reset_undo(self):
|
||||
self.undo.reset_undo()
|
||||
|
||||
def short_title(self):
|
||||
filename = self.io.filename
|
||||
if filename:
|
||||
filename = os.path.basename(filename)
|
||||
return filename
|
||||
|
||||
def long_title(self):
|
||||
return self.io.filename or ""
|
||||
|
||||
def center_insert_event(self, event):
|
||||
self.center()
|
||||
|
||||
def center(self, mark="insert"):
|
||||
text = self.text
|
||||
top, bot = self.getwindowlines()
|
||||
lineno = self.getlineno(mark)
|
||||
height = bot - top
|
||||
newtop = max(1, lineno - height/2)
|
||||
text.yview(float(newtop))
|
||||
|
||||
def getwindowlines(self):
|
||||
text = self.text
|
||||
top = self.getlineno("@0,0")
|
||||
bot = self.getlineno("@0,65535")
|
||||
if top == bot and text.winfo_height() == 1:
|
||||
# Geometry manager hasn't run yet
|
||||
height = int(text['height'])
|
||||
bot = top + height - 1
|
||||
return top, bot
|
||||
|
||||
def getlineno(self, mark="insert"):
|
||||
text = self.text
|
||||
return int(float(text.index(mark)))
|
||||
|
||||
def close_event(self, event):
|
||||
self.close()
|
||||
|
||||
def maybesave(self):
|
||||
if self.io:
|
||||
return self.io.maybesave()
|
||||
|
||||
def close(self):
|
||||
self.top.wm_deiconify()
|
||||
self.top.tkraise()
|
||||
reply = self.maybesave()
|
||||
if reply != "cancel":
|
||||
self._close()
|
||||
return reply
|
||||
|
||||
def _close(self):
|
||||
WindowList.unregister_callback(self.postwindowsmenu)
|
||||
if self.close_hook:
|
||||
self.close_hook()
|
||||
self.flist = None
|
||||
colorizing = 0
|
||||
self.unload_extensions()
|
||||
self.io.close(); self.io = None
|
||||
self.undo = None # XXX
|
||||
if self.color:
|
||||
colorizing = self.color.colorizing
|
||||
doh = colorizing and self.top
|
||||
self.color.close(doh) # Cancel colorization
|
||||
self.text = None
|
||||
self.vars = None
|
||||
self.per.close(); self.per = None
|
||||
if not colorizing:
|
||||
self.top.destroy()
|
||||
|
||||
def load_extensions(self):
|
||||
self.extensions = {}
|
||||
self.load_standard_extensions()
|
||||
|
||||
def unload_extensions(self):
|
||||
for ins in self.extensions.values():
|
||||
if hasattr(ins, "close"):
|
||||
ins.close()
|
||||
self.extensions = {}
|
||||
|
||||
def load_standard_extensions(self):
|
||||
for name in self.get_standard_extension_names():
|
||||
try:
|
||||
self.load_extension(name)
|
||||
except:
|
||||
print "Failed to load extension", `name`
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def get_standard_extension_names(self):
|
||||
return idleconf.getextensions()
|
||||
|
||||
def load_extension(self, name):
|
||||
mod = __import__(name, globals(), locals(), [])
|
||||
cls = getattr(mod, name)
|
||||
ins = cls(self)
|
||||
self.extensions[name] = ins
|
||||
kdnames = ["keydefs"]
|
||||
if sys.platform == 'win32':
|
||||
kdnames.append("windows_keydefs")
|
||||
elif sys.platform == 'mac':
|
||||
kdnames.append("mac_keydefs")
|
||||
else:
|
||||
kdnames.append("unix_keydefs")
|
||||
keydefs = {}
|
||||
for kdname in kdnames:
|
||||
if hasattr(ins, kdname):
|
||||
keydefs.update(getattr(ins, kdname))
|
||||
if keydefs:
|
||||
self.apply_bindings(keydefs)
|
||||
for vevent in keydefs.keys():
|
||||
methodname = string.replace(vevent, "-", "_")
|
||||
while methodname[:1] == '<':
|
||||
methodname = methodname[1:]
|
||||
while methodname[-1:] == '>':
|
||||
methodname = methodname[:-1]
|
||||
methodname = methodname + "_event"
|
||||
if hasattr(ins, methodname):
|
||||
self.text.bind(vevent, getattr(ins, methodname))
|
||||
if hasattr(ins, "menudefs"):
|
||||
self.fill_menus(ins.menudefs, keydefs)
|
||||
return ins
|
||||
|
||||
def apply_bindings(self, keydefs=None):
|
||||
if keydefs is None:
|
||||
keydefs = self.Bindings.default_keydefs
|
||||
text = self.text
|
||||
text.keydefs = keydefs
|
||||
for event, keylist in keydefs.items():
|
||||
if keylist:
|
||||
apply(text.event_add, (event,) + tuple(keylist))
|
||||
|
||||
def fill_menus(self, defs=None, keydefs=None):
|
||||
# Fill the menus. Menus that are absent or None in
|
||||
# self.menudict are ignored.
|
||||
if defs is None:
|
||||
defs = self.Bindings.menudefs
|
||||
if keydefs is None:
|
||||
keydefs = self.Bindings.default_keydefs
|
||||
menudict = self.menudict
|
||||
text = self.text
|
||||
for mname, itemlist in defs:
|
||||
menu = menudict.get(mname)
|
||||
if not menu:
|
||||
continue
|
||||
for item in itemlist:
|
||||
if not item:
|
||||
menu.add_separator()
|
||||
else:
|
||||
label, event = item
|
||||
checkbutton = (label[:1] == '!')
|
||||
if checkbutton:
|
||||
label = label[1:]
|
||||
underline, label = prepstr(label)
|
||||
accelerator = get_accelerator(keydefs, event)
|
||||
def command(text=text, event=event):
|
||||
text.event_generate(event)
|
||||
if checkbutton:
|
||||
var = self.getrawvar(event, BooleanVar)
|
||||
menu.add_checkbutton(label=label, underline=underline,
|
||||
command=command, accelerator=accelerator,
|
||||
variable=var)
|
||||
else:
|
||||
menu.add_command(label=label, underline=underline,
|
||||
command=command, accelerator=accelerator)
|
||||
|
||||
def getvar(self, name):
|
||||
var = self.getrawvar(name)
|
||||
if var:
|
||||
return var.get()
|
||||
|
||||
def setvar(self, name, value, vartype=None):
|
||||
var = self.getrawvar(name, vartype)
|
||||
if var:
|
||||
var.set(value)
|
||||
|
||||
def getrawvar(self, name, vartype=None):
|
||||
var = self.vars.get(name)
|
||||
if not var and vartype:
|
||||
self.vars[name] = var = vartype(self.text)
|
||||
return var
|
||||
|
||||
# Tk implementations of "virtual text methods" -- each platform
|
||||
# reusing IDLE's support code needs to define these for its GUI's
|
||||
# flavor of widget.
|
||||
|
||||
# Is character at text_index in a Python string? Return 0 for
|
||||
# "guaranteed no", true for anything else. This info is expensive
|
||||
# to compute ab initio, but is probably already known by the
|
||||
# platform's colorizer.
|
||||
|
||||
def is_char_in_string(self, text_index):
|
||||
if self.color:
|
||||
# Return true iff colorizer hasn't (re)gotten this far
|
||||
# yet, or the character is tagged as being in a string
|
||||
return self.text.tag_prevrange("TODO", text_index) or \
|
||||
"STRING" in self.text.tag_names(text_index)
|
||||
else:
|
||||
# The colorizer is missing: assume the worst
|
||||
return 1
|
||||
|
||||
# If a selection is defined in the text widget, return (start,
|
||||
# end) as Tkinter text indices, otherwise return (None, None)
|
||||
def get_selection_indices(self):
|
||||
try:
|
||||
first = self.text.index("sel.first")
|
||||
last = self.text.index("sel.last")
|
||||
return first, last
|
||||
except TclError:
|
||||
return None, None
|
||||
|
||||
# Return the text widget's current view of what a tab stop means
|
||||
# (equivalent width in spaces).
|
||||
|
||||
def get_tabwidth(self):
|
||||
current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
|
||||
return int(current)
|
||||
|
||||
# Set the text widget's current view of what a tab stop means.
|
||||
|
||||
def set_tabwidth(self, newtabwidth):
|
||||
text = self.text
|
||||
if self.get_tabwidth() != newtabwidth:
|
||||
pixels = text.tk.call("font", "measure", text["font"],
|
||||
"-displayof", text.master,
|
||||
"n" * newtabwith)
|
||||
text.configure(tabs=pixels)
|
||||
|
||||
def prepstr(s):
|
||||
# Helper to extract the underscore from a string, e.g.
|
||||
# prepstr("Co_py") returns (2, "Copy").
|
||||
i = string.find(s, '_')
|
||||
if i >= 0:
|
||||
s = s[:i] + s[i+1:]
|
||||
return i, s
|
||||
|
||||
|
||||
keynames = {
|
||||
'bracketleft': '[',
|
||||
'bracketright': ']',
|
||||
'slash': '/',
|
||||
}
|
||||
|
||||
def get_accelerator(keydefs, event):
|
||||
keylist = keydefs.get(event)
|
||||
if not keylist:
|
||||
return ""
|
||||
s = keylist[0]
|
||||
s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
|
||||
s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
|
||||
s = re.sub("Key-", "", s)
|
||||
s = re.sub("Cancel","Ctrl-Break",s) # dscherer@cmu.edu
|
||||
s = re.sub("Control-", "Ctrl-", s)
|
||||
s = re.sub("-", "+", s)
|
||||
s = re.sub("><", " ", s)
|
||||
s = re.sub("<", "", s)
|
||||
s = re.sub(">", "", s)
|
||||
return s
|
||||
|
||||
|
||||
def fixwordbreaks(root):
|
||||
# Make sure that Tk's double-click and next/previous word
|
||||
# operations use our definition of a word (i.e. an identifier)
|
||||
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=root, filename=filename)
|
||||
edit.set_close_hook(root.quit)
|
||||
root.mainloop()
|
||||
root.destroy()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
Loading…
Add table
Add a link
Reference in a new issue