Open Media Library Platform
This commit is contained in:
commit
411ad5b16f
5849 changed files with 1778641 additions and 0 deletions
224
Darwin/lib/python2.7/idlelib/AutoComplete.py
Normal file
224
Darwin/lib/python2.7/idlelib/AutoComplete.py
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
"""AutoComplete.py - An IDLE extension for automatically completing names.
|
||||
|
||||
This extension can complete either attribute names of file names. It can pop
|
||||
a window with all available names, for the user to select from.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
# This string includes all chars that may be in a file name (without a path
|
||||
# separator)
|
||||
FILENAME_CHARS = string.ascii_letters + string.digits + os.curdir + "._~#$:-"
|
||||
# This string includes all chars that may be in an identifier
|
||||
ID_CHARS = string.ascii_letters + string.digits + "_"
|
||||
|
||||
# These constants represent the two different types of completions
|
||||
COMPLETE_ATTRIBUTES, COMPLETE_FILES = range(1, 2+1)
|
||||
|
||||
from idlelib import AutoCompleteWindow
|
||||
from idlelib.HyperParser import HyperParser
|
||||
|
||||
import __main__
|
||||
|
||||
SEPS = os.sep
|
||||
if os.altsep: # e.g. '/' on Windows...
|
||||
SEPS += os.altsep
|
||||
|
||||
class AutoComplete:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
("Show Completions", "<<force-open-completions>>"),
|
||||
])
|
||||
]
|
||||
|
||||
popupwait = idleConf.GetOption("extensions", "AutoComplete",
|
||||
"popupwait", type="int", default=0)
|
||||
|
||||
def __init__(self, editwin=None):
|
||||
self.editwin = editwin
|
||||
if editwin is None: # subprocess and test
|
||||
return
|
||||
self.text = editwin.text
|
||||
self.autocompletewindow = None
|
||||
|
||||
# id of delayed call, and the index of the text insert when the delayed
|
||||
# call was issued. If _delayed_completion_id is None, there is no
|
||||
# delayed call.
|
||||
self._delayed_completion_id = None
|
||||
self._delayed_completion_index = None
|
||||
|
||||
def _make_autocomplete_window(self):
|
||||
return AutoCompleteWindow.AutoCompleteWindow(self.text)
|
||||
|
||||
def _remove_autocomplete_window(self, event=None):
|
||||
if self.autocompletewindow:
|
||||
self.autocompletewindow.hide_window()
|
||||
self.autocompletewindow = None
|
||||
|
||||
def force_open_completions_event(self, event):
|
||||
"""Happens when the user really wants to open a completion list, even
|
||||
if a function call is needed.
|
||||
"""
|
||||
self.open_completions(True, False, True)
|
||||
|
||||
def try_open_completions_event(self, event):
|
||||
"""Happens when it would be nice to open a completion list, but not
|
||||
really necessary, for example after an dot, so function
|
||||
calls won't be made.
|
||||
"""
|
||||
lastchar = self.text.get("insert-1c")
|
||||
if lastchar == ".":
|
||||
self._open_completions_later(False, False, False,
|
||||
COMPLETE_ATTRIBUTES)
|
||||
elif lastchar in SEPS:
|
||||
self._open_completions_later(False, False, False,
|
||||
COMPLETE_FILES)
|
||||
|
||||
def autocomplete_event(self, event):
|
||||
"""Happens when the user wants to complete his word, and if necessary,
|
||||
open a completion list after that (if there is more than one
|
||||
completion)
|
||||
"""
|
||||
if hasattr(event, "mc_state") and event.mc_state:
|
||||
# A modifier was pressed along with the tab, continue as usual.
|
||||
return
|
||||
if self.autocompletewindow and self.autocompletewindow.is_active():
|
||||
self.autocompletewindow.complete()
|
||||
return "break"
|
||||
else:
|
||||
opened = self.open_completions(False, True, True)
|
||||
if opened:
|
||||
return "break"
|
||||
|
||||
def _open_completions_later(self, *args):
|
||||
self._delayed_completion_index = self.text.index("insert")
|
||||
if self._delayed_completion_id is not None:
|
||||
self.text.after_cancel(self._delayed_completion_id)
|
||||
self._delayed_completion_id = \
|
||||
self.text.after(self.popupwait, self._delayed_open_completions,
|
||||
*args)
|
||||
|
||||
def _delayed_open_completions(self, *args):
|
||||
self._delayed_completion_id = None
|
||||
if self.text.index("insert") != self._delayed_completion_index:
|
||||
return
|
||||
self.open_completions(*args)
|
||||
|
||||
def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
|
||||
"""Find the completions and create the AutoCompleteWindow.
|
||||
Return True if successful (no syntax error or so found).
|
||||
if complete is True, then if there's nothing to complete and no
|
||||
start of completion, won't open completions and return False.
|
||||
If mode is given, will open a completion list only in this mode.
|
||||
"""
|
||||
# Cancel another delayed call, if it exists.
|
||||
if self._delayed_completion_id is not None:
|
||||
self.text.after_cancel(self._delayed_completion_id)
|
||||
self._delayed_completion_id = None
|
||||
|
||||
hp = HyperParser(self.editwin, "insert")
|
||||
curline = self.text.get("insert linestart", "insert")
|
||||
i = j = len(curline)
|
||||
if hp.is_in_string() and (not mode or mode==COMPLETE_FILES):
|
||||
self._remove_autocomplete_window()
|
||||
mode = COMPLETE_FILES
|
||||
while i and curline[i-1] in FILENAME_CHARS:
|
||||
i -= 1
|
||||
comp_start = curline[i:j]
|
||||
j = i
|
||||
while i and curline[i-1] in FILENAME_CHARS + SEPS:
|
||||
i -= 1
|
||||
comp_what = curline[i:j]
|
||||
elif hp.is_in_code() and (not mode or mode==COMPLETE_ATTRIBUTES):
|
||||
self._remove_autocomplete_window()
|
||||
mode = COMPLETE_ATTRIBUTES
|
||||
while i and curline[i-1] in ID_CHARS:
|
||||
i -= 1
|
||||
comp_start = curline[i:j]
|
||||
if i and curline[i-1] == '.':
|
||||
hp.set_index("insert-%dc" % (len(curline)-(i-1)))
|
||||
comp_what = hp.get_expression()
|
||||
if not comp_what or \
|
||||
(not evalfuncs and comp_what.find('(') != -1):
|
||||
return
|
||||
else:
|
||||
comp_what = ""
|
||||
else:
|
||||
return
|
||||
|
||||
if complete and not comp_what and not comp_start:
|
||||
return
|
||||
comp_lists = self.fetch_completions(comp_what, mode)
|
||||
if not comp_lists[0]:
|
||||
return
|
||||
self.autocompletewindow = self._make_autocomplete_window()
|
||||
return not self.autocompletewindow.show_window(
|
||||
comp_lists, "insert-%dc" % len(comp_start),
|
||||
complete, mode, userWantsWin)
|
||||
|
||||
def fetch_completions(self, what, mode):
|
||||
"""Return a pair of lists of completions for something. The first list
|
||||
is a sublist of the second. Both are sorted.
|
||||
|
||||
If there is a Python subprocess, get the comp. list there. Otherwise,
|
||||
either fetch_completions() is running in the subprocess itself or it
|
||||
was called in an IDLE EditorWindow before any script had been run.
|
||||
|
||||
The subprocess environment is that of the most recently run script. If
|
||||
two unrelated modules are being edited some calltips in the current
|
||||
module may be inoperative if the module was not the last to run.
|
||||
"""
|
||||
try:
|
||||
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
|
||||
except:
|
||||
rpcclt = None
|
||||
if rpcclt:
|
||||
return rpcclt.remotecall("exec", "get_the_completion_list",
|
||||
(what, mode), {})
|
||||
else:
|
||||
if mode == COMPLETE_ATTRIBUTES:
|
||||
if what == "":
|
||||
namespace = __main__.__dict__.copy()
|
||||
namespace.update(__main__.__builtins__.__dict__)
|
||||
bigl = eval("dir()", namespace)
|
||||
bigl.sort()
|
||||
if "__all__" in bigl:
|
||||
smalll = sorted(eval("__all__", namespace))
|
||||
else:
|
||||
smalll = [s for s in bigl if s[:1] != '_']
|
||||
else:
|
||||
try:
|
||||
entity = self.get_entity(what)
|
||||
bigl = dir(entity)
|
||||
bigl.sort()
|
||||
if "__all__" in bigl:
|
||||
smalll = sorted(entity.__all__)
|
||||
else:
|
||||
smalll = [s for s in bigl if s[:1] != '_']
|
||||
except:
|
||||
return [], []
|
||||
|
||||
elif mode == COMPLETE_FILES:
|
||||
if what == "":
|
||||
what = "."
|
||||
try:
|
||||
expandedpath = os.path.expanduser(what)
|
||||
bigl = os.listdir(expandedpath)
|
||||
bigl.sort()
|
||||
smalll = [s for s in bigl if s[:1] != '.']
|
||||
except OSError:
|
||||
return [], []
|
||||
|
||||
if not smalll:
|
||||
smalll = bigl
|
||||
return smalll, bigl
|
||||
|
||||
def get_entity(self, name):
|
||||
"""Lookup name in a namespace spanning sys.modules and __main.dict__"""
|
||||
namespace = sys.modules.copy()
|
||||
namespace.update(__main__.__dict__)
|
||||
return eval(name, namespace)
|
||||
406
Darwin/lib/python2.7/idlelib/AutoCompleteWindow.py
Normal file
406
Darwin/lib/python2.7/idlelib/AutoCompleteWindow.py
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
"""
|
||||
An auto-completion window for IDLE, used by the AutoComplete extension
|
||||
"""
|
||||
from Tkinter import *
|
||||
from idlelib.MultiCall import MC_SHIFT
|
||||
from idlelib.AutoComplete import COMPLETE_FILES, COMPLETE_ATTRIBUTES
|
||||
|
||||
HIDE_VIRTUAL_EVENT_NAME = "<<autocompletewindow-hide>>"
|
||||
HIDE_SEQUENCES = ("<FocusOut>", "<ButtonPress>")
|
||||
KEYPRESS_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keypress>>"
|
||||
# We need to bind event beyond <Key> so that the function will be called
|
||||
# before the default specific IDLE function
|
||||
KEYPRESS_SEQUENCES = ("<Key>", "<Key-BackSpace>", "<Key-Return>", "<Key-Tab>",
|
||||
"<Key-Up>", "<Key-Down>", "<Key-Home>", "<Key-End>",
|
||||
"<Key-Prior>", "<Key-Next>")
|
||||
KEYRELEASE_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keyrelease>>"
|
||||
KEYRELEASE_SEQUENCE = "<KeyRelease>"
|
||||
LISTUPDATE_SEQUENCE = "<B1-ButtonRelease>"
|
||||
WINCONFIG_SEQUENCE = "<Configure>"
|
||||
DOUBLECLICK_SEQUENCE = "<B1-Double-ButtonRelease>"
|
||||
|
||||
class AutoCompleteWindow:
|
||||
|
||||
def __init__(self, widget):
|
||||
# The widget (Text) on which we place the AutoCompleteWindow
|
||||
self.widget = widget
|
||||
# The widgets we create
|
||||
self.autocompletewindow = self.listbox = self.scrollbar = None
|
||||
# The default foreground and background of a selection. Saved because
|
||||
# they are changed to the regular colors of list items when the
|
||||
# completion start is not a prefix of the selected completion
|
||||
self.origselforeground = self.origselbackground = None
|
||||
# The list of completions
|
||||
self.completions = None
|
||||
# A list with more completions, or None
|
||||
self.morecompletions = None
|
||||
# The completion mode. Either AutoComplete.COMPLETE_ATTRIBUTES or
|
||||
# AutoComplete.COMPLETE_FILES
|
||||
self.mode = None
|
||||
# The current completion start, on the text box (a string)
|
||||
self.start = None
|
||||
# The index of the start of the completion
|
||||
self.startindex = None
|
||||
# The last typed start, used so that when the selection changes,
|
||||
# the new start will be as close as possible to the last typed one.
|
||||
self.lasttypedstart = None
|
||||
# Do we have an indication that the user wants the completion window
|
||||
# (for example, he clicked the list)
|
||||
self.userwantswindow = None
|
||||
# event ids
|
||||
self.hideid = self.keypressid = self.listupdateid = self.winconfigid \
|
||||
= self.keyreleaseid = self.doubleclickid = None
|
||||
# Flag set if last keypress was a tab
|
||||
self.lastkey_was_tab = False
|
||||
|
||||
def _change_start(self, newstart):
|
||||
min_len = min(len(self.start), len(newstart))
|
||||
i = 0
|
||||
while i < min_len and self.start[i] == newstart[i]:
|
||||
i += 1
|
||||
if i < len(self.start):
|
||||
self.widget.delete("%s+%dc" % (self.startindex, i),
|
||||
"%s+%dc" % (self.startindex, len(self.start)))
|
||||
if i < len(newstart):
|
||||
self.widget.insert("%s+%dc" % (self.startindex, i),
|
||||
newstart[i:])
|
||||
self.start = newstart
|
||||
|
||||
def _binary_search(self, s):
|
||||
"""Find the first index in self.completions where completions[i] is
|
||||
greater or equal to s, or the last index if there is no such
|
||||
one."""
|
||||
i = 0; j = len(self.completions)
|
||||
while j > i:
|
||||
m = (i + j) // 2
|
||||
if self.completions[m] >= s:
|
||||
j = m
|
||||
else:
|
||||
i = m + 1
|
||||
return min(i, len(self.completions)-1)
|
||||
|
||||
def _complete_string(self, s):
|
||||
"""Assuming that s is the prefix of a string in self.completions,
|
||||
return the longest string which is a prefix of all the strings which
|
||||
s is a prefix of them. If s is not a prefix of a string, return s."""
|
||||
first = self._binary_search(s)
|
||||
if self.completions[first][:len(s)] != s:
|
||||
# There is not even one completion which s is a prefix of.
|
||||
return s
|
||||
# Find the end of the range of completions where s is a prefix of.
|
||||
i = first + 1
|
||||
j = len(self.completions)
|
||||
while j > i:
|
||||
m = (i + j) // 2
|
||||
if self.completions[m][:len(s)] != s:
|
||||
j = m
|
||||
else:
|
||||
i = m + 1
|
||||
last = i-1
|
||||
|
||||
if first == last: # only one possible completion
|
||||
return self.completions[first]
|
||||
|
||||
# We should return the maximum prefix of first and last
|
||||
first_comp = self.completions[first]
|
||||
last_comp = self.completions[last]
|
||||
min_len = min(len(first_comp), len(last_comp))
|
||||
i = len(s)
|
||||
while i < min_len and first_comp[i] == last_comp[i]:
|
||||
i += 1
|
||||
return first_comp[:i]
|
||||
|
||||
def _selection_changed(self):
|
||||
"""Should be called when the selection of the Listbox has changed.
|
||||
Updates the Listbox display and calls _change_start."""
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
|
||||
self.listbox.see(cursel)
|
||||
|
||||
lts = self.lasttypedstart
|
||||
selstart = self.completions[cursel]
|
||||
if self._binary_search(lts) == cursel:
|
||||
newstart = lts
|
||||
else:
|
||||
min_len = min(len(lts), len(selstart))
|
||||
i = 0
|
||||
while i < min_len and lts[i] == selstart[i]:
|
||||
i += 1
|
||||
newstart = selstart[:i]
|
||||
self._change_start(newstart)
|
||||
|
||||
if self.completions[cursel][:len(self.start)] == self.start:
|
||||
# start is a prefix of the selected completion
|
||||
self.listbox.configure(selectbackground=self.origselbackground,
|
||||
selectforeground=self.origselforeground)
|
||||
else:
|
||||
self.listbox.configure(selectbackground=self.listbox.cget("bg"),
|
||||
selectforeground=self.listbox.cget("fg"))
|
||||
# If there are more completions, show them, and call me again.
|
||||
if self.morecompletions:
|
||||
self.completions = self.morecompletions
|
||||
self.morecompletions = None
|
||||
self.listbox.delete(0, END)
|
||||
for item in self.completions:
|
||||
self.listbox.insert(END, item)
|
||||
self.listbox.select_set(self._binary_search(self.start))
|
||||
self._selection_changed()
|
||||
|
||||
def show_window(self, comp_lists, index, complete, mode, userWantsWin):
|
||||
"""Show the autocomplete list, bind events.
|
||||
If complete is True, complete the text, and if there is exactly one
|
||||
matching completion, don't open a list."""
|
||||
# Handle the start we already have
|
||||
self.completions, self.morecompletions = comp_lists
|
||||
self.mode = mode
|
||||
self.startindex = self.widget.index(index)
|
||||
self.start = self.widget.get(self.startindex, "insert")
|
||||
if complete:
|
||||
completed = self._complete_string(self.start)
|
||||
start = self.start
|
||||
self._change_start(completed)
|
||||
i = self._binary_search(completed)
|
||||
if self.completions[i] == completed and \
|
||||
(i == len(self.completions)-1 or
|
||||
self.completions[i+1][:len(completed)] != completed):
|
||||
# There is exactly one matching completion
|
||||
return completed == start
|
||||
self.userwantswindow = userWantsWin
|
||||
self.lasttypedstart = self.start
|
||||
|
||||
# Put widgets in place
|
||||
self.autocompletewindow = acw = Toplevel(self.widget)
|
||||
# Put it in a position so that it is not seen.
|
||||
acw.wm_geometry("+10000+10000")
|
||||
# Make it float
|
||||
acw.wm_overrideredirect(1)
|
||||
try:
|
||||
# This command is only needed and available on Tk >= 8.4.0 for OSX
|
||||
# Without it, call tips intrude on the typing process by grabbing
|
||||
# the focus.
|
||||
acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w,
|
||||
"help", "noActivates")
|
||||
except TclError:
|
||||
pass
|
||||
self.scrollbar = scrollbar = Scrollbar(acw, orient=VERTICAL)
|
||||
self.listbox = listbox = Listbox(acw, yscrollcommand=scrollbar.set,
|
||||
exportselection=False, bg="white")
|
||||
for item in self.completions:
|
||||
listbox.insert(END, item)
|
||||
self.origselforeground = listbox.cget("selectforeground")
|
||||
self.origselbackground = listbox.cget("selectbackground")
|
||||
scrollbar.config(command=listbox.yview)
|
||||
scrollbar.pack(side=RIGHT, fill=Y)
|
||||
listbox.pack(side=LEFT, fill=BOTH, expand=True)
|
||||
|
||||
# Initialize the listbox selection
|
||||
self.listbox.select_set(self._binary_search(self.start))
|
||||
self._selection_changed()
|
||||
|
||||
# bind events
|
||||
self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
|
||||
self.hide_event)
|
||||
for seq in HIDE_SEQUENCES:
|
||||
self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.keypressid = self.widget.bind(KEYPRESS_VIRTUAL_EVENT_NAME,
|
||||
self.keypress_event)
|
||||
for seq in KEYPRESS_SEQUENCES:
|
||||
self.widget.event_add(KEYPRESS_VIRTUAL_EVENT_NAME, seq)
|
||||
self.keyreleaseid = self.widget.bind(KEYRELEASE_VIRTUAL_EVENT_NAME,
|
||||
self.keyrelease_event)
|
||||
self.widget.event_add(KEYRELEASE_VIRTUAL_EVENT_NAME,KEYRELEASE_SEQUENCE)
|
||||
self.listupdateid = listbox.bind(LISTUPDATE_SEQUENCE,
|
||||
self.listselect_event)
|
||||
self.winconfigid = acw.bind(WINCONFIG_SEQUENCE, self.winconfig_event)
|
||||
self.doubleclickid = listbox.bind(DOUBLECLICK_SEQUENCE,
|
||||
self.doubleclick_event)
|
||||
|
||||
def winconfig_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
# Position the completion list window
|
||||
text = self.widget
|
||||
text.see(self.startindex)
|
||||
x, y, cx, cy = text.bbox(self.startindex)
|
||||
acw = self.autocompletewindow
|
||||
acw_width, acw_height = acw.winfo_width(), acw.winfo_height()
|
||||
text_width, text_height = text.winfo_width(), text.winfo_height()
|
||||
new_x = text.winfo_rootx() + min(x, max(0, text_width - acw_width))
|
||||
new_y = text.winfo_rooty() + y
|
||||
if (text_height - (y + cy) >= acw_height # enough height below
|
||||
or y < acw_height): # not enough height above
|
||||
# place acw below current line
|
||||
new_y += cy
|
||||
else:
|
||||
# place acw above current line
|
||||
new_y -= acw_height
|
||||
acw.wm_geometry("+%d+%d" % (new_x, new_y))
|
||||
|
||||
def hide_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
self.hide_window()
|
||||
|
||||
def listselect_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
self.userwantswindow = True
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
self._change_start(self.completions[cursel])
|
||||
|
||||
def doubleclick_event(self, event):
|
||||
# Put the selected completion in the text, and close the list
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
self._change_start(self.completions[cursel])
|
||||
self.hide_window()
|
||||
|
||||
def keypress_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
keysym = event.keysym
|
||||
if hasattr(event, "mc_state"):
|
||||
state = event.mc_state
|
||||
else:
|
||||
state = 0
|
||||
if keysym != "Tab":
|
||||
self.lastkey_was_tab = False
|
||||
if (len(keysym) == 1 or keysym in ("underscore", "BackSpace")
|
||||
or (self.mode == COMPLETE_FILES and keysym in
|
||||
("period", "minus"))) \
|
||||
and not (state & ~MC_SHIFT):
|
||||
# Normal editing of text
|
||||
if len(keysym) == 1:
|
||||
self._change_start(self.start + keysym)
|
||||
elif keysym == "underscore":
|
||||
self._change_start(self.start + '_')
|
||||
elif keysym == "period":
|
||||
self._change_start(self.start + '.')
|
||||
elif keysym == "minus":
|
||||
self._change_start(self.start + '-')
|
||||
else:
|
||||
# keysym == "BackSpace"
|
||||
if len(self.start) == 0:
|
||||
self.hide_window()
|
||||
return
|
||||
self._change_start(self.start[:-1])
|
||||
self.lasttypedstart = self.start
|
||||
self.listbox.select_clear(0, int(self.listbox.curselection()[0]))
|
||||
self.listbox.select_set(self._binary_search(self.start))
|
||||
self._selection_changed()
|
||||
return "break"
|
||||
|
||||
elif keysym == "Return":
|
||||
self.hide_window()
|
||||
return
|
||||
|
||||
elif (self.mode == COMPLETE_ATTRIBUTES and keysym in
|
||||
("period", "space", "parenleft", "parenright", "bracketleft",
|
||||
"bracketright")) or \
|
||||
(self.mode == COMPLETE_FILES and keysym in
|
||||
("slash", "backslash", "quotedbl", "apostrophe")) \
|
||||
and not (state & ~MC_SHIFT):
|
||||
# If start is a prefix of the selection, but is not '' when
|
||||
# completing file names, put the whole
|
||||
# selected completion. Anyway, close the list.
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
if self.completions[cursel][:len(self.start)] == self.start \
|
||||
and (self.mode == COMPLETE_ATTRIBUTES or self.start):
|
||||
self._change_start(self.completions[cursel])
|
||||
self.hide_window()
|
||||
return
|
||||
|
||||
elif keysym in ("Home", "End", "Prior", "Next", "Up", "Down") and \
|
||||
not state:
|
||||
# Move the selection in the listbox
|
||||
self.userwantswindow = True
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
if keysym == "Home":
|
||||
newsel = 0
|
||||
elif keysym == "End":
|
||||
newsel = len(self.completions)-1
|
||||
elif keysym in ("Prior", "Next"):
|
||||
jump = self.listbox.nearest(self.listbox.winfo_height()) - \
|
||||
self.listbox.nearest(0)
|
||||
if keysym == "Prior":
|
||||
newsel = max(0, cursel-jump)
|
||||
else:
|
||||
assert keysym == "Next"
|
||||
newsel = min(len(self.completions)-1, cursel+jump)
|
||||
elif keysym == "Up":
|
||||
newsel = max(0, cursel-1)
|
||||
else:
|
||||
assert keysym == "Down"
|
||||
newsel = min(len(self.completions)-1, cursel+1)
|
||||
self.listbox.select_clear(cursel)
|
||||
self.listbox.select_set(newsel)
|
||||
self._selection_changed()
|
||||
self._change_start(self.completions[newsel])
|
||||
return "break"
|
||||
|
||||
elif (keysym == "Tab" and not state):
|
||||
if self.lastkey_was_tab:
|
||||
# two tabs in a row; insert current selection and close acw
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
self._change_start(self.completions[cursel])
|
||||
self.hide_window()
|
||||
return "break"
|
||||
else:
|
||||
# first tab; let AutoComplete handle the completion
|
||||
self.userwantswindow = True
|
||||
self.lastkey_was_tab = True
|
||||
return
|
||||
|
||||
elif any(s in keysym for s in ("Shift", "Control", "Alt",
|
||||
"Meta", "Command", "Option")):
|
||||
# A modifier key, so ignore
|
||||
return
|
||||
|
||||
else:
|
||||
# Unknown event, close the window and let it through.
|
||||
self.hide_window()
|
||||
return
|
||||
|
||||
def keyrelease_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
if self.widget.index("insert") != \
|
||||
self.widget.index("%s+%dc" % (self.startindex, len(self.start))):
|
||||
# If we didn't catch an event which moved the insert, close window
|
||||
self.hide_window()
|
||||
|
||||
def is_active(self):
|
||||
return self.autocompletewindow is not None
|
||||
|
||||
def complete(self):
|
||||
self._change_start(self._complete_string(self.start))
|
||||
# The selection doesn't change.
|
||||
|
||||
def hide_window(self):
|
||||
if not self.is_active():
|
||||
return
|
||||
|
||||
# unbind events
|
||||
for seq in HIDE_SEQUENCES:
|
||||
self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
|
||||
self.hideid = None
|
||||
for seq in KEYPRESS_SEQUENCES:
|
||||
self.widget.event_delete(KEYPRESS_VIRTUAL_EVENT_NAME, seq)
|
||||
self.widget.unbind(KEYPRESS_VIRTUAL_EVENT_NAME, self.keypressid)
|
||||
self.keypressid = None
|
||||
self.widget.event_delete(KEYRELEASE_VIRTUAL_EVENT_NAME,
|
||||
KEYRELEASE_SEQUENCE)
|
||||
self.widget.unbind(KEYRELEASE_VIRTUAL_EVENT_NAME, self.keyreleaseid)
|
||||
self.keyreleaseid = None
|
||||
self.listbox.unbind(LISTUPDATE_SEQUENCE, self.listupdateid)
|
||||
self.listupdateid = None
|
||||
self.autocompletewindow.unbind(WINCONFIG_SEQUENCE, self.winconfigid)
|
||||
self.winconfigid = None
|
||||
|
||||
# destroy widgets
|
||||
self.scrollbar.destroy()
|
||||
self.scrollbar = None
|
||||
self.listbox.destroy()
|
||||
self.listbox = None
|
||||
self.autocompletewindow.destroy()
|
||||
self.autocompletewindow = None
|
||||
83
Darwin/lib/python2.7/idlelib/AutoExpand.py
Normal file
83
Darwin/lib/python2.7/idlelib/AutoExpand.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import string
|
||||
import re
|
||||
|
||||
###$ event <<expand-word>>
|
||||
###$ win <Alt-slash>
|
||||
###$ unix <Alt-slash>
|
||||
|
||||
class AutoExpand:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
('E_xpand Word', '<<expand-word>>'),
|
||||
]),
|
||||
]
|
||||
|
||||
wordchars = string.ascii_letters + string.digits + "_"
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.text = editwin.text
|
||||
self.state = None
|
||||
|
||||
def expand_word_event(self, event):
|
||||
curinsert = self.text.index("insert")
|
||||
curline = self.text.get("insert linestart", "insert lineend")
|
||||
if not self.state:
|
||||
words = self.getwords()
|
||||
index = 0
|
||||
else:
|
||||
words, index, insert, line = self.state
|
||||
if insert != curinsert or line != curline:
|
||||
words = self.getwords()
|
||||
index = 0
|
||||
if not words:
|
||||
self.text.bell()
|
||||
return "break"
|
||||
word = self.getprevword()
|
||||
self.text.delete("insert - %d chars" % len(word), "insert")
|
||||
newword = words[index]
|
||||
index = (index + 1) % len(words)
|
||||
if index == 0:
|
||||
self.text.bell() # Warn we cycled around
|
||||
self.text.insert("insert", newword)
|
||||
curinsert = self.text.index("insert")
|
||||
curline = self.text.get("insert linestart", "insert lineend")
|
||||
self.state = words, index, curinsert, curline
|
||||
return "break"
|
||||
|
||||
def getwords(self):
|
||||
word = self.getprevword()
|
||||
if not word:
|
||||
return []
|
||||
before = self.text.get("1.0", "insert wordstart")
|
||||
wbefore = re.findall(r"\b" + word + r"\w+\b", before)
|
||||
del before
|
||||
after = self.text.get("insert wordend", "end")
|
||||
wafter = re.findall(r"\b" + word + r"\w+\b", after)
|
||||
del after
|
||||
if not wbefore and not wafter:
|
||||
return []
|
||||
words = []
|
||||
dict = {}
|
||||
# search backwards through words before
|
||||
wbefore.reverse()
|
||||
for w in wbefore:
|
||||
if dict.get(w):
|
||||
continue
|
||||
words.append(w)
|
||||
dict[w] = w
|
||||
# search onwards through words after
|
||||
for w in wafter:
|
||||
if dict.get(w):
|
||||
continue
|
||||
words.append(w)
|
||||
dict[w] = w
|
||||
words.append(word)
|
||||
return words
|
||||
|
||||
def getprevword(self):
|
||||
line = self.text.get("insert linestart", "insert")
|
||||
i = len(line)
|
||||
while i > 0 and line[i-1] in self.wordchars:
|
||||
i = i-1
|
||||
return line[i:]
|
||||
107
Darwin/lib/python2.7/idlelib/Bindings.py
Normal file
107
Darwin/lib/python2.7/idlelib/Bindings.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
"""Define the menu contents, hotkeys, and event bindings.
|
||||
|
||||
There is additional configuration information in the EditorWindow class (and
|
||||
subclasses): the menus are created there based on the menu_specs (class)
|
||||
variable, and menus not created are silently skipped in the code here. This
|
||||
makes it possible, for example, to define a Debug menu which is only present in
|
||||
the PythonShell window, and a Format menu which is only present in the Editor
|
||||
windows.
|
||||
|
||||
"""
|
||||
import sys
|
||||
from idlelib.configHandler import idleConf
|
||||
from idlelib import macosxSupport
|
||||
|
||||
menudefs = [
|
||||
# underscore prefixes character to underscore
|
||||
('file', [
|
||||
('_New File', '<<open-new-window>>'),
|
||||
('_Open...', '<<open-window-from-file>>'),
|
||||
('Open _Module...', '<<open-module>>'),
|
||||
('Class _Browser', '<<open-class-browser>>'),
|
||||
('_Path Browser', '<<open-path-browser>>'),
|
||||
None,
|
||||
('_Save', '<<save-window>>'),
|
||||
('Save _As...', '<<save-window-as-file>>'),
|
||||
('Save Cop_y As...', '<<save-copy-of-window-as-file>>'),
|
||||
None,
|
||||
('Prin_t Window', '<<print-window>>'),
|
||||
None,
|
||||
('_Close', '<<close-window>>'),
|
||||
('E_xit', '<<close-all-windows>>'),
|
||||
]),
|
||||
('edit', [
|
||||
('_Undo', '<<undo>>'),
|
||||
('_Redo', '<<redo>>'),
|
||||
None,
|
||||
('Cu_t', '<<cut>>'),
|
||||
('_Copy', '<<copy>>'),
|
||||
('_Paste', '<<paste>>'),
|
||||
('Select _All', '<<select-all>>'),
|
||||
None,
|
||||
('_Find...', '<<find>>'),
|
||||
('Find A_gain', '<<find-again>>'),
|
||||
('Find _Selection', '<<find-selection>>'),
|
||||
('Find in Files...', '<<find-in-files>>'),
|
||||
('R_eplace...', '<<replace>>'),
|
||||
('Go to _Line', '<<goto-line>>'),
|
||||
]),
|
||||
('format', [
|
||||
('_Indent Region', '<<indent-region>>'),
|
||||
('_Dedent Region', '<<dedent-region>>'),
|
||||
('Comment _Out Region', '<<comment-region>>'),
|
||||
('U_ncomment Region', '<<uncomment-region>>'),
|
||||
('Tabify Region', '<<tabify-region>>'),
|
||||
('Untabify Region', '<<untabify-region>>'),
|
||||
('Toggle Tabs', '<<toggle-tabs>>'),
|
||||
('New Indent Width', '<<change-indentwidth>>'),
|
||||
]),
|
||||
('run', [
|
||||
('Python Shell', '<<open-python-shell>>'),
|
||||
]),
|
||||
('shell', [
|
||||
('_View Last Restart', '<<view-restart>>'),
|
||||
('_Restart Shell', '<<restart-shell>>'),
|
||||
]),
|
||||
('debug', [
|
||||
('_Go to File/Line', '<<goto-file-line>>'),
|
||||
('!_Debugger', '<<toggle-debugger>>'),
|
||||
('_Stack Viewer', '<<open-stack-viewer>>'),
|
||||
('!_Auto-open Stack Viewer', '<<toggle-jit-stack-viewer>>'),
|
||||
]),
|
||||
('options', [
|
||||
('_Configure IDLE...', '<<open-config-dialog>>'),
|
||||
None,
|
||||
]),
|
||||
('help', [
|
||||
('_About IDLE', '<<about-idle>>'),
|
||||
None,
|
||||
('_IDLE Help', '<<help>>'),
|
||||
('Python _Docs', '<<python-docs>>'),
|
||||
]),
|
||||
]
|
||||
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
# Running as a proper MacOS application bundle. This block restructures
|
||||
# the menus a little to make them conform better to the HIG.
|
||||
|
||||
quitItem = menudefs[0][1][-1]
|
||||
closeItem = menudefs[0][1][-2]
|
||||
|
||||
# Remove the last 3 items of the file menu: a separator, close window and
|
||||
# quit. Close window will be reinserted just above the save item, where
|
||||
# it should be according to the HIG. Quit is in the application menu.
|
||||
del menudefs[0][1][-3:]
|
||||
menudefs[0][1].insert(6, closeItem)
|
||||
|
||||
# Remove the 'About' entry from the help menu, it is in the application
|
||||
# menu
|
||||
del menudefs[-1][1][0:2]
|
||||
|
||||
# Remove the 'Configure' entry from the options menu, it is in the
|
||||
# application menu as 'Preferences'
|
||||
del menudefs[-2][1][0:2]
|
||||
|
||||
default_keydefs = idleConf.GetCurrentKeySet()
|
||||
|
||||
del sys
|
||||
37
Darwin/lib/python2.7/idlelib/CREDITS.txt
Normal file
37
Darwin/lib/python2.7/idlelib/CREDITS.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
Guido van Rossum, as well as being the creator of the Python language, is the
|
||||
original creator of IDLE. Other contributors prior to Version 0.8 include
|
||||
Mark Hammond, Jeremy Hylton, Tim Peters, and Moshe Zadka.
|
||||
|
||||
IDLE's recent development was carried out in the SF IDLEfork project. The
|
||||
objective was to develop a version of IDLE which had an execution environment
|
||||
which could be initialized prior to each run of user code.
|
||||
|
||||
The IDLEfork project was initiated by David Scherer, with some help from Peter
|
||||
Schneider-Kamp and Nicholas Riley. David wrote the first version of the RPC
|
||||
code and designed a fast turn-around environment for VPython. Guido developed
|
||||
the RPC code and Remote Debugger currently integrated in IDLE. Bruce Sherwood
|
||||
contributed considerable time testing and suggesting improvements.
|
||||
|
||||
Besides David and Guido, the main developers who were active on IDLEfork
|
||||
are Stephen M. Gava, who implemented the configuration GUI, the new
|
||||
configuration system, and the About dialog, and Kurt B. Kaiser, who completed
|
||||
the integration of the RPC and remote debugger, implemented the threaded
|
||||
subprocess, and made a number of usability enhancements.
|
||||
|
||||
Other contributors include Raymond Hettinger, Tony Lownds (Mac integration),
|
||||
Neal Norwitz (code check and clean-up), Ronald Oussoren (Mac integration),
|
||||
Noam Raphael (Code Context, Call Tips, many other patches), and Chui Tey (RPC
|
||||
integration, debugger integration and persistent breakpoints).
|
||||
|
||||
Scott David Daniels, Tal Einat, Hernan Foffani, Christos Georgiou,
|
||||
Jim Jewett, Martin v. Löwis, Jason Orendorff, Guilherme Polo, Josh Robb,
|
||||
Nigel Rowe, Bruce Sherwood, Jeff Shute, and Weeble have submitted useful
|
||||
patches. Thanks, guys!
|
||||
|
||||
For additional details refer to NEWS.txt and Changelog.
|
||||
|
||||
Please contact the IDLE maintainer (kbk@shore.net) to have yourself included
|
||||
here if you are one of those we missed!
|
||||
|
||||
|
||||
|
||||
175
Darwin/lib/python2.7/idlelib/CallTipWindow.py
Normal file
175
Darwin/lib/python2.7/idlelib/CallTipWindow.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
"""A CallTip window class for Tkinter/IDLE.
|
||||
|
||||
After ToolTip.py, which uses ideas gleaned from PySol
|
||||
Used by the CallTips IDLE extension.
|
||||
|
||||
"""
|
||||
from Tkinter import *
|
||||
|
||||
HIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-hide>>"
|
||||
HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
|
||||
CHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
|
||||
CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
|
||||
CHECKHIDE_TIME = 100 # miliseconds
|
||||
|
||||
MARK_RIGHT = "calltipwindowregion_right"
|
||||
|
||||
class CallTip:
|
||||
|
||||
def __init__(self, widget):
|
||||
self.widget = widget
|
||||
self.tipwindow = self.label = None
|
||||
self.parenline = self.parencol = None
|
||||
self.lastline = None
|
||||
self.hideid = self.checkhideid = None
|
||||
self.checkhide_after_id = None
|
||||
|
||||
def position_window(self):
|
||||
"""Check if needs to reposition the window, and if so - do it."""
|
||||
curline = int(self.widget.index("insert").split('.')[0])
|
||||
if curline == self.lastline:
|
||||
return
|
||||
self.lastline = curline
|
||||
self.widget.see("insert")
|
||||
if curline == self.parenline:
|
||||
box = self.widget.bbox("%d.%d" % (self.parenline,
|
||||
self.parencol))
|
||||
else:
|
||||
box = self.widget.bbox("%d.0" % curline)
|
||||
if not box:
|
||||
box = list(self.widget.bbox("insert"))
|
||||
# align to left of window
|
||||
box[0] = 0
|
||||
box[2] = 0
|
||||
x = box[0] + self.widget.winfo_rootx() + 2
|
||||
y = box[1] + box[3] + self.widget.winfo_rooty()
|
||||
self.tipwindow.wm_geometry("+%d+%d" % (x, y))
|
||||
|
||||
def showtip(self, text, parenleft, parenright):
|
||||
"""Show the calltip, bind events which will close it and reposition it.
|
||||
"""
|
||||
# truncate overly long calltip
|
||||
if len(text) >= 79:
|
||||
textlines = text.splitlines()
|
||||
for i, line in enumerate(textlines):
|
||||
if len(line) > 79:
|
||||
textlines[i] = line[:75] + ' ...'
|
||||
text = '\n'.join(textlines)
|
||||
self.text = text
|
||||
if self.tipwindow or not self.text:
|
||||
return
|
||||
|
||||
self.widget.mark_set(MARK_RIGHT, parenright)
|
||||
self.parenline, self.parencol = map(
|
||||
int, self.widget.index(parenleft).split("."))
|
||||
|
||||
self.tipwindow = tw = Toplevel(self.widget)
|
||||
self.position_window()
|
||||
# remove border on calltip window
|
||||
tw.wm_overrideredirect(1)
|
||||
try:
|
||||
# This command is only needed and available on Tk >= 8.4.0 for OSX
|
||||
# Without it, call tips intrude on the typing process by grabbing
|
||||
# the focus.
|
||||
tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
|
||||
"help", "noActivates")
|
||||
except TclError:
|
||||
pass
|
||||
self.label = Label(tw, text=self.text, justify=LEFT,
|
||||
background="#ffffe0", relief=SOLID, borderwidth=1,
|
||||
font = self.widget['font'])
|
||||
self.label.pack()
|
||||
|
||||
self.checkhideid = self.widget.bind(CHECKHIDE_VIRTUAL_EVENT_NAME,
|
||||
self.checkhide_event)
|
||||
for seq in CHECKHIDE_SEQUENCES:
|
||||
self.widget.event_add(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
|
||||
self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
|
||||
self.hide_event)
|
||||
for seq in HIDE_SEQUENCES:
|
||||
self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
|
||||
def checkhide_event(self, event=None):
|
||||
if not self.tipwindow:
|
||||
# If the event was triggered by the same event that unbinded
|
||||
# this function, the function will be called nevertheless,
|
||||
# so do nothing in this case.
|
||||
return
|
||||
curline, curcol = map(int, self.widget.index("insert").split('.'))
|
||||
if curline < self.parenline or \
|
||||
(curline == self.parenline and curcol <= self.parencol) or \
|
||||
self.widget.compare("insert", ">", MARK_RIGHT):
|
||||
self.hidetip()
|
||||
else:
|
||||
self.position_window()
|
||||
if self.checkhide_after_id is not None:
|
||||
self.widget.after_cancel(self.checkhide_after_id)
|
||||
self.checkhide_after_id = \
|
||||
self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
|
||||
|
||||
def hide_event(self, event):
|
||||
if not self.tipwindow:
|
||||
# See the explanation in checkhide_event.
|
||||
return
|
||||
self.hidetip()
|
||||
|
||||
def hidetip(self):
|
||||
if not self.tipwindow:
|
||||
return
|
||||
|
||||
for seq in CHECKHIDE_SEQUENCES:
|
||||
self.widget.event_delete(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.widget.unbind(CHECKHIDE_VIRTUAL_EVENT_NAME, self.checkhideid)
|
||||
self.checkhideid = None
|
||||
for seq in HIDE_SEQUENCES:
|
||||
self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
|
||||
self.hideid = None
|
||||
|
||||
self.label.destroy()
|
||||
self.label = None
|
||||
self.tipwindow.destroy()
|
||||
self.tipwindow = None
|
||||
|
||||
self.widget.mark_unset(MARK_RIGHT)
|
||||
self.parenline = self.parencol = self.lastline = None
|
||||
|
||||
def is_active(self):
|
||||
return bool(self.tipwindow)
|
||||
|
||||
|
||||
|
||||
###############################
|
||||
#
|
||||
# Test Code
|
||||
#
|
||||
class container: # Conceptually an editor_window
|
||||
def __init__(self):
|
||||
root = Tk()
|
||||
text = self.text = Text(root)
|
||||
text.pack(side=LEFT, fill=BOTH, expand=1)
|
||||
text.insert("insert", "string.split")
|
||||
root.update()
|
||||
self.calltip = CallTip(text)
|
||||
|
||||
text.event_add("<<calltip-show>>", "(")
|
||||
text.event_add("<<calltip-hide>>", ")")
|
||||
text.bind("<<calltip-show>>", self.calltip_show)
|
||||
text.bind("<<calltip-hide>>", self.calltip_hide)
|
||||
|
||||
text.focus_set()
|
||||
root.mainloop()
|
||||
|
||||
def calltip_show(self, event):
|
||||
self.calltip.showtip("Hello world")
|
||||
|
||||
def calltip_hide(self, event):
|
||||
self.calltip.hidetip()
|
||||
|
||||
def main():
|
||||
# Test code
|
||||
c=container()
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
228
Darwin/lib/python2.7/idlelib/CallTips.py
Normal file
228
Darwin/lib/python2.7/idlelib/CallTips.py
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
"""CallTips.py - An IDLE Extension to Jog Your Memory
|
||||
|
||||
Call Tips are floating windows which display function, class, and method
|
||||
parameter and docstring information when you type an opening parenthesis, and
|
||||
which disappear when you type a closing parenthesis.
|
||||
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import types
|
||||
|
||||
from idlelib import CallTipWindow
|
||||
from idlelib.HyperParser import HyperParser
|
||||
|
||||
import __main__
|
||||
|
||||
class CallTips:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
("Show call tip", "<<force-open-calltip>>"),
|
||||
])
|
||||
]
|
||||
|
||||
def __init__(self, editwin=None):
|
||||
if editwin is None: # subprocess and test
|
||||
self.editwin = None
|
||||
return
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
self.calltip = None
|
||||
self._make_calltip_window = self._make_tk_calltip_window
|
||||
|
||||
def close(self):
|
||||
self._make_calltip_window = None
|
||||
|
||||
def _make_tk_calltip_window(self):
|
||||
# See __init__ for usage
|
||||
return CallTipWindow.CallTip(self.text)
|
||||
|
||||
def _remove_calltip_window(self, event=None):
|
||||
if self.calltip:
|
||||
self.calltip.hidetip()
|
||||
self.calltip = None
|
||||
|
||||
def force_open_calltip_event(self, event):
|
||||
"""Happens when the user really wants to open a CallTip, even if a
|
||||
function call is needed.
|
||||
"""
|
||||
self.open_calltip(True)
|
||||
|
||||
def try_open_calltip_event(self, event):
|
||||
"""Happens when it would be nice to open a CallTip, but not really
|
||||
necessary, for example after an opening bracket, so function calls
|
||||
won't be made.
|
||||
"""
|
||||
self.open_calltip(False)
|
||||
|
||||
def refresh_calltip_event(self, event):
|
||||
"""If there is already a calltip window, check if it is still needed,
|
||||
and if so, reload it.
|
||||
"""
|
||||
if self.calltip and self.calltip.is_active():
|
||||
self.open_calltip(False)
|
||||
|
||||
def open_calltip(self, evalfuncs):
|
||||
self._remove_calltip_window()
|
||||
|
||||
hp = HyperParser(self.editwin, "insert")
|
||||
sur_paren = hp.get_surrounding_brackets('(')
|
||||
if not sur_paren:
|
||||
return
|
||||
hp.set_index(sur_paren[0])
|
||||
expression = hp.get_expression()
|
||||
if not expression or (not evalfuncs and expression.find('(') != -1):
|
||||
return
|
||||
arg_text = self.fetch_tip(expression)
|
||||
if not arg_text:
|
||||
return
|
||||
self.calltip = self._make_calltip_window()
|
||||
self.calltip.showtip(arg_text, sur_paren[0], sur_paren[1])
|
||||
|
||||
def fetch_tip(self, expression):
|
||||
"""Return the argument list and docstring of a function or class
|
||||
|
||||
If there is a Python subprocess, get the calltip there. Otherwise,
|
||||
either fetch_tip() is running in the subprocess itself or it was called
|
||||
in an IDLE EditorWindow before any script had been run.
|
||||
|
||||
The subprocess environment is that of the most recently run script. If
|
||||
two unrelated modules are being edited some calltips in the current
|
||||
module may be inoperative if the module was not the last to run.
|
||||
|
||||
To find methods, fetch_tip must be fed a fully qualified name.
|
||||
|
||||
"""
|
||||
try:
|
||||
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
|
||||
except AttributeError:
|
||||
rpcclt = None
|
||||
if rpcclt:
|
||||
return rpcclt.remotecall("exec", "get_the_calltip",
|
||||
(expression,), {})
|
||||
else:
|
||||
entity = self.get_entity(expression)
|
||||
return get_arg_text(entity)
|
||||
|
||||
def get_entity(self, expression):
|
||||
"""Return the object corresponding to expression evaluated
|
||||
in a namespace spanning sys.modules and __main.dict__.
|
||||
"""
|
||||
if expression:
|
||||
namespace = sys.modules.copy()
|
||||
namespace.update(__main__.__dict__)
|
||||
try:
|
||||
return eval(expression, namespace)
|
||||
except BaseException:
|
||||
# An uncaught exception closes idle, and eval can raise any
|
||||
# exception, especially if user classes are involved.
|
||||
return None
|
||||
|
||||
def _find_constructor(class_ob):
|
||||
# Given a class object, return a function object used for the
|
||||
# constructor (ie, __init__() ) or None if we can't find one.
|
||||
try:
|
||||
return class_ob.__init__.im_func
|
||||
except AttributeError:
|
||||
for base in class_ob.__bases__:
|
||||
rc = _find_constructor(base)
|
||||
if rc is not None: return rc
|
||||
return None
|
||||
|
||||
def get_arg_text(ob):
|
||||
"""Get a string describing the arguments for the given object,
|
||||
only if it is callable."""
|
||||
arg_text = ""
|
||||
if ob is not None and hasattr(ob, '__call__'):
|
||||
arg_offset = 0
|
||||
if type(ob) in (types.ClassType, types.TypeType):
|
||||
# Look for the highest __init__ in the class chain.
|
||||
fob = _find_constructor(ob)
|
||||
if fob is None:
|
||||
fob = lambda: None
|
||||
else:
|
||||
arg_offset = 1
|
||||
elif type(ob)==types.MethodType:
|
||||
# bit of a hack for methods - turn it into a function
|
||||
# but we drop the "self" param.
|
||||
fob = ob.im_func
|
||||
arg_offset = 1
|
||||
else:
|
||||
fob = ob
|
||||
# Try to build one for Python defined functions
|
||||
if type(fob) in [types.FunctionType, types.LambdaType]:
|
||||
argcount = fob.func_code.co_argcount
|
||||
real_args = fob.func_code.co_varnames[arg_offset:argcount]
|
||||
defaults = fob.func_defaults or []
|
||||
defaults = list(map(lambda name: "=%s" % repr(name), defaults))
|
||||
defaults = [""] * (len(real_args) - len(defaults)) + defaults
|
||||
items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
|
||||
if fob.func_code.co_flags & 0x4:
|
||||
items.append("...")
|
||||
if fob.func_code.co_flags & 0x8:
|
||||
items.append("***")
|
||||
arg_text = ", ".join(items)
|
||||
arg_text = "(%s)" % re.sub("(?<!\d)\.\d+", "<tuple>", arg_text)
|
||||
# See if we can use the docstring
|
||||
doc = getattr(ob, "__doc__", "")
|
||||
if doc:
|
||||
doc = doc.lstrip()
|
||||
pos = doc.find("\n")
|
||||
if pos < 0 or pos > 70:
|
||||
pos = 70
|
||||
if arg_text:
|
||||
arg_text += "\n"
|
||||
arg_text += doc[:pos]
|
||||
return arg_text
|
||||
|
||||
#################################################
|
||||
#
|
||||
# Test code
|
||||
#
|
||||
if __name__=='__main__':
|
||||
|
||||
def t1(): "()"
|
||||
def t2(a, b=None): "(a, b=None)"
|
||||
def t3(a, *args): "(a, ...)"
|
||||
def t4(*args): "(...)"
|
||||
def t5(a, *args): "(a, ...)"
|
||||
def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
|
||||
def t7((a, b), c, (d, e)): "(<tuple>, c, <tuple>)"
|
||||
|
||||
class TC(object):
|
||||
"(ai=None, ...)"
|
||||
def __init__(self, ai=None, *b): "(ai=None, ...)"
|
||||
def t1(self): "()"
|
||||
def t2(self, ai, b=None): "(ai, b=None)"
|
||||
def t3(self, ai, *args): "(ai, ...)"
|
||||
def t4(self, *args): "(...)"
|
||||
def t5(self, ai, *args): "(ai, ...)"
|
||||
def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)"
|
||||
def t7(self, (ai, b), c, (d, e)): "(<tuple>, c, <tuple>)"
|
||||
|
||||
def test(tests):
|
||||
ct = CallTips()
|
||||
failed=[]
|
||||
for t in tests:
|
||||
expected = t.__doc__ + "\n" + t.__doc__
|
||||
name = t.__name__
|
||||
# exercise fetch_tip(), not just get_arg_text()
|
||||
try:
|
||||
qualified_name = "%s.%s" % (t.im_class.__name__, name)
|
||||
except AttributeError:
|
||||
qualified_name = name
|
||||
arg_text = ct.fetch_tip(qualified_name)
|
||||
if arg_text != expected:
|
||||
failed.append(t)
|
||||
fmt = "%s - expected %s, but got %s"
|
||||
print fmt % (t.__name__, expected, get_arg_text(t))
|
||||
print "%d of %d tests failed" % (len(failed), len(tests))
|
||||
|
||||
tc = TC()
|
||||
tests = (t1, t2, t3, t4, t5, t6, t7,
|
||||
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7)
|
||||
|
||||
# test(tests)
|
||||
from unittest import main
|
||||
main('idlelib.idle_test.test_calltips', verbosity=2, exit=False)
|
||||
1591
Darwin/lib/python2.7/idlelib/ChangeLog
Normal file
1591
Darwin/lib/python2.7/idlelib/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
221
Darwin/lib/python2.7/idlelib/ClassBrowser.py
Normal file
221
Darwin/lib/python2.7/idlelib/ClassBrowser.py
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
"""Class browser.
|
||||
|
||||
XXX TO DO:
|
||||
|
||||
- reparse when source changed (maybe just a button would be OK?)
|
||||
(or recheck on window popup)
|
||||
- add popup menu with more options (e.g. doc strings, base classes, imports)
|
||||
- show function argument list? (have to do pattern matching on source)
|
||||
- should the classes and methods lists also be in the module's menu bar?
|
||||
- add base classes to class browser tree
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pyclbr
|
||||
|
||||
from idlelib import PyShell
|
||||
from idlelib.WindowList import ListedToplevel
|
||||
from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
class ClassBrowser:
|
||||
|
||||
def __init__(self, flist, name, path):
|
||||
# XXX This API should change, if the file doesn't end in ".py"
|
||||
# XXX the code here is bogus!
|
||||
self.name = name
|
||||
self.file = os.path.join(path[0], self.name + ".py")
|
||||
self.init(flist)
|
||||
|
||||
def close(self, event=None):
|
||||
self.top.destroy()
|
||||
self.node.destroy()
|
||||
|
||||
def init(self, flist):
|
||||
self.flist = flist
|
||||
# reset pyclbr
|
||||
pyclbr._modules.clear()
|
||||
# create top
|
||||
self.top = top = ListedToplevel(flist.root)
|
||||
top.protocol("WM_DELETE_WINDOW", self.close)
|
||||
top.bind("<Escape>", self.close)
|
||||
self.settitle()
|
||||
top.focus_set()
|
||||
# create scrolled canvas
|
||||
theme = idleConf.GetOption('main','Theme','name')
|
||||
background = idleConf.GetHighlight(theme, 'normal')['background']
|
||||
sc = ScrolledCanvas(top, bg=background, highlightthickness=0, takefocus=1)
|
||||
sc.frame.pack(expand=1, fill="both")
|
||||
item = self.rootnode()
|
||||
self.node = node = TreeNode(sc.canvas, None, item)
|
||||
node.update()
|
||||
node.expand()
|
||||
|
||||
def settitle(self):
|
||||
self.top.wm_title("Class Browser - " + self.name)
|
||||
self.top.wm_iconname("Class Browser")
|
||||
|
||||
def rootnode(self):
|
||||
return ModuleBrowserTreeItem(self.file)
|
||||
|
||||
class ModuleBrowserTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
def GetText(self):
|
||||
return os.path.basename(self.file)
|
||||
|
||||
def GetIconName(self):
|
||||
return "python"
|
||||
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for name in self.listclasses():
|
||||
item = ClassBrowserTreeItem(name, self.classes, self.file)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
def OnDoubleClick(self):
|
||||
if os.path.normcase(self.file[-3:]) != ".py":
|
||||
return
|
||||
if not os.path.exists(self.file):
|
||||
return
|
||||
PyShell.flist.open(self.file)
|
||||
|
||||
def IsExpandable(self):
|
||||
return os.path.normcase(self.file[-3:]) == ".py"
|
||||
|
||||
def listclasses(self):
|
||||
dir, file = os.path.split(self.file)
|
||||
name, ext = os.path.splitext(file)
|
||||
if os.path.normcase(ext) != ".py":
|
||||
return []
|
||||
try:
|
||||
dict = pyclbr.readmodule_ex(name, [dir] + sys.path)
|
||||
except ImportError, msg:
|
||||
return []
|
||||
items = []
|
||||
self.classes = {}
|
||||
for key, cl in dict.items():
|
||||
if cl.module == name:
|
||||
s = key
|
||||
if hasattr(cl, 'super') and cl.super:
|
||||
supers = []
|
||||
for sup in cl.super:
|
||||
if type(sup) is type(''):
|
||||
sname = sup
|
||||
else:
|
||||
sname = sup.name
|
||||
if sup.module != cl.module:
|
||||
sname = "%s.%s" % (sup.module, sname)
|
||||
supers.append(sname)
|
||||
s = s + "(%s)" % ", ".join(supers)
|
||||
items.append((cl.lineno, s))
|
||||
self.classes[s] = cl
|
||||
items.sort()
|
||||
list = []
|
||||
for item, s in items:
|
||||
list.append(s)
|
||||
return list
|
||||
|
||||
class ClassBrowserTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, name, classes, file):
|
||||
self.name = name
|
||||
self.classes = classes
|
||||
self.file = file
|
||||
try:
|
||||
self.cl = self.classes[self.name]
|
||||
except (IndexError, KeyError):
|
||||
self.cl = None
|
||||
self.isfunction = isinstance(self.cl, pyclbr.Function)
|
||||
|
||||
def GetText(self):
|
||||
if self.isfunction:
|
||||
return "def " + self.name + "(...)"
|
||||
else:
|
||||
return "class " + self.name
|
||||
|
||||
def GetIconName(self):
|
||||
if self.isfunction:
|
||||
return "python"
|
||||
else:
|
||||
return "folder"
|
||||
|
||||
def IsExpandable(self):
|
||||
if self.cl:
|
||||
try:
|
||||
return not not self.cl.methods
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
def GetSubList(self):
|
||||
if not self.cl:
|
||||
return []
|
||||
sublist = []
|
||||
for name in self.listmethods():
|
||||
item = MethodBrowserTreeItem(name, self.cl, self.file)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
def OnDoubleClick(self):
|
||||
if not os.path.exists(self.file):
|
||||
return
|
||||
edit = PyShell.flist.open(self.file)
|
||||
if hasattr(self.cl, 'lineno'):
|
||||
lineno = self.cl.lineno
|
||||
edit.gotoline(lineno)
|
||||
|
||||
def listmethods(self):
|
||||
if not self.cl:
|
||||
return []
|
||||
items = []
|
||||
for name, lineno in self.cl.methods.items():
|
||||
items.append((lineno, name))
|
||||
items.sort()
|
||||
list = []
|
||||
for item, name in items:
|
||||
list.append(name)
|
||||
return list
|
||||
|
||||
class MethodBrowserTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, name, cl, file):
|
||||
self.name = name
|
||||
self.cl = cl
|
||||
self.file = file
|
||||
|
||||
def GetText(self):
|
||||
return "def " + self.name + "(...)"
|
||||
|
||||
def GetIconName(self):
|
||||
return "python" # XXX
|
||||
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
|
||||
def OnDoubleClick(self):
|
||||
if not os.path.exists(self.file):
|
||||
return
|
||||
edit = PyShell.flist.open(self.file)
|
||||
edit.gotoline(self.cl.methods[self.name])
|
||||
|
||||
def main():
|
||||
try:
|
||||
file = __file__
|
||||
except NameError:
|
||||
file = sys.argv[0]
|
||||
if sys.argv[1:]:
|
||||
file = sys.argv[1]
|
||||
else:
|
||||
file = sys.argv[0]
|
||||
dir, file = os.path.split(file)
|
||||
name = os.path.splitext(file)[0]
|
||||
ClassBrowser(PyShell.flist, name, [dir])
|
||||
if sys.stdin is sys.__stdin__:
|
||||
mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
176
Darwin/lib/python2.7/idlelib/CodeContext.py
Normal file
176
Darwin/lib/python2.7/idlelib/CodeContext.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
"""CodeContext - Extension to display the block context above the edit window
|
||||
|
||||
Once code has scrolled off the top of a window, it can be difficult to
|
||||
determine which block you are in. This extension implements a pane at the top
|
||||
of each IDLE edit window which provides block structure hints. These hints are
|
||||
the lines which contain the block opening keywords, e.g. 'if', for the
|
||||
enclosing block. The number of hint lines is determined by the numlines
|
||||
variable in the CodeContext section of config-extensions.def. Lines which do
|
||||
not open blocks are not shown in the context hints pane.
|
||||
|
||||
"""
|
||||
import Tkinter
|
||||
from Tkconstants import TOP, LEFT, X, W, SUNKEN
|
||||
import re
|
||||
from sys import maxint as INFINITY
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
BLOCKOPENERS = set(["class", "def", "elif", "else", "except", "finally", "for",
|
||||
"if", "try", "while", "with"])
|
||||
UPDATEINTERVAL = 100 # millisec
|
||||
FONTUPDATEINTERVAL = 1000 # millisec
|
||||
|
||||
getspacesfirstword =\
|
||||
lambda s, c=re.compile(r"^(\s*)(\w*)"): c.match(s).groups()
|
||||
|
||||
class CodeContext:
|
||||
menudefs = [('options', [('!Code Conte_xt', '<<toggle-code-context>>')])]
|
||||
context_depth = idleConf.GetOption("extensions", "CodeContext",
|
||||
"numlines", type="int", default=3)
|
||||
bgcolor = idleConf.GetOption("extensions", "CodeContext",
|
||||
"bgcolor", type="str", default="LightGray")
|
||||
fgcolor = idleConf.GetOption("extensions", "CodeContext",
|
||||
"fgcolor", type="str", default="Black")
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
self.textfont = self.text["font"]
|
||||
self.label = None
|
||||
# self.info is a list of (line number, indent level, line text, block
|
||||
# keyword) tuples providing the block structure associated with
|
||||
# self.topvisible (the linenumber of the line displayed at the top of
|
||||
# the edit window). self.info[0] is initialized as a 'dummy' line which
|
||||
# starts the toplevel 'block' of the module.
|
||||
self.info = [(0, -1, "", False)]
|
||||
self.topvisible = 1
|
||||
visible = idleConf.GetOption("extensions", "CodeContext",
|
||||
"visible", type="bool", default=False)
|
||||
if visible:
|
||||
self.toggle_code_context_event()
|
||||
self.editwin.setvar('<<toggle-code-context>>', True)
|
||||
# Start two update cycles, one for context lines, one for font changes.
|
||||
self.text.after(UPDATEINTERVAL, self.timer_event)
|
||||
self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)
|
||||
|
||||
def toggle_code_context_event(self, event=None):
|
||||
if not self.label:
|
||||
# Calculate the border width and horizontal padding required to
|
||||
# align the context with the text in the main Text widget.
|
||||
#
|
||||
# All values are passed through int(str(<value>)), since some
|
||||
# values may be pixel objects, which can't simply be added to ints.
|
||||
widgets = self.editwin.text, self.editwin.text_frame
|
||||
# Calculate the required vertical padding
|
||||
padx = 0
|
||||
for widget in widgets:
|
||||
padx += int(str( widget.pack_info()['padx'] ))
|
||||
padx += int(str( widget.cget('padx') ))
|
||||
# Calculate the required border width
|
||||
border = 0
|
||||
for widget in widgets:
|
||||
border += int(str( widget.cget('border') ))
|
||||
self.label = Tkinter.Label(self.editwin.top,
|
||||
text="\n" * (self.context_depth - 1),
|
||||
anchor=W, justify=LEFT,
|
||||
font=self.textfont,
|
||||
bg=self.bgcolor, fg=self.fgcolor,
|
||||
width=1, #don't request more than we get
|
||||
padx=padx, border=border,
|
||||
relief=SUNKEN)
|
||||
# Pack the label widget before and above the text_frame widget,
|
||||
# thus ensuring that it will appear directly above text_frame
|
||||
self.label.pack(side=TOP, fill=X, expand=False,
|
||||
before=self.editwin.text_frame)
|
||||
else:
|
||||
self.label.destroy()
|
||||
self.label = None
|
||||
idleConf.SetOption("extensions", "CodeContext", "visible",
|
||||
str(self.label is not None))
|
||||
idleConf.SaveUserCfgFiles()
|
||||
|
||||
def get_line_info(self, linenum):
|
||||
"""Get the line indent value, text, and any block start keyword
|
||||
|
||||
If the line does not start a block, the keyword value is False.
|
||||
The indentation of empty lines (or comment lines) is INFINITY.
|
||||
|
||||
"""
|
||||
text = self.text.get("%d.0" % linenum, "%d.end" % linenum)
|
||||
spaces, firstword = getspacesfirstword(text)
|
||||
opener = firstword in BLOCKOPENERS and firstword
|
||||
if len(text) == len(spaces) or text[len(spaces)] == '#':
|
||||
indent = INFINITY
|
||||
else:
|
||||
indent = len(spaces)
|
||||
return indent, text, opener
|
||||
|
||||
def get_context(self, new_topvisible, stopline=1, stopindent=0):
|
||||
"""Get context lines, starting at new_topvisible and working backwards.
|
||||
|
||||
Stop when stopline or stopindent is reached. Return a tuple of context
|
||||
data and the indent level at the top of the region inspected.
|
||||
|
||||
"""
|
||||
assert stopline > 0
|
||||
lines = []
|
||||
# The indentation level we are currently in:
|
||||
lastindent = INFINITY
|
||||
# For a line to be interesting, it must begin with a block opening
|
||||
# keyword, and have less indentation than lastindent.
|
||||
for linenum in xrange(new_topvisible, stopline-1, -1):
|
||||
indent, text, opener = self.get_line_info(linenum)
|
||||
if indent < lastindent:
|
||||
lastindent = indent
|
||||
if opener in ("else", "elif"):
|
||||
# We also show the if statement
|
||||
lastindent += 1
|
||||
if opener and linenum < new_topvisible and indent >= stopindent:
|
||||
lines.append((linenum, indent, text, opener))
|
||||
if lastindent <= stopindent:
|
||||
break
|
||||
lines.reverse()
|
||||
return lines, lastindent
|
||||
|
||||
def update_code_context(self):
|
||||
"""Update context information and lines visible in the context pane.
|
||||
|
||||
"""
|
||||
new_topvisible = int(self.text.index("@0,0").split('.')[0])
|
||||
if self.topvisible == new_topvisible: # haven't scrolled
|
||||
return
|
||||
if self.topvisible < new_topvisible: # scroll down
|
||||
lines, lastindent = self.get_context(new_topvisible,
|
||||
self.topvisible)
|
||||
# retain only context info applicable to the region
|
||||
# between topvisible and new_topvisible:
|
||||
while self.info[-1][1] >= lastindent:
|
||||
del self.info[-1]
|
||||
elif self.topvisible > new_topvisible: # scroll up
|
||||
stopindent = self.info[-1][1] + 1
|
||||
# retain only context info associated
|
||||
# with lines above new_topvisible:
|
||||
while self.info[-1][0] >= new_topvisible:
|
||||
stopindent = self.info[-1][1]
|
||||
del self.info[-1]
|
||||
lines, lastindent = self.get_context(new_topvisible,
|
||||
self.info[-1][0]+1,
|
||||
stopindent)
|
||||
self.info.extend(lines)
|
||||
self.topvisible = new_topvisible
|
||||
# empty lines in context pane:
|
||||
context_strings = [""] * max(0, self.context_depth - len(self.info))
|
||||
# followed by the context hint lines:
|
||||
context_strings += [x[2] for x in self.info[-self.context_depth:]]
|
||||
self.label["text"] = '\n'.join(context_strings)
|
||||
|
||||
def timer_event(self):
|
||||
if self.label:
|
||||
self.update_code_context()
|
||||
self.text.after(UPDATEINTERVAL, self.timer_event)
|
||||
|
||||
def font_timer_event(self):
|
||||
newtextfont = self.text["font"]
|
||||
if self.label and newtextfont != self.textfont:
|
||||
self.textfont = newtextfont
|
||||
self.label["font"] = self.textfont
|
||||
self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)
|
||||
268
Darwin/lib/python2.7/idlelib/ColorDelegator.py
Normal file
268
Darwin/lib/python2.7/idlelib/ColorDelegator.py
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
import time
|
||||
import re
|
||||
import keyword
|
||||
import __builtin__
|
||||
from Tkinter import *
|
||||
from idlelib.Delegator import Delegator
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
DEBUG = False
|
||||
|
||||
def any(name, alternates):
|
||||
"Return a named group pattern matching list of alternates."
|
||||
return "(?P<%s>" % name + "|".join(alternates) + ")"
|
||||
|
||||
def make_pat():
|
||||
kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
|
||||
builtinlist = [str(name) for name in dir(__builtin__)
|
||||
if not name.startswith('_')]
|
||||
# self.file = file("file") :
|
||||
# 1st 'file' colorized normal, 2nd as builtin, 3rd as string
|
||||
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
|
||||
comment = any("COMMENT", [r"#[^\n]*"])
|
||||
stringprefix = r"(\br|u|ur|R|U|UR|Ur|uR|b|B|br|Br|bR|BR)?"
|
||||
sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
|
||||
dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
|
||||
sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
|
||||
dq3string = stringprefix + r'"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
|
||||
string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
|
||||
return kw + "|" + builtin + "|" + comment + "|" + string +\
|
||||
"|" + any("SYNC", [r"\n"])
|
||||
|
||||
prog = re.compile(make_pat(), re.S)
|
||||
idprog = re.compile(r"\s+(\w+)", re.S)
|
||||
asprog = re.compile(r".*?\b(as)\b")
|
||||
|
||||
class ColorDelegator(Delegator):
|
||||
|
||||
def __init__(self):
|
||||
Delegator.__init__(self)
|
||||
self.prog = prog
|
||||
self.idprog = idprog
|
||||
self.asprog = asprog
|
||||
self.LoadTagDefs()
|
||||
|
||||
def setdelegate(self, delegate):
|
||||
if self.delegate is not None:
|
||||
self.unbind("<<toggle-auto-coloring>>")
|
||||
Delegator.setdelegate(self, delegate)
|
||||
if delegate is not None:
|
||||
self.config_colors()
|
||||
self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
|
||||
self.notify_range("1.0", "end")
|
||||
else:
|
||||
# No delegate - stop any colorizing
|
||||
self.stop_colorizing = True
|
||||
self.allow_colorizing = False
|
||||
|
||||
def config_colors(self):
|
||||
for tag, cnf in self.tagdefs.items():
|
||||
if cnf:
|
||||
self.tag_configure(tag, **cnf)
|
||||
self.tag_raise('sel')
|
||||
|
||||
def LoadTagDefs(self):
|
||||
theme = idleConf.GetOption('main','Theme','name')
|
||||
self.tagdefs = {
|
||||
"COMMENT": idleConf.GetHighlight(theme, "comment"),
|
||||
"KEYWORD": idleConf.GetHighlight(theme, "keyword"),
|
||||
"BUILTIN": idleConf.GetHighlight(theme, "builtin"),
|
||||
"STRING": idleConf.GetHighlight(theme, "string"),
|
||||
"DEFINITION": idleConf.GetHighlight(theme, "definition"),
|
||||
"SYNC": {'background':None,'foreground':None},
|
||||
"TODO": {'background':None,'foreground':None},
|
||||
"BREAK": idleConf.GetHighlight(theme, "break"),
|
||||
"ERROR": idleConf.GetHighlight(theme, "error"),
|
||||
# The following is used by ReplaceDialog:
|
||||
"hit": idleConf.GetHighlight(theme, "hit"),
|
||||
}
|
||||
|
||||
if DEBUG: print 'tagdefs',self.tagdefs
|
||||
|
||||
def insert(self, index, chars, tags=None):
|
||||
index = self.index(index)
|
||||
self.delegate.insert(index, chars, tags)
|
||||
self.notify_range(index, index + "+%dc" % len(chars))
|
||||
|
||||
def delete(self, index1, index2=None):
|
||||
index1 = self.index(index1)
|
||||
self.delegate.delete(index1, index2)
|
||||
self.notify_range(index1)
|
||||
|
||||
after_id = None
|
||||
allow_colorizing = True
|
||||
colorizing = False
|
||||
|
||||
def notify_range(self, index1, index2=None):
|
||||
self.tag_add("TODO", index1, index2)
|
||||
if self.after_id:
|
||||
if DEBUG: print "colorizing already scheduled"
|
||||
return
|
||||
if self.colorizing:
|
||||
self.stop_colorizing = True
|
||||
if DEBUG: print "stop colorizing"
|
||||
if self.allow_colorizing:
|
||||
if DEBUG: print "schedule colorizing"
|
||||
self.after_id = self.after(1, self.recolorize)
|
||||
|
||||
close_when_done = None # Window to be closed when done colorizing
|
||||
|
||||
def close(self, close_when_done=None):
|
||||
if self.after_id:
|
||||
after_id = self.after_id
|
||||
self.after_id = None
|
||||
if DEBUG: print "cancel scheduled recolorizer"
|
||||
self.after_cancel(after_id)
|
||||
self.allow_colorizing = False
|
||||
self.stop_colorizing = True
|
||||
if close_when_done:
|
||||
if not self.colorizing:
|
||||
close_when_done.destroy()
|
||||
else:
|
||||
self.close_when_done = close_when_done
|
||||
|
||||
def toggle_colorize_event(self, event):
|
||||
if self.after_id:
|
||||
after_id = self.after_id
|
||||
self.after_id = None
|
||||
if DEBUG: print "cancel scheduled recolorizer"
|
||||
self.after_cancel(after_id)
|
||||
if self.allow_colorizing and self.colorizing:
|
||||
if DEBUG: print "stop colorizing"
|
||||
self.stop_colorizing = True
|
||||
self.allow_colorizing = not self.allow_colorizing
|
||||
if self.allow_colorizing and not self.colorizing:
|
||||
self.after_id = self.after(1, self.recolorize)
|
||||
if DEBUG:
|
||||
print "auto colorizing turned",\
|
||||
self.allow_colorizing and "on" or "off"
|
||||
return "break"
|
||||
|
||||
def recolorize(self):
|
||||
self.after_id = None
|
||||
if not self.delegate:
|
||||
if DEBUG: print "no delegate"
|
||||
return
|
||||
if not self.allow_colorizing:
|
||||
if DEBUG: print "auto colorizing is off"
|
||||
return
|
||||
if self.colorizing:
|
||||
if DEBUG: print "already colorizing"
|
||||
return
|
||||
try:
|
||||
self.stop_colorizing = False
|
||||
self.colorizing = True
|
||||
if DEBUG: print "colorizing..."
|
||||
t0 = time.clock()
|
||||
self.recolorize_main()
|
||||
t1 = time.clock()
|
||||
if DEBUG: print "%.3f seconds" % (t1-t0)
|
||||
finally:
|
||||
self.colorizing = False
|
||||
if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
|
||||
if DEBUG: print "reschedule colorizing"
|
||||
self.after_id = self.after(1, self.recolorize)
|
||||
if self.close_when_done:
|
||||
top = self.close_when_done
|
||||
self.close_when_done = None
|
||||
top.destroy()
|
||||
|
||||
def recolorize_main(self):
|
||||
next = "1.0"
|
||||
while True:
|
||||
item = self.tag_nextrange("TODO", next)
|
||||
if not item:
|
||||
break
|
||||
head, tail = item
|
||||
self.tag_remove("SYNC", head, tail)
|
||||
item = self.tag_prevrange("SYNC", head)
|
||||
if item:
|
||||
head = item[1]
|
||||
else:
|
||||
head = "1.0"
|
||||
|
||||
chars = ""
|
||||
next = head
|
||||
lines_to_get = 1
|
||||
ok = False
|
||||
while not ok:
|
||||
mark = next
|
||||
next = self.index(mark + "+%d lines linestart" %
|
||||
lines_to_get)
|
||||
lines_to_get = min(lines_to_get * 2, 100)
|
||||
ok = "SYNC" in self.tag_names(next + "-1c")
|
||||
line = self.get(mark, next)
|
||||
##print head, "get", mark, next, "->", repr(line)
|
||||
if not line:
|
||||
return
|
||||
for tag in self.tagdefs.keys():
|
||||
self.tag_remove(tag, mark, next)
|
||||
chars = chars + line
|
||||
m = self.prog.search(chars)
|
||||
while m:
|
||||
for key, value in m.groupdict().items():
|
||||
if value:
|
||||
a, b = m.span(key)
|
||||
self.tag_add(key,
|
||||
head + "+%dc" % a,
|
||||
head + "+%dc" % b)
|
||||
if value in ("def", "class"):
|
||||
m1 = self.idprog.match(chars, b)
|
||||
if m1:
|
||||
a, b = m1.span(1)
|
||||
self.tag_add("DEFINITION",
|
||||
head + "+%dc" % a,
|
||||
head + "+%dc" % b)
|
||||
elif value == "import":
|
||||
# color all the "as" words on same line, except
|
||||
# if in a comment; cheap approximation to the
|
||||
# truth
|
||||
if '#' in chars:
|
||||
endpos = chars.index('#')
|
||||
else:
|
||||
endpos = len(chars)
|
||||
while True:
|
||||
m1 = self.asprog.match(chars, b, endpos)
|
||||
if not m1:
|
||||
break
|
||||
a, b = m1.span(1)
|
||||
self.tag_add("KEYWORD",
|
||||
head + "+%dc" % a,
|
||||
head + "+%dc" % b)
|
||||
m = self.prog.search(chars, m.end())
|
||||
if "SYNC" in self.tag_names(next + "-1c"):
|
||||
head = next
|
||||
chars = ""
|
||||
else:
|
||||
ok = False
|
||||
if not ok:
|
||||
# We're in an inconsistent state, and the call to
|
||||
# update may tell us to stop. It may also change
|
||||
# the correct value for "next" (since this is a
|
||||
# line.col string, not a true mark). So leave a
|
||||
# crumb telling the next invocation to resume here
|
||||
# in case update tells us to leave.
|
||||
self.tag_add("TODO", next)
|
||||
self.update()
|
||||
if self.stop_colorizing:
|
||||
if DEBUG: print "colorizing stopped"
|
||||
return
|
||||
|
||||
def removecolors(self):
|
||||
for tag in self.tagdefs.keys():
|
||||
self.tag_remove(tag, "1.0", "end")
|
||||
|
||||
def main():
|
||||
from idlelib.Percolator import Percolator
|
||||
root = Tk()
|
||||
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
|
||||
text = Text(background="white")
|
||||
text.pack(expand=1, fill="both")
|
||||
text.focus_set()
|
||||
p = Percolator(text)
|
||||
d = ColorDelegator()
|
||||
p.insertfilter(d)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
481
Darwin/lib/python2.7/idlelib/Debugger.py
Normal file
481
Darwin/lib/python2.7/idlelib/Debugger.py
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
import os
|
||||
import bdb
|
||||
import types
|
||||
from Tkinter import *
|
||||
from idlelib.WindowList import ListedToplevel
|
||||
from idlelib.ScrolledList import ScrolledList
|
||||
from idlelib import macosxSupport
|
||||
|
||||
|
||||
class Idb(bdb.Bdb):
|
||||
|
||||
def __init__(self, gui):
|
||||
self.gui = gui
|
||||
bdb.Bdb.__init__(self)
|
||||
|
||||
def user_line(self, frame):
|
||||
if self.in_rpc_code(frame):
|
||||
self.set_step()
|
||||
return
|
||||
message = self.__frame2message(frame)
|
||||
self.gui.interaction(message, frame)
|
||||
|
||||
def user_exception(self, frame, info):
|
||||
if self.in_rpc_code(frame):
|
||||
self.set_step()
|
||||
return
|
||||
message = self.__frame2message(frame)
|
||||
self.gui.interaction(message, frame, info)
|
||||
|
||||
def in_rpc_code(self, frame):
|
||||
if frame.f_code.co_filename.count('rpc.py'):
|
||||
return True
|
||||
else:
|
||||
prev_frame = frame.f_back
|
||||
if prev_frame.f_code.co_filename.count('Debugger.py'):
|
||||
# (that test will catch both Debugger.py and RemoteDebugger.py)
|
||||
return False
|
||||
return self.in_rpc_code(prev_frame)
|
||||
|
||||
def __frame2message(self, frame):
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
lineno = frame.f_lineno
|
||||
basename = os.path.basename(filename)
|
||||
message = "%s:%s" % (basename, lineno)
|
||||
if code.co_name != "?":
|
||||
message = "%s: %s()" % (message, code.co_name)
|
||||
return message
|
||||
|
||||
|
||||
class Debugger:
|
||||
|
||||
vstack = vsource = vlocals = vglobals = None
|
||||
|
||||
def __init__(self, pyshell, idb=None):
|
||||
if idb is None:
|
||||
idb = Idb(self)
|
||||
self.pyshell = pyshell
|
||||
self.idb = idb
|
||||
self.frame = None
|
||||
self.make_gui()
|
||||
self.interacting = 0
|
||||
|
||||
def run(self, *args):
|
||||
try:
|
||||
self.interacting = 1
|
||||
return self.idb.run(*args)
|
||||
finally:
|
||||
self.interacting = 0
|
||||
|
||||
def close(self, event=None):
|
||||
if self.interacting:
|
||||
self.top.bell()
|
||||
return
|
||||
if self.stackviewer:
|
||||
self.stackviewer.close(); self.stackviewer = None
|
||||
# Clean up pyshell if user clicked debugger control close widget.
|
||||
# (Causes a harmless extra cycle through close_debugger() if user
|
||||
# toggled debugger from pyshell Debug menu)
|
||||
self.pyshell.close_debugger()
|
||||
# Now close the debugger control window....
|
||||
self.top.destroy()
|
||||
|
||||
def make_gui(self):
|
||||
pyshell = self.pyshell
|
||||
self.flist = pyshell.flist
|
||||
self.root = root = pyshell.root
|
||||
self.top = top = ListedToplevel(root)
|
||||
self.top.wm_title("Debug Control")
|
||||
self.top.wm_iconname("Debug")
|
||||
top.wm_protocol("WM_DELETE_WINDOW", self.close)
|
||||
self.top.bind("<Escape>", self.close)
|
||||
#
|
||||
self.bframe = bframe = Frame(top)
|
||||
self.bframe.pack(anchor="w")
|
||||
self.buttons = bl = []
|
||||
#
|
||||
self.bcont = b = Button(bframe, text="Go", command=self.cont)
|
||||
bl.append(b)
|
||||
self.bstep = b = Button(bframe, text="Step", command=self.step)
|
||||
bl.append(b)
|
||||
self.bnext = b = Button(bframe, text="Over", command=self.next)
|
||||
bl.append(b)
|
||||
self.bret = b = Button(bframe, text="Out", command=self.ret)
|
||||
bl.append(b)
|
||||
self.bret = b = Button(bframe, text="Quit", command=self.quit)
|
||||
bl.append(b)
|
||||
#
|
||||
for b in bl:
|
||||
b.configure(state="disabled")
|
||||
b.pack(side="left")
|
||||
#
|
||||
self.cframe = cframe = Frame(bframe)
|
||||
self.cframe.pack(side="left")
|
||||
#
|
||||
if not self.vstack:
|
||||
self.__class__.vstack = BooleanVar(top)
|
||||
self.vstack.set(1)
|
||||
self.bstack = Checkbutton(cframe,
|
||||
text="Stack", command=self.show_stack, variable=self.vstack)
|
||||
self.bstack.grid(row=0, column=0)
|
||||
if not self.vsource:
|
||||
self.__class__.vsource = BooleanVar(top)
|
||||
self.bsource = Checkbutton(cframe,
|
||||
text="Source", command=self.show_source, variable=self.vsource)
|
||||
self.bsource.grid(row=0, column=1)
|
||||
if not self.vlocals:
|
||||
self.__class__.vlocals = BooleanVar(top)
|
||||
self.vlocals.set(1)
|
||||
self.blocals = Checkbutton(cframe,
|
||||
text="Locals", command=self.show_locals, variable=self.vlocals)
|
||||
self.blocals.grid(row=1, column=0)
|
||||
if not self.vglobals:
|
||||
self.__class__.vglobals = BooleanVar(top)
|
||||
self.bglobals = Checkbutton(cframe,
|
||||
text="Globals", command=self.show_globals, variable=self.vglobals)
|
||||
self.bglobals.grid(row=1, column=1)
|
||||
#
|
||||
self.status = Label(top, anchor="w")
|
||||
self.status.pack(anchor="w")
|
||||
self.error = Label(top, anchor="w")
|
||||
self.error.pack(anchor="w", fill="x")
|
||||
self.errorbg = self.error.cget("background")
|
||||
#
|
||||
self.fstack = Frame(top, height=1)
|
||||
self.fstack.pack(expand=1, fill="both")
|
||||
self.flocals = Frame(top)
|
||||
self.flocals.pack(expand=1, fill="both")
|
||||
self.fglobals = Frame(top, height=1)
|
||||
self.fglobals.pack(expand=1, fill="both")
|
||||
#
|
||||
if self.vstack.get():
|
||||
self.show_stack()
|
||||
if self.vlocals.get():
|
||||
self.show_locals()
|
||||
if self.vglobals.get():
|
||||
self.show_globals()
|
||||
|
||||
def interaction(self, message, frame, info=None):
|
||||
self.frame = frame
|
||||
self.status.configure(text=message)
|
||||
#
|
||||
if info:
|
||||
type, value, tb = info
|
||||
try:
|
||||
m1 = type.__name__
|
||||
except AttributeError:
|
||||
m1 = "%s" % str(type)
|
||||
if value is not None:
|
||||
try:
|
||||
m1 = "%s: %s" % (m1, str(value))
|
||||
except:
|
||||
pass
|
||||
bg = "yellow"
|
||||
else:
|
||||
m1 = ""
|
||||
tb = None
|
||||
bg = self.errorbg
|
||||
self.error.configure(text=m1, background=bg)
|
||||
#
|
||||
sv = self.stackviewer
|
||||
if sv:
|
||||
stack, i = self.idb.get_stack(self.frame, tb)
|
||||
sv.load_stack(stack, i)
|
||||
#
|
||||
self.show_variables(1)
|
||||
#
|
||||
if self.vsource.get():
|
||||
self.sync_source_line()
|
||||
#
|
||||
for b in self.buttons:
|
||||
b.configure(state="normal")
|
||||
#
|
||||
self.top.wakeup()
|
||||
self.root.mainloop()
|
||||
#
|
||||
for b in self.buttons:
|
||||
b.configure(state="disabled")
|
||||
self.status.configure(text="")
|
||||
self.error.configure(text="", background=self.errorbg)
|
||||
self.frame = None
|
||||
|
||||
def sync_source_line(self):
|
||||
frame = self.frame
|
||||
if not frame:
|
||||
return
|
||||
filename, lineno = self.__frame2fileline(frame)
|
||||
if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
|
||||
self.flist.gotofileline(filename, lineno)
|
||||
|
||||
def __frame2fileline(self, frame):
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
lineno = frame.f_lineno
|
||||
return filename, lineno
|
||||
|
||||
def cont(self):
|
||||
self.idb.set_continue()
|
||||
self.root.quit()
|
||||
|
||||
def step(self):
|
||||
self.idb.set_step()
|
||||
self.root.quit()
|
||||
|
||||
def next(self):
|
||||
self.idb.set_next(self.frame)
|
||||
self.root.quit()
|
||||
|
||||
def ret(self):
|
||||
self.idb.set_return(self.frame)
|
||||
self.root.quit()
|
||||
|
||||
def quit(self):
|
||||
self.idb.set_quit()
|
||||
self.root.quit()
|
||||
|
||||
stackviewer = None
|
||||
|
||||
def show_stack(self):
|
||||
if not self.stackviewer and self.vstack.get():
|
||||
self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
|
||||
if self.frame:
|
||||
stack, i = self.idb.get_stack(self.frame, None)
|
||||
sv.load_stack(stack, i)
|
||||
else:
|
||||
sv = self.stackviewer
|
||||
if sv and not self.vstack.get():
|
||||
self.stackviewer = None
|
||||
sv.close()
|
||||
self.fstack['height'] = 1
|
||||
|
||||
def show_source(self):
|
||||
if self.vsource.get():
|
||||
self.sync_source_line()
|
||||
|
||||
def show_frame(self, (frame, lineno)):
|
||||
self.frame = frame
|
||||
self.show_variables()
|
||||
|
||||
localsviewer = None
|
||||
globalsviewer = None
|
||||
|
||||
def show_locals(self):
|
||||
lv = self.localsviewer
|
||||
if self.vlocals.get():
|
||||
if not lv:
|
||||
self.localsviewer = NamespaceViewer(self.flocals, "Locals")
|
||||
else:
|
||||
if lv:
|
||||
self.localsviewer = None
|
||||
lv.close()
|
||||
self.flocals['height'] = 1
|
||||
self.show_variables()
|
||||
|
||||
def show_globals(self):
|
||||
gv = self.globalsviewer
|
||||
if self.vglobals.get():
|
||||
if not gv:
|
||||
self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
|
||||
else:
|
||||
if gv:
|
||||
self.globalsviewer = None
|
||||
gv.close()
|
||||
self.fglobals['height'] = 1
|
||||
self.show_variables()
|
||||
|
||||
def show_variables(self, force=0):
|
||||
lv = self.localsviewer
|
||||
gv = self.globalsviewer
|
||||
frame = self.frame
|
||||
if not frame:
|
||||
ldict = gdict = None
|
||||
else:
|
||||
ldict = frame.f_locals
|
||||
gdict = frame.f_globals
|
||||
if lv and gv and ldict is gdict:
|
||||
ldict = None
|
||||
if lv:
|
||||
lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
|
||||
if gv:
|
||||
gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
|
||||
|
||||
def set_breakpoint_here(self, filename, lineno):
|
||||
self.idb.set_break(filename, lineno)
|
||||
|
||||
def clear_breakpoint_here(self, filename, lineno):
|
||||
self.idb.clear_break(filename, lineno)
|
||||
|
||||
def clear_file_breaks(self, filename):
|
||||
self.idb.clear_all_file_breaks(filename)
|
||||
|
||||
def load_breakpoints(self):
|
||||
"Load PyShellEditorWindow breakpoints into subprocess debugger"
|
||||
pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
|
||||
for editwin in pyshell_edit_windows:
|
||||
filename = editwin.io.filename
|
||||
try:
|
||||
for lineno in editwin.breakpoints:
|
||||
self.set_breakpoint_here(filename, lineno)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
class StackViewer(ScrolledList):
|
||||
|
||||
def __init__(self, master, flist, gui):
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
# At least on with the stock AquaTk version on OSX 10.4 you'll
|
||||
# get an shaking GUI that eventually kills IDLE if the width
|
||||
# argument is specified.
|
||||
ScrolledList.__init__(self, master)
|
||||
else:
|
||||
ScrolledList.__init__(self, master, width=80)
|
||||
self.flist = flist
|
||||
self.gui = gui
|
||||
self.stack = []
|
||||
|
||||
def load_stack(self, stack, index=None):
|
||||
self.stack = stack
|
||||
self.clear()
|
||||
for i in range(len(stack)):
|
||||
frame, lineno = stack[i]
|
||||
try:
|
||||
modname = frame.f_globals["__name__"]
|
||||
except:
|
||||
modname = "?"
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
funcname = code.co_name
|
||||
import linecache
|
||||
sourceline = linecache.getline(filename, lineno)
|
||||
import string
|
||||
sourceline = string.strip(sourceline)
|
||||
if funcname in ("?", "", None):
|
||||
item = "%s, line %d: %s" % (modname, lineno, sourceline)
|
||||
else:
|
||||
item = "%s.%s(), line %d: %s" % (modname, funcname,
|
||||
lineno, sourceline)
|
||||
if i == index:
|
||||
item = "> " + item
|
||||
self.append(item)
|
||||
if index is not None:
|
||||
self.select(index)
|
||||
|
||||
def popup_event(self, event):
|
||||
"override base method"
|
||||
if self.stack:
|
||||
return ScrolledList.popup_event(self, event)
|
||||
|
||||
def fill_menu(self):
|
||||
"override base method"
|
||||
menu = self.menu
|
||||
menu.add_command(label="Go to source line",
|
||||
command=self.goto_source_line)
|
||||
menu.add_command(label="Show stack frame",
|
||||
command=self.show_stack_frame)
|
||||
|
||||
def on_select(self, index):
|
||||
"override base method"
|
||||
if 0 <= index < len(self.stack):
|
||||
self.gui.show_frame(self.stack[index])
|
||||
|
||||
def on_double(self, index):
|
||||
"override base method"
|
||||
self.show_source(index)
|
||||
|
||||
def goto_source_line(self):
|
||||
index = self.listbox.index("active")
|
||||
self.show_source(index)
|
||||
|
||||
def show_stack_frame(self):
|
||||
index = self.listbox.index("active")
|
||||
if 0 <= index < len(self.stack):
|
||||
self.gui.show_frame(self.stack[index])
|
||||
|
||||
def show_source(self, index):
|
||||
if not (0 <= index < len(self.stack)):
|
||||
return
|
||||
frame, lineno = self.stack[index]
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
if os.path.isfile(filename):
|
||||
edit = self.flist.open(filename)
|
||||
if edit:
|
||||
edit.gotoline(lineno)
|
||||
|
||||
|
||||
class NamespaceViewer:
|
||||
|
||||
def __init__(self, master, title, dict=None):
|
||||
width = 0
|
||||
height = 40
|
||||
if dict:
|
||||
height = 20*len(dict) # XXX 20 == observed height of Entry widget
|
||||
self.master = master
|
||||
self.title = title
|
||||
import repr
|
||||
self.repr = repr.Repr()
|
||||
self.repr.maxstring = 60
|
||||
self.repr.maxother = 60
|
||||
self.frame = frame = Frame(master)
|
||||
self.frame.pack(expand=1, fill="both")
|
||||
self.label = Label(frame, text=title, borderwidth=2, relief="groove")
|
||||
self.label.pack(fill="x")
|
||||
self.vbar = vbar = Scrollbar(frame, name="vbar")
|
||||
vbar.pack(side="right", fill="y")
|
||||
self.canvas = canvas = Canvas(frame,
|
||||
height=min(300, max(40, height)),
|
||||
scrollregion=(0, 0, width, height))
|
||||
canvas.pack(side="left", fill="both", expand=1)
|
||||
vbar["command"] = canvas.yview
|
||||
canvas["yscrollcommand"] = vbar.set
|
||||
self.subframe = subframe = Frame(canvas)
|
||||
self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
|
||||
self.load_dict(dict)
|
||||
|
||||
dict = -1
|
||||
|
||||
def load_dict(self, dict, force=0, rpc_client=None):
|
||||
if dict is self.dict and not force:
|
||||
return
|
||||
subframe = self.subframe
|
||||
frame = self.frame
|
||||
for c in subframe.children.values():
|
||||
c.destroy()
|
||||
self.dict = None
|
||||
if not dict:
|
||||
l = Label(subframe, text="None")
|
||||
l.grid(row=0, column=0)
|
||||
else:
|
||||
names = dict.keys()
|
||||
names.sort()
|
||||
row = 0
|
||||
for name in names:
|
||||
value = dict[name]
|
||||
svalue = self.repr.repr(value) # repr(value)
|
||||
# Strip extra quotes caused by calling repr on the (already)
|
||||
# repr'd value sent across the RPC interface:
|
||||
if rpc_client:
|
||||
svalue = svalue[1:-1]
|
||||
l = Label(subframe, text=name)
|
||||
l.grid(row=row, column=0, sticky="nw")
|
||||
l = Entry(subframe, width=0, borderwidth=0)
|
||||
l.insert(0, svalue)
|
||||
l.grid(row=row, column=1, sticky="nw")
|
||||
row = row+1
|
||||
self.dict = dict
|
||||
# XXX Could we use a <Configure> callback for the following?
|
||||
subframe.update_idletasks() # Alas!
|
||||
width = subframe.winfo_reqwidth()
|
||||
height = subframe.winfo_reqheight()
|
||||
canvas = self.canvas
|
||||
self.canvas["scrollregion"] = (0, 0, width, height)
|
||||
if height > 300:
|
||||
canvas["height"] = 300
|
||||
frame.pack(expand=1)
|
||||
else:
|
||||
canvas["height"] = height
|
||||
frame.pack(expand=0)
|
||||
|
||||
def close(self):
|
||||
self.frame.destroy()
|
||||
25
Darwin/lib/python2.7/idlelib/Delegator.py
Normal file
25
Darwin/lib/python2.7/idlelib/Delegator.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
class Delegator:
|
||||
|
||||
# The cache is only used to be able to change delegates!
|
||||
|
||||
def __init__(self, delegate=None):
|
||||
self.delegate = delegate
|
||||
self.__cache = set()
|
||||
|
||||
def __getattr__(self, name):
|
||||
attr = getattr(self.delegate, name) # May raise AttributeError
|
||||
setattr(self, name, attr)
|
||||
self.__cache.add(name)
|
||||
return attr
|
||||
|
||||
def resetcache(self):
|
||||
for key in self.__cache:
|
||||
try:
|
||||
delattr(self, key)
|
||||
except AttributeError:
|
||||
pass
|
||||
self.__cache.clear()
|
||||
|
||||
def setdelegate(self, delegate):
|
||||
self.resetcache()
|
||||
self.delegate = delegate
|
||||
1723
Darwin/lib/python2.7/idlelib/EditorWindow.py
Normal file
1723
Darwin/lib/python2.7/idlelib/EditorWindow.py
Normal file
File diff suppressed because it is too large
Load diff
124
Darwin/lib/python2.7/idlelib/FileList.py
Normal file
124
Darwin/lib/python2.7/idlelib/FileList.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import os
|
||||
from Tkinter import *
|
||||
import tkMessageBox
|
||||
|
||||
|
||||
class FileList:
|
||||
|
||||
# N.B. this import overridden in PyShellFileList.
|
||||
from idlelib.EditorWindow import EditorWindow
|
||||
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.dict = {}
|
||||
self.inversedict = {}
|
||||
self.vars = {} # For EditorWindow.getrawvar (shared Tcl variables)
|
||||
|
||||
def open(self, filename, action=None):
|
||||
assert filename
|
||||
filename = self.canonize(filename)
|
||||
if os.path.isdir(filename):
|
||||
# This can happen when bad filename is passed on command line:
|
||||
tkMessageBox.showerror(
|
||||
"File Error",
|
||||
"%r is a directory." % (filename,),
|
||||
master=self.root)
|
||||
return None
|
||||
key = os.path.normcase(filename)
|
||||
if key in self.dict:
|
||||
edit = self.dict[key]
|
||||
edit.top.wakeup()
|
||||
return edit
|
||||
if action:
|
||||
# Don't create window, perform 'action', e.g. open in same window
|
||||
return action(filename)
|
||||
else:
|
||||
return self.EditorWindow(self, filename, key)
|
||||
|
||||
def gotofileline(self, filename, lineno=None):
|
||||
edit = self.open(filename)
|
||||
if edit is not None and lineno is not None:
|
||||
edit.gotoline(lineno)
|
||||
|
||||
def new(self, filename=None):
|
||||
return self.EditorWindow(self, filename)
|
||||
|
||||
def close_all_callback(self, *args, **kwds):
|
||||
for edit in self.inversedict.keys():
|
||||
reply = edit.close()
|
||||
if reply == "cancel":
|
||||
break
|
||||
return "break"
|
||||
|
||||
def unregister_maybe_terminate(self, edit):
|
||||
try:
|
||||
key = self.inversedict[edit]
|
||||
except KeyError:
|
||||
print "Don't know this EditorWindow object. (close)"
|
||||
return
|
||||
if key:
|
||||
del self.dict[key]
|
||||
del self.inversedict[edit]
|
||||
if not self.inversedict:
|
||||
self.root.quit()
|
||||
|
||||
def filename_changed_edit(self, edit):
|
||||
edit.saved_change_hook()
|
||||
try:
|
||||
key = self.inversedict[edit]
|
||||
except KeyError:
|
||||
print "Don't know this EditorWindow object. (rename)"
|
||||
return
|
||||
filename = edit.io.filename
|
||||
if not filename:
|
||||
if key:
|
||||
del self.dict[key]
|
||||
self.inversedict[edit] = None
|
||||
return
|
||||
filename = self.canonize(filename)
|
||||
newkey = os.path.normcase(filename)
|
||||
if newkey == key:
|
||||
return
|
||||
if newkey in self.dict:
|
||||
conflict = self.dict[newkey]
|
||||
self.inversedict[conflict] = None
|
||||
tkMessageBox.showerror(
|
||||
"Name Conflict",
|
||||
"You now have multiple edit windows open for %r" % (filename,),
|
||||
master=self.root)
|
||||
self.dict[newkey] = edit
|
||||
self.inversedict[edit] = newkey
|
||||
if key:
|
||||
try:
|
||||
del self.dict[key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def canonize(self, filename):
|
||||
if not os.path.isabs(filename):
|
||||
try:
|
||||
pwd = os.getcwd()
|
||||
except os.error:
|
||||
pass
|
||||
else:
|
||||
filename = os.path.join(pwd, filename)
|
||||
return os.path.normpath(filename)
|
||||
|
||||
|
||||
def _test():
|
||||
from idlelib.EditorWindow import fixwordbreaks
|
||||
import sys
|
||||
root = Tk()
|
||||
fixwordbreaks(root)
|
||||
root.withdraw()
|
||||
flist = FileList(root)
|
||||
if sys.argv[1:]:
|
||||
for filename in sys.argv[1:]:
|
||||
flist.open(filename)
|
||||
else:
|
||||
flist.new()
|
||||
if flist.inversedict:
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
||||
191
Darwin/lib/python2.7/idlelib/FormatParagraph.py
Normal file
191
Darwin/lib/python2.7/idlelib/FormatParagraph.py
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
"""Extension to format a paragraph or selection to a max width.
|
||||
|
||||
Does basic, standard text formatting, and also understands Python
|
||||
comment blocks. Thus, for editing Python source code, this
|
||||
extension is really only suitable for reformatting these comment
|
||||
blocks or triple-quoted strings.
|
||||
|
||||
Known problems with comment reformatting:
|
||||
* If there is a selection marked, and the first line of the
|
||||
selection is not complete, the block will probably not be detected
|
||||
as comments, and will have the normal "text formatting" rules
|
||||
applied.
|
||||
* If a comment block has leading whitespace that mixes tabs and
|
||||
spaces, they will not be considered part of the same block.
|
||||
* Fancy comments, like this bulleted list, aren't handled :-)
|
||||
"""
|
||||
|
||||
import re
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
class FormatParagraph:
|
||||
|
||||
menudefs = [
|
||||
('format', [ # /s/edit/format dscherer@cmu.edu
|
||||
('Format Paragraph', '<<format-paragraph>>'),
|
||||
])
|
||||
]
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
|
||||
def close(self):
|
||||
self.editwin = None
|
||||
|
||||
def format_paragraph_event(self, event):
|
||||
"""Formats paragraph to a max width specified in idleConf.
|
||||
|
||||
If text is selected, format_paragraph_event will start breaking lines
|
||||
at the max width, starting from the beginning selection.
|
||||
|
||||
If no text is selected, format_paragraph_event uses the current
|
||||
cursor location to determine the paragraph (lines of text surrounded
|
||||
by blank lines) and formats it.
|
||||
"""
|
||||
maxformatwidth = idleConf.GetOption(
|
||||
'main', 'FormatParagraph', 'paragraph', type='int')
|
||||
text = self.editwin.text
|
||||
first, last = self.editwin.get_selection_indices()
|
||||
if first and last:
|
||||
data = text.get(first, last)
|
||||
comment_header = get_comment_header(data)
|
||||
else:
|
||||
first, last, comment_header, data = \
|
||||
find_paragraph(text, text.index("insert"))
|
||||
if comment_header:
|
||||
newdata = reformat_comment(data, maxformatwidth, comment_header)
|
||||
else:
|
||||
newdata = reformat_paragraph(data, maxformatwidth)
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
|
||||
if newdata != data:
|
||||
text.mark_set("insert", first)
|
||||
text.undo_block_start()
|
||||
text.delete(first, last)
|
||||
text.insert(first, newdata)
|
||||
text.undo_block_stop()
|
||||
else:
|
||||
text.mark_set("insert", last)
|
||||
text.see("insert")
|
||||
return "break"
|
||||
|
||||
def find_paragraph(text, mark):
|
||||
"""Returns the start/stop indices enclosing the paragraph that mark is in.
|
||||
|
||||
Also returns the comment format string, if any, and paragraph of text
|
||||
between the start/stop indices.
|
||||
"""
|
||||
lineno, col = map(int, mark.split("."))
|
||||
line = text.get("%d.0" % lineno, "%d.end" % lineno)
|
||||
|
||||
# Look for start of next paragraph if the index passed in is a blank line
|
||||
while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
|
||||
lineno = lineno + 1
|
||||
line = text.get("%d.0" % lineno, "%d.end" % lineno)
|
||||
first_lineno = lineno
|
||||
comment_header = get_comment_header(line)
|
||||
comment_header_len = len(comment_header)
|
||||
|
||||
# Once start line found, search for end of paragraph (a blank line)
|
||||
while get_comment_header(line)==comment_header and \
|
||||
not is_all_white(line[comment_header_len:]):
|
||||
lineno = lineno + 1
|
||||
line = text.get("%d.0" % lineno, "%d.end" % lineno)
|
||||
last = "%d.0" % lineno
|
||||
|
||||
# Search back to beginning of paragraph (first blank line before)
|
||||
lineno = first_lineno - 1
|
||||
line = text.get("%d.0" % lineno, "%d.end" % lineno)
|
||||
while lineno > 0 and \
|
||||
get_comment_header(line)==comment_header and \
|
||||
not is_all_white(line[comment_header_len:]):
|
||||
lineno = lineno - 1
|
||||
line = text.get("%d.0" % lineno, "%d.end" % lineno)
|
||||
first = "%d.0" % (lineno+1)
|
||||
|
||||
return first, last, comment_header, text.get(first, last)
|
||||
|
||||
# This should perhaps be replaced with textwrap.wrap
|
||||
def reformat_paragraph(data, limit):
|
||||
"""Return data reformatted to specified width (limit)."""
|
||||
lines = data.split("\n")
|
||||
i = 0
|
||||
n = len(lines)
|
||||
while i < n and is_all_white(lines[i]):
|
||||
i = i+1
|
||||
if i >= n:
|
||||
return data
|
||||
indent1 = get_indent(lines[i])
|
||||
if i+1 < n and not is_all_white(lines[i+1]):
|
||||
indent2 = get_indent(lines[i+1])
|
||||
else:
|
||||
indent2 = indent1
|
||||
new = lines[:i]
|
||||
partial = indent1
|
||||
while i < n and not is_all_white(lines[i]):
|
||||
# XXX Should take double space after period (etc.) into account
|
||||
words = re.split("(\s+)", lines[i])
|
||||
for j in range(0, len(words), 2):
|
||||
word = words[j]
|
||||
if not word:
|
||||
continue # Can happen when line ends in whitespace
|
||||
if len((partial + word).expandtabs()) > limit and \
|
||||
partial != indent1:
|
||||
new.append(partial.rstrip())
|
||||
partial = indent2
|
||||
partial = partial + word + " "
|
||||
if j+1 < len(words) and words[j+1] != " ":
|
||||
partial = partial + " "
|
||||
i = i+1
|
||||
new.append(partial.rstrip())
|
||||
# XXX Should reformat remaining paragraphs as well
|
||||
new.extend(lines[i:])
|
||||
return "\n".join(new)
|
||||
|
||||
def reformat_comment(data, limit, comment_header):
|
||||
"""Return data reformatted to specified width with comment header."""
|
||||
|
||||
# Remove header from the comment lines
|
||||
lc = len(comment_header)
|
||||
data = "\n".join(line[lc:] for line in data.split("\n"))
|
||||
# Reformat to maxformatwidth chars or a 20 char width,
|
||||
# whichever is greater.
|
||||
format_width = max(limit - len(comment_header), 20)
|
||||
newdata = reformat_paragraph(data, format_width)
|
||||
# re-split and re-insert the comment header.
|
||||
newdata = newdata.split("\n")
|
||||
# If the block ends in a \n, we dont want the comment prefix
|
||||
# inserted after it. (Im not sure it makes sense to reformat a
|
||||
# comment block that is not made of complete lines, but whatever!)
|
||||
# Can't think of a clean solution, so we hack away
|
||||
block_suffix = ""
|
||||
if not newdata[-1]:
|
||||
block_suffix = "\n"
|
||||
newdata = newdata[:-1]
|
||||
return '\n'.join(comment_header+line for line in newdata) + block_suffix
|
||||
|
||||
def is_all_white(line):
|
||||
"""Return True if line is empty or all whitespace."""
|
||||
|
||||
return re.match(r"^\s*$", line) is not None
|
||||
|
||||
def get_indent(line):
|
||||
"""Return the initial space or tab indent of line."""
|
||||
return re.match(r"^([ \t]*)", line).group()
|
||||
|
||||
def get_comment_header(line):
|
||||
"""Return string with leading whitespace and '#' from line or ''.
|
||||
|
||||
A null return indicates that the line is not a comment line. A non-
|
||||
null return, such as ' #', will be used to find the other lines of
|
||||
a comment block with the same indent.
|
||||
"""
|
||||
m = re.match(r"^([ \t]*#*)", line)
|
||||
if m is None: return ""
|
||||
return m.group(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from test import support; support.use_resources = ['gui']
|
||||
import unittest
|
||||
unittest.main('idlelib.idle_test.test_formatparagraph',
|
||||
verbosity=2, exit=False)
|
||||
127
Darwin/lib/python2.7/idlelib/GrepDialog.py
Normal file
127
Darwin/lib/python2.7/idlelib/GrepDialog.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import os
|
||||
import fnmatch
|
||||
import sys
|
||||
from Tkinter import *
|
||||
from idlelib import SearchEngine
|
||||
from idlelib.SearchDialogBase import SearchDialogBase
|
||||
|
||||
def grep(text, io=None, flist=None):
|
||||
root = text._root()
|
||||
engine = SearchEngine.get(root)
|
||||
if not hasattr(engine, "_grepdialog"):
|
||||
engine._grepdialog = GrepDialog(root, engine, flist)
|
||||
dialog = engine._grepdialog
|
||||
searchphrase = text.get("sel.first", "sel.last")
|
||||
dialog.open(text, searchphrase, io)
|
||||
|
||||
class GrepDialog(SearchDialogBase):
|
||||
|
||||
title = "Find in Files Dialog"
|
||||
icon = "Grep"
|
||||
needwrapbutton = 0
|
||||
|
||||
def __init__(self, root, engine, flist):
|
||||
SearchDialogBase.__init__(self, root, engine)
|
||||
self.flist = flist
|
||||
self.globvar = StringVar(root)
|
||||
self.recvar = BooleanVar(root)
|
||||
|
||||
def open(self, text, searchphrase, io=None):
|
||||
SearchDialogBase.open(self, text, searchphrase)
|
||||
if io:
|
||||
path = io.filename or ""
|
||||
else:
|
||||
path = ""
|
||||
dir, base = os.path.split(path)
|
||||
head, tail = os.path.splitext(base)
|
||||
if not tail:
|
||||
tail = ".py"
|
||||
self.globvar.set(os.path.join(dir, "*" + tail))
|
||||
|
||||
def create_entries(self):
|
||||
SearchDialogBase.create_entries(self)
|
||||
self.globent = self.make_entry("In files:", self.globvar)
|
||||
|
||||
def create_other_buttons(self):
|
||||
f = self.make_frame()
|
||||
|
||||
btn = Checkbutton(f, anchor="w",
|
||||
variable=self.recvar,
|
||||
text="Recurse down subdirectories")
|
||||
btn.pack(side="top", fill="both")
|
||||
btn.select()
|
||||
|
||||
def create_command_buttons(self):
|
||||
SearchDialogBase.create_command_buttons(self)
|
||||
self.make_button("Search Files", self.default_command, 1)
|
||||
|
||||
def default_command(self, event=None):
|
||||
prog = self.engine.getprog()
|
||||
if not prog:
|
||||
return
|
||||
path = self.globvar.get()
|
||||
if not path:
|
||||
self.top.bell()
|
||||
return
|
||||
from idlelib.OutputWindow import OutputWindow
|
||||
save = sys.stdout
|
||||
try:
|
||||
sys.stdout = OutputWindow(self.flist)
|
||||
self.grep_it(prog, path)
|
||||
finally:
|
||||
sys.stdout = save
|
||||
|
||||
def grep_it(self, prog, path):
|
||||
dir, base = os.path.split(path)
|
||||
list = self.findfiles(dir, base, self.recvar.get())
|
||||
list.sort()
|
||||
self.close()
|
||||
pat = self.engine.getpat()
|
||||
print "Searching %r in %s ..." % (pat, path)
|
||||
hits = 0
|
||||
for fn in list:
|
||||
try:
|
||||
with open(fn) as f:
|
||||
for lineno, line in enumerate(f, 1):
|
||||
if line[-1:] == '\n':
|
||||
line = line[:-1]
|
||||
if prog.search(line):
|
||||
sys.stdout.write("%s: %s: %s\n" %
|
||||
(fn, lineno, line))
|
||||
hits += 1
|
||||
except IOError as msg:
|
||||
print msg
|
||||
print(("Hits found: %s\n"
|
||||
"(Hint: right-click to open locations.)"
|
||||
% hits) if hits else "No hits.")
|
||||
|
||||
def findfiles(self, dir, base, rec):
|
||||
try:
|
||||
names = os.listdir(dir or os.curdir)
|
||||
except os.error as msg:
|
||||
print msg
|
||||
return []
|
||||
list = []
|
||||
subdirs = []
|
||||
for name in names:
|
||||
fn = os.path.join(dir, name)
|
||||
if os.path.isdir(fn):
|
||||
subdirs.append(fn)
|
||||
else:
|
||||
if fnmatch.fnmatch(name, base):
|
||||
list.append(fn)
|
||||
if rec:
|
||||
for subdir in subdirs:
|
||||
list.extend(self.findfiles(subdir, base, rec))
|
||||
return list
|
||||
|
||||
def close(self, event=None):
|
||||
if self.top:
|
||||
self.top.grab_release()
|
||||
self.top.withdraw()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# A human test is a bit tricky since EditorWindow() imports this module.
|
||||
# Hence Idle must be restarted after editing this file for a live test.
|
||||
import unittest
|
||||
unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False)
|
||||
296
Darwin/lib/python2.7/idlelib/HISTORY.txt
Normal file
296
Darwin/lib/python2.7/idlelib/HISTORY.txt
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
IDLE History
|
||||
============
|
||||
|
||||
This file contains the release messages for previous IDLE releases.
|
||||
As you read on you go back to the dark ages of IDLE's history.
|
||||
|
||||
|
||||
What's New in IDLEfork 0.8.1?
|
||||
=============================
|
||||
|
||||
*Release date: 22-Jul-2001*
|
||||
|
||||
- New tarball released as a result of the 'revitalisation' of the IDLEfork
|
||||
project.
|
||||
|
||||
- This release requires python 2.1 or better. Compatibility with earlier
|
||||
versions of python (especially ancient ones like 1.5x) is no longer a
|
||||
priority in IDLEfork development.
|
||||
|
||||
- This release is based on a merging of the earlier IDLE fork work with current
|
||||
cvs IDLE (post IDLE version 0.8), with some minor additional coding by Kurt
|
||||
B. Kaiser and Stephen M. Gava.
|
||||
|
||||
- This release is basically functional but also contains some known breakages,
|
||||
particularly with running things from the shell window. Also the debugger is
|
||||
not working, but I believe this was the case with the previous IDLE fork
|
||||
release (0.7.1) as well.
|
||||
|
||||
- This release is being made now to mark the point at which IDLEfork is
|
||||
launching into a new stage of development.
|
||||
|
||||
- IDLEfork CVS will now be branched to enable further development and
|
||||
exploration of the two "execution in a remote process" patches submitted by
|
||||
David Scherer (David's is currently in IDLEfork) and GvR, while stabilisation
|
||||
and development of less heavyweight improvements (like user customisation)
|
||||
can continue on the trunk.
|
||||
|
||||
|
||||
What's New in IDLEfork 0.7.1?
|
||||
==============================
|
||||
|
||||
*Release date: 15-Aug-2000*
|
||||
|
||||
- First project tarball released.
|
||||
|
||||
- This was the first release of IDLE fork, which at this stage was a
|
||||
combination of IDLE 0.5 and the VPython idle fork, with additional changes
|
||||
coded by David Scherer, Peter Schneider-Kamp and Nicholas Riley.
|
||||
|
||||
|
||||
|
||||
IDLEfork 0.7.1 - 29 May 2000
|
||||
-----------------------------
|
||||
|
||||
David Scherer <dscherer@cmu.edu>
|
||||
|
||||
- This is a modification of the CVS version of IDLE 0.5, updated as of
|
||||
2000-03-09. It is alpha software and might be unstable. If it breaks, you
|
||||
get to keep both pieces.
|
||||
|
||||
- If you have problems or suggestions, you should either contact me or post to
|
||||
the list at http://www.python.org/mailman/listinfo/idle-dev (making it clear
|
||||
that you are using this modified version of IDLE).
|
||||
|
||||
- Changes:
|
||||
|
||||
- The ExecBinding module, a replacement for ScriptBinding, executes programs
|
||||
in a separate process, piping standard I/O through an RPC mechanism to an
|
||||
OnDemandOutputWindow in IDLE. It supports executing unnamed programs
|
||||
(through a temporary file). It does not yet support debugging.
|
||||
|
||||
- When running programs with ExecBinding, tracebacks will be clipped to
|
||||
exclude system modules. If, however, a system module calls back into the
|
||||
user program, that part of the traceback will be shown.
|
||||
|
||||
- The OnDemandOutputWindow class has been improved. In particular, it now
|
||||
supports a readline() function used to implement user input, and a
|
||||
scroll_clear() operation which is used to hide the output of a previous run
|
||||
by scrolling it out of the window.
|
||||
|
||||
- Startup behavior has been changed. By default IDLE starts up with just a
|
||||
blank editor window, rather than an interactive window. Opening a file in
|
||||
such a blank window replaces the (nonexistent) contents of that window
|
||||
instead of creating another window. Because of the need to have a
|
||||
well-known port for the ExecBinding protocol, only one copy of IDLE can be
|
||||
running. Additional invocations use the RPC mechanism to report their
|
||||
command line arguments to the copy already running.
|
||||
|
||||
- The menus have been reorganized. In particular, the excessively large
|
||||
'edit' menu has been split up into 'edit', 'format', and 'run'.
|
||||
|
||||
- 'Python Documentation' now works on Windows, if the win32api module is
|
||||
present.
|
||||
|
||||
- A few key bindings have been changed: F1 now loads Python Documentation
|
||||
instead of the IDLE help; shift-TAB is now a synonym for unindent.
|
||||
|
||||
- New modules:
|
||||
|
||||
ExecBinding.py Executes program through loader
|
||||
loader.py Bootstraps user program
|
||||
protocol.py RPC protocol
|
||||
Remote.py User-process interpreter
|
||||
spawn.py OS-specific code to start programs
|
||||
|
||||
- Files modified:
|
||||
|
||||
autoindent.py ( bindings tweaked )
|
||||
bindings.py ( menus reorganized )
|
||||
config.txt ( execbinding enabled )
|
||||
editorwindow.py ( new menus, fixed 'Python Documentation' )
|
||||
filelist.py ( hook for "open in same window" )
|
||||
formatparagraph.py ( bindings tweaked )
|
||||
idle.bat ( removed absolute pathname )
|
||||
idle.pyw ( weird bug due to import with same name? )
|
||||
iobinding.py ( open in same window, EOL convention )
|
||||
keydefs.py ( bindings tweaked )
|
||||
outputwindow.py ( readline, scroll_clear, etc )
|
||||
pyshell.py ( changed startup behavior )
|
||||
readme.txt ( <Recursion on file with id=1234567> )
|
||||
|
||||
|
||||
|
||||
IDLE 0.5 - February 2000 - Release Notes
|
||||
----------------------------------------
|
||||
|
||||
This is an early release of IDLE, my own attempt at a Tkinter-based
|
||||
IDE for Python.
|
||||
|
||||
(For a more detailed change log, see the file ChangeLog.)
|
||||
|
||||
FEATURES
|
||||
|
||||
IDLE has the following features:
|
||||
|
||||
- coded in 100% pure Python, using the Tkinter GUI toolkit (i.e. Tcl/Tk)
|
||||
|
||||
- cross-platform: works on Windows and Unix (on the Mac, there are
|
||||
currently problems with Tcl/Tk)
|
||||
|
||||
- multi-window text editor with multiple undo, Python colorizing
|
||||
and many other features, e.g. smart indent and call tips
|
||||
|
||||
- Python shell window (a.k.a. interactive interpreter)
|
||||
|
||||
- debugger (not complete, but you can set breakpoints, view and step)
|
||||
|
||||
USAGE
|
||||
|
||||
The main program is in the file "idle.py"; on Unix, you should be able
|
||||
to run it by typing "./idle.py" to your shell. On Windows, you can
|
||||
run it by double-clicking it; you can use idle.pyw to avoid popping up
|
||||
a DOS console. If you want to pass command line arguments on Windows,
|
||||
use the batch file idle.bat.
|
||||
|
||||
Command line arguments: files passed on the command line are executed,
|
||||
not opened for editing, unless you give the -e command line option.
|
||||
Try "./idle.py -h" to see other command line options.
|
||||
|
||||
IDLE requires Python 1.5.2, so it is currently only usable with a
|
||||
Python 1.5.2 distribution. (An older version of IDLE is distributed
|
||||
with Python 1.5.2; you can drop this version on top of it.)
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
IDLE is covered by the standard Python copyright notice
|
||||
(http://www.python.org/doc/Copyright.html).
|
||||
|
||||
|
||||
New in IDLE 0.5 (2/15/2000)
|
||||
---------------------------
|
||||
|
||||
Tons of stuff, much of it contributed by Tim Peters and Mark Hammond:
|
||||
|
||||
- Status bar, displaying current line/column (Moshe Zadka).
|
||||
|
||||
- Better stack viewer, using tree widget. (XXX Only used by Stack
|
||||
Viewer menu, not by the debugger.)
|
||||
|
||||
- Format paragraph now recognizes Python block comments and reformats
|
||||
them correctly (MH)
|
||||
|
||||
- New version of pyclbr.py parses top-level functions and understands
|
||||
much more of Python's syntax; this is reflected in the class and path
|
||||
browsers (TP)
|
||||
|
||||
- Much better auto-indent; knows how to indent the insides of
|
||||
multi-line statements (TP)
|
||||
|
||||
- Call tip window pops up when you type the name of a known function
|
||||
followed by an open parenthesis. Hit ESC or click elsewhere in the
|
||||
window to close the tip window (MH)
|
||||
|
||||
- Comment out region now inserts ## to make it stand out more (TP)
|
||||
|
||||
- New path and class browsers based on a tree widget that looks
|
||||
familiar to Windows users
|
||||
|
||||
- Reworked script running commands to be more intuitive: I/O now
|
||||
always goes to the *Python Shell* window, and raw_input() works
|
||||
correctly. You use F5 to import/reload a module: this adds the module
|
||||
name to the __main__ namespace. You use Control-F5 to run a script:
|
||||
this runs the script *in* the __main__ namespace. The latter also
|
||||
sets sys.argv[] to the script name
|
||||
|
||||
|
||||
New in IDLE 0.4 (4/7/99)
|
||||
------------------------
|
||||
|
||||
Most important change: a new menu entry "File -> Path browser", shows
|
||||
a 4-column hierarchical browser which lets you browse sys.path,
|
||||
directories, modules, and classes. Yes, it's a superset of the Class
|
||||
browser menu entry. There's also a new internal module,
|
||||
MultiScrolledLists.py, which provides the framework for this dialog.
|
||||
|
||||
|
||||
New in IDLE 0.3 (2/17/99)
|
||||
-------------------------
|
||||
|
||||
Most important changes:
|
||||
|
||||
- Enabled support for running a module, with or without the debugger.
|
||||
Output goes to a new window. Pressing F5 in a module is effectively a
|
||||
reload of that module; Control-F5 loads it under the debugger.
|
||||
|
||||
- Re-enable tearing off the Windows menu, and make a torn-off Windows
|
||||
menu update itself whenever a window is opened or closed.
|
||||
|
||||
- Menu items can now be have a checkbox (when the menu label starts
|
||||
with "!"); use this for the Debugger and "Auto-open stack viewer"
|
||||
(was: JIT stack viewer) menu items.
|
||||
|
||||
- Added a Quit button to the Debugger API.
|
||||
|
||||
- The current directory is explicitly inserted into sys.path.
|
||||
|
||||
- Fix the debugger (when using Python 1.5.2b2) to use canonical
|
||||
filenames for breakpoints, so these actually work. (There's still a
|
||||
lot of work to be done to the management of breakpoints in the
|
||||
debugger though.)
|
||||
|
||||
- Closing a window that is still colorizing now actually works.
|
||||
|
||||
- Allow dragging of the separator between the two list boxes in the
|
||||
class browser.
|
||||
|
||||
- Bind ESC to "close window" of the debugger, stack viewer and class
|
||||
browser. It removes the selection highlighting in regular text
|
||||
windows. (These are standard Windows conventions.)
|
||||
|
||||
|
||||
New in IDLE 0.2 (1/8/99)
|
||||
------------------------
|
||||
|
||||
Lots of changes; here are the highlights:
|
||||
|
||||
General:
|
||||
|
||||
- You can now write and configure your own IDLE extension modules; see
|
||||
extend.txt.
|
||||
|
||||
|
||||
File menu:
|
||||
|
||||
The command to open the Python shell window is now in the File menu.
|
||||
|
||||
|
||||
Edit menu:
|
||||
|
||||
New Find dialog with more options; replace dialog; find in files dialog.
|
||||
|
||||
Commands to tabify or untabify a region.
|
||||
|
||||
Command to format a paragraph.
|
||||
|
||||
|
||||
Debug menu:
|
||||
|
||||
JIT (Just-In-Time) stack viewer toggle -- if set, the stack viewer
|
||||
automaticall pops up when you get a traceback.
|
||||
|
||||
Windows menu:
|
||||
|
||||
Zoom height -- make the window full height.
|
||||
|
||||
|
||||
Help menu:
|
||||
|
||||
The help text now show up in a regular window so you can search and
|
||||
even edit it if you like.
|
||||
|
||||
|
||||
|
||||
IDLE 0.1 was distributed with the Python 1.5.2b1 release on 12/22/98.
|
||||
|
||||
======================================================================
|
||||
246
Darwin/lib/python2.7/idlelib/HyperParser.py
Normal file
246
Darwin/lib/python2.7/idlelib/HyperParser.py
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
"""
|
||||
HyperParser
|
||||
===========
|
||||
This module defines the HyperParser class, which provides advanced parsing
|
||||
abilities for the ParenMatch and other extensions.
|
||||
The HyperParser uses PyParser. PyParser is intended mostly to give information
|
||||
on the proper indentation of code. HyperParser gives some information on the
|
||||
structure of code, used by extensions to help the user.
|
||||
"""
|
||||
|
||||
import string
|
||||
import keyword
|
||||
from idlelib import PyParse
|
||||
|
||||
class HyperParser:
|
||||
|
||||
def __init__(self, editwin, index):
|
||||
"""Initialize the HyperParser to analyze the surroundings of the given
|
||||
index.
|
||||
"""
|
||||
|
||||
self.editwin = editwin
|
||||
self.text = text = editwin.text
|
||||
|
||||
parser = PyParse.Parser(editwin.indentwidth, editwin.tabwidth)
|
||||
|
||||
def index2line(index):
|
||||
return int(float(index))
|
||||
lno = index2line(text.index(index))
|
||||
|
||||
if not editwin.context_use_ps1:
|
||||
for context in editwin.num_context_lines:
|
||||
startat = max(lno - context, 1)
|
||||
startatindex = repr(startat) + ".0"
|
||||
stopatindex = "%d.end" % lno
|
||||
# We add the newline because PyParse requires a newline at end.
|
||||
# We add a space so that index won't be at end of line, so that
|
||||
# its status will be the same as the char before it, if should.
|
||||
parser.set_str(text.get(startatindex, stopatindex)+' \n')
|
||||
bod = parser.find_good_parse_start(
|
||||
editwin._build_char_in_string_func(startatindex))
|
||||
if bod is not None or startat == 1:
|
||||
break
|
||||
parser.set_lo(bod or 0)
|
||||
else:
|
||||
r = text.tag_prevrange("console", index)
|
||||
if r:
|
||||
startatindex = r[1]
|
||||
else:
|
||||
startatindex = "1.0"
|
||||
stopatindex = "%d.end" % lno
|
||||
# We add the newline because PyParse requires a newline at end.
|
||||
# We add a space so that index won't be at end of line, so that
|
||||
# its status will be the same as the char before it, if should.
|
||||
parser.set_str(text.get(startatindex, stopatindex)+' \n')
|
||||
parser.set_lo(0)
|
||||
|
||||
# We want what the parser has, except for the last newline and space.
|
||||
self.rawtext = parser.str[:-2]
|
||||
# As far as I can see, parser.str preserves the statement we are in,
|
||||
# so that stopatindex can be used to synchronize the string with the
|
||||
# text box indices.
|
||||
self.stopatindex = stopatindex
|
||||
self.bracketing = parser.get_last_stmt_bracketing()
|
||||
# find which pairs of bracketing are openers. These always correspond
|
||||
# to a character of rawtext.
|
||||
self.isopener = [i>0 and self.bracketing[i][1] > self.bracketing[i-1][1]
|
||||
for i in range(len(self.bracketing))]
|
||||
|
||||
self.set_index(index)
|
||||
|
||||
def set_index(self, index):
|
||||
"""Set the index to which the functions relate. Note that it must be
|
||||
in the same statement.
|
||||
"""
|
||||
indexinrawtext = \
|
||||
len(self.rawtext) - len(self.text.get(index, self.stopatindex))
|
||||
if indexinrawtext < 0:
|
||||
raise ValueError("The index given is before the analyzed statement")
|
||||
self.indexinrawtext = indexinrawtext
|
||||
# find the rightmost bracket to which index belongs
|
||||
self.indexbracket = 0
|
||||
while self.indexbracket < len(self.bracketing)-1 and \
|
||||
self.bracketing[self.indexbracket+1][0] < self.indexinrawtext:
|
||||
self.indexbracket += 1
|
||||
if self.indexbracket < len(self.bracketing)-1 and \
|
||||
self.bracketing[self.indexbracket+1][0] == self.indexinrawtext and \
|
||||
not self.isopener[self.indexbracket+1]:
|
||||
self.indexbracket += 1
|
||||
|
||||
def is_in_string(self):
|
||||
"""Is the index given to the HyperParser is in a string?"""
|
||||
# The bracket to which we belong should be an opener.
|
||||
# If it's an opener, it has to have a character.
|
||||
return self.isopener[self.indexbracket] and \
|
||||
self.rawtext[self.bracketing[self.indexbracket][0]] in ('"', "'")
|
||||
|
||||
def is_in_code(self):
|
||||
"""Is the index given to the HyperParser is in a normal code?"""
|
||||
return not self.isopener[self.indexbracket] or \
|
||||
self.rawtext[self.bracketing[self.indexbracket][0]] not in \
|
||||
('#', '"', "'")
|
||||
|
||||
def get_surrounding_brackets(self, openers='([{', mustclose=False):
|
||||
"""If the index given to the HyperParser is surrounded by a bracket
|
||||
defined in openers (or at least has one before it), return the
|
||||
indices of the opening bracket and the closing bracket (or the
|
||||
end of line, whichever comes first).
|
||||
If it is not surrounded by brackets, or the end of line comes before
|
||||
the closing bracket and mustclose is True, returns None.
|
||||
"""
|
||||
bracketinglevel = self.bracketing[self.indexbracket][1]
|
||||
before = self.indexbracket
|
||||
while not self.isopener[before] or \
|
||||
self.rawtext[self.bracketing[before][0]] not in openers or \
|
||||
self.bracketing[before][1] > bracketinglevel:
|
||||
before -= 1
|
||||
if before < 0:
|
||||
return None
|
||||
bracketinglevel = min(bracketinglevel, self.bracketing[before][1])
|
||||
after = self.indexbracket + 1
|
||||
while after < len(self.bracketing) and \
|
||||
self.bracketing[after][1] >= bracketinglevel:
|
||||
after += 1
|
||||
|
||||
beforeindex = self.text.index("%s-%dc" %
|
||||
(self.stopatindex, len(self.rawtext)-self.bracketing[before][0]))
|
||||
if after >= len(self.bracketing) or \
|
||||
self.bracketing[after][0] > len(self.rawtext):
|
||||
if mustclose:
|
||||
return None
|
||||
afterindex = self.stopatindex
|
||||
else:
|
||||
# We are after a real char, so it is a ')' and we give the index
|
||||
# before it.
|
||||
afterindex = self.text.index("%s-%dc" %
|
||||
(self.stopatindex,
|
||||
len(self.rawtext)-(self.bracketing[after][0]-1)))
|
||||
|
||||
return beforeindex, afterindex
|
||||
|
||||
# This string includes all chars that may be in a white space
|
||||
_whitespace_chars = " \t\n\\"
|
||||
# This string includes all chars that may be in an identifier
|
||||
_id_chars = string.ascii_letters + string.digits + "_"
|
||||
# This string includes all chars that may be the first char of an identifier
|
||||
_id_first_chars = string.ascii_letters + "_"
|
||||
|
||||
# Given a string and pos, return the number of chars in the identifier
|
||||
# which ends at pos, or 0 if there is no such one. Saved words are not
|
||||
# identifiers.
|
||||
def _eat_identifier(self, str, limit, pos):
|
||||
i = pos
|
||||
while i > limit and str[i-1] in self._id_chars:
|
||||
i -= 1
|
||||
if i < pos and (str[i] not in self._id_first_chars or \
|
||||
keyword.iskeyword(str[i:pos])):
|
||||
i = pos
|
||||
return pos - i
|
||||
|
||||
def get_expression(self):
|
||||
"""Return a string with the Python expression which ends at the given
|
||||
index, which is empty if there is no real one.
|
||||
"""
|
||||
if not self.is_in_code():
|
||||
raise ValueError("get_expression should only be called if index "\
|
||||
"is inside a code.")
|
||||
|
||||
rawtext = self.rawtext
|
||||
bracketing = self.bracketing
|
||||
|
||||
brck_index = self.indexbracket
|
||||
brck_limit = bracketing[brck_index][0]
|
||||
pos = self.indexinrawtext
|
||||
|
||||
last_identifier_pos = pos
|
||||
postdot_phase = True
|
||||
|
||||
while 1:
|
||||
# Eat whitespaces, comments, and if postdot_phase is False - one dot
|
||||
while 1:
|
||||
if pos>brck_limit and rawtext[pos-1] in self._whitespace_chars:
|
||||
# Eat a whitespace
|
||||
pos -= 1
|
||||
elif not postdot_phase and \
|
||||
pos > brck_limit and rawtext[pos-1] == '.':
|
||||
# Eat a dot
|
||||
pos -= 1
|
||||
postdot_phase = True
|
||||
# The next line will fail if we are *inside* a comment, but we
|
||||
# shouldn't be.
|
||||
elif pos == brck_limit and brck_index > 0 and \
|
||||
rawtext[bracketing[brck_index-1][0]] == '#':
|
||||
# Eat a comment
|
||||
brck_index -= 2
|
||||
brck_limit = bracketing[brck_index][0]
|
||||
pos = bracketing[brck_index+1][0]
|
||||
else:
|
||||
# If we didn't eat anything, quit.
|
||||
break
|
||||
|
||||
if not postdot_phase:
|
||||
# We didn't find a dot, so the expression end at the last
|
||||
# identifier pos.
|
||||
break
|
||||
|
||||
ret = self._eat_identifier(rawtext, brck_limit, pos)
|
||||
if ret:
|
||||
# There is an identifier to eat
|
||||
pos = pos - ret
|
||||
last_identifier_pos = pos
|
||||
# Now, in order to continue the search, we must find a dot.
|
||||
postdot_phase = False
|
||||
# (the loop continues now)
|
||||
|
||||
elif pos == brck_limit:
|
||||
# We are at a bracketing limit. If it is a closing bracket,
|
||||
# eat the bracket, otherwise, stop the search.
|
||||
level = bracketing[brck_index][1]
|
||||
while brck_index > 0 and bracketing[brck_index-1][1] > level:
|
||||
brck_index -= 1
|
||||
if bracketing[brck_index][0] == brck_limit:
|
||||
# We were not at the end of a closing bracket
|
||||
break
|
||||
pos = bracketing[brck_index][0]
|
||||
brck_index -= 1
|
||||
brck_limit = bracketing[brck_index][0]
|
||||
last_identifier_pos = pos
|
||||
if rawtext[pos] in "([":
|
||||
# [] and () may be used after an identifier, so we
|
||||
# continue. postdot_phase is True, so we don't allow a dot.
|
||||
pass
|
||||
else:
|
||||
# We can't continue after other types of brackets
|
||||
if rawtext[pos] in "'\"":
|
||||
# Scan a string prefix
|
||||
while pos > 0 and rawtext[pos - 1] in "rRbBuU":
|
||||
pos -= 1
|
||||
last_identifier_pos = pos
|
||||
break
|
||||
|
||||
else:
|
||||
# We've found an operator or something.
|
||||
break
|
||||
|
||||
return rawtext[last_identifier_pos:self.indexinrawtext]
|
||||
597
Darwin/lib/python2.7/idlelib/IOBinding.py
Normal file
597
Darwin/lib/python2.7/idlelib/IOBinding.py
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
# changes by dscherer@cmu.edu
|
||||
# - IOBinding.open() replaces the current window with the opened file,
|
||||
# if the current window is both unmodified and unnamed
|
||||
# - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh
|
||||
# end-of-line conventions, instead of relying on the standard library,
|
||||
# which will only understand the local convention.
|
||||
|
||||
import os
|
||||
import types
|
||||
import pipes
|
||||
import sys
|
||||
import codecs
|
||||
import tempfile
|
||||
import tkFileDialog
|
||||
import tkMessageBox
|
||||
import re
|
||||
from Tkinter import *
|
||||
from SimpleDialog import SimpleDialog
|
||||
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
try:
|
||||
from codecs import BOM_UTF8
|
||||
except ImportError:
|
||||
# only available since Python 2.3
|
||||
BOM_UTF8 = '\xef\xbb\xbf'
|
||||
|
||||
# Try setting the locale, so that we can find out
|
||||
# what encoding to use
|
||||
try:
|
||||
import locale
|
||||
locale.setlocale(locale.LC_CTYPE, "")
|
||||
except (ImportError, locale.Error):
|
||||
pass
|
||||
|
||||
# Encoding for file names
|
||||
filesystemencoding = sys.getfilesystemencoding()
|
||||
|
||||
encoding = "ascii"
|
||||
if sys.platform == 'win32':
|
||||
# On Windows, we could use "mbcs". However, to give the user
|
||||
# a portable encoding name, we need to find the code page
|
||||
try:
|
||||
encoding = locale.getdefaultlocale()[1]
|
||||
codecs.lookup(encoding)
|
||||
except LookupError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
# Different things can fail here: the locale module may not be
|
||||
# loaded, it may not offer nl_langinfo, or CODESET, or the
|
||||
# resulting codeset may be unknown to Python. We ignore all
|
||||
# these problems, falling back to ASCII
|
||||
encoding = locale.nl_langinfo(locale.CODESET)
|
||||
if encoding is None or encoding is '':
|
||||
# situation occurs on Mac OS X
|
||||
encoding = 'ascii'
|
||||
codecs.lookup(encoding)
|
||||
except (NameError, AttributeError, LookupError):
|
||||
# Try getdefaultlocale well: it parses environment variables,
|
||||
# which may give a clue. Unfortunately, getdefaultlocale has
|
||||
# bugs that can cause ValueError.
|
||||
try:
|
||||
encoding = locale.getdefaultlocale()[1]
|
||||
if encoding is None or encoding is '':
|
||||
# situation occurs on Mac OS X
|
||||
encoding = 'ascii'
|
||||
codecs.lookup(encoding)
|
||||
except (ValueError, LookupError):
|
||||
pass
|
||||
|
||||
encoding = encoding.lower()
|
||||
|
||||
coding_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)')
|
||||
|
||||
class EncodingMessage(SimpleDialog):
|
||||
"Inform user that an encoding declaration is needed."
|
||||
def __init__(self, master, enc):
|
||||
self.should_edit = False
|
||||
|
||||
self.root = top = Toplevel(master)
|
||||
top.bind("<Return>", self.return_event)
|
||||
top.bind("<Escape>", self.do_ok)
|
||||
top.protocol("WM_DELETE_WINDOW", self.wm_delete_window)
|
||||
top.wm_title("I/O Warning")
|
||||
top.wm_iconname("I/O Warning")
|
||||
self.top = top
|
||||
|
||||
l1 = Label(top,
|
||||
text="Non-ASCII found, yet no encoding declared. Add a line like")
|
||||
l1.pack(side=TOP, anchor=W)
|
||||
l2 = Entry(top, font="courier")
|
||||
l2.insert(0, "# -*- coding: %s -*-" % enc)
|
||||
# For some reason, the text is not selectable anymore if the
|
||||
# widget is disabled.
|
||||
# l2['state'] = DISABLED
|
||||
l2.pack(side=TOP, anchor = W, fill=X)
|
||||
l3 = Label(top, text="to your file\n"
|
||||
"Choose OK to save this file as %s\n"
|
||||
"Edit your general options to silence this warning" % enc)
|
||||
l3.pack(side=TOP, anchor = W)
|
||||
|
||||
buttons = Frame(top)
|
||||
buttons.pack(side=TOP, fill=X)
|
||||
# Both return and cancel mean the same thing: do nothing
|
||||
self.default = self.cancel = 0
|
||||
b1 = Button(buttons, text="Ok", default="active",
|
||||
command=self.do_ok)
|
||||
b1.pack(side=LEFT, fill=BOTH, expand=1)
|
||||
b2 = Button(buttons, text="Edit my file",
|
||||
command=self.do_edit)
|
||||
b2.pack(side=LEFT, fill=BOTH, expand=1)
|
||||
|
||||
self._set_transient(master)
|
||||
|
||||
def do_ok(self):
|
||||
self.done(0)
|
||||
|
||||
def do_edit(self):
|
||||
self.done(1)
|
||||
|
||||
def coding_spec(str):
|
||||
"""Return the encoding declaration according to PEP 263.
|
||||
|
||||
Raise LookupError if the encoding is declared but unknown.
|
||||
"""
|
||||
# Only consider the first two lines
|
||||
lst = str.split("\n", 2)[:2]
|
||||
for line in lst:
|
||||
match = coding_re.match(line)
|
||||
if match is not None:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
name = match.group(1)
|
||||
# Check whether the encoding is known
|
||||
import codecs
|
||||
try:
|
||||
codecs.lookup(name)
|
||||
except LookupError:
|
||||
# The standard encoding error does not indicate the encoding
|
||||
raise LookupError, "Unknown encoding "+name
|
||||
return name
|
||||
|
||||
|
||||
class IOBinding:
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
|
||||
self.__id_save = self.text.bind("<<save-window>>", self.save)
|
||||
self.__id_saveas = self.text.bind("<<save-window-as-file>>",
|
||||
self.save_as)
|
||||
self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
|
||||
self.save_a_copy)
|
||||
self.fileencoding = None
|
||||
self.__id_print = self.text.bind("<<print-window>>", self.print_window)
|
||||
|
||||
def close(self):
|
||||
# Undo command bindings
|
||||
self.text.unbind("<<open-window-from-file>>", self.__id_open)
|
||||
self.text.unbind("<<save-window>>", self.__id_save)
|
||||
self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
|
||||
self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
|
||||
self.text.unbind("<<print-window>>", self.__id_print)
|
||||
# Break cycles
|
||||
self.editwin = None
|
||||
self.text = None
|
||||
self.filename_change_hook = None
|
||||
|
||||
def get_saved(self):
|
||||
return self.editwin.get_saved()
|
||||
|
||||
def set_saved(self, flag):
|
||||
self.editwin.set_saved(flag)
|
||||
|
||||
def reset_undo(self):
|
||||
self.editwin.reset_undo()
|
||||
|
||||
filename_change_hook = None
|
||||
|
||||
def set_filename_change_hook(self, hook):
|
||||
self.filename_change_hook = hook
|
||||
|
||||
filename = None
|
||||
dirname = None
|
||||
|
||||
def set_filename(self, filename):
|
||||
if filename and os.path.isdir(filename):
|
||||
self.filename = None
|
||||
self.dirname = filename
|
||||
else:
|
||||
self.filename = filename
|
||||
self.dirname = None
|
||||
self.set_saved(1)
|
||||
if self.filename_change_hook:
|
||||
self.filename_change_hook()
|
||||
|
||||
def open(self, event=None, editFile=None):
|
||||
flist = self.editwin.flist
|
||||
# Save in case parent window is closed (ie, during askopenfile()).
|
||||
if flist:
|
||||
if not editFile:
|
||||
filename = self.askopenfile()
|
||||
else:
|
||||
filename=editFile
|
||||
if filename:
|
||||
# If editFile is valid and already open, flist.open will
|
||||
# shift focus to its existing window.
|
||||
# If the current window exists and is a fresh unnamed,
|
||||
# unmodified editor window (not an interpreter shell),
|
||||
# pass self.loadfile to flist.open so it will load the file
|
||||
# in the current window (if the file is not already open)
|
||||
# instead of a new window.
|
||||
if (self.editwin and
|
||||
not getattr(self.editwin, 'interp', None) and
|
||||
not self.filename and
|
||||
self.get_saved()):
|
||||
flist.open(filename, self.loadfile)
|
||||
else:
|
||||
flist.open(filename)
|
||||
else:
|
||||
if self.text:
|
||||
self.text.focus_set()
|
||||
return "break"
|
||||
|
||||
# Code for use outside IDLE:
|
||||
if self.get_saved():
|
||||
reply = self.maybesave()
|
||||
if reply == "cancel":
|
||||
self.text.focus_set()
|
||||
return "break"
|
||||
if not editFile:
|
||||
filename = self.askopenfile()
|
||||
else:
|
||||
filename=editFile
|
||||
if filename:
|
||||
self.loadfile(filename)
|
||||
else:
|
||||
self.text.focus_set()
|
||||
return "break"
|
||||
|
||||
eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
|
||||
eol_re = re.compile(eol)
|
||||
eol_convention = os.linesep # Default
|
||||
|
||||
def loadfile(self, filename):
|
||||
try:
|
||||
# open the file in binary mode so that we can handle
|
||||
# end-of-line convention ourselves.
|
||||
with open(filename, 'rb') as f:
|
||||
chars = f.read()
|
||||
except IOError as msg:
|
||||
tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
|
||||
return False
|
||||
|
||||
chars = self.decode(chars)
|
||||
# We now convert all end-of-lines to '\n's
|
||||
firsteol = self.eol_re.search(chars)
|
||||
if firsteol:
|
||||
self.eol_convention = firsteol.group(0)
|
||||
if isinstance(self.eol_convention, unicode):
|
||||
# Make sure it is an ASCII string
|
||||
self.eol_convention = self.eol_convention.encode("ascii")
|
||||
chars = self.eol_re.sub(r"\n", chars)
|
||||
|
||||
self.text.delete("1.0", "end")
|
||||
self.set_filename(None)
|
||||
self.text.insert("1.0", chars)
|
||||
self.reset_undo()
|
||||
self.set_filename(filename)
|
||||
self.text.mark_set("insert", "1.0")
|
||||
self.text.yview("insert")
|
||||
self.updaterecentfileslist(filename)
|
||||
return True
|
||||
|
||||
def decode(self, chars):
|
||||
"""Create a Unicode string
|
||||
|
||||
If that fails, let Tcl try its best
|
||||
"""
|
||||
# Check presence of a UTF-8 signature first
|
||||
if chars.startswith(BOM_UTF8):
|
||||
try:
|
||||
chars = chars[3:].decode("utf-8")
|
||||
except UnicodeError:
|
||||
# has UTF-8 signature, but fails to decode...
|
||||
return chars
|
||||
else:
|
||||
# Indicates that this file originally had a BOM
|
||||
self.fileencoding = BOM_UTF8
|
||||
return chars
|
||||
# Next look for coding specification
|
||||
try:
|
||||
enc = coding_spec(chars)
|
||||
except LookupError as name:
|
||||
tkMessageBox.showerror(
|
||||
title="Error loading the file",
|
||||
message="The encoding '%s' is not known to this Python "\
|
||||
"installation. The file may not display correctly" % name,
|
||||
master = self.text)
|
||||
enc = None
|
||||
if enc:
|
||||
try:
|
||||
return unicode(chars, enc)
|
||||
except UnicodeError:
|
||||
pass
|
||||
# If it is ASCII, we need not to record anything
|
||||
try:
|
||||
return unicode(chars, 'ascii')
|
||||
except UnicodeError:
|
||||
pass
|
||||
# Finally, try the locale's encoding. This is deprecated;
|
||||
# the user should declare a non-ASCII encoding
|
||||
try:
|
||||
chars = unicode(chars, encoding)
|
||||
self.fileencoding = encoding
|
||||
except UnicodeError:
|
||||
pass
|
||||
return chars
|
||||
|
||||
def maybesave(self):
|
||||
if self.get_saved():
|
||||
return "yes"
|
||||
message = "Do you want to save %s before closing?" % (
|
||||
self.filename or "this untitled document")
|
||||
confirm = tkMessageBox.askyesnocancel(
|
||||
title="Save On Close",
|
||||
message=message,
|
||||
default=tkMessageBox.YES,
|
||||
master=self.text)
|
||||
if confirm:
|
||||
reply = "yes"
|
||||
self.save(None)
|
||||
if not self.get_saved():
|
||||
reply = "cancel"
|
||||
elif confirm is None:
|
||||
reply = "cancel"
|
||||
else:
|
||||
reply = "no"
|
||||
self.text.focus_set()
|
||||
return reply
|
||||
|
||||
def save(self, event):
|
||||
if not self.filename:
|
||||
self.save_as(event)
|
||||
else:
|
||||
if self.writefile(self.filename):
|
||||
self.set_saved(True)
|
||||
try:
|
||||
self.editwin.store_file_breaks()
|
||||
except AttributeError: # may be a PyShell
|
||||
pass
|
||||
self.text.focus_set()
|
||||
return "break"
|
||||
|
||||
def save_as(self, event):
|
||||
filename = self.asksavefile()
|
||||
if filename:
|
||||
if self.writefile(filename):
|
||||
self.set_filename(filename)
|
||||
self.set_saved(1)
|
||||
try:
|
||||
self.editwin.store_file_breaks()
|
||||
except AttributeError:
|
||||
pass
|
||||
self.text.focus_set()
|
||||
self.updaterecentfileslist(filename)
|
||||
return "break"
|
||||
|
||||
def save_a_copy(self, event):
|
||||
filename = self.asksavefile()
|
||||
if filename:
|
||||
self.writefile(filename)
|
||||
self.text.focus_set()
|
||||
self.updaterecentfileslist(filename)
|
||||
return "break"
|
||||
|
||||
def writefile(self, filename):
|
||||
self.fixlastline()
|
||||
chars = self.encode(self.text.get("1.0", "end-1c"))
|
||||
if self.eol_convention != "\n":
|
||||
chars = chars.replace("\n", self.eol_convention)
|
||||
try:
|
||||
with open(filename, "wb") as f:
|
||||
f.write(chars)
|
||||
return True
|
||||
except IOError as msg:
|
||||
tkMessageBox.showerror("I/O Error", str(msg),
|
||||
master=self.text)
|
||||
return False
|
||||
|
||||
def encode(self, chars):
|
||||
if isinstance(chars, types.StringType):
|
||||
# This is either plain ASCII, or Tk was returning mixed-encoding
|
||||
# text to us. Don't try to guess further.
|
||||
return chars
|
||||
# See whether there is anything non-ASCII in it.
|
||||
# If not, no need to figure out the encoding.
|
||||
try:
|
||||
return chars.encode('ascii')
|
||||
except UnicodeError:
|
||||
pass
|
||||
# If there is an encoding declared, try this first.
|
||||
try:
|
||||
enc = coding_spec(chars)
|
||||
failed = None
|
||||
except LookupError as msg:
|
||||
failed = msg
|
||||
enc = None
|
||||
if enc:
|
||||
try:
|
||||
return chars.encode(enc)
|
||||
except UnicodeError:
|
||||
failed = "Invalid encoding '%s'" % enc
|
||||
if failed:
|
||||
tkMessageBox.showerror(
|
||||
"I/O Error",
|
||||
"%s. Saving as UTF-8" % failed,
|
||||
master = self.text)
|
||||
# If there was a UTF-8 signature, use that. This should not fail
|
||||
if self.fileencoding == BOM_UTF8 or failed:
|
||||
return BOM_UTF8 + chars.encode("utf-8")
|
||||
# Try the original file encoding next, if any
|
||||
if self.fileencoding:
|
||||
try:
|
||||
return chars.encode(self.fileencoding)
|
||||
except UnicodeError:
|
||||
tkMessageBox.showerror(
|
||||
"I/O Error",
|
||||
"Cannot save this as '%s' anymore. Saving as UTF-8" \
|
||||
% self.fileencoding,
|
||||
master = self.text)
|
||||
return BOM_UTF8 + chars.encode("utf-8")
|
||||
# Nothing was declared, and we had not determined an encoding
|
||||
# on loading. Recommend an encoding line.
|
||||
config_encoding = idleConf.GetOption("main","EditorWindow",
|
||||
"encoding")
|
||||
if config_encoding == 'utf-8':
|
||||
# User has requested that we save files as UTF-8
|
||||
return BOM_UTF8 + chars.encode("utf-8")
|
||||
ask_user = True
|
||||
try:
|
||||
chars = chars.encode(encoding)
|
||||
enc = encoding
|
||||
if config_encoding == 'locale':
|
||||
ask_user = False
|
||||
except UnicodeError:
|
||||
chars = BOM_UTF8 + chars.encode("utf-8")
|
||||
enc = "utf-8"
|
||||
if not ask_user:
|
||||
return chars
|
||||
dialog = EncodingMessage(self.editwin.top, enc)
|
||||
dialog.go()
|
||||
if dialog.num == 1:
|
||||
# User asked us to edit the file
|
||||
encline = "# -*- coding: %s -*-\n" % enc
|
||||
firstline = self.text.get("1.0", "2.0")
|
||||
if firstline.startswith("#!"):
|
||||
# Insert encoding after #! line
|
||||
self.text.insert("2.0", encline)
|
||||
else:
|
||||
self.text.insert("1.0", encline)
|
||||
return self.encode(self.text.get("1.0", "end-1c"))
|
||||
return chars
|
||||
|
||||
def fixlastline(self):
|
||||
c = self.text.get("end-2c")
|
||||
if c != '\n':
|
||||
self.text.insert("end-1c", "\n")
|
||||
|
||||
def print_window(self, event):
|
||||
confirm = tkMessageBox.askokcancel(
|
||||
title="Print",
|
||||
message="Print to Default Printer",
|
||||
default=tkMessageBox.OK,
|
||||
master=self.text)
|
||||
if not confirm:
|
||||
self.text.focus_set()
|
||||
return "break"
|
||||
tempfilename = None
|
||||
saved = self.get_saved()
|
||||
if saved:
|
||||
filename = self.filename
|
||||
# shell undo is reset after every prompt, looks saved, probably isn't
|
||||
if not saved or filename is None:
|
||||
(tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_')
|
||||
filename = tempfilename
|
||||
os.close(tfd)
|
||||
if not self.writefile(tempfilename):
|
||||
os.unlink(tempfilename)
|
||||
return "break"
|
||||
platform = os.name
|
||||
printPlatform = True
|
||||
if platform == 'posix': #posix platform
|
||||
command = idleConf.GetOption('main','General',
|
||||
'print-command-posix')
|
||||
command = command + " 2>&1"
|
||||
elif platform == 'nt': #win32 platform
|
||||
command = idleConf.GetOption('main','General','print-command-win')
|
||||
else: #no printing for this platform
|
||||
printPlatform = False
|
||||
if printPlatform: #we can try to print for this platform
|
||||
command = command % pipes.quote(filename)
|
||||
pipe = os.popen(command, "r")
|
||||
# things can get ugly on NT if there is no printer available.
|
||||
output = pipe.read().strip()
|
||||
status = pipe.close()
|
||||
if status:
|
||||
output = "Printing failed (exit status 0x%x)\n" % \
|
||||
status + output
|
||||
if output:
|
||||
output = "Printing command: %s\n" % repr(command) + output
|
||||
tkMessageBox.showerror("Print status", output, master=self.text)
|
||||
else: #no printing for this platform
|
||||
message = "Printing is not enabled for this platform: %s" % platform
|
||||
tkMessageBox.showinfo("Print status", message, master=self.text)
|
||||
if tempfilename:
|
||||
os.unlink(tempfilename)
|
||||
return "break"
|
||||
|
||||
opendialog = None
|
||||
savedialog = None
|
||||
|
||||
filetypes = [
|
||||
("Python files", "*.py *.pyw", "TEXT"),
|
||||
("Text files", "*.txt", "TEXT"),
|
||||
("All files", "*"),
|
||||
]
|
||||
|
||||
def askopenfile(self):
|
||||
dir, base = self.defaultfilename("open")
|
||||
if not self.opendialog:
|
||||
self.opendialog = tkFileDialog.Open(master=self.text,
|
||||
filetypes=self.filetypes)
|
||||
filename = self.opendialog.show(initialdir=dir, initialfile=base)
|
||||
if isinstance(filename, unicode):
|
||||
filename = filename.encode(filesystemencoding)
|
||||
return filename
|
||||
|
||||
def defaultfilename(self, mode="open"):
|
||||
if self.filename:
|
||||
return os.path.split(self.filename)
|
||||
elif self.dirname:
|
||||
return self.dirname, ""
|
||||
else:
|
||||
try:
|
||||
pwd = os.getcwd()
|
||||
except os.error:
|
||||
pwd = ""
|
||||
return pwd, ""
|
||||
|
||||
def asksavefile(self):
|
||||
dir, base = self.defaultfilename("save")
|
||||
if not self.savedialog:
|
||||
self.savedialog = tkFileDialog.SaveAs(master=self.text,
|
||||
filetypes=self.filetypes)
|
||||
filename = self.savedialog.show(initialdir=dir, initialfile=base)
|
||||
if isinstance(filename, unicode):
|
||||
filename = filename.encode(filesystemencoding)
|
||||
return filename
|
||||
|
||||
def updaterecentfileslist(self,filename):
|
||||
"Update recent file list on all editor windows"
|
||||
self.editwin.update_recent_files_list(filename)
|
||||
|
||||
def test():
|
||||
root = Tk()
|
||||
class MyEditWin:
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.flist = None
|
||||
self.text.bind("<Control-o>", self.open)
|
||||
self.text.bind("<Control-s>", self.save)
|
||||
self.text.bind("<Alt-s>", self.save_as)
|
||||
self.text.bind("<Alt-z>", self.save_a_copy)
|
||||
def get_saved(self): return 0
|
||||
def set_saved(self, flag): pass
|
||||
def reset_undo(self): pass
|
||||
def open(self, event):
|
||||
self.text.event_generate("<<open-window-from-file>>")
|
||||
def save(self, event):
|
||||
self.text.event_generate("<<save-window>>")
|
||||
def save_as(self, event):
|
||||
self.text.event_generate("<<save-window-as-file>>")
|
||||
def save_a_copy(self, event):
|
||||
self.text.event_generate("<<save-copy-of-window-as-file>>")
|
||||
text = Text(root)
|
||||
text.pack()
|
||||
text.focus_set()
|
||||
editwin = MyEditWin(text)
|
||||
io = IOBinding(editwin)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
BIN
Darwin/lib/python2.7/idlelib/Icons/folder.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/folder.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 B |
BIN
Darwin/lib/python2.7/idlelib/Icons/idle.icns
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/idle.icns
Normal file
Binary file not shown.
BIN
Darwin/lib/python2.7/idlelib/Icons/minusnode.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/minusnode.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 B |
BIN
Darwin/lib/python2.7/idlelib/Icons/openfolder.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/openfolder.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 B |
BIN
Darwin/lib/python2.7/idlelib/Icons/plusnode.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/plusnode.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 B |
BIN
Darwin/lib/python2.7/idlelib/Icons/python.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/python.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 B |
BIN
Darwin/lib/python2.7/idlelib/Icons/tk.gif
Normal file
BIN
Darwin/lib/python2.7/idlelib/Icons/tk.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 B |
106
Darwin/lib/python2.7/idlelib/IdleHistory.py
Normal file
106
Darwin/lib/python2.7/idlelib/IdleHistory.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
"Implement Idle Shell history mechanism with History class"
|
||||
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
class History:
|
||||
''' Implement Idle Shell history mechanism.
|
||||
|
||||
store - Store source statement (called from PyShell.resetoutput).
|
||||
fetch - Fetch stored statement matching prefix already entered.
|
||||
history_next - Bound to <<history-next>> event (default Alt-N).
|
||||
history_prev - Bound to <<history-prev>> event (default Alt-P).
|
||||
'''
|
||||
def __init__(self, text):
|
||||
'''Initialize data attributes and bind event methods.
|
||||
|
||||
.text - Idle wrapper of tk Text widget, with .bell().
|
||||
.history - source statements, possibly with multiple lines.
|
||||
.prefix - source already entered at prompt; filters history list.
|
||||
.pointer - index into history.
|
||||
.cyclic - wrap around history list (or not).
|
||||
'''
|
||||
self.text = text
|
||||
self.history = []
|
||||
self.prefix = None
|
||||
self.pointer = None
|
||||
self.cyclic = idleConf.GetOption("main", "History", "cyclic", 1, "bool")
|
||||
text.bind("<<history-previous>>", self.history_prev)
|
||||
text.bind("<<history-next>>", self.history_next)
|
||||
|
||||
def history_next(self, event):
|
||||
"Fetch later statement; start with ealiest if cyclic."
|
||||
self.fetch(reverse=False)
|
||||
return "break"
|
||||
|
||||
def history_prev(self, event):
|
||||
"Fetch earlier statement; start with most recent."
|
||||
self.fetch(reverse=True)
|
||||
return "break"
|
||||
|
||||
def fetch(self, reverse):
|
||||
'''Fetch statememt and replace current line in text widget.
|
||||
|
||||
Set prefix and pointer as needed for successive fetches.
|
||||
Reset them to None, None when returning to the start line.
|
||||
Sound bell when return to start line or cannot leave a line
|
||||
because cyclic is False.
|
||||
'''
|
||||
nhist = len(self.history)
|
||||
pointer = self.pointer
|
||||
prefix = self.prefix
|
||||
if pointer is not None and prefix is not None:
|
||||
if self.text.compare("insert", "!=", "end-1c") or \
|
||||
self.text.get("iomark", "end-1c") != self.history[pointer]:
|
||||
pointer = prefix = None
|
||||
self.text.mark_set("insert", "end-1c") # != after cursor move
|
||||
if pointer is None or prefix is None:
|
||||
prefix = self.text.get("iomark", "end-1c")
|
||||
if reverse:
|
||||
pointer = nhist # will be decremented
|
||||
else:
|
||||
if self.cyclic:
|
||||
pointer = -1 # will be incremented
|
||||
else: # abort history_next
|
||||
self.text.bell()
|
||||
return
|
||||
nprefix = len(prefix)
|
||||
while 1:
|
||||
pointer += -1 if reverse else 1
|
||||
if pointer < 0 or pointer >= nhist:
|
||||
self.text.bell()
|
||||
if not self.cyclic and pointer < 0: # abort history_prev
|
||||
return
|
||||
else:
|
||||
if self.text.get("iomark", "end-1c") != prefix:
|
||||
self.text.delete("iomark", "end-1c")
|
||||
self.text.insert("iomark", prefix)
|
||||
pointer = prefix = None
|
||||
break
|
||||
item = self.history[pointer]
|
||||
if item[:nprefix] == prefix and len(item) > nprefix:
|
||||
self.text.delete("iomark", "end-1c")
|
||||
self.text.insert("iomark", item)
|
||||
break
|
||||
self.text.see("insert")
|
||||
self.text.tag_remove("sel", "1.0", "end")
|
||||
self.pointer = pointer
|
||||
self.prefix = prefix
|
||||
|
||||
def store(self, source):
|
||||
"Store Shell input statement into history list."
|
||||
source = source.strip()
|
||||
if len(source) > 2:
|
||||
# avoid duplicates
|
||||
try:
|
||||
self.history.remove(source)
|
||||
except ValueError:
|
||||
pass
|
||||
self.history.append(source)
|
||||
self.pointer = None
|
||||
self.prefix = None
|
||||
|
||||
if __name__ == "__main__":
|
||||
from test import test_support as support
|
||||
support.use_resources = ['gui']
|
||||
from unittest import main
|
||||
main('idlelib.idle_test.test_idlehistory', verbosity=2, exit=False)
|
||||
423
Darwin/lib/python2.7/idlelib/MultiCall.py
Normal file
423
Darwin/lib/python2.7/idlelib/MultiCall.py
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
"""
|
||||
MultiCall - a class which inherits its methods from a Tkinter widget (Text, for
|
||||
example), but enables multiple calls of functions per virtual event - all
|
||||
matching events will be called, not only the most specific one. This is done
|
||||
by wrapping the event functions - event_add, event_delete and event_info.
|
||||
MultiCall recognizes only a subset of legal event sequences. Sequences which
|
||||
are not recognized are treated by the original Tk handling mechanism. A
|
||||
more-specific event will be called before a less-specific event.
|
||||
|
||||
The recognized sequences are complete one-event sequences (no emacs-style
|
||||
Ctrl-X Ctrl-C, no shortcuts like <3>), for all types of events.
|
||||
Key/Button Press/Release events can have modifiers.
|
||||
The recognized modifiers are Shift, Control, Option and Command for Mac, and
|
||||
Control, Alt, Shift, Meta/M for other platforms.
|
||||
|
||||
For all events which were handled by MultiCall, a new member is added to the
|
||||
event instance passed to the binded functions - mc_type. This is one of the
|
||||
event type constants defined in this module (such as MC_KEYPRESS).
|
||||
For Key/Button events (which are handled by MultiCall and may receive
|
||||
modifiers), another member is added - mc_state. This member gives the state
|
||||
of the recognized modifiers, as a combination of the modifier constants
|
||||
also defined in this module (for example, MC_SHIFT).
|
||||
Using these members is absolutely portable.
|
||||
|
||||
The order by which events are called is defined by these rules:
|
||||
1. A more-specific event will be called before a less-specific event.
|
||||
2. A recently-binded event will be called before a previously-binded event,
|
||||
unless this conflicts with the first rule.
|
||||
Each function will be called at most once for each event.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import string
|
||||
import re
|
||||
import Tkinter
|
||||
from idlelib import macosxSupport
|
||||
|
||||
# the event type constants, which define the meaning of mc_type
|
||||
MC_KEYPRESS=0; MC_KEYRELEASE=1; MC_BUTTONPRESS=2; MC_BUTTONRELEASE=3;
|
||||
MC_ACTIVATE=4; MC_CIRCULATE=5; MC_COLORMAP=6; MC_CONFIGURE=7;
|
||||
MC_DEACTIVATE=8; MC_DESTROY=9; MC_ENTER=10; MC_EXPOSE=11; MC_FOCUSIN=12;
|
||||
MC_FOCUSOUT=13; MC_GRAVITY=14; MC_LEAVE=15; MC_MAP=16; MC_MOTION=17;
|
||||
MC_MOUSEWHEEL=18; MC_PROPERTY=19; MC_REPARENT=20; MC_UNMAP=21; MC_VISIBILITY=22;
|
||||
# the modifier state constants, which define the meaning of mc_state
|
||||
MC_SHIFT = 1<<0; MC_CONTROL = 1<<2; MC_ALT = 1<<3; MC_META = 1<<5
|
||||
MC_OPTION = 1<<6; MC_COMMAND = 1<<7
|
||||
|
||||
# define the list of modifiers, to be used in complex event types.
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
_modifiers = (("Shift",), ("Control",), ("Option",), ("Command",))
|
||||
_modifier_masks = (MC_SHIFT, MC_CONTROL, MC_OPTION, MC_COMMAND)
|
||||
else:
|
||||
_modifiers = (("Control",), ("Alt",), ("Shift",), ("Meta", "M"))
|
||||
_modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META)
|
||||
|
||||
# a dictionary to map a modifier name into its number
|
||||
_modifier_names = dict([(name, number)
|
||||
for number in range(len(_modifiers))
|
||||
for name in _modifiers[number]])
|
||||
|
||||
# A binder is a class which binds functions to one type of event. It has two
|
||||
# methods: bind and unbind, which get a function and a parsed sequence, as
|
||||
# returned by _parse_sequence(). There are two types of binders:
|
||||
# _SimpleBinder handles event types with no modifiers and no detail.
|
||||
# No Python functions are called when no events are binded.
|
||||
# _ComplexBinder handles event types with modifiers and a detail.
|
||||
# A Python function is called each time an event is generated.
|
||||
|
||||
class _SimpleBinder:
|
||||
def __init__(self, type, widget, widgetinst):
|
||||
self.type = type
|
||||
self.sequence = '<'+_types[type][0]+'>'
|
||||
self.widget = widget
|
||||
self.widgetinst = widgetinst
|
||||
self.bindedfuncs = []
|
||||
self.handlerid = None
|
||||
|
||||
def bind(self, triplet, func):
|
||||
if not self.handlerid:
|
||||
def handler(event, l = self.bindedfuncs, mc_type = self.type):
|
||||
event.mc_type = mc_type
|
||||
wascalled = {}
|
||||
for i in range(len(l)-1, -1, -1):
|
||||
func = l[i]
|
||||
if func not in wascalled:
|
||||
wascalled[func] = True
|
||||
r = func(event)
|
||||
if r:
|
||||
return r
|
||||
self.handlerid = self.widget.bind(self.widgetinst,
|
||||
self.sequence, handler)
|
||||
self.bindedfuncs.append(func)
|
||||
|
||||
def unbind(self, triplet, func):
|
||||
self.bindedfuncs.remove(func)
|
||||
if not self.bindedfuncs:
|
||||
self.widget.unbind(self.widgetinst, self.sequence, self.handlerid)
|
||||
self.handlerid = None
|
||||
|
||||
def __del__(self):
|
||||
if self.handlerid:
|
||||
self.widget.unbind(self.widgetinst, self.sequence, self.handlerid)
|
||||
|
||||
# An int in range(1 << len(_modifiers)) represents a combination of modifiers
|
||||
# (if the least significent bit is on, _modifiers[0] is on, and so on).
|
||||
# _state_subsets gives for each combination of modifiers, or *state*,
|
||||
# a list of the states which are a subset of it. This list is ordered by the
|
||||
# number of modifiers is the state - the most specific state comes first.
|
||||
_states = range(1 << len(_modifiers))
|
||||
_state_names = [''.join(m[0]+'-'
|
||||
for i, m in enumerate(_modifiers)
|
||||
if (1 << i) & s)
|
||||
for s in _states]
|
||||
|
||||
def expand_substates(states):
|
||||
'''For each item of states return a list containing all combinations of
|
||||
that item with individual bits reset, sorted by the number of set bits.
|
||||
'''
|
||||
def nbits(n):
|
||||
"number of bits set in n base 2"
|
||||
nb = 0
|
||||
while n:
|
||||
n, rem = divmod(n, 2)
|
||||
nb += rem
|
||||
return nb
|
||||
statelist = []
|
||||
for state in states:
|
||||
substates = list(set(state & x for x in states))
|
||||
substates.sort(key=nbits, reverse=True)
|
||||
statelist.append(substates)
|
||||
return statelist
|
||||
|
||||
_state_subsets = expand_substates(_states)
|
||||
|
||||
# _state_codes gives for each state, the portable code to be passed as mc_state
|
||||
_state_codes = []
|
||||
for s in _states:
|
||||
r = 0
|
||||
for i in range(len(_modifiers)):
|
||||
if (1 << i) & s:
|
||||
r |= _modifier_masks[i]
|
||||
_state_codes.append(r)
|
||||
|
||||
class _ComplexBinder:
|
||||
# This class binds many functions, and only unbinds them when it is deleted.
|
||||
# self.handlerids is the list of seqs and ids of binded handler functions.
|
||||
# The binded functions sit in a dictionary of lists of lists, which maps
|
||||
# a detail (or None) and a state into a list of functions.
|
||||
# When a new detail is discovered, handlers for all the possible states
|
||||
# are binded.
|
||||
|
||||
def __create_handler(self, lists, mc_type, mc_state):
|
||||
def handler(event, lists = lists,
|
||||
mc_type = mc_type, mc_state = mc_state,
|
||||
ishandlerrunning = self.ishandlerrunning,
|
||||
doafterhandler = self.doafterhandler):
|
||||
ishandlerrunning[:] = [True]
|
||||
event.mc_type = mc_type
|
||||
event.mc_state = mc_state
|
||||
wascalled = {}
|
||||
r = None
|
||||
for l in lists:
|
||||
for i in range(len(l)-1, -1, -1):
|
||||
func = l[i]
|
||||
if func not in wascalled:
|
||||
wascalled[func] = True
|
||||
r = l[i](event)
|
||||
if r:
|
||||
break
|
||||
if r:
|
||||
break
|
||||
ishandlerrunning[:] = []
|
||||
# Call all functions in doafterhandler and remove them from list
|
||||
for f in doafterhandler:
|
||||
f()
|
||||
doafterhandler[:] = []
|
||||
if r:
|
||||
return r
|
||||
return handler
|
||||
|
||||
def __init__(self, type, widget, widgetinst):
|
||||
self.type = type
|
||||
self.typename = _types[type][0]
|
||||
self.widget = widget
|
||||
self.widgetinst = widgetinst
|
||||
self.bindedfuncs = {None: [[] for s in _states]}
|
||||
self.handlerids = []
|
||||
# we don't want to change the lists of functions while a handler is
|
||||
# running - it will mess up the loop and anyway, we usually want the
|
||||
# change to happen from the next event. So we have a list of functions
|
||||
# for the handler to run after it finishes calling the binded functions.
|
||||
# It calls them only once.
|
||||
# ishandlerrunning is a list. An empty one means no, otherwise - yes.
|
||||
# this is done so that it would be mutable.
|
||||
self.ishandlerrunning = []
|
||||
self.doafterhandler = []
|
||||
for s in _states:
|
||||
lists = [self.bindedfuncs[None][i] for i in _state_subsets[s]]
|
||||
handler = self.__create_handler(lists, type, _state_codes[s])
|
||||
seq = '<'+_state_names[s]+self.typename+'>'
|
||||
self.handlerids.append((seq, self.widget.bind(self.widgetinst,
|
||||
seq, handler)))
|
||||
|
||||
def bind(self, triplet, func):
|
||||
if triplet[2] not in self.bindedfuncs:
|
||||
self.bindedfuncs[triplet[2]] = [[] for s in _states]
|
||||
for s in _states:
|
||||
lists = [ self.bindedfuncs[detail][i]
|
||||
for detail in (triplet[2], None)
|
||||
for i in _state_subsets[s] ]
|
||||
handler = self.__create_handler(lists, self.type,
|
||||
_state_codes[s])
|
||||
seq = "<%s%s-%s>"% (_state_names[s], self.typename, triplet[2])
|
||||
self.handlerids.append((seq, self.widget.bind(self.widgetinst,
|
||||
seq, handler)))
|
||||
doit = lambda: self.bindedfuncs[triplet[2]][triplet[0]].append(func)
|
||||
if not self.ishandlerrunning:
|
||||
doit()
|
||||
else:
|
||||
self.doafterhandler.append(doit)
|
||||
|
||||
def unbind(self, triplet, func):
|
||||
doit = lambda: self.bindedfuncs[triplet[2]][triplet[0]].remove(func)
|
||||
if not self.ishandlerrunning:
|
||||
doit()
|
||||
else:
|
||||
self.doafterhandler.append(doit)
|
||||
|
||||
def __del__(self):
|
||||
for seq, id in self.handlerids:
|
||||
self.widget.unbind(self.widgetinst, seq, id)
|
||||
|
||||
# define the list of event types to be handled by MultiEvent. the order is
|
||||
# compatible with the definition of event type constants.
|
||||
_types = (
|
||||
("KeyPress", "Key"), ("KeyRelease",), ("ButtonPress", "Button"),
|
||||
("ButtonRelease",), ("Activate",), ("Circulate",), ("Colormap",),
|
||||
("Configure",), ("Deactivate",), ("Destroy",), ("Enter",), ("Expose",),
|
||||
("FocusIn",), ("FocusOut",), ("Gravity",), ("Leave",), ("Map",),
|
||||
("Motion",), ("MouseWheel",), ("Property",), ("Reparent",), ("Unmap",),
|
||||
("Visibility",),
|
||||
)
|
||||
|
||||
# which binder should be used for every event type?
|
||||
_binder_classes = (_ComplexBinder,) * 4 + (_SimpleBinder,) * (len(_types)-4)
|
||||
|
||||
# A dictionary to map a type name into its number
|
||||
_type_names = dict([(name, number)
|
||||
for number in range(len(_types))
|
||||
for name in _types[number]])
|
||||
|
||||
_keysym_re = re.compile(r"^\w+$")
|
||||
_button_re = re.compile(r"^[1-5]$")
|
||||
def _parse_sequence(sequence):
|
||||
"""Get a string which should describe an event sequence. If it is
|
||||
successfully parsed as one, return a tuple containing the state (as an int),
|
||||
the event type (as an index of _types), and the detail - None if none, or a
|
||||
string if there is one. If the parsing is unsuccessful, return None.
|
||||
"""
|
||||
if not sequence or sequence[0] != '<' or sequence[-1] != '>':
|
||||
return None
|
||||
words = string.split(sequence[1:-1], '-')
|
||||
|
||||
modifiers = 0
|
||||
while words and words[0] in _modifier_names:
|
||||
modifiers |= 1 << _modifier_names[words[0]]
|
||||
del words[0]
|
||||
|
||||
if words and words[0] in _type_names:
|
||||
type = _type_names[words[0]]
|
||||
del words[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
if _binder_classes[type] is _SimpleBinder:
|
||||
if modifiers or words:
|
||||
return None
|
||||
else:
|
||||
detail = None
|
||||
else:
|
||||
# _ComplexBinder
|
||||
if type in [_type_names[s] for s in ("KeyPress", "KeyRelease")]:
|
||||
type_re = _keysym_re
|
||||
else:
|
||||
type_re = _button_re
|
||||
|
||||
if not words:
|
||||
detail = None
|
||||
elif len(words) == 1 and type_re.match(words[0]):
|
||||
detail = words[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
return modifiers, type, detail
|
||||
|
||||
def _triplet_to_sequence(triplet):
|
||||
if triplet[2]:
|
||||
return '<'+_state_names[triplet[0]]+_types[triplet[1]][0]+'-'+ \
|
||||
triplet[2]+'>'
|
||||
else:
|
||||
return '<'+_state_names[triplet[0]]+_types[triplet[1]][0]+'>'
|
||||
|
||||
_multicall_dict = {}
|
||||
def MultiCallCreator(widget):
|
||||
"""Return a MultiCall class which inherits its methods from the
|
||||
given widget class (for example, Tkinter.Text). This is used
|
||||
instead of a templating mechanism.
|
||||
"""
|
||||
if widget in _multicall_dict:
|
||||
return _multicall_dict[widget]
|
||||
|
||||
class MultiCall (widget):
|
||||
assert issubclass(widget, Tkinter.Misc)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
widget.__init__(self, *args, **kwargs)
|
||||
# a dictionary which maps a virtual event to a tuple with:
|
||||
# 0. the function binded
|
||||
# 1. a list of triplets - the sequences it is binded to
|
||||
self.__eventinfo = {}
|
||||
self.__binders = [_binder_classes[i](i, widget, self)
|
||||
for i in range(len(_types))]
|
||||
|
||||
def bind(self, sequence=None, func=None, add=None):
|
||||
#print "bind(%s, %s, %s) called." % (sequence, func, add)
|
||||
if type(sequence) is str and len(sequence) > 2 and \
|
||||
sequence[:2] == "<<" and sequence[-2:] == ">>":
|
||||
if sequence in self.__eventinfo:
|
||||
ei = self.__eventinfo[sequence]
|
||||
if ei[0] is not None:
|
||||
for triplet in ei[1]:
|
||||
self.__binders[triplet[1]].unbind(triplet, ei[0])
|
||||
ei[0] = func
|
||||
if ei[0] is not None:
|
||||
for triplet in ei[1]:
|
||||
self.__binders[triplet[1]].bind(triplet, func)
|
||||
else:
|
||||
self.__eventinfo[sequence] = [func, []]
|
||||
return widget.bind(self, sequence, func, add)
|
||||
|
||||
def unbind(self, sequence, funcid=None):
|
||||
if type(sequence) is str and len(sequence) > 2 and \
|
||||
sequence[:2] == "<<" and sequence[-2:] == ">>" and \
|
||||
sequence in self.__eventinfo:
|
||||
func, triplets = self.__eventinfo[sequence]
|
||||
if func is not None:
|
||||
for triplet in triplets:
|
||||
self.__binders[triplet[1]].unbind(triplet, func)
|
||||
self.__eventinfo[sequence][0] = None
|
||||
return widget.unbind(self, sequence, funcid)
|
||||
|
||||
def event_add(self, virtual, *sequences):
|
||||
#print "event_add(%s,%s) was called"%(repr(virtual),repr(sequences))
|
||||
if virtual not in self.__eventinfo:
|
||||
self.__eventinfo[virtual] = [None, []]
|
||||
|
||||
func, triplets = self.__eventinfo[virtual]
|
||||
for seq in sequences:
|
||||
triplet = _parse_sequence(seq)
|
||||
if triplet is None:
|
||||
#print >> sys.stderr, "Seq. %s was added by Tkinter."%seq
|
||||
widget.event_add(self, virtual, seq)
|
||||
else:
|
||||
if func is not None:
|
||||
self.__binders[triplet[1]].bind(triplet, func)
|
||||
triplets.append(triplet)
|
||||
|
||||
def event_delete(self, virtual, *sequences):
|
||||
if virtual not in self.__eventinfo:
|
||||
return
|
||||
func, triplets = self.__eventinfo[virtual]
|
||||
for seq in sequences:
|
||||
triplet = _parse_sequence(seq)
|
||||
if triplet is None:
|
||||
#print >> sys.stderr, "Seq. %s was deleted by Tkinter."%seq
|
||||
widget.event_delete(self, virtual, seq)
|
||||
else:
|
||||
if func is not None:
|
||||
self.__binders[triplet[1]].unbind(triplet, func)
|
||||
triplets.remove(triplet)
|
||||
|
||||
def event_info(self, virtual=None):
|
||||
if virtual is None or virtual not in self.__eventinfo:
|
||||
return widget.event_info(self, virtual)
|
||||
else:
|
||||
return tuple(map(_triplet_to_sequence,
|
||||
self.__eventinfo[virtual][1])) + \
|
||||
widget.event_info(self, virtual)
|
||||
|
||||
def __del__(self):
|
||||
for virtual in self.__eventinfo:
|
||||
func, triplets = self.__eventinfo[virtual]
|
||||
if func:
|
||||
for triplet in triplets:
|
||||
self.__binders[triplet[1]].unbind(triplet, func)
|
||||
|
||||
|
||||
_multicall_dict[widget] = MultiCall
|
||||
return MultiCall
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test
|
||||
root = Tkinter.Tk()
|
||||
text = MultiCallCreator(Tkinter.Text)(root)
|
||||
text.pack()
|
||||
def bindseq(seq, n=[0]):
|
||||
def handler(event):
|
||||
print seq
|
||||
text.bind("<<handler%d>>"%n[0], handler)
|
||||
text.event_add("<<handler%d>>"%n[0], seq)
|
||||
n[0] += 1
|
||||
bindseq("<Key>")
|
||||
bindseq("<Control-Key>")
|
||||
bindseq("<Alt-Key-a>")
|
||||
bindseq("<Control-Key-a>")
|
||||
bindseq("<Alt-Control-Key-a>")
|
||||
bindseq("<Key-b>")
|
||||
bindseq("<Control-Button-1>")
|
||||
bindseq("<Alt-Button-1>")
|
||||
bindseq("<FocusOut>")
|
||||
bindseq("<Enter>")
|
||||
bindseq("<Leave>")
|
||||
root.mainloop()
|
||||
32
Darwin/lib/python2.7/idlelib/MultiStatusBar.py
Normal file
32
Darwin/lib/python2.7/idlelib/MultiStatusBar.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from Tkinter import *
|
||||
|
||||
class MultiStatusBar(Frame):
|
||||
|
||||
def __init__(self, master=None, **kw):
|
||||
if master is None:
|
||||
master = Tk()
|
||||
Frame.__init__(self, master, **kw)
|
||||
self.labels = {}
|
||||
|
||||
def set_label(self, name, text='', side=LEFT):
|
||||
if name not in self.labels:
|
||||
label = Label(self, bd=1, relief=SUNKEN, anchor=W)
|
||||
label.pack(side=side)
|
||||
self.labels[name] = label
|
||||
else:
|
||||
label = self.labels[name]
|
||||
label.config(text=text)
|
||||
|
||||
def _test():
|
||||
b = Frame()
|
||||
c = Text(b)
|
||||
c.pack(side=TOP)
|
||||
a = MultiStatusBar(b)
|
||||
a.set_label("one", "hello")
|
||||
a.set_label("two", "world")
|
||||
a.pack(side=BOTTOM, fill=X)
|
||||
b.pack()
|
||||
b.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
||||
780
Darwin/lib/python2.7/idlelib/NEWS.txt
Normal file
780
Darwin/lib/python2.7/idlelib/NEWS.txt
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
What's New in IDLE 2.7.5?
|
||||
=========================
|
||||
|
||||
- Issue #17390: Display Python version on Idle title bar.
|
||||
Initial patch by Edmond Burnett.
|
||||
|
||||
|
||||
What's New in IDLE 2.7.4?
|
||||
=========================
|
||||
|
||||
- Issue #15318: Prevent writing to sys.stdin.
|
||||
|
||||
- Issue #13532, #15319: Check that arguments to sys.stdout.write are strings.
|
||||
|
||||
- Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE.
|
||||
|
||||
- Issue10365: File open dialog now works instead of crashing even when
|
||||
parent window is closed while dialog is open.
|
||||
|
||||
- Issue 14876: use user-selected font for highlight configuration.
|
||||
|
||||
- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X
|
||||
to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6.
|
||||
|
||||
- Issue #15853: Prevent IDLE crash on OS X when opening Preferences menu
|
||||
with certain versions of Tk 8.5. Initial patch by Kevin Walzer.
|
||||
|
||||
|
||||
What's New in IDLE 2.7.3?
|
||||
=========================
|
||||
|
||||
- Issue #14409: IDLE now properly executes commands in the Shell window
|
||||
when it cannot read the normal config files on startup and
|
||||
has to use the built-in default key bindings.
|
||||
There was previously a bug in one of the defaults.
|
||||
|
||||
- Issue #3573: IDLE hangs when passing invalid command line args
|
||||
(directory(ies) instead of file(s)).
|
||||
|
||||
|
||||
What's New in IDLE 2.7.2?
|
||||
=========================
|
||||
|
||||
*Release date: 29-May-2011*
|
||||
|
||||
- Issue #6378: Further adjust idle.bat to start associated Python
|
||||
|
||||
- Issue #11896: Save on Close failed despite selecting "Yes" in dialog.
|
||||
|
||||
- <Home> toggle failing on Tk 8.5, causing IDLE exits and strange selection
|
||||
behavior. Issue 4676. Improve selection extension behaviour.
|
||||
|
||||
- <Home> toggle non-functional when NumLock set on Windows. Issue 3851.
|
||||
|
||||
|
||||
What's New in IDLE 2.7?
|
||||
=======================
|
||||
|
||||
*Release date: 07-03-2010*
|
||||
|
||||
- idle.py modified and simplified to better support developing experimental
|
||||
versions of IDLE which are not installed in the standard location.
|
||||
|
||||
- OutputWindow/PyShell right click menu "Go to file/line" wasn't working with
|
||||
file paths containing spaces. Bug 5559.
|
||||
|
||||
- Windows: Version string for the .chm help file changed, file not being
|
||||
accessed Patch 5783 Guilherme Polo
|
||||
|
||||
- Allow multiple IDLE GUI/subprocess pairs to exist simultaneously. Thanks to
|
||||
David Scherer for suggesting the use of an ephemeral port for the GUI.
|
||||
Patch 1529142 Weeble.
|
||||
|
||||
- Remove port spec from run.py and fix bug where subprocess fails to
|
||||
extract port from command line when warnings are present.
|
||||
|
||||
- Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle
|
||||
mixed space/tab properly. Issue 5129, patch by Guilherme Polo.
|
||||
|
||||
- Issue #3549: On MacOS the preferences menu was not present
|
||||
|
||||
|
||||
What's New in IDLE 2.6?
|
||||
=======================
|
||||
|
||||
*Release date: 01-Oct-2008*
|
||||
|
||||
- Issue #2665: On Windows, an IDLE installation upgraded from an old version
|
||||
would not start if a custom theme was defined.
|
||||
|
||||
- Home / Control-A toggles between left margin and end of leading white
|
||||
space. Patch 1196903 Jeff Shute.
|
||||
|
||||
- Improved AutoCompleteWindow logic. Patch 2062 Tal Einat.
|
||||
|
||||
- Autocompletion of filenames now support alternate separators, e.g. the
|
||||
'/' char on Windows. Patch 2061 Tal Einat.
|
||||
|
||||
What's New in IDLE 2.6a1?
|
||||
=========================
|
||||
|
||||
*Release date: 29-Feb-2008*
|
||||
|
||||
- Configured selection highlighting colors were ignored; updating highlighting
|
||||
in the config dialog would cause non-Python files to be colored as if they
|
||||
were Python source; improve use of ColorDelagator. Patch 1334. Tal Einat.
|
||||
|
||||
- ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat.
|
||||
|
||||
- There was an error on exit if no sys.exitfunc was defined. Issue 1647.
|
||||
|
||||
- Could not open files in .idlerc directory if latter was hidden on Windows.
|
||||
Issue 1743, Issue 1862.
|
||||
|
||||
- Configure Dialog: improved layout for keybinding. Patch 1457 Tal Einat.
|
||||
|
||||
- tabpage.py updated: tabbedPages.py now supports multiple dynamic rows
|
||||
of tabs. Patch 1612746 Tal Einat.
|
||||
|
||||
- Add confirmation dialog before printing. Patch 1717170 Tal Einat.
|
||||
|
||||
- Show paste position if > 80 col. Patch 1659326 Tal Einat.
|
||||
|
||||
- Update cursor color without restarting. Patch 1725576 Tal Einat.
|
||||
|
||||
- Allow keyboard interrupt only when user code is executing in subprocess.
|
||||
Patch 1225 Tal Einat (reworked from IDLE-Spoon).
|
||||
|
||||
- configDialog cleanup. Patch 1730217 Tal Einat.
|
||||
|
||||
- textView cleanup. Patch 1718043 Tal Einat.
|
||||
|
||||
- Clean up EditorWindow close.
|
||||
|
||||
- Patch 1693258: Fix for duplicate "preferences" menu-OS X. Backport of r56204.
|
||||
|
||||
- OSX: Avoid crash for those versions of Tcl/Tk which don't have a console
|
||||
|
||||
- Bug in idlelib.MultiCall: Options dialog was crashing IDLE if there was an
|
||||
option in config-extensions w/o a value. Patch #1672481, Tal Einat
|
||||
|
||||
- Corrected some bugs in AutoComplete. Also, Page Up/Down in ACW implemented;
|
||||
mouse and cursor selection in ACWindow implemented; double Tab inserts
|
||||
current selection and closes ACW (similar to double-click and Return); scroll
|
||||
wheel now works in ACW. Added AutoComplete instructions to IDLE Help.
|
||||
|
||||
- AutoCompleteWindow moved below input line, will move above if there
|
||||
isn't enough space. Patch 1621265 Tal Einat
|
||||
|
||||
- Calltips now 'handle' tuples in the argument list (display '<tuple>' :)
|
||||
Suggested solution by Christos Georgiou, Bug 791968.
|
||||
|
||||
- Add 'raw' support to configHandler. Patch 1650174 Tal Einat.
|
||||
|
||||
- Avoid hang when encountering a duplicate in a completion list. Bug 1571112.
|
||||
|
||||
- Patch #1362975: Rework CodeContext indentation algorithm to
|
||||
avoid hard-coding pixel widths.
|
||||
|
||||
- Bug #813342: Start the IDLE subprocess with -Qnew if the parent
|
||||
is started with that option.
|
||||
|
||||
- Honor the "Cancel" action in the save dialog (Debian bug #299092)
|
||||
|
||||
- Some syntax errors were being caught by tokenize during the tabnanny
|
||||
check, resulting in obscure error messages. Do the syntax check
|
||||
first. Bug 1562716, 1562719
|
||||
|
||||
- IDLE's version number takes a big jump to match the version number of
|
||||
the Python release of which it's a part.
|
||||
|
||||
|
||||
What's New in IDLE 1.2?
|
||||
=======================
|
||||
|
||||
*Release date: 19-SEP-2006*
|
||||
|
||||
|
||||
What's New in IDLE 1.2c1?
|
||||
=========================
|
||||
|
||||
*Release date: 17-AUG-2006*
|
||||
|
||||
- File menu hotkeys: there were three 'p' assignments. Reassign the
|
||||
'Save Copy As' and 'Print' hotkeys to 'y' and 't'. Change the
|
||||
Shell hotkey from 's' to 'l'.
|
||||
|
||||
- IDLE honors new quit() and exit() commands from site.py Quitter() object.
|
||||
Patch 1540892, Jim Jewett
|
||||
|
||||
- The 'with' statement is now a Code Context block opener.
|
||||
Patch 1540851, Jim Jewett
|
||||
|
||||
- Retrieval of previous shell command was not always preserving indentation
|
||||
(since 1.2a1) Patch 1528468 Tal Einat.
|
||||
|
||||
- Changing tokenize (39046) to detect dedent broke tabnanny check (since 1.2a1)
|
||||
|
||||
- ToggleTab dialog was setting indent to 8 even if cancelled (since 1.2a1).
|
||||
|
||||
- When used w/o subprocess, all exceptions were preceded by an error
|
||||
message claiming they were IDLE internal errors (since 1.2a1).
|
||||
|
||||
What's New in IDLE 1.2b3?
|
||||
=========================
|
||||
|
||||
*Release date: 03-AUG-2006*
|
||||
|
||||
- Bug #1525817: Don't truncate short lines in IDLE's tool tips.
|
||||
|
||||
- Bug #1517990: IDLE keybindings on MacOS X now work correctly
|
||||
|
||||
- Bug #1517996: IDLE now longer shows the default Tk menu when a
|
||||
path browser, class browser or debugger is the frontmost window on MacOS X
|
||||
|
||||
- EditorWindow.test() was failing. Bug 1417598
|
||||
|
||||
- EditorWindow failed when used stand-alone if sys.ps1 not set.
|
||||
Bug 1010370 Dave Florek
|
||||
|
||||
- Tooltips failed on new-syle class __init__ args. Bug 1027566 Loren Guthrie
|
||||
|
||||
- Avoid occasional failure to detect closing paren properly.
|
||||
Patch 1407280 Tal Einat
|
||||
|
||||
- Rebinding Tab key was inserting 'tab' instead of 'Tab'. Bug 1179168.
|
||||
|
||||
- Colorizer now handles #<builtin> correctly, also unicode strings and
|
||||
'as' keyword in comment directly following import command. Closes 1325071.
|
||||
Patch 1479219 Tal Einat
|
||||
|
||||
What's New in IDLE 1.2b2?
|
||||
=========================
|
||||
|
||||
*Release date: 11-JUL-2006*
|
||||
|
||||
What's New in IDLE 1.2b1?
|
||||
=========================
|
||||
|
||||
*Release date: 20-JUN-2006*
|
||||
|
||||
What's New in IDLE 1.2a2?
|
||||
=========================
|
||||
|
||||
*Release date: 27-APR-2006*
|
||||
|
||||
What's New in IDLE 1.2a1?
|
||||
=========================
|
||||
|
||||
*Release date: 05-APR-2006*
|
||||
|
||||
- Patch #1162825: Support non-ASCII characters in IDLE window titles.
|
||||
|
||||
- Source file f.flush() after writing; trying to avoid lossage if user
|
||||
kills GUI.
|
||||
|
||||
- Options / Keys / Advanced dialog made functional. Also, allow binding
|
||||
of 'movement' keys.
|
||||
|
||||
- 'syntax' patch adds improved calltips and a new class attribute listbox.
|
||||
MultiCall module allows binding multiple actions to an event.
|
||||
Patch 906702 Noam Raphael
|
||||
|
||||
- Better indentation after first line of string continuation.
|
||||
IDLEfork Patch 681992, Noam Raphael
|
||||
|
||||
- Fixed CodeContext alignment problem, following suggestion from Tal Einat.
|
||||
|
||||
- Increased performance in CodeContext extension Patch 936169 Noam Raphael
|
||||
|
||||
- Mac line endings were incorrect when pasting code from some browsers
|
||||
when using X11 and the Fink distribution. Python Bug 1263656.
|
||||
|
||||
- <Enter> when cursor is on a previous command retrieves that command. Instead
|
||||
of replacing the input line, the previous command is now appended to the
|
||||
input line. Indentation is preserved, and undo is enabled.
|
||||
Patch 1196917 Jeff Shute
|
||||
|
||||
- Clarify "tab/space" Error Dialog and "Tab Width" Dialog associated with
|
||||
the Untabify command.
|
||||
|
||||
- Corrected "tab/space" Error Dialog to show correct menu for Untabify.
|
||||
Patch 1196980 Jeff Shute
|
||||
|
||||
- New files are colorized by default, and colorizing is removed when
|
||||
saving as non-Python files. Patch 1196895 Jeff Shute
|
||||
Closes Python Bugs 775012 and 800432, partial fix IDLEfork 763524
|
||||
|
||||
- Improve subprocess link error notification.
|
||||
|
||||
- run.py: use Queue's blocking feature instead of sleeping in the main
|
||||
loop. Patch # 1190163 Michiel de Hoon
|
||||
|
||||
- Add config-main option to make the 'history' feature non-cyclic.
|
||||
Default remains cyclic. Python Patch 914546 Noam Raphael.
|
||||
|
||||
- Removed ability to configure tabs indent from Options dialog. This 'feature'
|
||||
has never worked and no one has complained. It is still possible to set a
|
||||
default tabs (v. spaces) indent 'manually' via config-main.def (or to turn on
|
||||
tabs for the current EditorWindow via the Format menu) but IDLE will
|
||||
encourage indentation via spaces.
|
||||
|
||||
- Enable setting the indentation width using the Options dialog.
|
||||
Bug # 783877
|
||||
|
||||
- Add keybindings for del-word-left and del-word-right.
|
||||
|
||||
- Discourage using an indent width other than 8 when using tabs to indent
|
||||
Python code.
|
||||
|
||||
- Restore use of EditorWindow.set_indentation_params(), was dead code since
|
||||
Autoindent was merged into EditorWindow. This allows IDLE to conform to the
|
||||
indentation width of a loaded file. (But it still will not switch to tabs
|
||||
even if the file uses tabs.) Any change in indent width is local to that
|
||||
window.
|
||||
|
||||
- Add Tabnanny check before Run/F5, not just when Checking module.
|
||||
|
||||
- If an extension can't be loaded, print warning and skip it instead of
|
||||
erroring out.
|
||||
|
||||
- Improve error handling when .idlerc can't be created (warn and exit).
|
||||
|
||||
- The GUI was hanging if the shell window was closed while a raw_input()
|
||||
was pending. Restored the quit() of the readline() mainloop().
|
||||
http://mail.python.org/pipermail/idle-dev/2004-December/002307.html
|
||||
|
||||
- The remote procedure call module rpc.py can now access data attributes of
|
||||
remote registered objects. Changes to these attributes are local, however.
|
||||
|
||||
What's New in IDLE 1.1?
|
||||
=======================
|
||||
|
||||
*Release date: 30-NOV-2004*
|
||||
|
||||
- On OpenBSD, terminating IDLE with ctrl-c from the command line caused a
|
||||
stuck subprocess MainThread because only the SocketThread was exiting.
|
||||
|
||||
What's New in IDLE 1.1b3/rc1?
|
||||
=============================
|
||||
|
||||
*Release date: 18-NOV-2004*
|
||||
|
||||
- Saving a Keyset w/o making changes (by using the "Save as New Custom Key Set"
|
||||
button) caused IDLE to fail on restart (no new keyset was created in
|
||||
config-keys.cfg). Also true for Theme/highlights. Python Bug 1064535.
|
||||
|
||||
- A change to the linecache.py API caused IDLE to exit when an exception was
|
||||
raised while running without the subprocess (-n switch). Python Bug 1063840.
|
||||
|
||||
What's New in IDLE 1.1b2?
|
||||
=========================
|
||||
|
||||
*Release date: 03-NOV-2004*
|
||||
|
||||
- When paragraph reformat width was made configurable, a bug was
|
||||
introduced that caused reformatting of comment blocks to ignore how
|
||||
far the block was indented, effectively adding the indentation width
|
||||
to the reformat width. This has been repaired, and the reformat
|
||||
width is again a bound on the total width of reformatted lines.
|
||||
|
||||
What's New in IDLE 1.1b1?
|
||||
=========================
|
||||
|
||||
*Release date: 15-OCT-2004*
|
||||
|
||||
|
||||
What's New in IDLE 1.1a3?
|
||||
=========================
|
||||
|
||||
*Release date: 02-SEP-2004*
|
||||
|
||||
- Improve keyboard focus binding, especially in Windows menu. Improve
|
||||
window raising, especially in the Windows menu and in the debugger.
|
||||
IDLEfork 763524.
|
||||
|
||||
- If user passes a non-existent filename on the commandline, just
|
||||
open a new file, don't raise a dialog. IDLEfork 854928.
|
||||
|
||||
|
||||
What's New in IDLE 1.1a2?
|
||||
=========================
|
||||
|
||||
*Release date: 05-AUG-2004*
|
||||
|
||||
- EditorWindow.py was not finding the .chm help file on Windows. Typo
|
||||
at Rev 1.54. Python Bug 990954
|
||||
|
||||
- checking sys.platform for substring 'win' was breaking IDLE docs on Mac
|
||||
(darwin). Also, Mac Safari browser requires full file:// URIs. SF 900580.
|
||||
|
||||
|
||||
What's New in IDLE 1.1a1?
|
||||
=========================
|
||||
|
||||
*Release date: 08-JUL-2004*
|
||||
|
||||
- Redirect the warning stream to the shell during the ScriptBinding check of
|
||||
user code and format the warning similarly to an exception for both that
|
||||
check and for runtime warnings raised in the subprocess.
|
||||
|
||||
- CodeContext hint pane visibility state is now persistent across sessions.
|
||||
The pane no longer appears in the shell window. Added capability to limit
|
||||
extensions to shell window or editor windows. Noam Raphael addition
|
||||
to Patch 936169.
|
||||
|
||||
- Paragraph reformat width is now a configurable parameter in the
|
||||
Options GUI.
|
||||
|
||||
- New Extension: CodeContext. Provides block structuring hints for code
|
||||
which has scrolled above an edit window. Patch 936169 Noam Raphael.
|
||||
|
||||
- If nulls somehow got into the strings in recent-files.lst
|
||||
EditorWindow.update_recent_files_list() was failing. Python Bug 931336.
|
||||
|
||||
- If the normal background is changed via Configure/Highlighting, it will
|
||||
update immediately, thanks to the previously mentioned patch by Nigel Rowe.
|
||||
|
||||
- Add a highlight theme for builtin keywords. Python Patch 805830 Nigel Rowe
|
||||
This also fixed IDLEfork bug [ 693418 ] Normal text background color not
|
||||
refreshed and Python bug [897872 ] Unknown color name on HP-UX
|
||||
|
||||
- rpc.py:SocketIO - Large modules were generating large pickles when downloaded
|
||||
to the execution server. The return of the OK response from the subprocess
|
||||
initialization was interfering and causing the sending socket to be not
|
||||
ready. Add an IO ready test to fix this. Moved the polling IO ready test
|
||||
into pollpacket().
|
||||
|
||||
- Fix typo in rpc.py, s/b "pickle.PicklingError" not "pickle.UnpicklingError".
|
||||
|
||||
- Added a Tk error dialog to run.py inform the user if the subprocess can't
|
||||
connect to the user GUI process. Added a timeout to the GUI's listening
|
||||
socket. Added Tk error dialogs to PyShell.py to announce a failure to bind
|
||||
the port or connect to the subprocess. Clean up error handling during
|
||||
connection initiation phase. This is an update of Python Patch 778323.
|
||||
|
||||
- Print correct exception even if source file changed since shell was
|
||||
restarted. IDLEfork Patch 869012 Noam Raphael
|
||||
|
||||
- Keybindings with the Shift modifier now work correctly. So do bindings which
|
||||
use the Space key. Limit unmodified user keybindings to the function keys.
|
||||
Python Bug 775353, IDLEfork Bugs 755647, 761557
|
||||
|
||||
- After an exception, run.py was not setting the exception vector. Noam
|
||||
Raphael suggested correcting this so pdb's postmortem pm() would work.
|
||||
IDLEfork Patch 844675
|
||||
|
||||
- IDLE now does not fail to save the file anymore if the Tk buffer is not a
|
||||
Unicode string, yet eol_convention is. Python Bugs 774680, 788378
|
||||
|
||||
- IDLE didn't start correctly when Python was installed in "Program Files" on
|
||||
W2K and XP. Python Bugs 780451, 784183
|
||||
|
||||
- config-main.def documentation incorrectly referred to idle- instead of
|
||||
config- filenames. SF 782759 Also added note about .idlerc location.
|
||||
|
||||
|
||||
What's New in IDLE 1.0?
|
||||
=======================
|
||||
|
||||
*Release date: 29-Jul-2003*
|
||||
|
||||
- Added a banner to the shell discussing warnings possibly raised by personal
|
||||
firewall software. Added same comment to README.txt.
|
||||
|
||||
|
||||
What's New in IDLE 1.0 release candidate 2?
|
||||
===========================================
|
||||
|
||||
*Release date: 24-Jul-2003*
|
||||
|
||||
- Calltip error when docstring was None Python Bug 775541
|
||||
|
||||
|
||||
What's New in IDLE 1.0 release candidate 1?
|
||||
===========================================
|
||||
|
||||
*Release date: 18-Jul-2003*
|
||||
|
||||
- Updated extend.txt, help.txt, and config-extensions.def to correctly
|
||||
reflect the current status of the configuration system. Python Bug 768469
|
||||
|
||||
- Fixed: Call Tip Trimming May Loop Forever. Python Patch 769142 (Daniels)
|
||||
|
||||
- Replaced apply(f, args, kwds) with f(*args, **kwargs) to improve performance
|
||||
Python Patch 768187
|
||||
|
||||
- Break or continue statements outside a loop were causing IDLE crash
|
||||
Python Bug 767794
|
||||
|
||||
- Convert Unicode strings from readline to IOBinding.encoding. Also set
|
||||
sys.std{in|out|err}.encoding, for both the local and the subprocess case.
|
||||
SF IDLEfork patch 682347.
|
||||
|
||||
|
||||
What's New in IDLE 1.0b2?
|
||||
=========================
|
||||
|
||||
*Release date: 29-Jun-2003*
|
||||
|
||||
- Extend AboutDialog.ViewFile() to support file encodings. Make the CREDITS
|
||||
file Latin-1.
|
||||
|
||||
- Updated the About dialog to reflect re-integration into Python. Provide
|
||||
buttons to display Python's NEWS, License, and Credits, plus additional
|
||||
buttons for IDLE's README and NEWS.
|
||||
|
||||
- TextViewer() now has a third parameter which allows inserting text into the
|
||||
viewer instead of reading from a file.
|
||||
|
||||
- (Created the .../Lib/idlelib directory in the Python CVS, which is a clone of
|
||||
IDLEfork modified to install in the Python environment. The code in the
|
||||
interrupt module has been moved to thread.interrupt_main(). )
|
||||
|
||||
- Printing the Shell window was failing if it was not saved first SF 748975
|
||||
|
||||
- When using the Search in Files dialog, if the user had a selection
|
||||
highlighted in his Editor window, insert it into the dialog search field.
|
||||
|
||||
- The Python Shell entry was disappearing from the Windows menu.
|
||||
|
||||
- Update the Windows file list when a file name change occurs
|
||||
|
||||
- Change to File / Open Module: always pop up the dialog, using the current
|
||||
selection as the default value. This is easier to use habitually.
|
||||
|
||||
- Avoided a problem with starting the subprocess when 'localhost' doesn't
|
||||
resolve to the user's loopback interface. SF 747772
|
||||
|
||||
- Fixed an issue with highlighted errors never de-colorizing. SF 747677. Also
|
||||
improved notification of Tabnanny Token Error.
|
||||
|
||||
- File / New will by default save in the directory of the Edit window from
|
||||
which it was initiated. SF 748973 Guido van Rossum patch.
|
||||
|
||||
|
||||
What's New in IDLEfork 0.9b1?
|
||||
=============================
|
||||
|
||||
*Release date: 02-Jun-2003*
|
||||
|
||||
- The current working directory of the execution environment (and shell
|
||||
following completion of execution) is now that of the module being run.
|
||||
|
||||
- Added the delete-exitfunc option to config-main.def. (This option is not
|
||||
included in the Options dialog.) Setting this to True (the default) will
|
||||
cause IDLE to not run sys.exitfunc/atexit when the subprocess exits.
|
||||
|
||||
- IDLE now preserves the line ending codes when editing a file produced on
|
||||
a different platform. SF 661759, SF 538584
|
||||
|
||||
- Reduced default editor font size to 10 point and increased window height
|
||||
to provide a better initial impression on Windows.
|
||||
|
||||
- Options / Fonts/Tabs / Set Base Editor Font: List box was not highlighting
|
||||
the default font when first installed on Windows. SF 661676
|
||||
|
||||
- Added Autosave feature: when user runs code from edit window, if the file
|
||||
has been modified IDLE will silently save it if Autosave is enabled. The
|
||||
option is set in the Options dialog, and the default is to prompt the
|
||||
user to save the file. SF 661318 Bruce Sherwood patch.
|
||||
|
||||
- Improved the RESTART annotation in the shell window when the user restarts
|
||||
the shell while it is generating output. Also improved annotation when user
|
||||
repeatedly hammers the Ctrl-F6 restart.
|
||||
|
||||
- Allow IDLE to run when not installed and cwd is not the IDLE directory
|
||||
SF Patch 686254 "Run IDLEfork from any directory without set-up" - Raphael
|
||||
|
||||
- When a module is run from an EditorWindow: if its directory is not in
|
||||
sys.path, prepend it. This allows the module to import other modules in
|
||||
the same directory. Do the same for a script run from the command line.
|
||||
|
||||
- Correctly restart the subprocess if it is running user code and the user
|
||||
attempts to run some other module or restarts the shell. Do the same if
|
||||
the link is broken and it is possible to restart the subprocess and re-
|
||||
connect to the GUI. SF RFE 661321.
|
||||
|
||||
- Improved exception reporting when running commands or scripts from the
|
||||
command line.
|
||||
|
||||
- Added a -n command line switch to start IDLE without the subprocess.
|
||||
Removed the Shell menu when running in that mode. Updated help messages.
|
||||
|
||||
- Added a comment to the shell startup header to indicate when IDLE is not
|
||||
using the subprocess.
|
||||
|
||||
- Restore the ability to run without the subprocess. This can be important for
|
||||
some platforms or configurations. (Running without the subprocess allows the
|
||||
debugger to trace through parts of IDLE itself, which may or may not be
|
||||
desirable, depending on your point of view. In addition, the traditional
|
||||
reload/import tricks must be use if user source code is changed.) This is
|
||||
helpful for developing IDLE using IDLE, because one instance can be used to
|
||||
edit the code and a separate instance run to test changes. (Multiple
|
||||
concurrent IDLE instances with subprocesses is a future feature)
|
||||
|
||||
- Improve the error message a user gets when saving a file with non-ASCII
|
||||
characters and no source encoding is specified. Done by adding a dialog
|
||||
'EncodingMessage', which contains the line to add in a fixed-font entry
|
||||
widget, and which has a button to add that line to the file automatically.
|
||||
Also, add a configuration option 'EditorWindow/encoding', which has three
|
||||
possible values: none, utf-8, and locale. None is the default: IDLE will show
|
||||
this dialog when non-ASCII characters are encountered. utf-8 means that files
|
||||
with non-ASCII characters are saved as utf-8-with-bom. locale means that
|
||||
files are saved in the locale's encoding; the dialog is only displayed if the
|
||||
source contains characters outside the locale's charset. SF 710733 - Loewis
|
||||
|
||||
- Improved I/O response by tweaking the wait parameter in various
|
||||
calls to signal.signal().
|
||||
|
||||
- Implemented a threaded subprocess which allows interrupting a pass
|
||||
loop in user code using the 'interrupt' extension. User code runs
|
||||
in MainThread, while the RPCServer is handled by SockThread. This is
|
||||
necessary because Windows doesn't support signals.
|
||||
|
||||
- Implemented the 'interrupt' extension module, which allows a subthread
|
||||
to raise a KeyboardInterrupt in the main thread.
|
||||
|
||||
- Attempting to save the shell raised an error related to saving
|
||||
breakpoints, which are not implemented in the shell
|
||||
|
||||
- Provide a correct message when 'exit' or 'quit' are entered at the
|
||||
IDLE command prompt SF 695861
|
||||
|
||||
- Eliminate extra blank line in shell output caused by not flushing
|
||||
stdout when user code ends with an unterminated print. SF 695861
|
||||
|
||||
- Moved responsibility for exception formatting (i.e. pruning IDLE internal
|
||||
calls) out of rpc.py into the client and server.
|
||||
|
||||
- Exit IDLE cleanly even when doing subprocess I/O
|
||||
|
||||
- Handle subprocess interrupt with an RPC message.
|
||||
|
||||
- Restart the subprocess if it terminates itself. (VPython programs do that)
|
||||
|
||||
- Support subclassing of exceptions, including in the shell, by moving the
|
||||
exception formatting to the subprocess.
|
||||
|
||||
|
||||
|
||||
What's New in IDLEfork 0.9 Alpha 2?
|
||||
===================================
|
||||
|
||||
*Release date: 27-Jan-2003*
|
||||
|
||||
- Updated INSTALL.txt to claify use of the python2 rpm.
|
||||
|
||||
- Improved formatting in IDLE Help.
|
||||
|
||||
- Run menu: Replace "Run Script" with "Run Module".
|
||||
|
||||
- Code encountering an unhandled exception under the debugger now shows
|
||||
the correct traceback, with IDLE internal levels pruned out.
|
||||
|
||||
- If an exception occurs entirely in IDLE, don't prune the IDLE internal
|
||||
modules from the traceback displayed.
|
||||
|
||||
- Class Browser and Path Browser now use Alt-Key-2 for vertical zoom.
|
||||
|
||||
- IDLE icons will now install correctly even when setup.py is run from the
|
||||
build directory
|
||||
|
||||
- Class Browser now compatible with Python2.3 version of pyclbr.py
|
||||
|
||||
- Left cursor move in presence of selected text now moves from left end
|
||||
of the selection.
|
||||
|
||||
- Add Meta keybindings to "IDLE Classic Windows" to handle reversed
|
||||
Alt/Meta on some Linux distros.
|
||||
|
||||
- Change default: IDLE now starts with Python Shell.
|
||||
|
||||
- Removed the File Path from the Additional Help Sources scrolled list.
|
||||
|
||||
- Add capability to access Additional Help Sources on the web if the
|
||||
Help File Path begins with //http or www. (Otherwise local path is
|
||||
validated, as before.)
|
||||
|
||||
- Additional Help Sources were not being posted on the Help menu in the
|
||||
order entered. Implement sorting the list by [HelpFiles] 'option'
|
||||
number.
|
||||
|
||||
- Add Browse button to New Help Source dialog. Arrange to start in
|
||||
Python/Doc if platform is Windows, otherwise start in current directory.
|
||||
|
||||
- Put the Additional Help Sources directly on the Help menu instead of in
|
||||
an Extra Help cascade menu. Rearrange the Help menu so the Additional
|
||||
Help Sources come last. Update help.txt appropriately.
|
||||
|
||||
- Fix Tk root pop-ups in configSectionNameDialog.py and configDialog.py
|
||||
|
||||
- Uniform capitalization in General tab of ConfigDialog, update the doc string.
|
||||
|
||||
- Fix bug in ConfigDialog where SaveAllChangedConfig() was unexpectedly
|
||||
deleting Additional Help Sources from the user's config file.
|
||||
|
||||
- Make configHelpSourceEdit OK button the default and bind <Return>
|
||||
|
||||
- Fix Tk root pop-ups in configHelpSourceEdit: error dialogs not attached
|
||||
to parents.
|
||||
|
||||
- Use os.startfile() to open both Additional Help and Python Help on the
|
||||
Windows platform. The application associated with the file type will act as
|
||||
the viewer. Windows help files (.chm) are now supported via the
|
||||
Settings/General/Additional Help facility.
|
||||
|
||||
- If Python Help files are installed locally on Linux, use them instead of
|
||||
accessing python.org.
|
||||
|
||||
- Make the methods for finding the Python help docs more robust, and make
|
||||
them work in the installed configuration, also.
|
||||
|
||||
- On the Save Before Run dialog, make the OK button the default. One
|
||||
less mouse action!
|
||||
|
||||
- Add a method: EditorWindow.get_geometry() for future use in implementing
|
||||
window location persistence.
|
||||
|
||||
- Removed the "Help/Advice" menu entry. Thanks, David! We'll remember!
|
||||
|
||||
- Change the "Classic Windows" theme's paste key to be <ctrl-v>.
|
||||
|
||||
- Rearrange the Shell menu to put Stack Viewer entries adjacent.
|
||||
|
||||
- Add the ability to restart the subprocess interpreter from the shell window;
|
||||
add an associated menu entry "Shell/Restart" with binding Control-F6. Update
|
||||
IDLE help.
|
||||
|
||||
- Upon a restart, annotate the shell window with a "restart boundary". Add a
|
||||
shell window menu "Shell/View Restart" with binding F6 to jump to the most
|
||||
recent restart boundary.
|
||||
|
||||
- Add Shell menu to Python Shell; change "Settings" to "Options".
|
||||
|
||||
- Remove incorrect comment in setup.py: IDLEfork is now installed as a package.
|
||||
|
||||
- Add INSTALL.txt, HISTORY.txt, NEWS.txt to installed configuration.
|
||||
|
||||
- In installer text, fix reference to Visual Python, should be VPython.
|
||||
Properly credit David Scherer.
|
||||
|
||||
- Modified idle, idle.py, idle.pyw to improve exception handling.
|
||||
|
||||
|
||||
What's New in IDLEfork 0.9 Alpha 1?
|
||||
===================================
|
||||
|
||||
*Release date: 31-Dec-2002*
|
||||
|
||||
- First release of major new functionality. For further details refer to
|
||||
Idle-dev and/or the Sourceforge CVS.
|
||||
|
||||
- Adapted to the Mac platform.
|
||||
|
||||
- Overhauled the IDLE startup options and revised the idle -h help message,
|
||||
which provides details of command line usage.
|
||||
|
||||
- Multiple bug fixes and usability enhancements.
|
||||
|
||||
- Introduced the new RPC implementation, which includes a debugger. The output
|
||||
of user code is to the shell, and the shell may be used to inspect the
|
||||
environment after the run has finished. (In version 0.8.1 the shell
|
||||
environment was separate from the environment of the user code.)
|
||||
|
||||
- Introduced the configuration GUI and a new About dialog.
|
||||
|
||||
- Removed David Scherer's Remote Procedure Call code and replaced with Guido
|
||||
van Rossum's. GvR code has support for the IDLE debugger and uses the shell
|
||||
to inspect the environment of code Run from an Edit window. Files removed:
|
||||
ExecBinding.py, loader.py, protocol.py, Remote.py, spawn.py
|
||||
|
||||
--------------------------------------------------------------------
|
||||
Refer to HISTORY.txt for additional information on earlier releases.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
151
Darwin/lib/python2.7/idlelib/ObjectBrowser.py
Normal file
151
Darwin/lib/python2.7/idlelib/ObjectBrowser.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# XXX TO DO:
|
||||
# - popup menu
|
||||
# - support partial or total redisplay
|
||||
# - more doc strings
|
||||
# - tooltips
|
||||
|
||||
# object browser
|
||||
|
||||
# XXX TO DO:
|
||||
# - for classes/modules, add "open source" to object browser
|
||||
|
||||
from idlelib.TreeWidget import TreeItem, TreeNode, ScrolledCanvas
|
||||
|
||||
from repr import Repr
|
||||
|
||||
myrepr = Repr()
|
||||
myrepr.maxstring = 100
|
||||
myrepr.maxother = 100
|
||||
|
||||
class ObjectTreeItem(TreeItem):
|
||||
def __init__(self, labeltext, object, setfunction=None):
|
||||
self.labeltext = labeltext
|
||||
self.object = object
|
||||
self.setfunction = setfunction
|
||||
def GetLabelText(self):
|
||||
return self.labeltext
|
||||
def GetText(self):
|
||||
return myrepr.repr(self.object)
|
||||
def GetIconName(self):
|
||||
if not self.IsExpandable():
|
||||
return "python"
|
||||
def IsEditable(self):
|
||||
return self.setfunction is not None
|
||||
def SetText(self, text):
|
||||
try:
|
||||
value = eval(text)
|
||||
self.setfunction(value)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.object = value
|
||||
def IsExpandable(self):
|
||||
return not not dir(self.object)
|
||||
def GetSubList(self):
|
||||
keys = dir(self.object)
|
||||
sublist = []
|
||||
for key in keys:
|
||||
try:
|
||||
value = getattr(self.object, key)
|
||||
except AttributeError:
|
||||
continue
|
||||
item = make_objecttreeitem(
|
||||
str(key) + " =",
|
||||
value,
|
||||
lambda value, key=key, object=self.object:
|
||||
setattr(object, key, value))
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
class InstanceTreeItem(ObjectTreeItem):
|
||||
def IsExpandable(self):
|
||||
return True
|
||||
def GetSubList(self):
|
||||
sublist = ObjectTreeItem.GetSubList(self)
|
||||
sublist.insert(0,
|
||||
make_objecttreeitem("__class__ =", self.object.__class__))
|
||||
return sublist
|
||||
|
||||
class ClassTreeItem(ObjectTreeItem):
|
||||
def IsExpandable(self):
|
||||
return True
|
||||
def GetSubList(self):
|
||||
sublist = ObjectTreeItem.GetSubList(self)
|
||||
if len(self.object.__bases__) == 1:
|
||||
item = make_objecttreeitem("__bases__[0] =",
|
||||
self.object.__bases__[0])
|
||||
else:
|
||||
item = make_objecttreeitem("__bases__ =", self.object.__bases__)
|
||||
sublist.insert(0, item)
|
||||
return sublist
|
||||
|
||||
class AtomicObjectTreeItem(ObjectTreeItem):
|
||||
def IsExpandable(self):
|
||||
return 0
|
||||
|
||||
class SequenceTreeItem(ObjectTreeItem):
|
||||
def IsExpandable(self):
|
||||
return len(self.object) > 0
|
||||
def keys(self):
|
||||
return range(len(self.object))
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for key in self.keys():
|
||||
try:
|
||||
value = self.object[key]
|
||||
except KeyError:
|
||||
continue
|
||||
def setfunction(value, key=key, object=self.object):
|
||||
object[key] = value
|
||||
item = make_objecttreeitem("%r:" % (key,), value, setfunction)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
class DictTreeItem(SequenceTreeItem):
|
||||
def keys(self):
|
||||
keys = self.object.keys()
|
||||
try:
|
||||
keys.sort()
|
||||
except:
|
||||
pass
|
||||
return keys
|
||||
|
||||
from types import *
|
||||
|
||||
dispatch = {
|
||||
IntType: AtomicObjectTreeItem,
|
||||
LongType: AtomicObjectTreeItem,
|
||||
FloatType: AtomicObjectTreeItem,
|
||||
StringType: AtomicObjectTreeItem,
|
||||
TupleType: SequenceTreeItem,
|
||||
ListType: SequenceTreeItem,
|
||||
DictType: DictTreeItem,
|
||||
InstanceType: InstanceTreeItem,
|
||||
ClassType: ClassTreeItem,
|
||||
}
|
||||
|
||||
def make_objecttreeitem(labeltext, object, setfunction=None):
|
||||
t = type(object)
|
||||
if t in dispatch:
|
||||
c = dispatch[t]
|
||||
else:
|
||||
c = ObjectTreeItem
|
||||
return c(labeltext, object, setfunction)
|
||||
|
||||
# Test script
|
||||
|
||||
def _test():
|
||||
import sys
|
||||
from Tkinter import Tk
|
||||
root = Tk()
|
||||
root.configure(bd=0, bg="yellow")
|
||||
root.focus_set()
|
||||
sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1)
|
||||
sc.frame.pack(expand=1, fill="both")
|
||||
item = make_objecttreeitem("sys", sys)
|
||||
node = TreeNode(sc.canvas, None, item)
|
||||
node.update()
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
||||
149
Darwin/lib/python2.7/idlelib/OutputWindow.py
Normal file
149
Darwin/lib/python2.7/idlelib/OutputWindow.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
from Tkinter import *
|
||||
from idlelib.EditorWindow import EditorWindow
|
||||
import re
|
||||
import tkMessageBox
|
||||
from idlelib import IOBinding
|
||||
|
||||
class OutputWindow(EditorWindow):
|
||||
|
||||
"""An editor window that can serve as an output file.
|
||||
|
||||
Also the future base class for the Python shell window.
|
||||
This class has no input facilities.
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
EditorWindow.__init__(self, *args)
|
||||
self.text.bind("<<goto-file-line>>", self.goto_file_line)
|
||||
|
||||
# Customize EditorWindow
|
||||
|
||||
def ispythonsource(self, filename):
|
||||
# No colorization needed
|
||||
return 0
|
||||
|
||||
def short_title(self):
|
||||
return "Output"
|
||||
|
||||
def maybesave(self):
|
||||
# Override base class method -- don't ask any questions
|
||||
if self.get_saved():
|
||||
return "yes"
|
||||
else:
|
||||
return "no"
|
||||
|
||||
# Act as output file
|
||||
|
||||
def write(self, s, tags=(), mark="insert"):
|
||||
# Tk assumes that byte strings are Latin-1;
|
||||
# we assume that they are in the locale's encoding
|
||||
if isinstance(s, str):
|
||||
try:
|
||||
s = unicode(s, IOBinding.encoding)
|
||||
except UnicodeError:
|
||||
# some other encoding; let Tcl deal with it
|
||||
pass
|
||||
self.text.insert(mark, s, tags)
|
||||
self.text.see(mark)
|
||||
self.text.update()
|
||||
|
||||
def writelines(self, lines):
|
||||
for line in lines:
|
||||
self.write(line)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
# Our own right-button menu
|
||||
|
||||
rmenu_specs = [
|
||||
("Cut", "<<cut>>", "rmenu_check_cut"),
|
||||
("Copy", "<<copy>>", "rmenu_check_copy"),
|
||||
("Paste", "<<paste>>", "rmenu_check_paste"),
|
||||
(None, None, None),
|
||||
("Go to file/line", "<<goto-file-line>>", None),
|
||||
]
|
||||
|
||||
file_line_pats = [
|
||||
# order of patterns matters
|
||||
r'file "([^"]*)", line (\d+)',
|
||||
r'([^\s]+)\((\d+)\)',
|
||||
r'^(\s*\S.*?):\s*(\d+):', # Win filename, maybe starting with spaces
|
||||
r'([^\s]+):\s*(\d+):', # filename or path, ltrim
|
||||
r'^\s*(\S.*?):\s*(\d+):', # Win abs path with embedded spaces, ltrim
|
||||
]
|
||||
|
||||
file_line_progs = None
|
||||
|
||||
def goto_file_line(self, event=None):
|
||||
if self.file_line_progs is None:
|
||||
l = []
|
||||
for pat in self.file_line_pats:
|
||||
l.append(re.compile(pat, re.IGNORECASE))
|
||||
self.file_line_progs = l
|
||||
# x, y = self.event.x, self.event.y
|
||||
# self.text.mark_set("insert", "@%d,%d" % (x, y))
|
||||
line = self.text.get("insert linestart", "insert lineend")
|
||||
result = self._file_line_helper(line)
|
||||
if not result:
|
||||
# Try the previous line. This is handy e.g. in tracebacks,
|
||||
# where you tend to right-click on the displayed source line
|
||||
line = self.text.get("insert -1line linestart",
|
||||
"insert -1line lineend")
|
||||
result = self._file_line_helper(line)
|
||||
if not result:
|
||||
tkMessageBox.showerror(
|
||||
"No special line",
|
||||
"The line you point at doesn't look like "
|
||||
"a valid file name followed by a line number.",
|
||||
master=self.text)
|
||||
return
|
||||
filename, lineno = result
|
||||
edit = self.flist.open(filename)
|
||||
edit.gotoline(lineno)
|
||||
|
||||
def _file_line_helper(self, line):
|
||||
for prog in self.file_line_progs:
|
||||
match = prog.search(line)
|
||||
if match:
|
||||
filename, lineno = match.group(1, 2)
|
||||
try:
|
||||
f = open(filename, "r")
|
||||
f.close()
|
||||
break
|
||||
except IOError:
|
||||
continue
|
||||
else:
|
||||
return None
|
||||
try:
|
||||
return filename, int(lineno)
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
# These classes are currently not used but might come in handy
|
||||
|
||||
class OnDemandOutputWindow:
|
||||
|
||||
tagdefs = {
|
||||
# XXX Should use IdlePrefs.ColorPrefs
|
||||
"stdout": {"foreground": "blue"},
|
||||
"stderr": {"foreground": "#007700"},
|
||||
}
|
||||
|
||||
def __init__(self, flist):
|
||||
self.flist = flist
|
||||
self.owin = None
|
||||
|
||||
def write(self, s, tags, mark):
|
||||
if not self.owin:
|
||||
self.setup()
|
||||
self.owin.write(s, tags, mark)
|
||||
|
||||
def setup(self):
|
||||
self.owin = owin = OutputWindow(self.flist)
|
||||
text = owin.text
|
||||
for tag, cnf in self.tagdefs.items():
|
||||
if cnf:
|
||||
text.tag_configure(tag, **cnf)
|
||||
text.tag_raise('sel')
|
||||
self.write = self.owin.write
|
||||
172
Darwin/lib/python2.7/idlelib/ParenMatch.py
Normal file
172
Darwin/lib/python2.7/idlelib/ParenMatch.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
"""ParenMatch -- An IDLE extension for parenthesis matching.
|
||||
|
||||
When you hit a right paren, the cursor should move briefly to the left
|
||||
paren. Paren here is used generically; the matching applies to
|
||||
parentheses, square brackets, and curly braces.
|
||||
"""
|
||||
|
||||
from idlelib.HyperParser import HyperParser
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
_openers = {')':'(',']':'[','}':'{'}
|
||||
CHECK_DELAY = 100 # miliseconds
|
||||
|
||||
class ParenMatch:
|
||||
"""Highlight matching parentheses
|
||||
|
||||
There are three supported style of paren matching, based loosely
|
||||
on the Emacs options. The style is select based on the
|
||||
HILITE_STYLE attribute; it can be changed used the set_style
|
||||
method.
|
||||
|
||||
The supported styles are:
|
||||
|
||||
default -- When a right paren is typed, highlight the matching
|
||||
left paren for 1/2 sec.
|
||||
|
||||
expression -- When a right paren is typed, highlight the entire
|
||||
expression from the left paren to the right paren.
|
||||
|
||||
TODO:
|
||||
- extend IDLE with configuration dialog to change options
|
||||
- implement rest of Emacs highlight styles (see below)
|
||||
- print mismatch warning in IDLE status window
|
||||
|
||||
Note: In Emacs, there are several styles of highlight where the
|
||||
matching paren is highlighted whenever the cursor is immediately
|
||||
to the right of a right paren. I don't know how to do that in Tk,
|
||||
so I haven't bothered.
|
||||
"""
|
||||
menudefs = [
|
||||
('edit', [
|
||||
("Show surrounding parens", "<<flash-paren>>"),
|
||||
])
|
||||
]
|
||||
STYLE = idleConf.GetOption('extensions','ParenMatch','style',
|
||||
default='expression')
|
||||
FLASH_DELAY = idleConf.GetOption('extensions','ParenMatch','flash-delay',
|
||||
type='int',default=500)
|
||||
HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(),'hilite')
|
||||
BELL = idleConf.GetOption('extensions','ParenMatch','bell',
|
||||
type='bool',default=1)
|
||||
|
||||
RESTORE_VIRTUAL_EVENT_NAME = "<<parenmatch-check-restore>>"
|
||||
# We want the restore event be called before the usual return and
|
||||
# backspace events.
|
||||
RESTORE_SEQUENCES = ("<KeyPress>", "<ButtonPress>",
|
||||
"<Key-Return>", "<Key-BackSpace>")
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.text = editwin.text
|
||||
# Bind the check-restore event to the function restore_event,
|
||||
# so that we can then use activate_restore (which calls event_add)
|
||||
# and deactivate_restore (which calls event_delete).
|
||||
editwin.text.bind(self.RESTORE_VIRTUAL_EVENT_NAME,
|
||||
self.restore_event)
|
||||
self.counter = 0
|
||||
self.is_restore_active = 0
|
||||
self.set_style(self.STYLE)
|
||||
|
||||
def activate_restore(self):
|
||||
if not self.is_restore_active:
|
||||
for seq in self.RESTORE_SEQUENCES:
|
||||
self.text.event_add(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.is_restore_active = True
|
||||
|
||||
def deactivate_restore(self):
|
||||
if self.is_restore_active:
|
||||
for seq in self.RESTORE_SEQUENCES:
|
||||
self.text.event_delete(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
|
||||
self.is_restore_active = False
|
||||
|
||||
def set_style(self, style):
|
||||
self.STYLE = style
|
||||
if style == "default":
|
||||
self.create_tag = self.create_tag_default
|
||||
self.set_timeout = self.set_timeout_last
|
||||
elif style == "expression":
|
||||
self.create_tag = self.create_tag_expression
|
||||
self.set_timeout = self.set_timeout_none
|
||||
|
||||
def flash_paren_event(self, event):
|
||||
indices = HyperParser(self.editwin, "insert").get_surrounding_brackets()
|
||||
if indices is None:
|
||||
self.warn_mismatched()
|
||||
return
|
||||
self.activate_restore()
|
||||
self.create_tag(indices)
|
||||
self.set_timeout_last()
|
||||
|
||||
def paren_closed_event(self, event):
|
||||
# If it was a shortcut and not really a closing paren, quit.
|
||||
closer = self.text.get("insert-1c")
|
||||
if closer not in _openers:
|
||||
return
|
||||
hp = HyperParser(self.editwin, "insert-1c")
|
||||
if not hp.is_in_code():
|
||||
return
|
||||
indices = hp.get_surrounding_brackets(_openers[closer], True)
|
||||
if indices is None:
|
||||
self.warn_mismatched()
|
||||
return
|
||||
self.activate_restore()
|
||||
self.create_tag(indices)
|
||||
self.set_timeout()
|
||||
|
||||
def restore_event(self, event=None):
|
||||
self.text.tag_delete("paren")
|
||||
self.deactivate_restore()
|
||||
self.counter += 1 # disable the last timer, if there is one.
|
||||
|
||||
def handle_restore_timer(self, timer_count):
|
||||
if timer_count == self.counter:
|
||||
self.restore_event()
|
||||
|
||||
def warn_mismatched(self):
|
||||
if self.BELL:
|
||||
self.text.bell()
|
||||
|
||||
# any one of the create_tag_XXX methods can be used depending on
|
||||
# the style
|
||||
|
||||
def create_tag_default(self, indices):
|
||||
"""Highlight the single paren that matches"""
|
||||
self.text.tag_add("paren", indices[0])
|
||||
self.text.tag_config("paren", self.HILITE_CONFIG)
|
||||
|
||||
def create_tag_expression(self, indices):
|
||||
"""Highlight the entire expression"""
|
||||
if self.text.get(indices[1]) in (')', ']', '}'):
|
||||
rightindex = indices[1]+"+1c"
|
||||
else:
|
||||
rightindex = indices[1]
|
||||
self.text.tag_add("paren", indices[0], rightindex)
|
||||
self.text.tag_config("paren", self.HILITE_CONFIG)
|
||||
|
||||
# any one of the set_timeout_XXX methods can be used depending on
|
||||
# the style
|
||||
|
||||
def set_timeout_none(self):
|
||||
"""Highlight will remain until user input turns it off
|
||||
or the insert has moved"""
|
||||
# After CHECK_DELAY, call a function which disables the "paren" tag
|
||||
# if the event is for the most recent timer and the insert has changed,
|
||||
# or schedules another call for itself.
|
||||
self.counter += 1
|
||||
def callme(callme, self=self, c=self.counter,
|
||||
index=self.text.index("insert")):
|
||||
if index != self.text.index("insert"):
|
||||
self.handle_restore_timer(c)
|
||||
else:
|
||||
self.editwin.text_frame.after(CHECK_DELAY, callme, callme)
|
||||
self.editwin.text_frame.after(CHECK_DELAY, callme, callme)
|
||||
|
||||
def set_timeout_last(self):
|
||||
"""The last highlight created will be removed after .5 sec"""
|
||||
# associate a counter with an event; only disable the "paren"
|
||||
# tag if the event is for the most recent timer.
|
||||
self.counter += 1
|
||||
self.editwin.text_frame.after(self.FLASH_DELAY,
|
||||
lambda self=self, c=self.counter: \
|
||||
self.handle_restore_timer(c))
|
||||
96
Darwin/lib/python2.7/idlelib/PathBrowser.py
Normal file
96
Darwin/lib/python2.7/idlelib/PathBrowser.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import os
|
||||
import sys
|
||||
import imp
|
||||
|
||||
from idlelib.TreeWidget import TreeItem
|
||||
from idlelib.ClassBrowser import ClassBrowser, ModuleBrowserTreeItem
|
||||
|
||||
class PathBrowser(ClassBrowser):
|
||||
|
||||
def __init__(self, flist):
|
||||
self.init(flist)
|
||||
|
||||
def settitle(self):
|
||||
self.top.wm_title("Path Browser")
|
||||
self.top.wm_iconname("Path Browser")
|
||||
|
||||
def rootnode(self):
|
||||
return PathBrowserTreeItem()
|
||||
|
||||
class PathBrowserTreeItem(TreeItem):
|
||||
|
||||
def GetText(self):
|
||||
return "sys.path"
|
||||
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for dir in sys.path:
|
||||
item = DirBrowserTreeItem(dir)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
class DirBrowserTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, dir, packages=[]):
|
||||
self.dir = dir
|
||||
self.packages = packages
|
||||
|
||||
def GetText(self):
|
||||
if not self.packages:
|
||||
return self.dir
|
||||
else:
|
||||
return self.packages[-1] + ": package"
|
||||
|
||||
def GetSubList(self):
|
||||
try:
|
||||
names = os.listdir(self.dir or os.curdir)
|
||||
except os.error:
|
||||
return []
|
||||
packages = []
|
||||
for name in names:
|
||||
file = os.path.join(self.dir, name)
|
||||
if self.ispackagedir(file):
|
||||
nn = os.path.normcase(name)
|
||||
packages.append((nn, name, file))
|
||||
packages.sort()
|
||||
sublist = []
|
||||
for nn, name, file in packages:
|
||||
item = DirBrowserTreeItem(file, self.packages + [name])
|
||||
sublist.append(item)
|
||||
for nn, name in self.listmodules(names):
|
||||
item = ModuleBrowserTreeItem(os.path.join(self.dir, name))
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
def ispackagedir(self, file):
|
||||
if not os.path.isdir(file):
|
||||
return 0
|
||||
init = os.path.join(file, "__init__.py")
|
||||
return os.path.exists(init)
|
||||
|
||||
def listmodules(self, allnames):
|
||||
modules = {}
|
||||
suffixes = imp.get_suffixes()
|
||||
sorted = []
|
||||
for suff, mode, flag in suffixes:
|
||||
i = -len(suff)
|
||||
for name in allnames[:]:
|
||||
normed_name = os.path.normcase(name)
|
||||
if normed_name[i:] == suff:
|
||||
mod_name = name[:i]
|
||||
if mod_name not in modules:
|
||||
modules[mod_name] = None
|
||||
sorted.append((normed_name, name))
|
||||
allnames.remove(name)
|
||||
sorted.sort()
|
||||
return sorted
|
||||
|
||||
def main():
|
||||
from idlelib import PyShell
|
||||
PathBrowser(PyShell.flist)
|
||||
if sys.stdin is sys.__stdin__:
|
||||
mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
from unittest import main
|
||||
main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False)
|
||||
85
Darwin/lib/python2.7/idlelib/Percolator.py
Normal file
85
Darwin/lib/python2.7/idlelib/Percolator.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
from idlelib.WidgetRedirector import WidgetRedirector
|
||||
from idlelib.Delegator import Delegator
|
||||
|
||||
class Percolator:
|
||||
|
||||
def __init__(self, text):
|
||||
# XXX would be nice to inherit from Delegator
|
||||
self.text = text
|
||||
self.redir = WidgetRedirector(text)
|
||||
self.top = self.bottom = Delegator(text)
|
||||
self.bottom.insert = self.redir.register("insert", self.insert)
|
||||
self.bottom.delete = self.redir.register("delete", self.delete)
|
||||
self.filters = []
|
||||
|
||||
def close(self):
|
||||
while self.top is not self.bottom:
|
||||
self.removefilter(self.top)
|
||||
self.top = None
|
||||
self.bottom.setdelegate(None); self.bottom = None
|
||||
self.redir.close(); self.redir = None
|
||||
self.text = None
|
||||
|
||||
def insert(self, index, chars, tags=None):
|
||||
# Could go away if inheriting from Delegator
|
||||
self.top.insert(index, chars, tags)
|
||||
|
||||
def delete(self, index1, index2=None):
|
||||
# Could go away if inheriting from Delegator
|
||||
self.top.delete(index1, index2)
|
||||
|
||||
def insertfilter(self, filter):
|
||||
# Perhaps rename to pushfilter()?
|
||||
assert isinstance(filter, Delegator)
|
||||
assert filter.delegate is None
|
||||
filter.setdelegate(self.top)
|
||||
self.top = filter
|
||||
|
||||
def removefilter(self, filter):
|
||||
# XXX Perhaps should only support popfilter()?
|
||||
assert isinstance(filter, Delegator)
|
||||
assert filter.delegate is not None
|
||||
f = self.top
|
||||
if f is filter:
|
||||
self.top = filter.delegate
|
||||
filter.setdelegate(None)
|
||||
else:
|
||||
while f.delegate is not filter:
|
||||
assert f is not self.bottom
|
||||
f.resetcache()
|
||||
f = f.delegate
|
||||
f.setdelegate(filter.delegate)
|
||||
filter.setdelegate(None)
|
||||
|
||||
|
||||
def main():
|
||||
class Tracer(Delegator):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
Delegator.__init__(self, None)
|
||||
def insert(self, *args):
|
||||
print self.name, ": insert", args
|
||||
self.delegate.insert(*args)
|
||||
def delete(self, *args):
|
||||
print self.name, ": delete", args
|
||||
self.delegate.delete(*args)
|
||||
root = Tk()
|
||||
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
|
||||
text = Text()
|
||||
text.pack()
|
||||
text.focus_set()
|
||||
p = Percolator(text)
|
||||
t1 = Tracer("t1")
|
||||
t2 = Tracer("t2")
|
||||
p.insertfilter(t1)
|
||||
p.insertfilter(t2)
|
||||
root.mainloop()
|
||||
p.removefilter(t2)
|
||||
root.mainloop()
|
||||
p.insertfilter(t2)
|
||||
p.removefilter(t1)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
from Tkinter import *
|
||||
main()
|
||||
594
Darwin/lib/python2.7/idlelib/PyParse.py
Normal file
594
Darwin/lib/python2.7/idlelib/PyParse.py
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
# Reason last stmt is continued (or C_NONE if it's not).
|
||||
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE,
|
||||
C_STRING_NEXT_LINES, C_BRACKET) = range(5)
|
||||
|
||||
if 0: # for throwaway debugging output
|
||||
def dump(*stuff):
|
||||
sys.__stdout__.write(" ".join(map(str, stuff)) + "\n")
|
||||
|
||||
# Find what looks like the start of a popular stmt.
|
||||
|
||||
_synchre = re.compile(r"""
|
||||
^
|
||||
[ \t]*
|
||||
(?: while
|
||||
| else
|
||||
| def
|
||||
| return
|
||||
| assert
|
||||
| break
|
||||
| class
|
||||
| continue
|
||||
| elif
|
||||
| try
|
||||
| except
|
||||
| raise
|
||||
| import
|
||||
| yield
|
||||
)
|
||||
\b
|
||||
""", re.VERBOSE | re.MULTILINE).search
|
||||
|
||||
# Match blank line or non-indenting comment line.
|
||||
|
||||
_junkre = re.compile(r"""
|
||||
[ \t]*
|
||||
(?: \# \S .* )?
|
||||
\n
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Match any flavor of string; the terminating quote is optional
|
||||
# so that we're robust in the face of incomplete program text.
|
||||
|
||||
_match_stringre = re.compile(r"""
|
||||
\""" [^"\\]* (?:
|
||||
(?: \\. | "(?!"") )
|
||||
[^"\\]*
|
||||
)*
|
||||
(?: \""" )?
|
||||
|
||||
| " [^"\\\n]* (?: \\. [^"\\\n]* )* "?
|
||||
|
||||
| ''' [^'\\]* (?:
|
||||
(?: \\. | '(?!'') )
|
||||
[^'\\]*
|
||||
)*
|
||||
(?: ''' )?
|
||||
|
||||
| ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
|
||||
""", re.VERBOSE | re.DOTALL).match
|
||||
|
||||
# Match a line that starts with something interesting;
|
||||
# used to find the first item of a bracket structure.
|
||||
|
||||
_itemre = re.compile(r"""
|
||||
[ \t]*
|
||||
[^\s#\\] # if we match, m.end()-1 is the interesting char
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Match start of stmts that should be followed by a dedent.
|
||||
|
||||
_closere = re.compile(r"""
|
||||
\s*
|
||||
(?: return
|
||||
| break
|
||||
| continue
|
||||
| raise
|
||||
| pass
|
||||
)
|
||||
\b
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Chew up non-special chars as quickly as possible. If match is
|
||||
# successful, m.end() less 1 is the index of the last boring char
|
||||
# matched. If match is unsuccessful, the string starts with an
|
||||
# interesting char.
|
||||
|
||||
_chew_ordinaryre = re.compile(r"""
|
||||
[^[\](){}#'"\\]+
|
||||
""", re.VERBOSE).match
|
||||
|
||||
# Build translation table to map uninteresting chars to "x", open
|
||||
# brackets to "(", and close brackets to ")".
|
||||
|
||||
_tran = ['x'] * 256
|
||||
for ch in "({[":
|
||||
_tran[ord(ch)] = '('
|
||||
for ch in ")}]":
|
||||
_tran[ord(ch)] = ')'
|
||||
for ch in "\"'\\\n#":
|
||||
_tran[ord(ch)] = ch
|
||||
_tran = ''.join(_tran)
|
||||
del ch
|
||||
|
||||
try:
|
||||
UnicodeType = type(unicode(""))
|
||||
except NameError:
|
||||
UnicodeType = None
|
||||
|
||||
class Parser:
|
||||
|
||||
def __init__(self, indentwidth, tabwidth):
|
||||
self.indentwidth = indentwidth
|
||||
self.tabwidth = tabwidth
|
||||
|
||||
def set_str(self, str):
|
||||
assert len(str) == 0 or str[-1] == '\n'
|
||||
if type(str) is UnicodeType:
|
||||
# The parse functions have no idea what to do with Unicode, so
|
||||
# replace all Unicode characters with "x". This is "safe"
|
||||
# so long as the only characters germane to parsing the structure
|
||||
# of Python are 7-bit ASCII. It's *necessary* because Unicode
|
||||
# strings don't have a .translate() method that supports
|
||||
# deletechars.
|
||||
uniphooey = str
|
||||
str = []
|
||||
push = str.append
|
||||
for raw in map(ord, uniphooey):
|
||||
push(raw < 127 and chr(raw) or "x")
|
||||
str = "".join(str)
|
||||
self.str = str
|
||||
self.study_level = 0
|
||||
|
||||
# Return index of a good place to begin parsing, as close to the
|
||||
# end of the string as possible. This will be the start of some
|
||||
# popular stmt like "if" or "def". Return None if none found:
|
||||
# the caller should pass more prior context then, if possible, or
|
||||
# if not (the entire program text up until the point of interest
|
||||
# has already been tried) pass 0 to set_lo.
|
||||
#
|
||||
# This will be reliable iff given a reliable is_char_in_string
|
||||
# function, meaning that when it says "no", it's absolutely
|
||||
# guaranteed that the char is not in a string.
|
||||
|
||||
def find_good_parse_start(self, is_char_in_string=None,
|
||||
_synchre=_synchre):
|
||||
str, pos = self.str, None
|
||||
|
||||
if not is_char_in_string:
|
||||
# no clue -- make the caller pass everything
|
||||
return None
|
||||
|
||||
# Peek back from the end for a good place to start,
|
||||
# but don't try too often; pos will be left None, or
|
||||
# bumped to a legitimate synch point.
|
||||
limit = len(str)
|
||||
for tries in range(5):
|
||||
i = str.rfind(":\n", 0, limit)
|
||||
if i < 0:
|
||||
break
|
||||
i = str.rfind('\n', 0, i) + 1 # start of colon line
|
||||
m = _synchre(str, i, limit)
|
||||
if m and not is_char_in_string(m.start()):
|
||||
pos = m.start()
|
||||
break
|
||||
limit = i
|
||||
if pos is None:
|
||||
# Nothing looks like a block-opener, or stuff does
|
||||
# but is_char_in_string keeps returning true; most likely
|
||||
# we're in or near a giant string, the colorizer hasn't
|
||||
# caught up enough to be helpful, or there simply *aren't*
|
||||
# any interesting stmts. In any of these cases we're
|
||||
# going to have to parse the whole thing to be sure, so
|
||||
# give it one last try from the start, but stop wasting
|
||||
# time here regardless of the outcome.
|
||||
m = _synchre(str)
|
||||
if m and not is_char_in_string(m.start()):
|
||||
pos = m.start()
|
||||
return pos
|
||||
|
||||
# Peeking back worked; look forward until _synchre no longer
|
||||
# matches.
|
||||
i = pos + 1
|
||||
while 1:
|
||||
m = _synchre(str, i)
|
||||
if m:
|
||||
s, i = m.span()
|
||||
if not is_char_in_string(s):
|
||||
pos = s
|
||||
else:
|
||||
break
|
||||
return pos
|
||||
|
||||
# Throw away the start of the string. Intended to be called with
|
||||
# find_good_parse_start's result.
|
||||
|
||||
def set_lo(self, lo):
|
||||
assert lo == 0 or self.str[lo-1] == '\n'
|
||||
if lo > 0:
|
||||
self.str = self.str[lo:]
|
||||
|
||||
# As quickly as humanly possible <wink>, find the line numbers (0-
|
||||
# based) of the non-continuation lines.
|
||||
# Creates self.{goodlines, continuation}.
|
||||
|
||||
def _study1(self):
|
||||
if self.study_level >= 1:
|
||||
return
|
||||
self.study_level = 1
|
||||
|
||||
# Map all uninteresting characters to "x", all open brackets
|
||||
# to "(", all close brackets to ")", then collapse runs of
|
||||
# uninteresting characters. This can cut the number of chars
|
||||
# by a factor of 10-40, and so greatly speed the following loop.
|
||||
str = self.str
|
||||
str = str.translate(_tran)
|
||||
str = str.replace('xxxxxxxx', 'x')
|
||||
str = str.replace('xxxx', 'x')
|
||||
str = str.replace('xx', 'x')
|
||||
str = str.replace('xx', 'x')
|
||||
str = str.replace('\nx', '\n')
|
||||
# note that replacing x\n with \n would be incorrect, because
|
||||
# x may be preceded by a backslash
|
||||
|
||||
# March over the squashed version of the program, accumulating
|
||||
# the line numbers of non-continued stmts, and determining
|
||||
# whether & why the last stmt is a continuation.
|
||||
continuation = C_NONE
|
||||
level = lno = 0 # level is nesting level; lno is line number
|
||||
self.goodlines = goodlines = [0]
|
||||
push_good = goodlines.append
|
||||
i, n = 0, len(str)
|
||||
while i < n:
|
||||
ch = str[i]
|
||||
i = i+1
|
||||
|
||||
# cases are checked in decreasing order of frequency
|
||||
if ch == 'x':
|
||||
continue
|
||||
|
||||
if ch == '\n':
|
||||
lno = lno + 1
|
||||
if level == 0:
|
||||
push_good(lno)
|
||||
# else we're in an unclosed bracket structure
|
||||
continue
|
||||
|
||||
if ch == '(':
|
||||
level = level + 1
|
||||
continue
|
||||
|
||||
if ch == ')':
|
||||
if level:
|
||||
level = level - 1
|
||||
# else the program is invalid, but we can't complain
|
||||
continue
|
||||
|
||||
if ch == '"' or ch == "'":
|
||||
# consume the string
|
||||
quote = ch
|
||||
if str[i-1:i+2] == quote * 3:
|
||||
quote = quote * 3
|
||||
firstlno = lno
|
||||
w = len(quote) - 1
|
||||
i = i+w
|
||||
while i < n:
|
||||
ch = str[i]
|
||||
i = i+1
|
||||
|
||||
if ch == 'x':
|
||||
continue
|
||||
|
||||
if str[i-1:i+w] == quote:
|
||||
i = i+w
|
||||
break
|
||||
|
||||
if ch == '\n':
|
||||
lno = lno + 1
|
||||
if w == 0:
|
||||
# unterminated single-quoted string
|
||||
if level == 0:
|
||||
push_good(lno)
|
||||
break
|
||||
continue
|
||||
|
||||
if ch == '\\':
|
||||
assert i < n
|
||||
if str[i] == '\n':
|
||||
lno = lno + 1
|
||||
i = i+1
|
||||
continue
|
||||
|
||||
# else comment char or paren inside string
|
||||
|
||||
else:
|
||||
# didn't break out of the loop, so we're still
|
||||
# inside a string
|
||||
if (lno - 1) == firstlno:
|
||||
# before the previous \n in str, we were in the first
|
||||
# line of the string
|
||||
continuation = C_STRING_FIRST_LINE
|
||||
else:
|
||||
continuation = C_STRING_NEXT_LINES
|
||||
continue # with outer loop
|
||||
|
||||
if ch == '#':
|
||||
# consume the comment
|
||||
i = str.find('\n', i)
|
||||
assert i >= 0
|
||||
continue
|
||||
|
||||
assert ch == '\\'
|
||||
assert i < n
|
||||
if str[i] == '\n':
|
||||
lno = lno + 1
|
||||
if i+1 == n:
|
||||
continuation = C_BACKSLASH
|
||||
i = i+1
|
||||
|
||||
# The last stmt may be continued for all 3 reasons.
|
||||
# String continuation takes precedence over bracket
|
||||
# continuation, which beats backslash continuation.
|
||||
if (continuation != C_STRING_FIRST_LINE
|
||||
and continuation != C_STRING_NEXT_LINES and level > 0):
|
||||
continuation = C_BRACKET
|
||||
self.continuation = continuation
|
||||
|
||||
# Push the final line number as a sentinel value, regardless of
|
||||
# whether it's continued.
|
||||
assert (continuation == C_NONE) == (goodlines[-1] == lno)
|
||||
if goodlines[-1] != lno:
|
||||
push_good(lno)
|
||||
|
||||
def get_continuation_type(self):
|
||||
self._study1()
|
||||
return self.continuation
|
||||
|
||||
# study1 was sufficient to determine the continuation status,
|
||||
# but doing more requires looking at every character. study2
|
||||
# does this for the last interesting statement in the block.
|
||||
# Creates:
|
||||
# self.stmt_start, stmt_end
|
||||
# slice indices of last interesting stmt
|
||||
# self.stmt_bracketing
|
||||
# the bracketing structure of the last interesting stmt;
|
||||
# for example, for the statement "say(boo) or die", stmt_bracketing
|
||||
# will be [(0, 0), (3, 1), (8, 0)]. Strings and comments are
|
||||
# treated as brackets, for the matter.
|
||||
# self.lastch
|
||||
# last non-whitespace character before optional trailing
|
||||
# comment
|
||||
# self.lastopenbracketpos
|
||||
# if continuation is C_BRACKET, index of last open bracket
|
||||
|
||||
def _study2(self):
|
||||
if self.study_level >= 2:
|
||||
return
|
||||
self._study1()
|
||||
self.study_level = 2
|
||||
|
||||
# Set p and q to slice indices of last interesting stmt.
|
||||
str, goodlines = self.str, self.goodlines
|
||||
i = len(goodlines) - 1
|
||||
p = len(str) # index of newest line
|
||||
while i:
|
||||
assert p
|
||||
# p is the index of the stmt at line number goodlines[i].
|
||||
# Move p back to the stmt at line number goodlines[i-1].
|
||||
q = p
|
||||
for nothing in range(goodlines[i-1], goodlines[i]):
|
||||
# tricky: sets p to 0 if no preceding newline
|
||||
p = str.rfind('\n', 0, p-1) + 1
|
||||
# The stmt str[p:q] isn't a continuation, but may be blank
|
||||
# or a non-indenting comment line.
|
||||
if _junkre(str, p):
|
||||
i = i-1
|
||||
else:
|
||||
break
|
||||
if i == 0:
|
||||
# nothing but junk!
|
||||
assert p == 0
|
||||
q = p
|
||||
self.stmt_start, self.stmt_end = p, q
|
||||
|
||||
# Analyze this stmt, to find the last open bracket (if any)
|
||||
# and last interesting character (if any).
|
||||
lastch = ""
|
||||
stack = [] # stack of open bracket indices
|
||||
push_stack = stack.append
|
||||
bracketing = [(p, 0)]
|
||||
while p < q:
|
||||
# suck up all except ()[]{}'"#\\
|
||||
m = _chew_ordinaryre(str, p, q)
|
||||
if m:
|
||||
# we skipped at least one boring char
|
||||
newp = m.end()
|
||||
# back up over totally boring whitespace
|
||||
i = newp - 1 # index of last boring char
|
||||
while i >= p and str[i] in " \t\n":
|
||||
i = i-1
|
||||
if i >= p:
|
||||
lastch = str[i]
|
||||
p = newp
|
||||
if p >= q:
|
||||
break
|
||||
|
||||
ch = str[p]
|
||||
|
||||
if ch in "([{":
|
||||
push_stack(p)
|
||||
bracketing.append((p, len(stack)))
|
||||
lastch = ch
|
||||
p = p+1
|
||||
continue
|
||||
|
||||
if ch in ")]}":
|
||||
if stack:
|
||||
del stack[-1]
|
||||
lastch = ch
|
||||
p = p+1
|
||||
bracketing.append((p, len(stack)))
|
||||
continue
|
||||
|
||||
if ch == '"' or ch == "'":
|
||||
# consume string
|
||||
# Note that study1 did this with a Python loop, but
|
||||
# we use a regexp here; the reason is speed in both
|
||||
# cases; the string may be huge, but study1 pre-squashed
|
||||
# strings to a couple of characters per line. study1
|
||||
# also needed to keep track of newlines, and we don't
|
||||
# have to.
|
||||
bracketing.append((p, len(stack)+1))
|
||||
lastch = ch
|
||||
p = _match_stringre(str, p, q).end()
|
||||
bracketing.append((p, len(stack)))
|
||||
continue
|
||||
|
||||
if ch == '#':
|
||||
# consume comment and trailing newline
|
||||
bracketing.append((p, len(stack)+1))
|
||||
p = str.find('\n', p, q) + 1
|
||||
assert p > 0
|
||||
bracketing.append((p, len(stack)))
|
||||
continue
|
||||
|
||||
assert ch == '\\'
|
||||
p = p+1 # beyond backslash
|
||||
assert p < q
|
||||
if str[p] != '\n':
|
||||
# the program is invalid, but can't complain
|
||||
lastch = ch + str[p]
|
||||
p = p+1 # beyond escaped char
|
||||
|
||||
# end while p < q:
|
||||
|
||||
self.lastch = lastch
|
||||
if stack:
|
||||
self.lastopenbracketpos = stack[-1]
|
||||
self.stmt_bracketing = tuple(bracketing)
|
||||
|
||||
# Assuming continuation is C_BRACKET, return the number
|
||||
# of spaces the next line should be indented.
|
||||
|
||||
def compute_bracket_indent(self):
|
||||
self._study2()
|
||||
assert self.continuation == C_BRACKET
|
||||
j = self.lastopenbracketpos
|
||||
str = self.str
|
||||
n = len(str)
|
||||
origi = i = str.rfind('\n', 0, j) + 1
|
||||
j = j+1 # one beyond open bracket
|
||||
# find first list item; set i to start of its line
|
||||
while j < n:
|
||||
m = _itemre(str, j)
|
||||
if m:
|
||||
j = m.end() - 1 # index of first interesting char
|
||||
extra = 0
|
||||
break
|
||||
else:
|
||||
# this line is junk; advance to next line
|
||||
i = j = str.find('\n', j) + 1
|
||||
else:
|
||||
# nothing interesting follows the bracket;
|
||||
# reproduce the bracket line's indentation + a level
|
||||
j = i = origi
|
||||
while str[j] in " \t":
|
||||
j = j+1
|
||||
extra = self.indentwidth
|
||||
return len(str[i:j].expandtabs(self.tabwidth)) + extra
|
||||
|
||||
# Return number of physical lines in last stmt (whether or not
|
||||
# it's an interesting stmt! this is intended to be called when
|
||||
# continuation is C_BACKSLASH).
|
||||
|
||||
def get_num_lines_in_stmt(self):
|
||||
self._study1()
|
||||
goodlines = self.goodlines
|
||||
return goodlines[-1] - goodlines[-2]
|
||||
|
||||
# Assuming continuation is C_BACKSLASH, return the number of spaces
|
||||
# the next line should be indented. Also assuming the new line is
|
||||
# the first one following the initial line of the stmt.
|
||||
|
||||
def compute_backslash_indent(self):
|
||||
self._study2()
|
||||
assert self.continuation == C_BACKSLASH
|
||||
str = self.str
|
||||
i = self.stmt_start
|
||||
while str[i] in " \t":
|
||||
i = i+1
|
||||
startpos = i
|
||||
|
||||
# See whether the initial line starts an assignment stmt; i.e.,
|
||||
# look for an = operator
|
||||
endpos = str.find('\n', startpos) + 1
|
||||
found = level = 0
|
||||
while i < endpos:
|
||||
ch = str[i]
|
||||
if ch in "([{":
|
||||
level = level + 1
|
||||
i = i+1
|
||||
elif ch in ")]}":
|
||||
if level:
|
||||
level = level - 1
|
||||
i = i+1
|
||||
elif ch == '"' or ch == "'":
|
||||
i = _match_stringre(str, i, endpos).end()
|
||||
elif ch == '#':
|
||||
break
|
||||
elif level == 0 and ch == '=' and \
|
||||
(i == 0 or str[i-1] not in "=<>!") and \
|
||||
str[i+1] != '=':
|
||||
found = 1
|
||||
break
|
||||
else:
|
||||
i = i+1
|
||||
|
||||
if found:
|
||||
# found a legit =, but it may be the last interesting
|
||||
# thing on the line
|
||||
i = i+1 # move beyond the =
|
||||
found = re.match(r"\s*\\", str[i:endpos]) is None
|
||||
|
||||
if not found:
|
||||
# oh well ... settle for moving beyond the first chunk
|
||||
# of non-whitespace chars
|
||||
i = startpos
|
||||
while str[i] not in " \t\n":
|
||||
i = i+1
|
||||
|
||||
return len(str[self.stmt_start:i].expandtabs(\
|
||||
self.tabwidth)) + 1
|
||||
|
||||
# Return the leading whitespace on the initial line of the last
|
||||
# interesting stmt.
|
||||
|
||||
def get_base_indent_string(self):
|
||||
self._study2()
|
||||
i, n = self.stmt_start, self.stmt_end
|
||||
j = i
|
||||
str = self.str
|
||||
while j < n and str[j] in " \t":
|
||||
j = j + 1
|
||||
return str[i:j]
|
||||
|
||||
# Did the last interesting stmt open a block?
|
||||
|
||||
def is_block_opener(self):
|
||||
self._study2()
|
||||
return self.lastch == ':'
|
||||
|
||||
# Did the last interesting stmt close a block?
|
||||
|
||||
def is_block_closer(self):
|
||||
self._study2()
|
||||
return _closere(self.str, self.stmt_start) is not None
|
||||
|
||||
# index of last open bracket ({[, or None if none
|
||||
lastopenbracketpos = None
|
||||
|
||||
def get_last_open_bracket_pos(self):
|
||||
self._study2()
|
||||
return self.lastopenbracketpos
|
||||
|
||||
# the structure of the bracketing of the last interesting statement,
|
||||
# in the format defined in _study2, or None if the text didn't contain
|
||||
# anything
|
||||
stmt_bracketing = None
|
||||
|
||||
def get_last_stmt_bracketing(self):
|
||||
self._study2()
|
||||
return self.stmt_bracketing
|
||||
1590
Darwin/lib/python2.7/idlelib/PyShell.py
Normal file
1590
Darwin/lib/python2.7/idlelib/PyShell.py
Normal file
File diff suppressed because it is too large
Load diff
63
Darwin/lib/python2.7/idlelib/README.txt
Normal file
63
Darwin/lib/python2.7/idlelib/README.txt
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
IDLE is Python's Tkinter-based Integrated DeveLopment Environment.
|
||||
|
||||
IDLE emphasizes a lightweight, clean design with a simple user interface.
|
||||
Although it is suitable for beginners, even advanced users will find that
|
||||
IDLE has everything they really need to develop pure Python code.
|
||||
|
||||
IDLE features a multi-window text editor with multiple undo, Python colorizing,
|
||||
and many other capabilities, e.g. smart indent, call tips, and autocompletion.
|
||||
|
||||
The editor has comprehensive search functions, including searching through
|
||||
multiple files. Class browsers and path browsers provide fast access to
|
||||
code objects from a top level viewpoint without dealing with code folding.
|
||||
|
||||
There is a Python Shell window which features colorizing and command recall.
|
||||
|
||||
IDLE executes Python code in a separate process, which is restarted for each
|
||||
Run (F5) initiated from an editor window. The environment can also be
|
||||
restarted from the Shell window without restarting IDLE.
|
||||
|
||||
This enhancement has often been requested, and is now finally available. The
|
||||
magic "reload/import *" incantations are no longer required when editing and
|
||||
testing a module two or three steps down the import chain.
|
||||
|
||||
(Personal firewall software may warn about the connection IDLE makes to its
|
||||
subprocess using this computer's internal loopback interface. This connection
|
||||
is not visible on any external interface and no data is sent to or received
|
||||
from the Internet.)
|
||||
|
||||
It is possible to interrupt tightly looping user code, even on Windows.
|
||||
|
||||
Applications which cannot support subprocesses and/or sockets can still run
|
||||
IDLE in a single process.
|
||||
|
||||
IDLE has an integrated debugger with stepping, persistent breakpoints, and call
|
||||
stack visibility.
|
||||
|
||||
There is a GUI configuration manager which makes it easy to select fonts,
|
||||
colors, keybindings, and startup options. This facility includes a feature
|
||||
which allows the user to specify additional help sources, either locally or on
|
||||
the web.
|
||||
|
||||
IDLE is coded in 100% pure Python, using the Tkinter GUI toolkit (Tk/Tcl)
|
||||
and is cross-platform, working on Unix, Mac, and Windows.
|
||||
|
||||
IDLE accepts command line arguments. Try idle -h to see the options.
|
||||
|
||||
|
||||
If you find bugs or have suggestions, let us know about them by using the
|
||||
Python Bug Tracker:
|
||||
|
||||
http://sourceforge.net/projects/python
|
||||
|
||||
Patches are always appreciated at the Python Patch Tracker, and change
|
||||
requests should be posted to the RFE Tracker.
|
||||
|
||||
For further details and links, read the Help files and check the IDLE home
|
||||
page at
|
||||
|
||||
http://www.python.org/idle/
|
||||
|
||||
There is a mail list for IDLE: idle-dev@python.org. You can join at
|
||||
|
||||
http://mail.python.org/mailman/listinfo/idle-dev
|
||||
380
Darwin/lib/python2.7/idlelib/RemoteDebugger.py
Normal file
380
Darwin/lib/python2.7/idlelib/RemoteDebugger.py
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
"""Support for remote Python debugging.
|
||||
|
||||
Some ASCII art to describe the structure:
|
||||
|
||||
IN PYTHON SUBPROCESS # IN IDLE PROCESS
|
||||
#
|
||||
# oid='gui_adapter'
|
||||
+----------+ # +------------+ +-----+
|
||||
| GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI |
|
||||
+-----+--calls-->+----------+ # +------------+ +-----+
|
||||
| Idb | # /
|
||||
+-----+<-calls--+------------+ # +----------+<--calls-/
|
||||
| IdbAdapter |<--remote#call--| IdbProxy |
|
||||
+------------+ # +----------+
|
||||
oid='idb_adapter' #
|
||||
|
||||
The purpose of the Proxy and Adapter classes is to translate certain
|
||||
arguments and return values that cannot be transported through the RPC
|
||||
barrier, in particular frame and traceback objects.
|
||||
|
||||
"""
|
||||
|
||||
import types
|
||||
from idlelib import rpc
|
||||
from idlelib import Debugger
|
||||
|
||||
debugging = 0
|
||||
|
||||
idb_adap_oid = "idb_adapter"
|
||||
gui_adap_oid = "gui_adapter"
|
||||
|
||||
#=======================================
|
||||
#
|
||||
# In the PYTHON subprocess:
|
||||
|
||||
frametable = {}
|
||||
dicttable = {}
|
||||
codetable = {}
|
||||
tracebacktable = {}
|
||||
|
||||
def wrap_frame(frame):
|
||||
fid = id(frame)
|
||||
frametable[fid] = frame
|
||||
return fid
|
||||
|
||||
def wrap_info(info):
|
||||
"replace info[2], a traceback instance, by its ID"
|
||||
if info is None:
|
||||
return None
|
||||
else:
|
||||
traceback = info[2]
|
||||
assert isinstance(traceback, types.TracebackType)
|
||||
traceback_id = id(traceback)
|
||||
tracebacktable[traceback_id] = traceback
|
||||
modified_info = (info[0], info[1], traceback_id)
|
||||
return modified_info
|
||||
|
||||
class GUIProxy:
|
||||
|
||||
def __init__(self, conn, gui_adap_oid):
|
||||
self.conn = conn
|
||||
self.oid = gui_adap_oid
|
||||
|
||||
def interaction(self, message, frame, info=None):
|
||||
# calls rpc.SocketIO.remotecall() via run.MyHandler instance
|
||||
# pass frame and traceback object IDs instead of the objects themselves
|
||||
self.conn.remotecall(self.oid, "interaction",
|
||||
(message, wrap_frame(frame), wrap_info(info)),
|
||||
{})
|
||||
|
||||
class IdbAdapter:
|
||||
|
||||
def __init__(self, idb):
|
||||
self.idb = idb
|
||||
|
||||
#----------called by an IdbProxy----------
|
||||
|
||||
def set_step(self):
|
||||
self.idb.set_step()
|
||||
|
||||
def set_quit(self):
|
||||
self.idb.set_quit()
|
||||
|
||||
def set_continue(self):
|
||||
self.idb.set_continue()
|
||||
|
||||
def set_next(self, fid):
|
||||
frame = frametable[fid]
|
||||
self.idb.set_next(frame)
|
||||
|
||||
def set_return(self, fid):
|
||||
frame = frametable[fid]
|
||||
self.idb.set_return(frame)
|
||||
|
||||
def get_stack(self, fid, tbid):
|
||||
##print >>sys.__stderr__, "get_stack(%r, %r)" % (fid, tbid)
|
||||
frame = frametable[fid]
|
||||
if tbid is None:
|
||||
tb = None
|
||||
else:
|
||||
tb = tracebacktable[tbid]
|
||||
stack, i = self.idb.get_stack(frame, tb)
|
||||
##print >>sys.__stderr__, "get_stack() ->", stack
|
||||
stack = [(wrap_frame(frame), k) for frame, k in stack]
|
||||
##print >>sys.__stderr__, "get_stack() ->", stack
|
||||
return stack, i
|
||||
|
||||
def run(self, cmd):
|
||||
import __main__
|
||||
self.idb.run(cmd, __main__.__dict__)
|
||||
|
||||
def set_break(self, filename, lineno):
|
||||
msg = self.idb.set_break(filename, lineno)
|
||||
return msg
|
||||
|
||||
def clear_break(self, filename, lineno):
|
||||
msg = self.idb.clear_break(filename, lineno)
|
||||
return msg
|
||||
|
||||
def clear_all_file_breaks(self, filename):
|
||||
msg = self.idb.clear_all_file_breaks(filename)
|
||||
return msg
|
||||
|
||||
#----------called by a FrameProxy----------
|
||||
|
||||
def frame_attr(self, fid, name):
|
||||
frame = frametable[fid]
|
||||
return getattr(frame, name)
|
||||
|
||||
def frame_globals(self, fid):
|
||||
frame = frametable[fid]
|
||||
dict = frame.f_globals
|
||||
did = id(dict)
|
||||
dicttable[did] = dict
|
||||
return did
|
||||
|
||||
def frame_locals(self, fid):
|
||||
frame = frametable[fid]
|
||||
dict = frame.f_locals
|
||||
did = id(dict)
|
||||
dicttable[did] = dict
|
||||
return did
|
||||
|
||||
def frame_code(self, fid):
|
||||
frame = frametable[fid]
|
||||
code = frame.f_code
|
||||
cid = id(code)
|
||||
codetable[cid] = code
|
||||
return cid
|
||||
|
||||
#----------called by a CodeProxy----------
|
||||
|
||||
def code_name(self, cid):
|
||||
code = codetable[cid]
|
||||
return code.co_name
|
||||
|
||||
def code_filename(self, cid):
|
||||
code = codetable[cid]
|
||||
return code.co_filename
|
||||
|
||||
#----------called by a DictProxy----------
|
||||
|
||||
def dict_keys(self, did):
|
||||
dict = dicttable[did]
|
||||
return dict.keys()
|
||||
|
||||
def dict_item(self, did, key):
|
||||
dict = dicttable[did]
|
||||
value = dict[key]
|
||||
value = repr(value)
|
||||
return value
|
||||
|
||||
#----------end class IdbAdapter----------
|
||||
|
||||
|
||||
def start_debugger(rpchandler, gui_adap_oid):
|
||||
"""Start the debugger and its RPC link in the Python subprocess
|
||||
|
||||
Start the subprocess side of the split debugger and set up that side of the
|
||||
RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
|
||||
objects and linking them together. Register the IdbAdapter with the
|
||||
RPCServer to handle RPC requests from the split debugger GUI via the
|
||||
IdbProxy.
|
||||
|
||||
"""
|
||||
gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
|
||||
idb = Debugger.Idb(gui_proxy)
|
||||
idb_adap = IdbAdapter(idb)
|
||||
rpchandler.register(idb_adap_oid, idb_adap)
|
||||
return idb_adap_oid
|
||||
|
||||
|
||||
#=======================================
|
||||
#
|
||||
# In the IDLE process:
|
||||
|
||||
|
||||
class FrameProxy:
|
||||
|
||||
def __init__(self, conn, fid):
|
||||
self._conn = conn
|
||||
self._fid = fid
|
||||
self._oid = "idb_adapter"
|
||||
self._dictcache = {}
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name[:1] == "_":
|
||||
raise AttributeError, name
|
||||
if name == "f_code":
|
||||
return self._get_f_code()
|
||||
if name == "f_globals":
|
||||
return self._get_f_globals()
|
||||
if name == "f_locals":
|
||||
return self._get_f_locals()
|
||||
return self._conn.remotecall(self._oid, "frame_attr",
|
||||
(self._fid, name), {})
|
||||
|
||||
def _get_f_code(self):
|
||||
cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {})
|
||||
return CodeProxy(self._conn, self._oid, cid)
|
||||
|
||||
def _get_f_globals(self):
|
||||
did = self._conn.remotecall(self._oid, "frame_globals",
|
||||
(self._fid,), {})
|
||||
return self._get_dict_proxy(did)
|
||||
|
||||
def _get_f_locals(self):
|
||||
did = self._conn.remotecall(self._oid, "frame_locals",
|
||||
(self._fid,), {})
|
||||
return self._get_dict_proxy(did)
|
||||
|
||||
def _get_dict_proxy(self, did):
|
||||
if did in self._dictcache:
|
||||
return self._dictcache[did]
|
||||
dp = DictProxy(self._conn, self._oid, did)
|
||||
self._dictcache[did] = dp
|
||||
return dp
|
||||
|
||||
|
||||
class CodeProxy:
|
||||
|
||||
def __init__(self, conn, oid, cid):
|
||||
self._conn = conn
|
||||
self._oid = oid
|
||||
self._cid = cid
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == "co_name":
|
||||
return self._conn.remotecall(self._oid, "code_name",
|
||||
(self._cid,), {})
|
||||
if name == "co_filename":
|
||||
return self._conn.remotecall(self._oid, "code_filename",
|
||||
(self._cid,), {})
|
||||
|
||||
|
||||
class DictProxy:
|
||||
|
||||
def __init__(self, conn, oid, did):
|
||||
self._conn = conn
|
||||
self._oid = oid
|
||||
self._did = did
|
||||
|
||||
def keys(self):
|
||||
return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {})
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._conn.remotecall(self._oid, "dict_item",
|
||||
(self._did, key), {})
|
||||
|
||||
def __getattr__(self, name):
|
||||
##print >>sys.__stderr__, "failed DictProxy.__getattr__:", name
|
||||
raise AttributeError, name
|
||||
|
||||
|
||||
class GUIAdapter:
|
||||
|
||||
def __init__(self, conn, gui):
|
||||
self.conn = conn
|
||||
self.gui = gui
|
||||
|
||||
def interaction(self, message, fid, modified_info):
|
||||
##print "interaction: (%s, %s, %s)" % (message, fid, modified_info)
|
||||
frame = FrameProxy(self.conn, fid)
|
||||
self.gui.interaction(message, frame, modified_info)
|
||||
|
||||
|
||||
class IdbProxy:
|
||||
|
||||
def __init__(self, conn, shell, oid):
|
||||
self.oid = oid
|
||||
self.conn = conn
|
||||
self.shell = shell
|
||||
|
||||
def call(self, methodname, *args, **kwargs):
|
||||
##print "**IdbProxy.call %s %s %s" % (methodname, args, kwargs)
|
||||
value = self.conn.remotecall(self.oid, methodname, args, kwargs)
|
||||
##print "**IdbProxy.call %s returns %r" % (methodname, value)
|
||||
return value
|
||||
|
||||
def run(self, cmd, locals):
|
||||
# Ignores locals on purpose!
|
||||
seq = self.conn.asyncqueue(self.oid, "run", (cmd,), {})
|
||||
self.shell.interp.active_seq = seq
|
||||
|
||||
def get_stack(self, frame, tbid):
|
||||
# passing frame and traceback IDs, not the objects themselves
|
||||
stack, i = self.call("get_stack", frame._fid, tbid)
|
||||
stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack]
|
||||
return stack, i
|
||||
|
||||
def set_continue(self):
|
||||
self.call("set_continue")
|
||||
|
||||
def set_step(self):
|
||||
self.call("set_step")
|
||||
|
||||
def set_next(self, frame):
|
||||
self.call("set_next", frame._fid)
|
||||
|
||||
def set_return(self, frame):
|
||||
self.call("set_return", frame._fid)
|
||||
|
||||
def set_quit(self):
|
||||
self.call("set_quit")
|
||||
|
||||
def set_break(self, filename, lineno):
|
||||
msg = self.call("set_break", filename, lineno)
|
||||
return msg
|
||||
|
||||
def clear_break(self, filename, lineno):
|
||||
msg = self.call("clear_break", filename, lineno)
|
||||
return msg
|
||||
|
||||
def clear_all_file_breaks(self, filename):
|
||||
msg = self.call("clear_all_file_breaks", filename)
|
||||
return msg
|
||||
|
||||
def start_remote_debugger(rpcclt, pyshell):
|
||||
"""Start the subprocess debugger, initialize the debugger GUI and RPC link
|
||||
|
||||
Request the RPCServer start the Python subprocess debugger and link. Set
|
||||
up the Idle side of the split debugger by instantiating the IdbProxy,
|
||||
debugger GUI, and debugger GUIAdapter objects and linking them together.
|
||||
|
||||
Register the GUIAdapter with the RPCClient to handle debugger GUI
|
||||
interaction requests coming from the subprocess debugger via the GUIProxy.
|
||||
|
||||
The IdbAdapter will pass execution and environment requests coming from the
|
||||
Idle debugger GUI to the subprocess debugger via the IdbProxy.
|
||||
|
||||
"""
|
||||
global idb_adap_oid
|
||||
|
||||
idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
|
||||
(gui_adap_oid,), {})
|
||||
idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid)
|
||||
gui = Debugger.Debugger(pyshell, idb_proxy)
|
||||
gui_adap = GUIAdapter(rpcclt, gui)
|
||||
rpcclt.register(gui_adap_oid, gui_adap)
|
||||
return gui
|
||||
|
||||
def close_remote_debugger(rpcclt):
|
||||
"""Shut down subprocess debugger and Idle side of debugger RPC link
|
||||
|
||||
Request that the RPCServer shut down the subprocess debugger and link.
|
||||
Unregister the GUIAdapter, which will cause a GC on the Idle process
|
||||
debugger and RPC link objects. (The second reference to the debugger GUI
|
||||
is deleted in PyShell.close_remote_debugger().)
|
||||
|
||||
"""
|
||||
close_subprocess_debugger(rpcclt)
|
||||
rpcclt.unregister(gui_adap_oid)
|
||||
|
||||
def close_subprocess_debugger(rpcclt):
|
||||
rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
|
||||
|
||||
def restart_subprocess_debugger(rpcclt):
|
||||
idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\
|
||||
(gui_adap_oid,), {})
|
||||
assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid'
|
||||
36
Darwin/lib/python2.7/idlelib/RemoteObjectBrowser.py
Normal file
36
Darwin/lib/python2.7/idlelib/RemoteObjectBrowser.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
from idlelib import rpc
|
||||
|
||||
def remote_object_tree_item(item):
|
||||
wrapper = WrappedObjectTreeItem(item)
|
||||
oid = id(wrapper)
|
||||
rpc.objecttable[oid] = wrapper
|
||||
return oid
|
||||
|
||||
class WrappedObjectTreeItem:
|
||||
# Lives in PYTHON subprocess
|
||||
|
||||
def __init__(self, item):
|
||||
self.__item = item
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = getattr(self.__item, name)
|
||||
return value
|
||||
|
||||
def _GetSubList(self):
|
||||
list = self.__item._GetSubList()
|
||||
return map(remote_object_tree_item, list)
|
||||
|
||||
class StubObjectTreeItem:
|
||||
# Lives in IDLE process
|
||||
|
||||
def __init__(self, sockio, oid):
|
||||
self.sockio = sockio
|
||||
self.oid = oid
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = rpc.MethodProxy(self.sockio, self.oid, name)
|
||||
return value
|
||||
|
||||
def _GetSubList(self):
|
||||
list = self.sockio.remotecall(self.oid, "_GetSubList", (), {})
|
||||
return [StubObjectTreeItem(self.sockio, oid) for oid in list]
|
||||
189
Darwin/lib/python2.7/idlelib/ReplaceDialog.py
Normal file
189
Darwin/lib/python2.7/idlelib/ReplaceDialog.py
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
from Tkinter import *
|
||||
|
||||
from idlelib import SearchEngine
|
||||
from idlelib.SearchDialogBase import SearchDialogBase
|
||||
import re
|
||||
|
||||
|
||||
def replace(text):
|
||||
root = text._root()
|
||||
engine = SearchEngine.get(root)
|
||||
if not hasattr(engine, "_replacedialog"):
|
||||
engine._replacedialog = ReplaceDialog(root, engine)
|
||||
dialog = engine._replacedialog
|
||||
dialog.open(text)
|
||||
|
||||
|
||||
class ReplaceDialog(SearchDialogBase):
|
||||
|
||||
title = "Replace Dialog"
|
||||
icon = "Replace"
|
||||
|
||||
def __init__(self, root, engine):
|
||||
SearchDialogBase.__init__(self, root, engine)
|
||||
self.replvar = StringVar(root)
|
||||
|
||||
def open(self, text):
|
||||
SearchDialogBase.open(self, text)
|
||||
try:
|
||||
first = text.index("sel.first")
|
||||
except TclError:
|
||||
first = None
|
||||
try:
|
||||
last = text.index("sel.last")
|
||||
except TclError:
|
||||
last = None
|
||||
first = first or text.index("insert")
|
||||
last = last or first
|
||||
self.show_hit(first, last)
|
||||
self.ok = 1
|
||||
|
||||
def create_entries(self):
|
||||
SearchDialogBase.create_entries(self)
|
||||
self.replent = self.make_entry("Replace with:", self.replvar)
|
||||
|
||||
def create_command_buttons(self):
|
||||
SearchDialogBase.create_command_buttons(self)
|
||||
self.make_button("Find", self.find_it)
|
||||
self.make_button("Replace", self.replace_it)
|
||||
self.make_button("Replace+Find", self.default_command, 1)
|
||||
self.make_button("Replace All", self.replace_all)
|
||||
|
||||
def find_it(self, event=None):
|
||||
self.do_find(0)
|
||||
|
||||
def replace_it(self, event=None):
|
||||
if self.do_find(self.ok):
|
||||
self.do_replace()
|
||||
|
||||
def default_command(self, event=None):
|
||||
if self.do_find(self.ok):
|
||||
if self.do_replace(): # Only find next match if replace succeeded.
|
||||
# A bad re can cause a it to fail.
|
||||
self.do_find(0)
|
||||
|
||||
def _replace_expand(self, m, repl):
|
||||
""" Helper function for expanding a regular expression
|
||||
in the replace field, if needed. """
|
||||
if self.engine.isre():
|
||||
try:
|
||||
new = m.expand(repl)
|
||||
except re.error:
|
||||
self.engine.report_error(repl, 'Invalid Replace Expression')
|
||||
new = None
|
||||
else:
|
||||
new = repl
|
||||
return new
|
||||
|
||||
def replace_all(self, event=None):
|
||||
prog = self.engine.getprog()
|
||||
if not prog:
|
||||
return
|
||||
repl = self.replvar.get()
|
||||
text = self.text
|
||||
res = self.engine.search_text(text, prog)
|
||||
if not res:
|
||||
text.bell()
|
||||
return
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
text.tag_remove("hit", "1.0", "end")
|
||||
line = res[0]
|
||||
col = res[1].start()
|
||||
if self.engine.iswrap():
|
||||
line = 1
|
||||
col = 0
|
||||
ok = 1
|
||||
first = last = None
|
||||
# XXX ought to replace circular instead of top-to-bottom when wrapping
|
||||
text.undo_block_start()
|
||||
while 1:
|
||||
res = self.engine.search_forward(text, prog, line, col, 0, ok)
|
||||
if not res:
|
||||
break
|
||||
line, m = res
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
orig = m.group()
|
||||
new = self._replace_expand(m, repl)
|
||||
if new is None:
|
||||
break
|
||||
i, j = m.span()
|
||||
first = "%d.%d" % (line, i)
|
||||
last = "%d.%d" % (line, j)
|
||||
if new == orig:
|
||||
text.mark_set("insert", last)
|
||||
else:
|
||||
text.mark_set("insert", first)
|
||||
if first != last:
|
||||
text.delete(first, last)
|
||||
if new:
|
||||
text.insert(first, new)
|
||||
col = i + len(new)
|
||||
ok = 0
|
||||
text.undo_block_stop()
|
||||
if first and last:
|
||||
self.show_hit(first, last)
|
||||
self.close()
|
||||
|
||||
def do_find(self, ok=0):
|
||||
if not self.engine.getprog():
|
||||
return False
|
||||
text = self.text
|
||||
res = self.engine.search_text(text, None, ok)
|
||||
if not res:
|
||||
text.bell()
|
||||
return False
|
||||
line, m = res
|
||||
i, j = m.span()
|
||||
first = "%d.%d" % (line, i)
|
||||
last = "%d.%d" % (line, j)
|
||||
self.show_hit(first, last)
|
||||
self.ok = 1
|
||||
return True
|
||||
|
||||
def do_replace(self):
|
||||
prog = self.engine.getprog()
|
||||
if not prog:
|
||||
return False
|
||||
text = self.text
|
||||
try:
|
||||
first = pos = text.index("sel.first")
|
||||
last = text.index("sel.last")
|
||||
except TclError:
|
||||
pos = None
|
||||
if not pos:
|
||||
first = last = pos = text.index("insert")
|
||||
line, col = SearchEngine.get_line_col(pos)
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
m = prog.match(chars, col)
|
||||
if not prog:
|
||||
return False
|
||||
new = self._replace_expand(m, self.replvar.get())
|
||||
if new is None:
|
||||
return False
|
||||
text.mark_set("insert", first)
|
||||
text.undo_block_start()
|
||||
if m.group():
|
||||
text.delete(first, last)
|
||||
if new:
|
||||
text.insert(first, new)
|
||||
text.undo_block_stop()
|
||||
self.show_hit(first, text.index("insert"))
|
||||
self.ok = 0
|
||||
return True
|
||||
|
||||
def show_hit(self, first, last):
|
||||
text = self.text
|
||||
text.mark_set("insert", first)
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
text.tag_add("sel", first, last)
|
||||
text.tag_remove("hit", "1.0", "end")
|
||||
if first == last:
|
||||
text.tag_add("hit", first)
|
||||
else:
|
||||
text.tag_add("hit", first, last)
|
||||
text.see("insert")
|
||||
text.update_idletasks()
|
||||
|
||||
def close(self, event=None):
|
||||
SearchDialogBase.close(self, event)
|
||||
self.text.tag_remove("hit", "1.0", "end")
|
||||
33
Darwin/lib/python2.7/idlelib/RstripExtension.py
Normal file
33
Darwin/lib/python2.7/idlelib/RstripExtension.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
'Provides "Strip trailing whitespace" under the "Format" menu.'
|
||||
|
||||
class RstripExtension:
|
||||
|
||||
menudefs = [
|
||||
('format', [None, ('Strip trailing whitespace', '<<do-rstrip>>'), ] ), ]
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.editwin.text.bind("<<do-rstrip>>", self.do_rstrip)
|
||||
|
||||
def do_rstrip(self, event=None):
|
||||
|
||||
text = self.editwin.text
|
||||
undo = self.editwin.undo
|
||||
|
||||
undo.undo_block_start()
|
||||
|
||||
end_line = int(float(text.index('end')))
|
||||
for cur in range(1, end_line):
|
||||
txt = text.get('%i.0' % cur, '%i.end' % cur)
|
||||
raw = len(txt)
|
||||
cut = len(txt.rstrip())
|
||||
# Since text.delete() marks file as changed, even if not,
|
||||
# only call it when needed to actually delete something.
|
||||
if cut < raw:
|
||||
text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
|
||||
|
||||
undo.undo_block_stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import unittest
|
||||
unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False)
|
||||
222
Darwin/lib/python2.7/idlelib/ScriptBinding.py
Normal file
222
Darwin/lib/python2.7/idlelib/ScriptBinding.py
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
"""Extension to execute code outside the Python shell window.
|
||||
|
||||
This adds the following commands:
|
||||
|
||||
- Check module does a full syntax check of the current module.
|
||||
It also runs the tabnanny to catch any inconsistent tabs.
|
||||
|
||||
- Run module executes the module's code in the __main__ namespace. The window
|
||||
must have been saved previously. The module is added to sys.modules, and is
|
||||
also added to the __main__ namespace.
|
||||
|
||||
XXX GvR Redesign this interface (yet again) as follows:
|
||||
|
||||
- Present a dialog box for ``Run Module''
|
||||
|
||||
- Allow specify command line arguments in the dialog box
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import tabnanny
|
||||
import tokenize
|
||||
import tkMessageBox
|
||||
from idlelib import PyShell
|
||||
|
||||
from idlelib.configHandler import idleConf
|
||||
from idlelib import macosxSupport
|
||||
|
||||
IDENTCHARS = string.ascii_letters + string.digits + "_"
|
||||
|
||||
indent_message = """Error: Inconsistent indentation detected!
|
||||
|
||||
1) Your indentation is outright incorrect (easy to fix), OR
|
||||
|
||||
2) Your indentation mixes tabs and spaces.
|
||||
|
||||
To fix case 2, change all tabs to spaces by using Edit->Select All followed \
|
||||
by Format->Untabify Region and specify the number of columns used by each tab.
|
||||
"""
|
||||
|
||||
class ScriptBinding:
|
||||
|
||||
menudefs = [
|
||||
('run', [None,
|
||||
('Check Module', '<<check-module>>'),
|
||||
('Run Module', '<<run-module>>'), ]), ]
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
# Provide instance variables referenced by Debugger
|
||||
# XXX This should be done differently
|
||||
self.flist = self.editwin.flist
|
||||
self.root = self.editwin.root
|
||||
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event)
|
||||
|
||||
def check_module_event(self, event):
|
||||
filename = self.getfilename()
|
||||
if not filename:
|
||||
return 'break'
|
||||
if not self.checksyntax(filename):
|
||||
return 'break'
|
||||
if not self.tabnanny(filename):
|
||||
return 'break'
|
||||
|
||||
def tabnanny(self, filename):
|
||||
f = open(filename, 'r')
|
||||
try:
|
||||
tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
|
||||
except tokenize.TokenError as msg:
|
||||
msgtxt, (lineno, start) = msg
|
||||
self.editwin.gotoline(lineno)
|
||||
self.errorbox("Tabnanny Tokenizing Error",
|
||||
"Token Error: %s" % msgtxt)
|
||||
return False
|
||||
except tabnanny.NannyNag as nag:
|
||||
# The error messages from tabnanny are too confusing...
|
||||
self.editwin.gotoline(nag.get_lineno())
|
||||
self.errorbox("Tab/space error", indent_message)
|
||||
return False
|
||||
return True
|
||||
|
||||
def checksyntax(self, filename):
|
||||
self.shell = shell = self.flist.open_shell()
|
||||
saved_stream = shell.get_warning_stream()
|
||||
shell.set_warning_stream(shell.stderr)
|
||||
with open(filename, 'r') as f:
|
||||
source = f.read()
|
||||
if '\r' in source:
|
||||
source = re.sub(r"\r\n", "\n", source)
|
||||
source = re.sub(r"\r", "\n", source)
|
||||
if source and source[-1] != '\n':
|
||||
source = source + '\n'
|
||||
text = self.editwin.text
|
||||
text.tag_remove("ERROR", "1.0", "end")
|
||||
try:
|
||||
try:
|
||||
# If successful, return the compiled code
|
||||
return compile(source, filename, "exec")
|
||||
except (SyntaxError, OverflowError, ValueError) as err:
|
||||
try:
|
||||
msg, (errorfilename, lineno, offset, line) = err
|
||||
if not errorfilename:
|
||||
err.args = msg, (filename, lineno, offset, line)
|
||||
err.filename = filename
|
||||
self.colorize_syntax_error(msg, lineno, offset)
|
||||
except:
|
||||
msg = "*** " + str(err)
|
||||
self.errorbox("Syntax error",
|
||||
"There's an error in your program:\n" + msg)
|
||||
return False
|
||||
finally:
|
||||
shell.set_warning_stream(saved_stream)
|
||||
|
||||
def colorize_syntax_error(self, msg, lineno, offset):
|
||||
text = self.editwin.text
|
||||
pos = "0.0 + %d lines + %d chars" % (lineno-1, offset-1)
|
||||
text.tag_add("ERROR", pos)
|
||||
char = text.get(pos)
|
||||
if char and char in IDENTCHARS:
|
||||
text.tag_add("ERROR", pos + " wordstart", pos)
|
||||
if '\n' == text.get(pos): # error at line end
|
||||
text.mark_set("insert", pos)
|
||||
else:
|
||||
text.mark_set("insert", pos + "+1c")
|
||||
text.see(pos)
|
||||
|
||||
def run_module_event(self, event):
|
||||
"""Run the module after setting up the environment.
|
||||
|
||||
First check the syntax. If OK, make sure the shell is active and
|
||||
then transfer the arguments, set the run environment's working
|
||||
directory to the directory of the module being executed and also
|
||||
add that directory to its sys.path if not already included.
|
||||
|
||||
"""
|
||||
filename = self.getfilename()
|
||||
if not filename:
|
||||
return 'break'
|
||||
code = self.checksyntax(filename)
|
||||
if not code:
|
||||
return 'break'
|
||||
if not self.tabnanny(filename):
|
||||
return 'break'
|
||||
interp = self.shell.interp
|
||||
if PyShell.use_subprocess:
|
||||
interp.restart_subprocess(with_cwd=False)
|
||||
dirname = os.path.dirname(filename)
|
||||
# XXX Too often this discards arguments the user just set...
|
||||
interp.runcommand("""if 1:
|
||||
__file__ = {filename!r}
|
||||
import sys as _sys
|
||||
from os.path import basename as _basename
|
||||
if (not _sys.argv or
|
||||
_basename(_sys.argv[0]) != _basename(__file__)):
|
||||
_sys.argv = [__file__]
|
||||
import os as _os
|
||||
_os.chdir({dirname!r})
|
||||
del _sys, _basename, _os
|
||||
\n""".format(filename=filename, dirname=dirname))
|
||||
interp.prepend_syspath(filename)
|
||||
# XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still
|
||||
# go to __stderr__. With subprocess, they go to the shell.
|
||||
# Need to change streams in PyShell.ModifiedInterpreter.
|
||||
interp.runcode(code)
|
||||
return 'break'
|
||||
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
# Tk-Cocoa in MacOSX is broken until at least
|
||||
# Tk 8.5.9, and without this rather
|
||||
# crude workaround IDLE would hang when a user
|
||||
# tries to run a module using the keyboard shortcut
|
||||
# (the menu item works fine).
|
||||
_run_module_event = run_module_event
|
||||
|
||||
def run_module_event(self, event):
|
||||
self.editwin.text_frame.after(200,
|
||||
lambda: self.editwin.text_frame.event_generate('<<run-module-event-2>>'))
|
||||
return 'break'
|
||||
|
||||
def getfilename(self):
|
||||
"""Get source filename. If not saved, offer to save (or create) file
|
||||
|
||||
The debugger requires a source file. Make sure there is one, and that
|
||||
the current version of the source buffer has been saved. If the user
|
||||
declines to save or cancels the Save As dialog, return None.
|
||||
|
||||
If the user has configured IDLE for Autosave, the file will be
|
||||
silently saved if it already exists and is dirty.
|
||||
|
||||
"""
|
||||
filename = self.editwin.io.filename
|
||||
if not self.editwin.get_saved():
|
||||
autosave = idleConf.GetOption('main', 'General',
|
||||
'autosave', type='bool')
|
||||
if autosave and filename:
|
||||
self.editwin.io.save(None)
|
||||
else:
|
||||
confirm = self.ask_save_dialog()
|
||||
self.editwin.text.focus_set()
|
||||
if confirm:
|
||||
self.editwin.io.save(None)
|
||||
filename = self.editwin.io.filename
|
||||
else:
|
||||
filename = None
|
||||
return filename
|
||||
|
||||
def ask_save_dialog(self):
|
||||
msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?"
|
||||
confirm = tkMessageBox.askokcancel(title="Save Before Run or Check",
|
||||
message=msg,
|
||||
default=tkMessageBox.OK,
|
||||
master=self.editwin.text)
|
||||
return confirm
|
||||
|
||||
def errorbox(self, title, message):
|
||||
# XXX This should really be a function of EditorWindow...
|
||||
tkMessageBox.showerror(title, message, master=self.editwin.text)
|
||||
self.editwin.text.focus_set()
|
||||
139
Darwin/lib/python2.7/idlelib/ScrolledList.py
Normal file
139
Darwin/lib/python2.7/idlelib/ScrolledList.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
from Tkinter import *
|
||||
|
||||
class ScrolledList:
|
||||
|
||||
default = "(None)"
|
||||
|
||||
def __init__(self, master, **options):
|
||||
# Create top frame, with scrollbar and listbox
|
||||
self.master = master
|
||||
self.frame = frame = Frame(master)
|
||||
self.frame.pack(fill="both", expand=1)
|
||||
self.vbar = vbar = Scrollbar(frame, name="vbar")
|
||||
self.vbar.pack(side="right", fill="y")
|
||||
self.listbox = listbox = Listbox(frame, exportselection=0,
|
||||
background="white")
|
||||
if options:
|
||||
listbox.configure(options)
|
||||
listbox.pack(expand=1, fill="both")
|
||||
# Tie listbox and scrollbar together
|
||||
vbar["command"] = listbox.yview
|
||||
listbox["yscrollcommand"] = vbar.set
|
||||
# Bind events to the list box
|
||||
listbox.bind("<ButtonRelease-1>", self.click_event)
|
||||
listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
|
||||
listbox.bind("<ButtonPress-3>", self.popup_event)
|
||||
listbox.bind("<Key-Up>", self.up_event)
|
||||
listbox.bind("<Key-Down>", self.down_event)
|
||||
# Mark as empty
|
||||
self.clear()
|
||||
|
||||
def close(self):
|
||||
self.frame.destroy()
|
||||
|
||||
def clear(self):
|
||||
self.listbox.delete(0, "end")
|
||||
self.empty = 1
|
||||
self.listbox.insert("end", self.default)
|
||||
|
||||
def append(self, item):
|
||||
if self.empty:
|
||||
self.listbox.delete(0, "end")
|
||||
self.empty = 0
|
||||
self.listbox.insert("end", str(item))
|
||||
|
||||
def get(self, index):
|
||||
return self.listbox.get(index)
|
||||
|
||||
def click_event(self, event):
|
||||
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
||||
index = self.listbox.index("active")
|
||||
self.select(index)
|
||||
self.on_select(index)
|
||||
return "break"
|
||||
|
||||
def double_click_event(self, event):
|
||||
index = self.listbox.index("active")
|
||||
self.select(index)
|
||||
self.on_double(index)
|
||||
return "break"
|
||||
|
||||
menu = None
|
||||
|
||||
def popup_event(self, event):
|
||||
if not self.menu:
|
||||
self.make_menu()
|
||||
menu = self.menu
|
||||
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
||||
index = self.listbox.index("active")
|
||||
self.select(index)
|
||||
menu.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
def make_menu(self):
|
||||
menu = Menu(self.listbox, tearoff=0)
|
||||
self.menu = menu
|
||||
self.fill_menu()
|
||||
|
||||
def up_event(self, event):
|
||||
index = self.listbox.index("active")
|
||||
if self.listbox.selection_includes(index):
|
||||
index = index - 1
|
||||
else:
|
||||
index = self.listbox.size() - 1
|
||||
if index < 0:
|
||||
self.listbox.bell()
|
||||
else:
|
||||
self.select(index)
|
||||
self.on_select(index)
|
||||
return "break"
|
||||
|
||||
def down_event(self, event):
|
||||
index = self.listbox.index("active")
|
||||
if self.listbox.selection_includes(index):
|
||||
index = index + 1
|
||||
else:
|
||||
index = 0
|
||||
if index >= self.listbox.size():
|
||||
self.listbox.bell()
|
||||
else:
|
||||
self.select(index)
|
||||
self.on_select(index)
|
||||
return "break"
|
||||
|
||||
def select(self, index):
|
||||
self.listbox.focus_set()
|
||||
self.listbox.activate(index)
|
||||
self.listbox.selection_clear(0, "end")
|
||||
self.listbox.selection_set(index)
|
||||
self.listbox.see(index)
|
||||
|
||||
# Methods to override for specific actions
|
||||
|
||||
def fill_menu(self):
|
||||
pass
|
||||
|
||||
def on_select(self, index):
|
||||
pass
|
||||
|
||||
def on_double(self, index):
|
||||
pass
|
||||
|
||||
|
||||
def test():
|
||||
root = Tk()
|
||||
root.protocol("WM_DELETE_WINDOW", root.destroy)
|
||||
class MyScrolledList(ScrolledList):
|
||||
def fill_menu(self): self.menu.add_command(label="pass")
|
||||
def on_select(self, index): print "select", self.get(index)
|
||||
def on_double(self, index): print "double", self.get(index)
|
||||
s = MyScrolledList(root)
|
||||
for i in range(30):
|
||||
s.append("item %02d" % i)
|
||||
return root
|
||||
|
||||
def main():
|
||||
root = test()
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
67
Darwin/lib/python2.7/idlelib/SearchDialog.py
Normal file
67
Darwin/lib/python2.7/idlelib/SearchDialog.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
from Tkinter import *
|
||||
|
||||
from idlelib import SearchEngine
|
||||
from idlelib.SearchDialogBase import SearchDialogBase
|
||||
|
||||
def _setup(text):
|
||||
root = text._root()
|
||||
engine = SearchEngine.get(root)
|
||||
if not hasattr(engine, "_searchdialog"):
|
||||
engine._searchdialog = SearchDialog(root, engine)
|
||||
return engine._searchdialog
|
||||
|
||||
def find(text):
|
||||
pat = text.get("sel.first", "sel.last")
|
||||
return _setup(text).open(text,pat)
|
||||
|
||||
def find_again(text):
|
||||
return _setup(text).find_again(text)
|
||||
|
||||
def find_selection(text):
|
||||
return _setup(text).find_selection(text)
|
||||
|
||||
class SearchDialog(SearchDialogBase):
|
||||
|
||||
def create_widgets(self):
|
||||
f = SearchDialogBase.create_widgets(self)
|
||||
self.make_button("Find Next", self.default_command, 1)
|
||||
|
||||
def default_command(self, event=None):
|
||||
if not self.engine.getprog():
|
||||
return
|
||||
self.find_again(self.text)
|
||||
|
||||
def find_again(self, text):
|
||||
if not self.engine.getpat():
|
||||
self.open(text)
|
||||
return False
|
||||
if not self.engine.getprog():
|
||||
return False
|
||||
res = self.engine.search_text(text)
|
||||
if res:
|
||||
line, m = res
|
||||
i, j = m.span()
|
||||
first = "%d.%d" % (line, i)
|
||||
last = "%d.%d" % (line, j)
|
||||
try:
|
||||
selfirst = text.index("sel.first")
|
||||
sellast = text.index("sel.last")
|
||||
if selfirst == first and sellast == last:
|
||||
text.bell()
|
||||
return False
|
||||
except TclError:
|
||||
pass
|
||||
text.tag_remove("sel", "1.0", "end")
|
||||
text.tag_add("sel", first, last)
|
||||
text.mark_set("insert", self.engine.isback() and first or last)
|
||||
text.see("insert")
|
||||
return True
|
||||
else:
|
||||
text.bell()
|
||||
return False
|
||||
|
||||
def find_selection(self, text):
|
||||
pat = text.get("sel.first", "sel.last")
|
||||
if pat:
|
||||
self.engine.setcookedpat(pat)
|
||||
return self.find_again(text)
|
||||
157
Darwin/lib/python2.7/idlelib/SearchDialogBase.py
Normal file
157
Darwin/lib/python2.7/idlelib/SearchDialogBase.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
'''Define SearchDialogBase used by Search, Replace, and Grep dialogs.'''
|
||||
from Tkinter import *
|
||||
|
||||
class SearchDialogBase:
|
||||
'''Create most of a modal search dialog (make_frame, create_widgets).
|
||||
|
||||
The wide left column contains:
|
||||
1 or 2 text entry lines (create_entries, make_entry);
|
||||
a row of standard radiobuttons (create_option_buttons);
|
||||
a row of dialog specific radiobuttons (create_other_buttons).
|
||||
|
||||
The narrow right column contains command buttons
|
||||
(create_command_buttons, make_button).
|
||||
These are bound to functions that execute the command.
|
||||
|
||||
Except for command buttons, this base class is not limited to
|
||||
items common to all three subclasses. Rather, it is the Find dialog
|
||||
minus the "Find Next" command and its execution function.
|
||||
The other dialogs override methods to replace and add widgets.
|
||||
'''
|
||||
|
||||
title = "Search Dialog"
|
||||
icon = "Search"
|
||||
needwrapbutton = 1
|
||||
|
||||
def __init__(self, root, engine):
|
||||
self.root = root
|
||||
self.engine = engine
|
||||
self.top = None
|
||||
|
||||
def open(self, text, searchphrase=None):
|
||||
self.text = text
|
||||
if not self.top:
|
||||
self.create_widgets()
|
||||
else:
|
||||
self.top.deiconify()
|
||||
self.top.tkraise()
|
||||
if searchphrase:
|
||||
self.ent.delete(0,"end")
|
||||
self.ent.insert("end",searchphrase)
|
||||
self.ent.focus_set()
|
||||
self.ent.selection_range(0, "end")
|
||||
self.ent.icursor(0)
|
||||
self.top.grab_set()
|
||||
|
||||
def close(self, event=None):
|
||||
if self.top:
|
||||
self.top.grab_release()
|
||||
self.top.withdraw()
|
||||
|
||||
def create_widgets(self):
|
||||
top = Toplevel(self.root)
|
||||
top.bind("<Return>", self.default_command)
|
||||
top.bind("<Escape>", self.close)
|
||||
top.protocol("WM_DELETE_WINDOW", self.close)
|
||||
top.wm_title(self.title)
|
||||
top.wm_iconname(self.icon)
|
||||
self.top = top
|
||||
|
||||
self.row = 0
|
||||
self.top.grid_columnconfigure(0, pad=2, weight=0)
|
||||
self.top.grid_columnconfigure(1, pad=2, minsize=100, weight=100)
|
||||
|
||||
self.create_entries()
|
||||
self.create_option_buttons()
|
||||
self.create_other_buttons()
|
||||
return self.create_command_buttons()
|
||||
|
||||
def make_entry(self, label, var):
|
||||
l = Label(self.top, text=label)
|
||||
l.grid(row=self.row, column=0, sticky="nw")
|
||||
e = Entry(self.top, textvariable=var, exportselection=0)
|
||||
e.grid(row=self.row, column=1, sticky="nwe")
|
||||
self.row = self.row + 1
|
||||
return e
|
||||
|
||||
def make_frame(self,labeltext=None):
|
||||
if labeltext:
|
||||
l = Label(self.top, text=labeltext)
|
||||
l.grid(row=self.row, column=0, sticky="nw")
|
||||
f = Frame(self.top)
|
||||
f.grid(row=self.row, column=1, columnspan=1, sticky="nwe")
|
||||
self.row = self.row + 1
|
||||
return f
|
||||
|
||||
def make_button(self, label, command, isdef=0):
|
||||
b = Button(self.buttonframe,
|
||||
text=label, command=command,
|
||||
default=isdef and "active" or "normal")
|
||||
cols,rows=self.buttonframe.grid_size()
|
||||
b.grid(pady=1,row=rows,column=0,sticky="ew")
|
||||
self.buttonframe.grid(rowspan=rows+1)
|
||||
return b
|
||||
|
||||
def create_entries(self):
|
||||
self.ent = self.make_entry("Find:", self.engine.patvar)
|
||||
|
||||
def create_option_buttons(self):
|
||||
f = self.make_frame("Options")
|
||||
|
||||
btn = Checkbutton(f, anchor="w",
|
||||
variable=self.engine.revar,
|
||||
text="Regular expression")
|
||||
btn.pack(side="left", fill="both")
|
||||
if self.engine.isre():
|
||||
btn.select()
|
||||
|
||||
btn = Checkbutton(f, anchor="w",
|
||||
variable=self.engine.casevar,
|
||||
text="Match case")
|
||||
btn.pack(side="left", fill="both")
|
||||
if self.engine.iscase():
|
||||
btn.select()
|
||||
|
||||
btn = Checkbutton(f, anchor="w",
|
||||
variable=self.engine.wordvar,
|
||||
text="Whole word")
|
||||
btn.pack(side="left", fill="both")
|
||||
if self.engine.isword():
|
||||
btn.select()
|
||||
|
||||
if self.needwrapbutton:
|
||||
btn = Checkbutton(f, anchor="w",
|
||||
variable=self.engine.wrapvar,
|
||||
text="Wrap around")
|
||||
btn.pack(side="left", fill="both")
|
||||
if self.engine.iswrap():
|
||||
btn.select()
|
||||
|
||||
def create_other_buttons(self):
|
||||
f = self.make_frame("Direction")
|
||||
|
||||
#lbl = Label(f, text="Direction: ")
|
||||
#lbl.pack(side="left")
|
||||
|
||||
btn = Radiobutton(f, anchor="w",
|
||||
variable=self.engine.backvar, value=1,
|
||||
text="Up")
|
||||
btn.pack(side="left", fill="both")
|
||||
if self.engine.isback():
|
||||
btn.select()
|
||||
|
||||
btn = Radiobutton(f, anchor="w",
|
||||
variable=self.engine.backvar, value=0,
|
||||
text="Down")
|
||||
btn.pack(side="left", fill="both")
|
||||
if not self.engine.isback():
|
||||
btn.select()
|
||||
|
||||
def create_command_buttons(self):
|
||||
#
|
||||
# place button frame on the right
|
||||
f = self.buttonframe = Frame(self.top)
|
||||
f.grid(row=0,column=2,padx=2,pady=2,ipadx=2,ipady=2)
|
||||
|
||||
b = self.make_button("close", self.close)
|
||||
b.lower()
|
||||
236
Darwin/lib/python2.7/idlelib/SearchEngine.py
Normal file
236
Darwin/lib/python2.7/idlelib/SearchEngine.py
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
'''Define SearchEngine for search dialogs.'''
|
||||
import re
|
||||
from Tkinter import StringVar, BooleanVar, TclError
|
||||
import tkMessageBox
|
||||
|
||||
def get(root):
|
||||
'''Return the singleton SearchEngine instance for the process.
|
||||
|
||||
The single SearchEngine saves settings between dialog instances.
|
||||
If there is not a SearchEngine already, make one.
|
||||
'''
|
||||
if not hasattr(root, "_searchengine"):
|
||||
root._searchengine = SearchEngine(root)
|
||||
# This creates a cycle that persists until root is deleted.
|
||||
return root._searchengine
|
||||
|
||||
class SearchEngine:
|
||||
"""Handles searching a text widget for Find, Replace, and Grep."""
|
||||
|
||||
def __init__(self, root):
|
||||
'''Initialize Variables that save search state.
|
||||
|
||||
The dialogs bind these to the UI elements present in the dialogs.
|
||||
'''
|
||||
self.root = root # need for report_error()
|
||||
self.patvar = StringVar(root, '') # search pattern
|
||||
self.revar = BooleanVar(root, False) # regular expression?
|
||||
self.casevar = BooleanVar(root, False) # match case?
|
||||
self.wordvar = BooleanVar(root, False) # match whole word?
|
||||
self.wrapvar = BooleanVar(root, True) # wrap around buffer?
|
||||
self.backvar = BooleanVar(root, False) # search backwards?
|
||||
|
||||
# Access methods
|
||||
|
||||
def getpat(self):
|
||||
return self.patvar.get()
|
||||
|
||||
def setpat(self, pat):
|
||||
self.patvar.set(pat)
|
||||
|
||||
def isre(self):
|
||||
return self.revar.get()
|
||||
|
||||
def iscase(self):
|
||||
return self.casevar.get()
|
||||
|
||||
def isword(self):
|
||||
return self.wordvar.get()
|
||||
|
||||
def iswrap(self):
|
||||
return self.wrapvar.get()
|
||||
|
||||
def isback(self):
|
||||
return self.backvar.get()
|
||||
|
||||
# Higher level access methods
|
||||
|
||||
def setcookedpat(self, pat):
|
||||
"Set pattern after escaping if re."
|
||||
# called only in SearchDialog.py: 66
|
||||
if self.isre():
|
||||
pat = re.escape(pat)
|
||||
self.setpat(pat)
|
||||
|
||||
def getcookedpat(self):
|
||||
pat = self.getpat()
|
||||
if not self.isre(): # if True, see setcookedpat
|
||||
pat = re.escape(pat)
|
||||
if self.isword():
|
||||
pat = r"\b%s\b" % pat
|
||||
return pat
|
||||
|
||||
def getprog(self):
|
||||
"Return compiled cooked search pattern."
|
||||
pat = self.getpat()
|
||||
if not pat:
|
||||
self.report_error(pat, "Empty regular expression")
|
||||
return None
|
||||
pat = self.getcookedpat()
|
||||
flags = 0
|
||||
if not self.iscase():
|
||||
flags = flags | re.IGNORECASE
|
||||
try:
|
||||
prog = re.compile(pat, flags)
|
||||
except re.error as what:
|
||||
try:
|
||||
msg, col = what
|
||||
except:
|
||||
msg = str(what)
|
||||
col = -1
|
||||
self.report_error(pat, msg, col)
|
||||
return None
|
||||
return prog
|
||||
|
||||
def report_error(self, pat, msg, col=-1):
|
||||
# Derived class could override this with something fancier
|
||||
msg = "Error: " + str(msg)
|
||||
if pat:
|
||||
msg = msg + "\nPattern: " + str(pat)
|
||||
if col >= 0:
|
||||
msg = msg + "\nOffset: " + str(col)
|
||||
tkMessageBox.showerror("Regular expression error",
|
||||
msg, master=self.root)
|
||||
|
||||
def search_text(self, text, prog=None, ok=0):
|
||||
'''Return (lineno, matchobj) or None for forward/backward search.
|
||||
|
||||
This function calls the right function with the right arguments.
|
||||
It directly return the result of that call.
|
||||
|
||||
Text is a text widget. Prog is a precompiled pattern.
|
||||
The ok parameteris a bit complicated as it has two effects.
|
||||
|
||||
If there is a selection, the search begin at either end,
|
||||
depending on the direction setting and ok, with ok meaning that
|
||||
the search starts with the selection. Otherwise, search begins
|
||||
at the insert mark.
|
||||
|
||||
To aid progress, the search functions do not return an empty
|
||||
match at the starting position unless ok is True.
|
||||
'''
|
||||
|
||||
if not prog:
|
||||
prog = self.getprog()
|
||||
if not prog:
|
||||
return None # Compilation failed -- stop
|
||||
wrap = self.wrapvar.get()
|
||||
first, last = get_selection(text)
|
||||
if self.isback():
|
||||
if ok:
|
||||
start = last
|
||||
else:
|
||||
start = first
|
||||
line, col = get_line_col(start)
|
||||
res = self.search_backward(text, prog, line, col, wrap, ok)
|
||||
else:
|
||||
if ok:
|
||||
start = first
|
||||
else:
|
||||
start = last
|
||||
line, col = get_line_col(start)
|
||||
res = self.search_forward(text, prog, line, col, wrap, ok)
|
||||
return res
|
||||
|
||||
def search_forward(self, text, prog, line, col, wrap, ok=0):
|
||||
wrapped = 0
|
||||
startline = line
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
while chars:
|
||||
m = prog.search(chars[:-1], col)
|
||||
if m:
|
||||
if ok or m.end() > col:
|
||||
return line, m
|
||||
line = line + 1
|
||||
if wrapped and line > startline:
|
||||
break
|
||||
col = 0
|
||||
ok = 1
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
if not chars and wrap:
|
||||
wrapped = 1
|
||||
wrap = 0
|
||||
line = 1
|
||||
chars = text.get("1.0", "2.0")
|
||||
return None
|
||||
|
||||
def search_backward(self, text, prog, line, col, wrap, ok=0):
|
||||
wrapped = 0
|
||||
startline = line
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
while 1:
|
||||
m = search_reverse(prog, chars[:-1], col)
|
||||
if m:
|
||||
if ok or m.start() < col:
|
||||
return line, m
|
||||
line = line - 1
|
||||
if wrapped and line < startline:
|
||||
break
|
||||
ok = 1
|
||||
if line <= 0:
|
||||
if not wrap:
|
||||
break
|
||||
wrapped = 1
|
||||
wrap = 0
|
||||
pos = text.index("end-1c")
|
||||
line, col = map(int, pos.split("."))
|
||||
chars = text.get("%d.0" % line, "%d.0" % (line+1))
|
||||
col = len(chars) - 1
|
||||
return None
|
||||
|
||||
def search_reverse(prog, chars, col):
|
||||
'''Search backwards and return an re match object or None.
|
||||
|
||||
This is done by searching forwards until there is no match.
|
||||
Prog: compiled re object with a search method returning a match.
|
||||
Chars: line of text, without \n.
|
||||
Col: stop index for the search; the limit for match.end().
|
||||
'''
|
||||
m = prog.search(chars)
|
||||
if not m:
|
||||
return None
|
||||
found = None
|
||||
i, j = m.span() # m.start(), m.end() == match slice indexes
|
||||
while i < col and j <= col:
|
||||
found = m
|
||||
if i == j:
|
||||
j = j+1
|
||||
m = prog.search(chars, j)
|
||||
if not m:
|
||||
break
|
||||
i, j = m.span()
|
||||
return found
|
||||
|
||||
def get_selection(text):
|
||||
'''Return tuple of 'line.col' indexes from selection or insert mark.
|
||||
'''
|
||||
try:
|
||||
first = text.index("sel.first")
|
||||
last = text.index("sel.last")
|
||||
except TclError:
|
||||
first = last = None
|
||||
if not first:
|
||||
first = text.index("insert")
|
||||
if not last:
|
||||
last = first
|
||||
return first, last
|
||||
|
||||
def get_line_col(index):
|
||||
'''Return (line, col) tuple of ints from 'line.col' string.'''
|
||||
line, col = map(int, index.split(".")) # Fails on invalid index
|
||||
return line, col
|
||||
|
||||
if __name__ == "__main__":
|
||||
from test import support; support.use_resources = ['gui']
|
||||
import unittest
|
||||
unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)
|
||||
137
Darwin/lib/python2.7/idlelib/StackViewer.py
Normal file
137
Darwin/lib/python2.7/idlelib/StackViewer.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import os
|
||||
import sys
|
||||
import linecache
|
||||
|
||||
from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas
|
||||
from idlelib.ObjectBrowser import ObjectTreeItem, make_objecttreeitem
|
||||
|
||||
def StackBrowser(root, flist=None, tb=None, top=None):
|
||||
if top is None:
|
||||
from Tkinter import Toplevel
|
||||
top = Toplevel(root)
|
||||
sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
|
||||
sc.frame.pack(expand=1, fill="both")
|
||||
item = StackTreeItem(flist, tb)
|
||||
node = TreeNode(sc.canvas, None, item)
|
||||
node.expand()
|
||||
|
||||
class StackTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, flist=None, tb=None):
|
||||
self.flist = flist
|
||||
self.stack = self.get_stack(tb)
|
||||
self.text = self.get_exception()
|
||||
|
||||
def get_stack(self, tb):
|
||||
if tb is None:
|
||||
tb = sys.last_traceback
|
||||
stack = []
|
||||
if tb and tb.tb_frame is None:
|
||||
tb = tb.tb_next
|
||||
while tb is not None:
|
||||
stack.append((tb.tb_frame, tb.tb_lineno))
|
||||
tb = tb.tb_next
|
||||
return stack
|
||||
|
||||
def get_exception(self):
|
||||
type = sys.last_type
|
||||
value = sys.last_value
|
||||
if hasattr(type, "__name__"):
|
||||
type = type.__name__
|
||||
s = str(type)
|
||||
if value is not None:
|
||||
s = s + ": " + str(value)
|
||||
return s
|
||||
|
||||
def GetText(self):
|
||||
return self.text
|
||||
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for info in self.stack:
|
||||
item = FrameTreeItem(info, self.flist)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
class FrameTreeItem(TreeItem):
|
||||
|
||||
def __init__(self, info, flist):
|
||||
self.info = info
|
||||
self.flist = flist
|
||||
|
||||
def GetText(self):
|
||||
frame, lineno = self.info
|
||||
try:
|
||||
modname = frame.f_globals["__name__"]
|
||||
except:
|
||||
modname = "?"
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
funcname = code.co_name
|
||||
sourceline = linecache.getline(filename, lineno)
|
||||
sourceline = sourceline.strip()
|
||||
if funcname in ("?", "", None):
|
||||
item = "%s, line %d: %s" % (modname, lineno, sourceline)
|
||||
else:
|
||||
item = "%s.%s(...), line %d: %s" % (modname, funcname,
|
||||
lineno, sourceline)
|
||||
return item
|
||||
|
||||
def GetSubList(self):
|
||||
frame, lineno = self.info
|
||||
sublist = []
|
||||
if frame.f_globals is not frame.f_locals:
|
||||
item = VariablesTreeItem("<locals>", frame.f_locals, self.flist)
|
||||
sublist.append(item)
|
||||
item = VariablesTreeItem("<globals>", frame.f_globals, self.flist)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
def OnDoubleClick(self):
|
||||
if self.flist:
|
||||
frame, lineno = self.info
|
||||
filename = frame.f_code.co_filename
|
||||
if os.path.isfile(filename):
|
||||
self.flist.gotofileline(filename, lineno)
|
||||
|
||||
class VariablesTreeItem(ObjectTreeItem):
|
||||
|
||||
def GetText(self):
|
||||
return self.labeltext
|
||||
|
||||
def GetLabelText(self):
|
||||
return None
|
||||
|
||||
def IsExpandable(self):
|
||||
return len(self.object) > 0
|
||||
|
||||
def keys(self):
|
||||
return self.object.keys()
|
||||
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for key in self.keys():
|
||||
try:
|
||||
value = self.object[key]
|
||||
except KeyError:
|
||||
continue
|
||||
def setfunction(value, key=key, object=self.object):
|
||||
object[key] = value
|
||||
item = make_objecttreeitem(key + " =", value, setfunction)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
|
||||
def _test():
|
||||
try:
|
||||
import testcode
|
||||
reload(testcode)
|
||||
except:
|
||||
sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info()
|
||||
from Tkinter import Tk
|
||||
root = Tk()
|
||||
StackBrowser(None, top=root)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
210
Darwin/lib/python2.7/idlelib/TODO.txt
Normal file
210
Darwin/lib/python2.7/idlelib/TODO.txt
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
Original IDLE todo, much of it now outdated:
|
||||
============================================
|
||||
TO DO:
|
||||
|
||||
- improve debugger:
|
||||
- manage breakpoints globally, allow bp deletion, tbreak, cbreak etc.
|
||||
- real object browser
|
||||
- help on how to use it (a simple help button will do wonders)
|
||||
- performance? (updates of large sets of locals are slow)
|
||||
- better integration of "debug module"
|
||||
- debugger should be global resource (attached to flist, not to shell)
|
||||
- fix the stupid bug where you need to step twice
|
||||
- display class name in stack viewer entries for methods
|
||||
- suppress tracing through IDLE internals (e.g. print) DONE
|
||||
- add a button to suppress through a specific module or class or method
|
||||
- more object inspection to stack viewer, e.g. to view all array items
|
||||
- insert the initial current directory into sys.path DONE
|
||||
- default directory attribute for each window instead of only for windows
|
||||
that have an associated filename
|
||||
- command expansion from keywords, module contents, other buffers, etc.
|
||||
- "Recent documents" menu item DONE
|
||||
- Filter region command
|
||||
- Optional horizontal scroll bar
|
||||
- more Emacsisms:
|
||||
- ^K should cut to buffer
|
||||
- M-[, M-] to move by paragraphs
|
||||
- incremental search?
|
||||
- search should indicate wrap-around in some way
|
||||
- restructure state sensitive code to avoid testing flags all the time
|
||||
- persistent user state (e.g. window and cursor positions, bindings)
|
||||
- make backups when saving
|
||||
- check file mtimes at various points
|
||||
- Pluggable interface with RCS/CVS/Perforce/Clearcase
|
||||
- better help?
|
||||
- don't open second class browser on same module (nor second path browser)
|
||||
- unify class and path browsers
|
||||
- Need to define a standard way whereby one can determine one is running
|
||||
inside IDLE (needed for Tk mainloop, also handy for $PYTHONSTARTUP)
|
||||
- Add more utility methods for use by extensions (a la get_selection)
|
||||
- Way to run command in totally separate interpreter (fork+os.system?) DONE
|
||||
- Way to find definition of fully-qualified name:
|
||||
In other words, select "UserDict.UserDict", hit some magic key and
|
||||
it loads up UserDict.py and finds the first def or class for UserDict.
|
||||
- need a way to force colorization on/off
|
||||
- need a way to force auto-indent on/off
|
||||
|
||||
Details:
|
||||
|
||||
- ^O (on Unix -- open-line) should honor autoindent
|
||||
- after paste, show end of pasted text
|
||||
- on Windows, should turn short filename to long filename (not only in argv!)
|
||||
(shouldn't this be done -- or undone -- by ntpath.normpath?)
|
||||
- new autoindent after colon even indents when the colon is in a comment!
|
||||
- sometimes forward slashes in pathname remain
|
||||
- sometimes star in window name remains in Windows menu
|
||||
- With unix bindings, ESC by itself is ignored
|
||||
- Sometimes for no apparent reason a selection from the cursor to the
|
||||
end of the command buffer appears, which is hard to get rid of
|
||||
because it stays when you are typing!
|
||||
- The Line/Col in the status bar can be wrong initially in PyShell DONE
|
||||
|
||||
Structural problems:
|
||||
|
||||
- too much knowledge in FileList about EditorWindow (for example)
|
||||
- should add some primitives for accessing the selection etc.
|
||||
to repeat cumbersome code over and over
|
||||
|
||||
======================================================================
|
||||
|
||||
Jeff Bauer suggests:
|
||||
|
||||
- Open Module doesn't appear to handle hierarchical packages.
|
||||
- Class browser should also allow hierarchical packages.
|
||||
- Open and Open Module could benefit from a history, DONE
|
||||
either command line style, or Microsoft recent-file
|
||||
style.
|
||||
- Add a Smalltalk-style inspector (i.e. Tkinspect)
|
||||
|
||||
The last suggestion is already a reality, but not yet
|
||||
integrated into IDLE. I use a module called inspector.py,
|
||||
that used to be available from python.org(?) It no longer
|
||||
appears to be in the contributed section, and the source
|
||||
has no author attribution.
|
||||
|
||||
In any case, the code is useful for visually navigating
|
||||
an object's attributes, including its container hierarchy.
|
||||
|
||||
>>> from inspector import Tkinspect
|
||||
>>> Tkinspect(None, myObject)
|
||||
|
||||
Tkinspect could probably be extended and refined to
|
||||
integrate better into IDLE.
|
||||
|
||||
======================================================================
|
||||
|
||||
Comparison to PTUI
|
||||
------------------
|
||||
|
||||
+ PTUI's help is better (HTML!)
|
||||
|
||||
+ PTUI can attach a shell to any module
|
||||
|
||||
+ PTUI has some more I/O commands:
|
||||
open multiple
|
||||
append
|
||||
examine (what's that?)
|
||||
|
||||
======================================================================
|
||||
|
||||
Notes after trying to run Grail
|
||||
-------------------------------
|
||||
|
||||
- Grail does stuff to sys.path based on sys.argv[0]; you must set
|
||||
sys.argv[0] to something decent first (it is normally set to the path of
|
||||
the idle script).
|
||||
|
||||
- Grail must be exec'ed in __main__ because that's imported by some
|
||||
other parts of Grail.
|
||||
|
||||
- Grail uses a module called History and so does idle :-(
|
||||
|
||||
======================================================================
|
||||
|
||||
Robin Friedrich's items:
|
||||
|
||||
Things I'd like to see:
|
||||
- I'd like support for shift-click extending the selection. There's a
|
||||
bug now that it doesn't work the first time you try it.
|
||||
- Printing is needed. How hard can that be on Windows? FIRST CUT DONE
|
||||
- The python-mode trick of autoindenting a line with <tab> is neat and
|
||||
very handy.
|
||||
- (someday) a spellchecker for docstrings and comments.
|
||||
- a pagedown/up command key which moves to next class/def statement (top
|
||||
level)
|
||||
- split window capability
|
||||
- DnD text relocation/copying
|
||||
|
||||
Things I don't want to see.
|
||||
- line numbers... will probably slow things down way too much.
|
||||
- Please use another icon for the tree browser leaf. The small snake
|
||||
isn't cutting it.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
- Customizable views (multi-window or multi-pane). (Markus Gritsch)
|
||||
|
||||
- Being able to double click (maybe double right click) on a callable
|
||||
object in the editor which shows the source of the object, if
|
||||
possible. (Gerrit Holl)
|
||||
|
||||
- Hooks into the guts, like in Emacs. (Mike Romberg)
|
||||
|
||||
- Sharing the editor with a remote tutor. (Martijn Faassen)
|
||||
|
||||
- Multiple views on the same file. (Tony J Ibbs)
|
||||
|
||||
- Store breakpoints in a global (per-project) database (GvR); Dirk
|
||||
Heise adds: save some space-trimmed context and search around when
|
||||
reopening a file that might have been edited by someone else.
|
||||
|
||||
- Capture menu events in extensions without changing the IDLE source.
|
||||
(Matthias Barmeier)
|
||||
|
||||
- Use overlapping panels (a "notebook" in MFC terms I think) for info
|
||||
that doesn't need to be accessible simultaneously (e.g. HTML source
|
||||
and output). Use multi-pane windows for info that does need to be
|
||||
shown together (e.g. class browser and source). (Albert Brandl)
|
||||
|
||||
- A project should invisibly track all symbols, for instant search,
|
||||
replace and cross-ref. Projects should be allowed to span multiple
|
||||
directories, hosts, etc. Project management files are placed in a
|
||||
directory you specify. A global mapping between project names and
|
||||
project directories should exist [not so sure --GvR]. (Tim Peters)
|
||||
|
||||
- Merge attr-tips and auto-expand. (Mark Hammond, Tim Peters)
|
||||
|
||||
- Python Shell should behave more like a "shell window" as users know
|
||||
it -- i.e. you can only edit the current command, and the cursor can't
|
||||
escape from the command area. (Albert Brandl)
|
||||
|
||||
- Set X11 class to "idle/Idle", set icon and title to something
|
||||
beginning with "idle" -- for window manangers. (Randall Hopper)
|
||||
|
||||
- Config files editable through a preferences dialog. (me) DONE
|
||||
|
||||
- Config files still editable outside the preferences dialog.
|
||||
(Randall Hopper) DONE
|
||||
|
||||
- When you're editing a command in PyShell, and there are only blank
|
||||
lines below the cursor, hitting Return should ignore or delete those
|
||||
blank lines rather than deciding you're not on the last line. (me)
|
||||
|
||||
- Run command (F5 c.s.) should be more like Pythonwin's Run -- a
|
||||
dialog with options to give command line arguments, run the debugger,
|
||||
etc. (me)
|
||||
|
||||
- Shouldn't be able to delete part of the prompt (or any text before
|
||||
it) in the PyShell. (Martijn Faassen) DONE
|
||||
|
||||
- Emacs style auto-fill (also smart about comments and strings).
|
||||
(Jeremy Hylton)
|
||||
|
||||
- Output of Run Script should go to a separate output window, not to
|
||||
the shell window. Output of separate runs should all go to the same
|
||||
window but clearly delimited. (David Scherer) REJECT FIRST, LATTER DONE
|
||||
|
||||
- GUI form designer to kick VB's butt. (Robert Geiger) THAT'S NOT IDLE
|
||||
|
||||
- Printing! Possibly via generation of PDF files which the user must
|
||||
then send to the printer separately. (Dinu Gherman) FIRST CUT
|
||||
89
Darwin/lib/python2.7/idlelib/ToolTip.py
Normal file
89
Darwin/lib/python2.7/idlelib/ToolTip.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# general purpose 'tooltip' routines - currently unused in idlefork
|
||||
# (although the 'calltips' extension is partly based on this code)
|
||||
# may be useful for some purposes in (or almost in ;) the current project scope
|
||||
# Ideas gleaned from PySol
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
class ToolTipBase:
|
||||
|
||||
def __init__(self, button):
|
||||
self.button = button
|
||||
self.tipwindow = None
|
||||
self.id = None
|
||||
self.x = self.y = 0
|
||||
self._id1 = self.button.bind("<Enter>", self.enter)
|
||||
self._id2 = self.button.bind("<Leave>", self.leave)
|
||||
self._id3 = self.button.bind("<ButtonPress>", self.leave)
|
||||
|
||||
def enter(self, event=None):
|
||||
self.schedule()
|
||||
|
||||
def leave(self, event=None):
|
||||
self.unschedule()
|
||||
self.hidetip()
|
||||
|
||||
def schedule(self):
|
||||
self.unschedule()
|
||||
self.id = self.button.after(1500, self.showtip)
|
||||
|
||||
def unschedule(self):
|
||||
id = self.id
|
||||
self.id = None
|
||||
if id:
|
||||
self.button.after_cancel(id)
|
||||
|
||||
def showtip(self):
|
||||
if self.tipwindow:
|
||||
return
|
||||
# The tip window must be completely outside the button;
|
||||
# otherwise when the mouse enters the tip window we get
|
||||
# a leave event and it disappears, and then we get an enter
|
||||
# event and it reappears, and so on forever :-(
|
||||
x = self.button.winfo_rootx() + 20
|
||||
y = self.button.winfo_rooty() + self.button.winfo_height() + 1
|
||||
self.tipwindow = tw = Toplevel(self.button)
|
||||
tw.wm_overrideredirect(1)
|
||||
tw.wm_geometry("+%d+%d" % (x, y))
|
||||
self.showcontents()
|
||||
|
||||
def showcontents(self, text="Your text here"):
|
||||
# Override this in derived class
|
||||
label = Label(self.tipwindow, text=text, justify=LEFT,
|
||||
background="#ffffe0", relief=SOLID, borderwidth=1)
|
||||
label.pack()
|
||||
|
||||
def hidetip(self):
|
||||
tw = self.tipwindow
|
||||
self.tipwindow = None
|
||||
if tw:
|
||||
tw.destroy()
|
||||
|
||||
class ToolTip(ToolTipBase):
|
||||
def __init__(self, button, text):
|
||||
ToolTipBase.__init__(self, button)
|
||||
self.text = text
|
||||
def showcontents(self):
|
||||
ToolTipBase.showcontents(self, self.text)
|
||||
|
||||
class ListboxToolTip(ToolTipBase):
|
||||
def __init__(self, button, items):
|
||||
ToolTipBase.__init__(self, button)
|
||||
self.items = items
|
||||
def showcontents(self):
|
||||
listbox = Listbox(self.tipwindow, background="#ffffe0")
|
||||
listbox.pack()
|
||||
for item in self.items:
|
||||
listbox.insert(END, item)
|
||||
|
||||
def main():
|
||||
# Test code
|
||||
root = Tk()
|
||||
b = Button(root, text="Hello", command=root.destroy)
|
||||
b.pack()
|
||||
root.update()
|
||||
tip = ListboxToolTip(b, ["Hello", "world"])
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
477
Darwin/lib/python2.7/idlelib/TreeWidget.py
Normal file
477
Darwin/lib/python2.7/idlelib/TreeWidget.py
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
# XXX TO DO:
|
||||
# - popup menu
|
||||
# - support partial or total redisplay
|
||||
# - key bindings (instead of quick-n-dirty bindings on Canvas):
|
||||
# - up/down arrow keys to move focus around
|
||||
# - ditto for page up/down, home/end
|
||||
# - left/right arrows to expand/collapse & move out/in
|
||||
# - more doc strings
|
||||
# - add icons for "file", "module", "class", "method"; better "python" icon
|
||||
# - callback for selection???
|
||||
# - multiple-item selection
|
||||
# - tooltips
|
||||
# - redo geometry without magic numbers
|
||||
# - keep track of object ids to allow more careful cleaning
|
||||
# - optimize tree redraw after expand of subnode
|
||||
|
||||
import os
|
||||
from Tkinter import *
|
||||
import imp
|
||||
|
||||
from idlelib import ZoomHeight
|
||||
from idlelib.configHandler import idleConf
|
||||
|
||||
ICONDIR = "Icons"
|
||||
|
||||
# Look for Icons subdirectory in the same directory as this module
|
||||
try:
|
||||
_icondir = os.path.join(os.path.dirname(__file__), ICONDIR)
|
||||
except NameError:
|
||||
_icondir = ICONDIR
|
||||
if os.path.isdir(_icondir):
|
||||
ICONDIR = _icondir
|
||||
elif not os.path.isdir(ICONDIR):
|
||||
raise RuntimeError, "can't find icon directory (%r)" % (ICONDIR,)
|
||||
|
||||
def listicons(icondir=ICONDIR):
|
||||
"""Utility to display the available icons."""
|
||||
root = Tk()
|
||||
import glob
|
||||
list = glob.glob(os.path.join(icondir, "*.gif"))
|
||||
list.sort()
|
||||
images = []
|
||||
row = column = 0
|
||||
for file in list:
|
||||
name = os.path.splitext(os.path.basename(file))[0]
|
||||
image = PhotoImage(file=file, master=root)
|
||||
images.append(image)
|
||||
label = Label(root, image=image, bd=1, relief="raised")
|
||||
label.grid(row=row, column=column)
|
||||
label = Label(root, text=name)
|
||||
label.grid(row=row+1, column=column)
|
||||
column = column + 1
|
||||
if column >= 10:
|
||||
row = row+2
|
||||
column = 0
|
||||
root.images = images
|
||||
|
||||
|
||||
class TreeNode:
|
||||
|
||||
def __init__(self, canvas, parent, item):
|
||||
self.canvas = canvas
|
||||
self.parent = parent
|
||||
self.item = item
|
||||
self.state = 'collapsed'
|
||||
self.selected = False
|
||||
self.children = []
|
||||
self.x = self.y = None
|
||||
self.iconimages = {} # cache of PhotoImage instances for icons
|
||||
|
||||
def destroy(self):
|
||||
for c in self.children[:]:
|
||||
self.children.remove(c)
|
||||
c.destroy()
|
||||
self.parent = None
|
||||
|
||||
def geticonimage(self, name):
|
||||
try:
|
||||
return self.iconimages[name]
|
||||
except KeyError:
|
||||
pass
|
||||
file, ext = os.path.splitext(name)
|
||||
ext = ext or ".gif"
|
||||
fullname = os.path.join(ICONDIR, file + ext)
|
||||
image = PhotoImage(master=self.canvas, file=fullname)
|
||||
self.iconimages[name] = image
|
||||
return image
|
||||
|
||||
def select(self, event=None):
|
||||
if self.selected:
|
||||
return
|
||||
self.deselectall()
|
||||
self.selected = True
|
||||
self.canvas.delete(self.image_id)
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
|
||||
def deselect(self, event=None):
|
||||
if not self.selected:
|
||||
return
|
||||
self.selected = False
|
||||
self.canvas.delete(self.image_id)
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
|
||||
def deselectall(self):
|
||||
if self.parent:
|
||||
self.parent.deselectall()
|
||||
else:
|
||||
self.deselecttree()
|
||||
|
||||
def deselecttree(self):
|
||||
if self.selected:
|
||||
self.deselect()
|
||||
for child in self.children:
|
||||
child.deselecttree()
|
||||
|
||||
def flip(self, event=None):
|
||||
if self.state == 'expanded':
|
||||
self.collapse()
|
||||
else:
|
||||
self.expand()
|
||||
self.item.OnDoubleClick()
|
||||
return "break"
|
||||
|
||||
def expand(self, event=None):
|
||||
if not self.item._IsExpandable():
|
||||
return
|
||||
if self.state != 'expanded':
|
||||
self.state = 'expanded'
|
||||
self.update()
|
||||
self.view()
|
||||
|
||||
def collapse(self, event=None):
|
||||
if self.state != 'collapsed':
|
||||
self.state = 'collapsed'
|
||||
self.update()
|
||||
|
||||
def view(self):
|
||||
top = self.y - 2
|
||||
bottom = self.lastvisiblechild().y + 17
|
||||
height = bottom - top
|
||||
visible_top = self.canvas.canvasy(0)
|
||||
visible_height = self.canvas.winfo_height()
|
||||
visible_bottom = self.canvas.canvasy(visible_height)
|
||||
if visible_top <= top and bottom <= visible_bottom:
|
||||
return
|
||||
x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion'])
|
||||
if top >= visible_top and height <= visible_height:
|
||||
fraction = top + height - visible_height
|
||||
else:
|
||||
fraction = top
|
||||
fraction = float(fraction) / y1
|
||||
self.canvas.yview_moveto(fraction)
|
||||
|
||||
def lastvisiblechild(self):
|
||||
if self.children and self.state == 'expanded':
|
||||
return self.children[-1].lastvisiblechild()
|
||||
else:
|
||||
return self
|
||||
|
||||
def update(self):
|
||||
if self.parent:
|
||||
self.parent.update()
|
||||
else:
|
||||
oldcursor = self.canvas['cursor']
|
||||
self.canvas['cursor'] = "watch"
|
||||
self.canvas.update()
|
||||
self.canvas.delete(ALL) # XXX could be more subtle
|
||||
self.draw(7, 2)
|
||||
x0, y0, x1, y1 = self.canvas.bbox(ALL)
|
||||
self.canvas.configure(scrollregion=(0, 0, x1, y1))
|
||||
self.canvas['cursor'] = oldcursor
|
||||
|
||||
def draw(self, x, y):
|
||||
# XXX This hard-codes too many geometry constants!
|
||||
self.x, self.y = x, y
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
if self.state != 'expanded':
|
||||
return y+17
|
||||
# draw children
|
||||
if not self.children:
|
||||
sublist = self.item._GetSubList()
|
||||
if not sublist:
|
||||
# _IsExpandable() was mistaken; that's allowed
|
||||
return y+17
|
||||
for item in sublist:
|
||||
child = self.__class__(self.canvas, self, item)
|
||||
self.children.append(child)
|
||||
cx = x+20
|
||||
cy = y+17
|
||||
cylast = 0
|
||||
for child in self.children:
|
||||
cylast = cy
|
||||
self.canvas.create_line(x+9, cy+7, cx, cy+7, fill="gray50")
|
||||
cy = child.draw(cx, cy)
|
||||
if child.item._IsExpandable():
|
||||
if child.state == 'expanded':
|
||||
iconname = "minusnode"
|
||||
callback = child.collapse
|
||||
else:
|
||||
iconname = "plusnode"
|
||||
callback = child.expand
|
||||
image = self.geticonimage(iconname)
|
||||
id = self.canvas.create_image(x+9, cylast+7, image=image)
|
||||
# XXX This leaks bindings until canvas is deleted:
|
||||
self.canvas.tag_bind(id, "<1>", callback)
|
||||
self.canvas.tag_bind(id, "<Double-1>", lambda x: None)
|
||||
id = self.canvas.create_line(x+9, y+10, x+9, cylast+7,
|
||||
##stipple="gray50", # XXX Seems broken in Tk 8.0.x
|
||||
fill="gray50")
|
||||
self.canvas.tag_lower(id) # XXX .lower(id) before Python 1.5.2
|
||||
return cy
|
||||
|
||||
def drawicon(self):
|
||||
if self.selected:
|
||||
imagename = (self.item.GetSelectedIconName() or
|
||||
self.item.GetIconName() or
|
||||
"openfolder")
|
||||
else:
|
||||
imagename = self.item.GetIconName() or "folder"
|
||||
image = self.geticonimage(imagename)
|
||||
id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image)
|
||||
self.image_id = id
|
||||
self.canvas.tag_bind(id, "<1>", self.select)
|
||||
self.canvas.tag_bind(id, "<Double-1>", self.flip)
|
||||
|
||||
def drawtext(self):
|
||||
textx = self.x+20-1
|
||||
texty = self.y-1
|
||||
labeltext = self.item.GetLabelText()
|
||||
if labeltext:
|
||||
id = self.canvas.create_text(textx, texty, anchor="nw",
|
||||
text=labeltext)
|
||||
self.canvas.tag_bind(id, "<1>", self.select)
|
||||
self.canvas.tag_bind(id, "<Double-1>", self.flip)
|
||||
x0, y0, x1, y1 = self.canvas.bbox(id)
|
||||
textx = max(x1, 200) + 10
|
||||
text = self.item.GetText() or "<no text>"
|
||||
try:
|
||||
self.entry
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
self.edit_finish()
|
||||
try:
|
||||
label = self.label
|
||||
except AttributeError:
|
||||
# padding carefully selected (on Windows) to match Entry widget:
|
||||
self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
|
||||
theme = idleConf.GetOption('main','Theme','name')
|
||||
if self.selected:
|
||||
self.label.configure(idleConf.GetHighlight(theme, 'hilite'))
|
||||
else:
|
||||
self.label.configure(idleConf.GetHighlight(theme, 'normal'))
|
||||
id = self.canvas.create_window(textx, texty,
|
||||
anchor="nw", window=self.label)
|
||||
self.label.bind("<1>", self.select_or_edit)
|
||||
self.label.bind("<Double-1>", self.flip)
|
||||
self.text_id = id
|
||||
|
||||
def select_or_edit(self, event=None):
|
||||
if self.selected and self.item.IsEditable():
|
||||
self.edit(event)
|
||||
else:
|
||||
self.select(event)
|
||||
|
||||
def edit(self, event=None):
|
||||
self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
|
||||
self.entry.insert(0, self.label['text'])
|
||||
self.entry.selection_range(0, END)
|
||||
self.entry.pack(ipadx=5)
|
||||
self.entry.focus_set()
|
||||
self.entry.bind("<Return>", self.edit_finish)
|
||||
self.entry.bind("<Escape>", self.edit_cancel)
|
||||
|
||||
def edit_finish(self, event=None):
|
||||
try:
|
||||
entry = self.entry
|
||||
del self.entry
|
||||
except AttributeError:
|
||||
return
|
||||
text = entry.get()
|
||||
entry.destroy()
|
||||
if text and text != self.item.GetText():
|
||||
self.item.SetText(text)
|
||||
text = self.item.GetText()
|
||||
self.label['text'] = text
|
||||
self.drawtext()
|
||||
self.canvas.focus_set()
|
||||
|
||||
def edit_cancel(self, event=None):
|
||||
try:
|
||||
entry = self.entry
|
||||
del self.entry
|
||||
except AttributeError:
|
||||
return
|
||||
entry.destroy()
|
||||
self.drawtext()
|
||||
self.canvas.focus_set()
|
||||
|
||||
|
||||
class TreeItem:
|
||||
|
||||
"""Abstract class representing tree items.
|
||||
|
||||
Methods should typically be overridden, otherwise a default action
|
||||
is used.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor. Do whatever you need to do."""
|
||||
|
||||
def GetText(self):
|
||||
"""Return text string to display."""
|
||||
|
||||
def GetLabelText(self):
|
||||
"""Return label text string to display in front of text (if any)."""
|
||||
|
||||
expandable = None
|
||||
|
||||
def _IsExpandable(self):
|
||||
"""Do not override! Called by TreeNode."""
|
||||
if self.expandable is None:
|
||||
self.expandable = self.IsExpandable()
|
||||
return self.expandable
|
||||
|
||||
def IsExpandable(self):
|
||||
"""Return whether there are subitems."""
|
||||
return 1
|
||||
|
||||
def _GetSubList(self):
|
||||
"""Do not override! Called by TreeNode."""
|
||||
if not self.IsExpandable():
|
||||
return []
|
||||
sublist = self.GetSubList()
|
||||
if not sublist:
|
||||
self.expandable = 0
|
||||
return sublist
|
||||
|
||||
def IsEditable(self):
|
||||
"""Return whether the item's text may be edited."""
|
||||
|
||||
def SetText(self, text):
|
||||
"""Change the item's text (if it is editable)."""
|
||||
|
||||
def GetIconName(self):
|
||||
"""Return name of icon to be displayed normally."""
|
||||
|
||||
def GetSelectedIconName(self):
|
||||
"""Return name of icon to be displayed when selected."""
|
||||
|
||||
def GetSubList(self):
|
||||
"""Return list of items forming sublist."""
|
||||
|
||||
def OnDoubleClick(self):
|
||||
"""Called on a double-click on the item."""
|
||||
|
||||
|
||||
# Example application
|
||||
|
||||
class FileTreeItem(TreeItem):
|
||||
|
||||
"""Example TreeItem subclass -- browse the file system."""
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def GetText(self):
|
||||
return os.path.basename(self.path) or self.path
|
||||
|
||||
def IsEditable(self):
|
||||
return os.path.basename(self.path) != ""
|
||||
|
||||
def SetText(self, text):
|
||||
newpath = os.path.dirname(self.path)
|
||||
newpath = os.path.join(newpath, text)
|
||||
if os.path.dirname(newpath) != os.path.dirname(self.path):
|
||||
return
|
||||
try:
|
||||
os.rename(self.path, newpath)
|
||||
self.path = newpath
|
||||
except os.error:
|
||||
pass
|
||||
|
||||
def GetIconName(self):
|
||||
if not self.IsExpandable():
|
||||
return "python" # XXX wish there was a "file" icon
|
||||
|
||||
def IsExpandable(self):
|
||||
return os.path.isdir(self.path)
|
||||
|
||||
def GetSubList(self):
|
||||
try:
|
||||
names = os.listdir(self.path)
|
||||
except os.error:
|
||||
return []
|
||||
names.sort(key = os.path.normcase)
|
||||
sublist = []
|
||||
for name in names:
|
||||
item = FileTreeItem(os.path.join(self.path, name))
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
|
||||
# A canvas widget with scroll bars and some useful bindings
|
||||
|
||||
class ScrolledCanvas:
|
||||
def __init__(self, master, **opts):
|
||||
if 'yscrollincrement' not in opts:
|
||||
opts['yscrollincrement'] = 17
|
||||
self.master = master
|
||||
self.frame = Frame(master)
|
||||
self.frame.rowconfigure(0, weight=1)
|
||||
self.frame.columnconfigure(0, weight=1)
|
||||
self.canvas = Canvas(self.frame, **opts)
|
||||
self.canvas.grid(row=0, column=0, sticky="nsew")
|
||||
self.vbar = Scrollbar(self.frame, name="vbar")
|
||||
self.vbar.grid(row=0, column=1, sticky="nse")
|
||||
self.hbar = Scrollbar(self.frame, name="hbar", orient="horizontal")
|
||||
self.hbar.grid(row=1, column=0, sticky="ews")
|
||||
self.canvas['yscrollcommand'] = self.vbar.set
|
||||
self.vbar['command'] = self.canvas.yview
|
||||
self.canvas['xscrollcommand'] = self.hbar.set
|
||||
self.hbar['command'] = self.canvas.xview
|
||||
self.canvas.bind("<Key-Prior>", self.page_up)
|
||||
self.canvas.bind("<Key-Next>", self.page_down)
|
||||
self.canvas.bind("<Key-Up>", self.unit_up)
|
||||
self.canvas.bind("<Key-Down>", self.unit_down)
|
||||
#if isinstance(master, Toplevel) or isinstance(master, Tk):
|
||||
self.canvas.bind("<Alt-Key-2>", self.zoom_height)
|
||||
self.canvas.focus_set()
|
||||
def page_up(self, event):
|
||||
self.canvas.yview_scroll(-1, "page")
|
||||
return "break"
|
||||
def page_down(self, event):
|
||||
self.canvas.yview_scroll(1, "page")
|
||||
return "break"
|
||||
def unit_up(self, event):
|
||||
self.canvas.yview_scroll(-1, "unit")
|
||||
return "break"
|
||||
def unit_down(self, event):
|
||||
self.canvas.yview_scroll(1, "unit")
|
||||
return "break"
|
||||
def zoom_height(self, event):
|
||||
ZoomHeight.zoom_height(self.master)
|
||||
return "break"
|
||||
|
||||
|
||||
# Testing functions
|
||||
|
||||
def test():
|
||||
from idlelib import PyShell
|
||||
root = Toplevel(PyShell.root)
|
||||
root.configure(bd=0, bg="yellow")
|
||||
root.focus_set()
|
||||
sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1)
|
||||
sc.frame.pack(expand=1, fill="both")
|
||||
item = FileTreeItem("C:/windows/desktop")
|
||||
node = TreeNode(sc.canvas, None, item)
|
||||
node.expand()
|
||||
|
||||
def test2():
|
||||
# test w/o scrolling canvas
|
||||
root = Tk()
|
||||
root.configure(bd=0)
|
||||
canvas = Canvas(root, bg="white", highlightthickness=0)
|
||||
canvas.pack(expand=1, fill="both")
|
||||
item = FileTreeItem(os.curdir)
|
||||
node = TreeNode(canvas, None, item)
|
||||
node.update()
|
||||
canvas.focus_set()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
352
Darwin/lib/python2.7/idlelib/UndoDelegator.py
Normal file
352
Darwin/lib/python2.7/idlelib/UndoDelegator.py
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
import string
|
||||
from Tkinter import *
|
||||
|
||||
from idlelib.Delegator import Delegator
|
||||
|
||||
#$ event <<redo>>
|
||||
#$ win <Control-y>
|
||||
#$ unix <Alt-z>
|
||||
|
||||
#$ event <<undo>>
|
||||
#$ win <Control-z>
|
||||
#$ unix <Control-z>
|
||||
|
||||
#$ event <<dump-undo-state>>
|
||||
#$ win <Control-backslash>
|
||||
#$ unix <Control-backslash>
|
||||
|
||||
|
||||
class UndoDelegator(Delegator):
|
||||
|
||||
max_undo = 1000
|
||||
|
||||
def __init__(self):
|
||||
Delegator.__init__(self)
|
||||
self.reset_undo()
|
||||
|
||||
def setdelegate(self, delegate):
|
||||
if self.delegate is not None:
|
||||
self.unbind("<<undo>>")
|
||||
self.unbind("<<redo>>")
|
||||
self.unbind("<<dump-undo-state>>")
|
||||
Delegator.setdelegate(self, delegate)
|
||||
if delegate is not None:
|
||||
self.bind("<<undo>>", self.undo_event)
|
||||
self.bind("<<redo>>", self.redo_event)
|
||||
self.bind("<<dump-undo-state>>", self.dump_event)
|
||||
|
||||
def dump_event(self, event):
|
||||
from pprint import pprint
|
||||
pprint(self.undolist[:self.pointer])
|
||||
print "pointer:", self.pointer,
|
||||
print "saved:", self.saved,
|
||||
print "can_merge:", self.can_merge,
|
||||
print "get_saved():", self.get_saved()
|
||||
pprint(self.undolist[self.pointer:])
|
||||
return "break"
|
||||
|
||||
def reset_undo(self):
|
||||
self.was_saved = -1
|
||||
self.pointer = 0
|
||||
self.undolist = []
|
||||
self.undoblock = 0 # or a CommandSequence instance
|
||||
self.set_saved(1)
|
||||
|
||||
def set_saved(self, flag):
|
||||
if flag:
|
||||
self.saved = self.pointer
|
||||
else:
|
||||
self.saved = -1
|
||||
self.can_merge = False
|
||||
self.check_saved()
|
||||
|
||||
def get_saved(self):
|
||||
return self.saved == self.pointer
|
||||
|
||||
saved_change_hook = None
|
||||
|
||||
def set_saved_change_hook(self, hook):
|
||||
self.saved_change_hook = hook
|
||||
|
||||
was_saved = -1
|
||||
|
||||
def check_saved(self):
|
||||
is_saved = self.get_saved()
|
||||
if is_saved != self.was_saved:
|
||||
self.was_saved = is_saved
|
||||
if self.saved_change_hook:
|
||||
self.saved_change_hook()
|
||||
|
||||
def insert(self, index, chars, tags=None):
|
||||
self.addcmd(InsertCommand(index, chars, tags))
|
||||
|
||||
def delete(self, index1, index2=None):
|
||||
self.addcmd(DeleteCommand(index1, index2))
|
||||
|
||||
# Clients should call undo_block_start() and undo_block_stop()
|
||||
# around a sequence of editing cmds to be treated as a unit by
|
||||
# undo & redo. Nested matching calls are OK, and the inner calls
|
||||
# then act like nops. OK too if no editing cmds, or only one
|
||||
# editing cmd, is issued in between: if no cmds, the whole
|
||||
# sequence has no effect; and if only one cmd, that cmd is entered
|
||||
# directly into the undo list, as if undo_block_xxx hadn't been
|
||||
# called. The intent of all that is to make this scheme easy
|
||||
# to use: all the client has to worry about is making sure each
|
||||
# _start() call is matched by a _stop() call.
|
||||
|
||||
def undo_block_start(self):
|
||||
if self.undoblock == 0:
|
||||
self.undoblock = CommandSequence()
|
||||
self.undoblock.bump_depth()
|
||||
|
||||
def undo_block_stop(self):
|
||||
if self.undoblock.bump_depth(-1) == 0:
|
||||
cmd = self.undoblock
|
||||
self.undoblock = 0
|
||||
if len(cmd) > 0:
|
||||
if len(cmd) == 1:
|
||||
# no need to wrap a single cmd
|
||||
cmd = cmd.getcmd(0)
|
||||
# this blk of cmds, or single cmd, has already
|
||||
# been done, so don't execute it again
|
||||
self.addcmd(cmd, 0)
|
||||
|
||||
def addcmd(self, cmd, execute=True):
|
||||
if execute:
|
||||
cmd.do(self.delegate)
|
||||
if self.undoblock != 0:
|
||||
self.undoblock.append(cmd)
|
||||
return
|
||||
if self.can_merge and self.pointer > 0:
|
||||
lastcmd = self.undolist[self.pointer-1]
|
||||
if lastcmd.merge(cmd):
|
||||
return
|
||||
self.undolist[self.pointer:] = [cmd]
|
||||
if self.saved > self.pointer:
|
||||
self.saved = -1
|
||||
self.pointer = self.pointer + 1
|
||||
if len(self.undolist) > self.max_undo:
|
||||
##print "truncating undo list"
|
||||
del self.undolist[0]
|
||||
self.pointer = self.pointer - 1
|
||||
if self.saved >= 0:
|
||||
self.saved = self.saved - 1
|
||||
self.can_merge = True
|
||||
self.check_saved()
|
||||
|
||||
def undo_event(self, event):
|
||||
if self.pointer == 0:
|
||||
self.bell()
|
||||
return "break"
|
||||
cmd = self.undolist[self.pointer - 1]
|
||||
cmd.undo(self.delegate)
|
||||
self.pointer = self.pointer - 1
|
||||
self.can_merge = False
|
||||
self.check_saved()
|
||||
return "break"
|
||||
|
||||
def redo_event(self, event):
|
||||
if self.pointer >= len(self.undolist):
|
||||
self.bell()
|
||||
return "break"
|
||||
cmd = self.undolist[self.pointer]
|
||||
cmd.redo(self.delegate)
|
||||
self.pointer = self.pointer + 1
|
||||
self.can_merge = False
|
||||
self.check_saved()
|
||||
return "break"
|
||||
|
||||
|
||||
class Command:
|
||||
|
||||
# Base class for Undoable commands
|
||||
|
||||
tags = None
|
||||
|
||||
def __init__(self, index1, index2, chars, tags=None):
|
||||
self.marks_before = {}
|
||||
self.marks_after = {}
|
||||
self.index1 = index1
|
||||
self.index2 = index2
|
||||
self.chars = chars
|
||||
if tags:
|
||||
self.tags = tags
|
||||
|
||||
def __repr__(self):
|
||||
s = self.__class__.__name__
|
||||
t = (self.index1, self.index2, self.chars, self.tags)
|
||||
if self.tags is None:
|
||||
t = t[:-1]
|
||||
return s + repr(t)
|
||||
|
||||
def do(self, text):
|
||||
pass
|
||||
|
||||
def redo(self, text):
|
||||
pass
|
||||
|
||||
def undo(self, text):
|
||||
pass
|
||||
|
||||
def merge(self, cmd):
|
||||
return 0
|
||||
|
||||
def save_marks(self, text):
|
||||
marks = {}
|
||||
for name in text.mark_names():
|
||||
if name != "insert" and name != "current":
|
||||
marks[name] = text.index(name)
|
||||
return marks
|
||||
|
||||
def set_marks(self, text, marks):
|
||||
for name, index in marks.items():
|
||||
text.mark_set(name, index)
|
||||
|
||||
|
||||
class InsertCommand(Command):
|
||||
|
||||
# Undoable insert command
|
||||
|
||||
def __init__(self, index1, chars, tags=None):
|
||||
Command.__init__(self, index1, None, chars, tags)
|
||||
|
||||
def do(self, text):
|
||||
self.marks_before = self.save_marks(text)
|
||||
self.index1 = text.index(self.index1)
|
||||
if text.compare(self.index1, ">", "end-1c"):
|
||||
# Insert before the final newline
|
||||
self.index1 = text.index("end-1c")
|
||||
text.insert(self.index1, self.chars, self.tags)
|
||||
self.index2 = text.index("%s+%dc" % (self.index1, len(self.chars)))
|
||||
self.marks_after = self.save_marks(text)
|
||||
##sys.__stderr__.write("do: %s\n" % self)
|
||||
|
||||
def redo(self, text):
|
||||
text.mark_set('insert', self.index1)
|
||||
text.insert(self.index1, self.chars, self.tags)
|
||||
self.set_marks(text, self.marks_after)
|
||||
text.see('insert')
|
||||
##sys.__stderr__.write("redo: %s\n" % self)
|
||||
|
||||
def undo(self, text):
|
||||
text.mark_set('insert', self.index1)
|
||||
text.delete(self.index1, self.index2)
|
||||
self.set_marks(text, self.marks_before)
|
||||
text.see('insert')
|
||||
##sys.__stderr__.write("undo: %s\n" % self)
|
||||
|
||||
def merge(self, cmd):
|
||||
if self.__class__ is not cmd.__class__:
|
||||
return False
|
||||
if self.index2 != cmd.index1:
|
||||
return False
|
||||
if self.tags != cmd.tags:
|
||||
return False
|
||||
if len(cmd.chars) != 1:
|
||||
return False
|
||||
if self.chars and \
|
||||
self.classify(self.chars[-1]) != self.classify(cmd.chars):
|
||||
return False
|
||||
self.index2 = cmd.index2
|
||||
self.chars = self.chars + cmd.chars
|
||||
return True
|
||||
|
||||
alphanumeric = string.ascii_letters + string.digits + "_"
|
||||
|
||||
def classify(self, c):
|
||||
if c in self.alphanumeric:
|
||||
return "alphanumeric"
|
||||
if c == "\n":
|
||||
return "newline"
|
||||
return "punctuation"
|
||||
|
||||
|
||||
class DeleteCommand(Command):
|
||||
|
||||
# Undoable delete command
|
||||
|
||||
def __init__(self, index1, index2=None):
|
||||
Command.__init__(self, index1, index2, None, None)
|
||||
|
||||
def do(self, text):
|
||||
self.marks_before = self.save_marks(text)
|
||||
self.index1 = text.index(self.index1)
|
||||
if self.index2:
|
||||
self.index2 = text.index(self.index2)
|
||||
else:
|
||||
self.index2 = text.index(self.index1 + " +1c")
|
||||
if text.compare(self.index2, ">", "end-1c"):
|
||||
# Don't delete the final newline
|
||||
self.index2 = text.index("end-1c")
|
||||
self.chars = text.get(self.index1, self.index2)
|
||||
text.delete(self.index1, self.index2)
|
||||
self.marks_after = self.save_marks(text)
|
||||
##sys.__stderr__.write("do: %s\n" % self)
|
||||
|
||||
def redo(self, text):
|
||||
text.mark_set('insert', self.index1)
|
||||
text.delete(self.index1, self.index2)
|
||||
self.set_marks(text, self.marks_after)
|
||||
text.see('insert')
|
||||
##sys.__stderr__.write("redo: %s\n" % self)
|
||||
|
||||
def undo(self, text):
|
||||
text.mark_set('insert', self.index1)
|
||||
text.insert(self.index1, self.chars)
|
||||
self.set_marks(text, self.marks_before)
|
||||
text.see('insert')
|
||||
##sys.__stderr__.write("undo: %s\n" % self)
|
||||
|
||||
class CommandSequence(Command):
|
||||
|
||||
# Wrapper for a sequence of undoable cmds to be undone/redone
|
||||
# as a unit
|
||||
|
||||
def __init__(self):
|
||||
self.cmds = []
|
||||
self.depth = 0
|
||||
|
||||
def __repr__(self):
|
||||
s = self.__class__.__name__
|
||||
strs = []
|
||||
for cmd in self.cmds:
|
||||
strs.append(" %r" % (cmd,))
|
||||
return s + "(\n" + ",\n".join(strs) + "\n)"
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cmds)
|
||||
|
||||
def append(self, cmd):
|
||||
self.cmds.append(cmd)
|
||||
|
||||
def getcmd(self, i):
|
||||
return self.cmds[i]
|
||||
|
||||
def redo(self, text):
|
||||
for cmd in self.cmds:
|
||||
cmd.redo(text)
|
||||
|
||||
def undo(self, text):
|
||||
cmds = self.cmds[:]
|
||||
cmds.reverse()
|
||||
for cmd in cmds:
|
||||
cmd.undo(text)
|
||||
|
||||
def bump_depth(self, incr=1):
|
||||
self.depth = self.depth + incr
|
||||
return self.depth
|
||||
|
||||
def main():
|
||||
from idlelib.Percolator import Percolator
|
||||
root = Tk()
|
||||
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
|
||||
text = Text()
|
||||
text.pack()
|
||||
text.focus_set()
|
||||
p = Percolator(text)
|
||||
d = UndoDelegator()
|
||||
p.insertfilter(d)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
126
Darwin/lib/python2.7/idlelib/WidgetRedirector.py
Normal file
126
Darwin/lib/python2.7/idlelib/WidgetRedirector.py
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
from Tkinter import *
|
||||
|
||||
class WidgetRedirector:
|
||||
|
||||
"""Support for redirecting arbitrary widget subcommands.
|
||||
|
||||
Some Tk operations don't normally pass through Tkinter. For example, if a
|
||||
character is inserted into a Text widget by pressing a key, a default Tk
|
||||
binding to the widget's 'insert' operation is activated, and the Tk library
|
||||
processes the insert without calling back into Tkinter.
|
||||
|
||||
Although a binding to <Key> could be made via Tkinter, what we really want
|
||||
to do is to hook the Tk 'insert' operation itself.
|
||||
|
||||
When a widget is instantiated, a Tcl command is created whose name is the
|
||||
same as the pathname widget._w. This command is used to invoke the various
|
||||
widget operations, e.g. insert (for a Text widget). We are going to hook
|
||||
this command and provide a facility ('register') to intercept the widget
|
||||
operation.
|
||||
|
||||
In IDLE, the function being registered provides access to the top of a
|
||||
Percolator chain. At the bottom of the chain is a call to the original
|
||||
Tk widget operation.
|
||||
|
||||
"""
|
||||
def __init__(self, widget):
|
||||
self._operations = {}
|
||||
self.widget = widget # widget instance
|
||||
self.tk = tk = widget.tk # widget's root
|
||||
w = widget._w # widget's (full) Tk pathname
|
||||
self.orig = w + "_orig"
|
||||
# Rename the Tcl command within Tcl:
|
||||
tk.call("rename", w, self.orig)
|
||||
# Create a new Tcl command whose name is the widget's pathname, and
|
||||
# whose action is to dispatch on the operation passed to the widget:
|
||||
tk.createcommand(w, self.dispatch)
|
||||
|
||||
def __repr__(self):
|
||||
return "WidgetRedirector(%s<%s>)" % (self.widget.__class__.__name__,
|
||||
self.widget._w)
|
||||
|
||||
def close(self):
|
||||
for operation in list(self._operations):
|
||||
self.unregister(operation)
|
||||
widget = self.widget; del self.widget
|
||||
orig = self.orig; del self.orig
|
||||
tk = widget.tk
|
||||
w = widget._w
|
||||
tk.deletecommand(w)
|
||||
# restore the original widget Tcl command:
|
||||
tk.call("rename", orig, w)
|
||||
|
||||
def register(self, operation, function):
|
||||
self._operations[operation] = function
|
||||
setattr(self.widget, operation, function)
|
||||
return OriginalCommand(self, operation)
|
||||
|
||||
def unregister(self, operation):
|
||||
if operation in self._operations:
|
||||
function = self._operations[operation]
|
||||
del self._operations[operation]
|
||||
if hasattr(self.widget, operation):
|
||||
delattr(self.widget, operation)
|
||||
return function
|
||||
else:
|
||||
return None
|
||||
|
||||
def dispatch(self, operation, *args):
|
||||
'''Callback from Tcl which runs when the widget is referenced.
|
||||
|
||||
If an operation has been registered in self._operations, apply the
|
||||
associated function to the args passed into Tcl. Otherwise, pass the
|
||||
operation through to Tk via the original Tcl function.
|
||||
|
||||
Note that if a registered function is called, the operation is not
|
||||
passed through to Tk. Apply the function returned by self.register()
|
||||
to *args to accomplish that. For an example, see ColorDelegator.py.
|
||||
|
||||
'''
|
||||
m = self._operations.get(operation)
|
||||
try:
|
||||
if m:
|
||||
return m(*args)
|
||||
else:
|
||||
return self.tk.call((self.orig, operation) + args)
|
||||
except TclError:
|
||||
return ""
|
||||
|
||||
|
||||
class OriginalCommand:
|
||||
|
||||
def __init__(self, redir, operation):
|
||||
self.redir = redir
|
||||
self.operation = operation
|
||||
self.tk = redir.tk
|
||||
self.orig = redir.orig
|
||||
self.tk_call = self.tk.call
|
||||
self.orig_and_operation = (self.orig, self.operation)
|
||||
|
||||
def __repr__(self):
|
||||
return "OriginalCommand(%r, %r)" % (self.redir, self.operation)
|
||||
|
||||
def __call__(self, *args):
|
||||
return self.tk_call(self.orig_and_operation + args)
|
||||
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
|
||||
text = Text()
|
||||
text.pack()
|
||||
text.focus_set()
|
||||
redir = WidgetRedirector(text)
|
||||
global previous_tcl_fcn
|
||||
def my_insert(*args):
|
||||
print "insert", args
|
||||
previous_tcl_fcn(*args)
|
||||
previous_tcl_fcn = redir.register("insert", my_insert)
|
||||
root.mainloop()
|
||||
redir.unregister("insert") # runs after first 'close window'
|
||||
redir.close()
|
||||
root.mainloop()
|
||||
root.destroy()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
90
Darwin/lib/python2.7/idlelib/WindowList.py
Normal file
90
Darwin/lib/python2.7/idlelib/WindowList.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
from Tkinter import *
|
||||
|
||||
class WindowList:
|
||||
|
||||
def __init__(self):
|
||||
self.dict = {}
|
||||
self.callbacks = []
|
||||
|
||||
def add(self, window):
|
||||
window.after_idle(self.call_callbacks)
|
||||
self.dict[str(window)] = window
|
||||
|
||||
def delete(self, window):
|
||||
try:
|
||||
del self.dict[str(window)]
|
||||
except KeyError:
|
||||
# Sometimes, destroy() is called twice
|
||||
pass
|
||||
self.call_callbacks()
|
||||
|
||||
def add_windows_to_menu(self, menu):
|
||||
list = []
|
||||
for key in self.dict.keys():
|
||||
window = self.dict[key]
|
||||
try:
|
||||
title = window.get_title()
|
||||
except TclError:
|
||||
continue
|
||||
list.append((title, window))
|
||||
list.sort()
|
||||
for title, window in list:
|
||||
menu.add_command(label=title, command=window.wakeup)
|
||||
|
||||
def register_callback(self, callback):
|
||||
self.callbacks.append(callback)
|
||||
|
||||
def unregister_callback(self, callback):
|
||||
try:
|
||||
self.callbacks.remove(callback)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def call_callbacks(self):
|
||||
for callback in self.callbacks:
|
||||
try:
|
||||
callback()
|
||||
except:
|
||||
print "warning: callback failed in WindowList", \
|
||||
sys.exc_type, ":", sys.exc_value
|
||||
|
||||
registry = WindowList()
|
||||
|
||||
add_windows_to_menu = registry.add_windows_to_menu
|
||||
register_callback = registry.register_callback
|
||||
unregister_callback = registry.unregister_callback
|
||||
|
||||
|
||||
class ListedToplevel(Toplevel):
|
||||
|
||||
def __init__(self, master, **kw):
|
||||
Toplevel.__init__(self, master, kw)
|
||||
registry.add(self)
|
||||
self.focused_widget = self
|
||||
|
||||
def destroy(self):
|
||||
registry.delete(self)
|
||||
Toplevel.destroy(self)
|
||||
# If this is Idle's last window then quit the mainloop
|
||||
# (Needed for clean exit on Windows 98)
|
||||
if not registry.dict:
|
||||
self.quit()
|
||||
|
||||
def update_windowlist_registry(self, window):
|
||||
registry.call_callbacks()
|
||||
|
||||
def get_title(self):
|
||||
# Subclass can override
|
||||
return self.wm_title()
|
||||
|
||||
def wakeup(self):
|
||||
try:
|
||||
if self.wm_state() == "iconic":
|
||||
self.wm_withdraw()
|
||||
self.wm_deiconify()
|
||||
self.tkraise()
|
||||
self.focused_widget.focus_set()
|
||||
except TclError:
|
||||
# This can happen when the window menu was torn off.
|
||||
# Simply ignore it.
|
||||
pass
|
||||
51
Darwin/lib/python2.7/idlelib/ZoomHeight.py
Normal file
51
Darwin/lib/python2.7/idlelib/ZoomHeight.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Sample extension: zoom a window to maximum height
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from idlelib import macosxSupport
|
||||
|
||||
class ZoomHeight:
|
||||
|
||||
menudefs = [
|
||||
('windows', [
|
||||
('_Zoom Height', '<<zoom-height>>'),
|
||||
])
|
||||
]
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
|
||||
def zoom_height_event(self, event):
|
||||
top = self.editwin.top
|
||||
zoom_height(top)
|
||||
|
||||
def zoom_height(top):
|
||||
geom = top.wm_geometry()
|
||||
m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
|
||||
if not m:
|
||||
top.bell()
|
||||
return
|
||||
width, height, x, y = map(int, m.groups())
|
||||
newheight = top.winfo_screenheight()
|
||||
if sys.platform == 'win32':
|
||||
newy = 0
|
||||
newheight = newheight - 72
|
||||
|
||||
elif macosxSupport.runningAsOSXApp():
|
||||
# The '88' below is a magic number that avoids placing the bottom
|
||||
# of the window below the panel on my machine. I don't know how
|
||||
# to calculate the correct value for this with tkinter.
|
||||
newy = 22
|
||||
newheight = newheight - newy - 88
|
||||
|
||||
else:
|
||||
#newy = 24
|
||||
newy = 0
|
||||
#newheight = newheight - 96
|
||||
newheight = newheight - 88
|
||||
if height >= newheight:
|
||||
newgeom = ""
|
||||
else:
|
||||
newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy)
|
||||
top.wm_geometry(newgeom)
|
||||
1
Darwin/lib/python2.7/idlelib/__init__.py
Normal file
1
Darwin/lib/python2.7/idlelib/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Dummy file to make this a package.
|
||||
145
Darwin/lib/python2.7/idlelib/aboutDialog.py
Normal file
145
Darwin/lib/python2.7/idlelib/aboutDialog.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""About Dialog for IDLE
|
||||
|
||||
"""
|
||||
|
||||
from Tkinter import *
|
||||
import os
|
||||
|
||||
from idlelib import textView
|
||||
from idlelib import idlever
|
||||
|
||||
class AboutDialog(Toplevel):
|
||||
"""Modal about dialog for idle
|
||||
|
||||
"""
|
||||
def __init__(self,parent,title):
|
||||
Toplevel.__init__(self, parent)
|
||||
self.configure(borderwidth=5)
|
||||
self.geometry("+%d+%d" % (parent.winfo_rootx()+30,
|
||||
parent.winfo_rooty()+30))
|
||||
self.bg = "#707070"
|
||||
self.fg = "#ffffff"
|
||||
self.CreateWidgets()
|
||||
self.resizable(height=FALSE, width=FALSE)
|
||||
self.title(title)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.protocol("WM_DELETE_WINDOW", self.Ok)
|
||||
self.parent = parent
|
||||
self.buttonOk.focus_set()
|
||||
self.bind('<Return>',self.Ok) #dismiss dialog
|
||||
self.bind('<Escape>',self.Ok) #dismiss dialog
|
||||
self.wait_window()
|
||||
|
||||
def CreateWidgets(self):
|
||||
frameMain = Frame(self, borderwidth=2, relief=SUNKEN)
|
||||
frameButtons = Frame(self)
|
||||
frameButtons.pack(side=BOTTOM, fill=X)
|
||||
frameMain.pack(side=TOP, expand=TRUE, fill=BOTH)
|
||||
self.buttonOk = Button(frameButtons, text='Close',
|
||||
command=self.Ok)
|
||||
self.buttonOk.pack(padx=5, pady=5)
|
||||
#self.picture = Image('photo', data=self.pictureData)
|
||||
frameBg = Frame(frameMain, bg=self.bg)
|
||||
frameBg.pack(expand=TRUE, fill=BOTH)
|
||||
labelTitle = Label(frameBg, text='IDLE', fg=self.fg, bg=self.bg,
|
||||
font=('courier', 24, 'bold'))
|
||||
labelTitle.grid(row=0, column=0, sticky=W, padx=10, pady=10)
|
||||
#labelPicture = Label(frameBg, text='[picture]')
|
||||
#image=self.picture, bg=self.bg)
|
||||
#labelPicture.grid(row=1, column=1, sticky=W, rowspan=2,
|
||||
# padx=0, pady=3)
|
||||
byline = "Python's Integrated DeveLopment Environment" + 5*'\n'
|
||||
labelDesc = Label(frameBg, text=byline, justify=LEFT,
|
||||
fg=self.fg, bg=self.bg)
|
||||
labelDesc.grid(row=2, column=0, sticky=W, columnspan=3, padx=10, pady=5)
|
||||
labelEmail = Label(frameBg, text='email: idle-dev@python.org',
|
||||
justify=LEFT, fg=self.fg, bg=self.bg)
|
||||
labelEmail.grid(row=6, column=0, columnspan=2,
|
||||
sticky=W, padx=10, pady=0)
|
||||
labelWWW = Label(frameBg, text='www: http://www.python.org/idle/',
|
||||
justify=LEFT, fg=self.fg, bg=self.bg)
|
||||
labelWWW.grid(row=7, column=0, columnspan=2, sticky=W, padx=10, pady=0)
|
||||
Frame(frameBg, borderwidth=1, relief=SUNKEN,
|
||||
height=2, bg=self.bg).grid(row=8, column=0, sticky=EW,
|
||||
columnspan=3, padx=5, pady=5)
|
||||
labelPythonVer = Label(frameBg, text='Python version: ' + \
|
||||
sys.version.split()[0], fg=self.fg, bg=self.bg)
|
||||
labelPythonVer.grid(row=9, column=0, sticky=W, padx=10, pady=0)
|
||||
tkVer = self.tk.call('info', 'patchlevel')
|
||||
labelTkVer = Label(frameBg, text='Tk version: '+
|
||||
tkVer, fg=self.fg, bg=self.bg)
|
||||
labelTkVer.grid(row=9, column=1, sticky=W, padx=2, pady=0)
|
||||
py_button_f = Frame(frameBg, bg=self.bg)
|
||||
py_button_f.grid(row=10, column=0, columnspan=2, sticky=NSEW)
|
||||
buttonLicense = Button(py_button_f, text='License', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowLicense)
|
||||
buttonLicense.pack(side=LEFT, padx=10, pady=10)
|
||||
buttonCopyright = Button(py_button_f, text='Copyright', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowCopyright)
|
||||
buttonCopyright.pack(side=LEFT, padx=10, pady=10)
|
||||
buttonCredits = Button(py_button_f, text='Credits', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowPythonCredits)
|
||||
buttonCredits.pack(side=LEFT, padx=10, pady=10)
|
||||
Frame(frameBg, borderwidth=1, relief=SUNKEN,
|
||||
height=2, bg=self.bg).grid(row=11, column=0, sticky=EW,
|
||||
columnspan=3, padx=5, pady=5)
|
||||
idle_v = Label(frameBg, text='IDLE version: ' + idlever.IDLE_VERSION,
|
||||
fg=self.fg, bg=self.bg)
|
||||
idle_v.grid(row=12, column=0, sticky=W, padx=10, pady=0)
|
||||
idle_button_f = Frame(frameBg, bg=self.bg)
|
||||
idle_button_f.grid(row=13, column=0, columnspan=3, sticky=NSEW)
|
||||
idle_about_b = Button(idle_button_f, text='README', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowIDLEAbout)
|
||||
idle_about_b.pack(side=LEFT, padx=10, pady=10)
|
||||
idle_news_b = Button(idle_button_f, text='NEWS', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowIDLENEWS)
|
||||
idle_news_b.pack(side=LEFT, padx=10, pady=10)
|
||||
idle_credits_b = Button(idle_button_f, text='Credits', width=8,
|
||||
highlightbackground=self.bg,
|
||||
command=self.ShowIDLECredits)
|
||||
idle_credits_b.pack(side=LEFT, padx=10, pady=10)
|
||||
|
||||
def ShowLicense(self):
|
||||
self.display_printer_text('About - License', license)
|
||||
|
||||
def ShowCopyright(self):
|
||||
self.display_printer_text('About - Copyright', copyright)
|
||||
|
||||
def ShowPythonCredits(self):
|
||||
self.display_printer_text('About - Python Credits', credits)
|
||||
|
||||
def ShowIDLECredits(self):
|
||||
self.display_file_text('About - Credits', 'CREDITS.txt', 'iso-8859-1')
|
||||
|
||||
def ShowIDLEAbout(self):
|
||||
self.display_file_text('About - Readme', 'README.txt')
|
||||
|
||||
def ShowIDLENEWS(self):
|
||||
self.display_file_text('About - NEWS', 'NEWS.txt')
|
||||
|
||||
def display_printer_text(self, title, printer):
|
||||
printer._Printer__setup()
|
||||
text = '\n'.join(printer._Printer__lines)
|
||||
textView.view_text(self, title, text)
|
||||
|
||||
def display_file_text(self, title, filename, encoding=None):
|
||||
fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), filename)
|
||||
textView.view_file(self, title, fn, encoding)
|
||||
|
||||
def Ok(self, event=None):
|
||||
self.destroy()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test the dialog
|
||||
root = Tk()
|
||||
def run():
|
||||
from idlelib import aboutDialog
|
||||
aboutDialog.AboutDialog(root, 'About')
|
||||
Button(root, text='Dialog', command=run).pack()
|
||||
root.mainloop()
|
||||
96
Darwin/lib/python2.7/idlelib/config-extensions.def
Normal file
96
Darwin/lib/python2.7/idlelib/config-extensions.def
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# config-extensions.def
|
||||
#
|
||||
# IDLE reads several config files to determine user preferences. This
|
||||
# file is the default configuration file for IDLE extensions settings.
|
||||
#
|
||||
# Each extension must have at least one section, named after the extension
|
||||
# module. This section must contain an 'enable' item (=1 to enable the
|
||||
# extension, =0 to disable it), it may contain 'enable_editor' or 'enable_shell'
|
||||
# items, to apply it only to editor/shell windows, and may also contain any
|
||||
# other general configuration items for the extension.
|
||||
#
|
||||
# Each extension must define at least one section named ExtensionName_bindings
|
||||
# or ExtensionName_cfgBindings. If present, ExtensionName_bindings defines
|
||||
# virtual event bindings for the extension that are not user re-configurable.
|
||||
# If present, ExtensionName_cfgBindings defines virtual event bindings for the
|
||||
# extension that may be sensibly re-configured.
|
||||
#
|
||||
# If there are no keybindings for a menus' virtual events, include lines like
|
||||
# <<toggle-code-context>>= (See [CodeContext], below.)
|
||||
#
|
||||
# Currently it is necessary to manually modify this file to change extension
|
||||
# key bindings and default values. To customize, create
|
||||
# ~/.idlerc/config-extensions.cfg and append the appropriate customized
|
||||
# section(s). Those sections will override the defaults in this file.
|
||||
#
|
||||
# Note: If a keybinding is already in use when the extension is
|
||||
# loaded, the extension's virtual event's keybinding will be set to ''.
|
||||
#
|
||||
# See config-keys.def for notes on specifying keys and extend.txt for
|
||||
# information on creating IDLE extensions.
|
||||
|
||||
[FormatParagraph]
|
||||
enable=1
|
||||
[FormatParagraph_cfgBindings]
|
||||
format-paragraph=<Alt-Key-q>
|
||||
|
||||
[AutoExpand]
|
||||
enable=1
|
||||
[AutoExpand_cfgBindings]
|
||||
expand-word=<Alt-Key-slash>
|
||||
|
||||
[ZoomHeight]
|
||||
enable=1
|
||||
[ZoomHeight_cfgBindings]
|
||||
zoom-height=<Alt-Key-2>
|
||||
|
||||
[ScriptBinding]
|
||||
enable=1
|
||||
enable_shell=0
|
||||
enable_editor=1
|
||||
[ScriptBinding_cfgBindings]
|
||||
run-module=<Key-F5>
|
||||
check-module=<Alt-Key-x>
|
||||
|
||||
[CallTips]
|
||||
enable=1
|
||||
[CallTips_cfgBindings]
|
||||
force-open-calltip=<Control-Key-backslash>
|
||||
[CallTips_bindings]
|
||||
try-open-calltip=<KeyRelease-parenleft>
|
||||
refresh-calltip=<KeyRelease-parenright> <KeyRelease-0>
|
||||
|
||||
[ParenMatch]
|
||||
enable=1
|
||||
style= expression
|
||||
flash-delay= 500
|
||||
bell= 1
|
||||
[ParenMatch_cfgBindings]
|
||||
flash-paren=<Control-Key-0>
|
||||
[ParenMatch_bindings]
|
||||
paren-closed=<KeyRelease-parenright> <KeyRelease-bracketright> <KeyRelease-braceright>
|
||||
|
||||
[AutoComplete]
|
||||
enable=1
|
||||
popupwait=2000
|
||||
[AutoComplete_cfgBindings]
|
||||
force-open-completions=<Control-Key-space>
|
||||
[AutoComplete_bindings]
|
||||
autocomplete=<Key-Tab>
|
||||
try-open-completions=<KeyRelease-period> <KeyRelease-slash> <KeyRelease-backslash>
|
||||
|
||||
[CodeContext]
|
||||
enable=1
|
||||
enable_shell=0
|
||||
numlines=3
|
||||
visible=0
|
||||
bgcolor=LightGray
|
||||
fgcolor=Black
|
||||
[CodeContext_bindings]
|
||||
toggle-code-context=
|
||||
|
||||
[RstripExtension]
|
||||
enable=1
|
||||
enable_shell=0
|
||||
enable_editor=1
|
||||
|
||||
64
Darwin/lib/python2.7/idlelib/config-highlight.def
Normal file
64
Darwin/lib/python2.7/idlelib/config-highlight.def
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# IDLE reads several config files to determine user preferences. This
|
||||
# file is the default config file for idle highlight theme settings.
|
||||
|
||||
[IDLE Classic]
|
||||
normal-foreground= #000000
|
||||
normal-background= #ffffff
|
||||
keyword-foreground= #ff7700
|
||||
keyword-background= #ffffff
|
||||
builtin-foreground= #900090
|
||||
builtin-background= #ffffff
|
||||
comment-foreground= #dd0000
|
||||
comment-background= #ffffff
|
||||
string-foreground= #00aa00
|
||||
string-background= #ffffff
|
||||
definition-foreground= #0000ff
|
||||
definition-background= #ffffff
|
||||
hilite-foreground= #000000
|
||||
hilite-background= gray
|
||||
break-foreground= black
|
||||
break-background= #ffff55
|
||||
hit-foreground= #ffffff
|
||||
hit-background= #000000
|
||||
error-foreground= #000000
|
||||
error-background= #ff7777
|
||||
#cursor (only foreground can be set, restart IDLE)
|
||||
cursor-foreground= black
|
||||
#shell window
|
||||
stdout-foreground= blue
|
||||
stdout-background= #ffffff
|
||||
stderr-foreground= red
|
||||
stderr-background= #ffffff
|
||||
console-foreground= #770000
|
||||
console-background= #ffffff
|
||||
|
||||
[IDLE New]
|
||||
normal-foreground= #000000
|
||||
normal-background= #ffffff
|
||||
keyword-foreground= #ff7700
|
||||
keyword-background= #ffffff
|
||||
builtin-foreground= #900090
|
||||
builtin-background= #ffffff
|
||||
comment-foreground= #dd0000
|
||||
comment-background= #ffffff
|
||||
string-foreground= #00aa00
|
||||
string-background= #ffffff
|
||||
definition-foreground= #0000ff
|
||||
definition-background= #ffffff
|
||||
hilite-foreground= #000000
|
||||
hilite-background= gray
|
||||
break-foreground= black
|
||||
break-background= #ffff55
|
||||
hit-foreground= #ffffff
|
||||
hit-background= #000000
|
||||
error-foreground= #000000
|
||||
error-background= #ff7777
|
||||
#cursor (only foreground can be set, restart IDLE)
|
||||
cursor-foreground= black
|
||||
#shell window
|
||||
stdout-foreground= blue
|
||||
stdout-background= #ffffff
|
||||
stderr-foreground= red
|
||||
stderr-background= #ffffff
|
||||
console-foreground= #770000
|
||||
console-background= #ffffff
|
||||
214
Darwin/lib/python2.7/idlelib/config-keys.def
Normal file
214
Darwin/lib/python2.7/idlelib/config-keys.def
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
# IDLE reads several config files to determine user preferences. This
|
||||
# file is the default config file for idle key binding settings.
|
||||
# Where multiple keys are specified for an action: if they are separated
|
||||
# by a space (eg. action=<key1> <key2>) then the keys are alternatives, if
|
||||
# there is no space (eg. action=<key1><key2>) then the keys comprise a
|
||||
# single 'emacs style' multi-keystoke binding. The tk event specifier 'Key'
|
||||
# is used in all cases, for consistency in auto key conflict checking in the
|
||||
# configuration gui.
|
||||
|
||||
[IDLE Classic Windows]
|
||||
copy=<Control-Key-c> <Control-Key-C>
|
||||
cut=<Control-Key-x> <Control-Key-X>
|
||||
paste=<Control-Key-v> <Control-Key-V>
|
||||
beginning-of-line= <Key-Home>
|
||||
center-insert=<Control-Key-l> <Control-Key-L>
|
||||
close-all-windows=<Control-Key-q>
|
||||
close-window=<Alt-Key-F4> <Meta-Key-F4>
|
||||
do-nothing=<Control-Key-F12>
|
||||
end-of-file=<Control-Key-d> <Control-Key-D>
|
||||
python-docs=<Key-F1>
|
||||
python-context-help=<Shift-Key-F1>
|
||||
history-next=<Alt-Key-n> <Meta-Key-n>
|
||||
history-previous=<Alt-Key-p> <Meta-Key-p>
|
||||
interrupt-execution=<Control-Key-c> <Control-Key-C>
|
||||
view-restart=<Key-F6>
|
||||
restart-shell=<Control-Key-F6>
|
||||
open-class-browser=<Alt-Key-c> <Meta-Key-c> <Alt-Key-C>
|
||||
open-module=<Alt-Key-m> <Meta-Key-m> <Alt-Key-M>
|
||||
open-new-window=<Control-Key-n> <Control-Key-N>
|
||||
open-window-from-file=<Control-Key-o> <Control-Key-O>
|
||||
plain-newline-and-indent=<Control-Key-j> <Control-Key-J>
|
||||
print-window=<Control-Key-p> <Control-Key-P>
|
||||
redo=<Control-Shift-Key-Z>
|
||||
remove-selection=<Key-Escape>
|
||||
save-copy-of-window-as-file=<Alt-Shift-Key-S>
|
||||
save-window-as-file=<Control-Shift-Key-S>
|
||||
save-window=<Control-Key-s>
|
||||
select-all=<Control-Key-a>
|
||||
toggle-auto-coloring=<Control-Key-slash>
|
||||
undo=<Control-Key-z> <Control-Key-Z>
|
||||
find=<Control-Key-f> <Control-Key-F>
|
||||
find-again=<Control-Key-g> <Key-F3>
|
||||
find-in-files=<Alt-Key-F3> <Meta-Key-F3>
|
||||
find-selection=<Control-Key-F3>
|
||||
replace=<Control-Key-h> <Control-Key-H>
|
||||
goto-line=<Alt-Key-g> <Meta-Key-g>
|
||||
smart-backspace=<Key-BackSpace>
|
||||
newline-and-indent=<Key-Return> <Key-KP_Enter>
|
||||
smart-indent=<Key-Tab>
|
||||
indent-region=<Control-Key-bracketright>
|
||||
dedent-region=<Control-Key-bracketleft>
|
||||
comment-region=<Alt-Key-3> <Meta-Key-3>
|
||||
uncomment-region=<Alt-Key-4> <Meta-Key-4>
|
||||
tabify-region=<Alt-Key-5> <Meta-Key-5>
|
||||
untabify-region=<Alt-Key-6> <Meta-Key-6>
|
||||
toggle-tabs=<Alt-Key-t> <Meta-Key-t> <Alt-Key-T>
|
||||
change-indentwidth=<Alt-Key-u> <Meta-Key-u> <Alt-Key-U>
|
||||
del-word-left=<Control-Key-BackSpace>
|
||||
del-word-right=<Control-Key-Delete>
|
||||
|
||||
[IDLE Classic Unix]
|
||||
copy=<Alt-Key-w> <Meta-Key-w>
|
||||
cut=<Control-Key-w>
|
||||
paste=<Control-Key-y>
|
||||
beginning-of-line=<Control-Key-a> <Key-Home>
|
||||
center-insert=<Control-Key-l>
|
||||
close-all-windows=<Control-Key-x><Control-Key-c>
|
||||
close-window=<Control-Key-x><Control-Key-0>
|
||||
do-nothing=<Control-Key-x>
|
||||
end-of-file=<Control-Key-d>
|
||||
history-next=<Alt-Key-n> <Meta-Key-n>
|
||||
history-previous=<Alt-Key-p> <Meta-Key-p>
|
||||
interrupt-execution=<Control-Key-c>
|
||||
view-restart=<Key-F6>
|
||||
restart-shell=<Control-Key-F6>
|
||||
open-class-browser=<Control-Key-x><Control-Key-b>
|
||||
open-module=<Control-Key-x><Control-Key-m>
|
||||
open-new-window=<Control-Key-x><Control-Key-n>
|
||||
open-window-from-file=<Control-Key-x><Control-Key-f>
|
||||
plain-newline-and-indent=<Control-Key-j>
|
||||
print-window=<Control-x><Control-Key-p>
|
||||
python-docs=<Control-Key-h>
|
||||
python-context-help=<Control-Shift-Key-H>
|
||||
redo=<Alt-Key-z> <Meta-Key-z>
|
||||
remove-selection=<Key-Escape>
|
||||
save-copy-of-window-as-file=<Control-Key-x><Control-Key-y>
|
||||
save-window-as-file=<Control-Key-x><Control-Key-w>
|
||||
save-window=<Control-Key-x><Control-Key-s>
|
||||
select-all=<Alt-Key-a> <Meta-Key-a>
|
||||
toggle-auto-coloring=<Control-Key-slash>
|
||||
undo=<Control-Key-z>
|
||||
find=<Control-Key-u><Control-Key-u><Control-Key-s>
|
||||
find-again=<Control-Key-u><Control-Key-s>
|
||||
find-in-files=<Alt-Key-s> <Meta-Key-s>
|
||||
find-selection=<Control-Key-s>
|
||||
replace=<Control-Key-r>
|
||||
goto-line=<Alt-Key-g> <Meta-Key-g>
|
||||
smart-backspace=<Key-BackSpace>
|
||||
newline-and-indent=<Key-Return> <Key-KP_Enter>
|
||||
smart-indent=<Key-Tab>
|
||||
indent-region=<Control-Key-bracketright>
|
||||
dedent-region=<Control-Key-bracketleft>
|
||||
comment-region=<Alt-Key-3>
|
||||
uncomment-region=<Alt-Key-4>
|
||||
tabify-region=<Alt-Key-5>
|
||||
untabify-region=<Alt-Key-6>
|
||||
toggle-tabs=<Alt-Key-t>
|
||||
change-indentwidth=<Alt-Key-u>
|
||||
del-word-left=<Alt-Key-BackSpace>
|
||||
del-word-right=<Alt-Key-d>
|
||||
|
||||
[IDLE Classic Mac]
|
||||
copy=<Command-Key-c>
|
||||
cut=<Command-Key-x>
|
||||
paste=<Command-Key-v>
|
||||
beginning-of-line= <Key-Home>
|
||||
center-insert=<Control-Key-l>
|
||||
close-all-windows=<Command-Key-q>
|
||||
close-window=<Command-Key-w>
|
||||
do-nothing=<Control-Key-F12>
|
||||
end-of-file=<Control-Key-d>
|
||||
python-docs=<Key-F1>
|
||||
python-context-help=<Shift-Key-F1>
|
||||
history-next=<Control-Key-n>
|
||||
history-previous=<Control-Key-p>
|
||||
interrupt-execution=<Control-Key-c>
|
||||
view-restart=<Key-F6>
|
||||
restart-shell=<Control-Key-F6>
|
||||
open-class-browser=<Command-Key-b>
|
||||
open-module=<Command-Key-m>
|
||||
open-new-window=<Command-Key-n>
|
||||
open-window-from-file=<Command-Key-o>
|
||||
plain-newline-and-indent=<Control-Key-j>
|
||||
print-window=<Command-Key-p>
|
||||
redo=<Shift-Command-Key-Z>
|
||||
remove-selection=<Key-Escape>
|
||||
save-window-as-file=<Shift-Command-Key-S>
|
||||
save-window=<Command-Key-s>
|
||||
save-copy-of-window-as-file=<Option-Command-Key-s>
|
||||
select-all=<Command-Key-a>
|
||||
toggle-auto-coloring=<Control-Key-slash>
|
||||
undo=<Command-Key-z>
|
||||
find=<Command-Key-f>
|
||||
find-again=<Command-Key-g> <Key-F3>
|
||||
find-in-files=<Command-Key-F3>
|
||||
find-selection=<Shift-Command-Key-F3>
|
||||
replace=<Command-Key-r>
|
||||
goto-line=<Command-Key-j>
|
||||
smart-backspace=<Key-BackSpace>
|
||||
newline-and-indent=<Key-Return> <Key-KP_Enter>
|
||||
smart-indent=<Key-Tab>
|
||||
indent-region=<Command-Key-bracketright>
|
||||
dedent-region=<Command-Key-bracketleft>
|
||||
comment-region=<Control-Key-3>
|
||||
uncomment-region=<Control-Key-4>
|
||||
tabify-region=<Control-Key-5>
|
||||
untabify-region=<Control-Key-6>
|
||||
toggle-tabs=<Control-Key-t>
|
||||
change-indentwidth=<Control-Key-u>
|
||||
del-word-left=<Control-Key-BackSpace>
|
||||
del-word-right=<Control-Key-Delete>
|
||||
|
||||
[IDLE Classic OSX]
|
||||
toggle-tabs = <Control-Key-t>
|
||||
interrupt-execution = <Control-Key-c>
|
||||
untabify-region = <Control-Key-6>
|
||||
remove-selection = <Key-Escape>
|
||||
print-window = <Command-Key-p>
|
||||
replace = <Command-Key-r>
|
||||
goto-line = <Command-Key-j>
|
||||
plain-newline-and-indent = <Control-Key-j>
|
||||
history-previous = <Control-Key-p>
|
||||
beginning-of-line = <Control-Key-Left>
|
||||
end-of-line = <Control-Key-Right>
|
||||
comment-region = <Control-Key-3>
|
||||
redo = <Shift-Command-Key-Z>
|
||||
close-window = <Command-Key-w>
|
||||
restart-shell = <Control-Key-F6>
|
||||
save-window-as-file = <Shift-Command-Key-S>
|
||||
close-all-windows = <Command-Key-q>
|
||||
view-restart = <Key-F6>
|
||||
tabify-region = <Control-Key-5>
|
||||
find-again = <Command-Key-g> <Key-F3>
|
||||
find = <Command-Key-f>
|
||||
toggle-auto-coloring = <Control-Key-slash>
|
||||
select-all = <Command-Key-a>
|
||||
smart-backspace = <Key-BackSpace>
|
||||
change-indentwidth = <Control-Key-u>
|
||||
do-nothing = <Control-Key-F12>
|
||||
smart-indent = <Key-Tab>
|
||||
center-insert = <Control-Key-l>
|
||||
history-next = <Control-Key-n>
|
||||
del-word-right = <Option-Key-Delete>
|
||||
undo = <Command-Key-z>
|
||||
save-window = <Command-Key-s>
|
||||
uncomment-region = <Control-Key-4>
|
||||
cut = <Command-Key-x>
|
||||
find-in-files = <Command-Key-F3>
|
||||
dedent-region = <Command-Key-bracketleft>
|
||||
copy = <Command-Key-c>
|
||||
paste = <Command-Key-v>
|
||||
indent-region = <Command-Key-bracketright>
|
||||
del-word-left = <Option-Key-BackSpace> <Option-Command-Key-BackSpace>
|
||||
newline-and-indent = <Key-Return> <Key-KP_Enter>
|
||||
end-of-file = <Control-Key-d>
|
||||
open-class-browser = <Command-Key-b>
|
||||
open-new-window = <Command-Key-n>
|
||||
open-module = <Command-Key-m>
|
||||
find-selection = <Shift-Command-Key-F3>
|
||||
python-context-help = <Shift-Key-F1>
|
||||
save-copy-of-window-as-file = <Option-Command-Key-s>
|
||||
open-window-from-file = <Command-Key-o>
|
||||
python-docs = <Key-F1>
|
||||
|
||||
79
Darwin/lib/python2.7/idlelib/config-main.def
Normal file
79
Darwin/lib/python2.7/idlelib/config-main.def
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# IDLE reads several config files to determine user preferences. This
|
||||
# file is the default config file for general idle settings.
|
||||
#
|
||||
# When IDLE starts, it will look in
|
||||
# the following two sets of files, in order:
|
||||
#
|
||||
# default configuration
|
||||
# ---------------------
|
||||
# config-main.def the default general config file
|
||||
# config-extensions.def the default extension config file
|
||||
# config-highlight.def the default highlighting config file
|
||||
# config-keys.def the default keybinding config file
|
||||
#
|
||||
# user configuration
|
||||
# -------------------
|
||||
# ~/.idlerc/config-main.cfg the user general config file
|
||||
# ~/.idlerc/config-extensions.cfg the user extension config file
|
||||
# ~/.idlerc/config-highlight.cfg the user highlighting config file
|
||||
# ~/.idlerc/config-keys.cfg the user keybinding config file
|
||||
#
|
||||
# On Windows2000 and Windows XP the .idlerc directory is at
|
||||
# Documents and Settings\<username>\.idlerc
|
||||
#
|
||||
# On Windows98 it is at c:\.idlerc
|
||||
#
|
||||
# Any options the user saves through the config dialog will be saved to
|
||||
# the relevant user config file. Reverting any general setting to the
|
||||
# default causes that entry to be wiped from the user file and re-read
|
||||
# from the default file. User highlighting themes or keybinding sets are
|
||||
# retained unless specifically deleted within the config dialog. Choosing
|
||||
# one of the default themes or keysets just applies the relevant settings
|
||||
# from the default file.
|
||||
#
|
||||
# Additional help sources are listed in the [HelpFiles] section and must be
|
||||
# viewable by a web browser (or the Windows Help viewer in the case of .chm
|
||||
# files). These sources will be listed on the Help menu. The pattern is
|
||||
# <sequence_number = menu item;/path/to/help/source>
|
||||
# You can't use a semi-colon in a menu item or path. The path will be platform
|
||||
# specific because of path separators, drive specs etc.
|
||||
#
|
||||
# It is best to use the Configuration GUI to set up additional help sources!
|
||||
# Example:
|
||||
#1 = My Extra Help Source;/usr/share/doc/foo/index.html
|
||||
#2 = Another Help Source;/path/to/another.pdf
|
||||
|
||||
[General]
|
||||
editor-on-startup= 0
|
||||
autosave= 0
|
||||
print-command-posix=lpr %s
|
||||
print-command-win=start /min notepad /p %s
|
||||
delete-exitfunc= 1
|
||||
|
||||
[EditorWindow]
|
||||
width= 80
|
||||
height= 40
|
||||
font= courier
|
||||
font-size= 10
|
||||
font-bold= 0
|
||||
encoding= none
|
||||
|
||||
[FormatParagraph]
|
||||
paragraph=70
|
||||
|
||||
[Indent]
|
||||
use-spaces= 1
|
||||
num-spaces= 4
|
||||
|
||||
[Theme]
|
||||
default= 1
|
||||
name= IDLE Classic
|
||||
|
||||
[Keys]
|
||||
default= 1
|
||||
name= IDLE Classic Windows
|
||||
|
||||
[History]
|
||||
cyclic=1
|
||||
|
||||
[HelpFiles]
|
||||
1158
Darwin/lib/python2.7/idlelib/configDialog.py
Normal file
1158
Darwin/lib/python2.7/idlelib/configDialog.py
Normal file
File diff suppressed because it is too large
Load diff
719
Darwin/lib/python2.7/idlelib/configHandler.py
Normal file
719
Darwin/lib/python2.7/idlelib/configHandler.py
Normal file
|
|
@ -0,0 +1,719 @@
|
|||
"""Provides access to stored IDLE configuration information.
|
||||
|
||||
Refer to the comments at the beginning of config-main.def for a description of
|
||||
the available configuration files and the design implemented to update user
|
||||
configuration information. In particular, user configuration choices which
|
||||
duplicate the defaults will be removed from the user's configuration files,
|
||||
and if a file becomes empty, it will be deleted.
|
||||
|
||||
The contents of the user files may be altered using the Options/Configure IDLE
|
||||
menu to access the configuration GUI (configDialog.py), or manually.
|
||||
|
||||
Throughout this module there is an emphasis on returning useable defaults
|
||||
when a problem occurs in returning a requested configuration value back to
|
||||
idle. This is to allow IDLE to continue to function in spite of errors in
|
||||
the retrieval of config information. When a default is returned instead of
|
||||
a requested config value, a message is printed to stderr to aid in
|
||||
configuration problem notification and resolution.
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
from idlelib import macosxSupport
|
||||
from ConfigParser import ConfigParser, NoOptionError, NoSectionError
|
||||
|
||||
class InvalidConfigType(Exception): pass
|
||||
class InvalidConfigSet(Exception): pass
|
||||
class InvalidFgBg(Exception): pass
|
||||
class InvalidTheme(Exception): pass
|
||||
|
||||
class IdleConfParser(ConfigParser):
|
||||
"""
|
||||
A ConfigParser specialised for idle configuration file handling
|
||||
"""
|
||||
def __init__(self, cfgFile, cfgDefaults=None):
|
||||
"""
|
||||
cfgFile - string, fully specified configuration file name
|
||||
"""
|
||||
self.file=cfgFile
|
||||
ConfigParser.__init__(self,defaults=cfgDefaults)
|
||||
|
||||
def Get(self, section, option, type=None, default=None, raw=False):
|
||||
"""
|
||||
Get an option value for given section/option or return default.
|
||||
If type is specified, return as type.
|
||||
"""
|
||||
if not self.has_option(section, option):
|
||||
return default
|
||||
if type=='bool':
|
||||
return self.getboolean(section, option)
|
||||
elif type=='int':
|
||||
return self.getint(section, option)
|
||||
else:
|
||||
return self.get(section, option, raw=raw)
|
||||
|
||||
def GetOptionList(self,section):
|
||||
"""
|
||||
Get an option list for given section
|
||||
"""
|
||||
if self.has_section(section):
|
||||
return self.options(section)
|
||||
else: #return a default value
|
||||
return []
|
||||
|
||||
def Load(self):
|
||||
"""
|
||||
Load the configuration file from disk
|
||||
"""
|
||||
self.read(self.file)
|
||||
|
||||
class IdleUserConfParser(IdleConfParser):
|
||||
"""
|
||||
IdleConfigParser specialised for user configuration handling.
|
||||
"""
|
||||
|
||||
def AddSection(self,section):
|
||||
"""
|
||||
if section doesn't exist, add it
|
||||
"""
|
||||
if not self.has_section(section):
|
||||
self.add_section(section)
|
||||
|
||||
def RemoveEmptySections(self):
|
||||
"""
|
||||
remove any sections that have no options
|
||||
"""
|
||||
for section in self.sections():
|
||||
if not self.GetOptionList(section):
|
||||
self.remove_section(section)
|
||||
|
||||
def IsEmpty(self):
|
||||
"""
|
||||
Remove empty sections and then return 1 if parser has no sections
|
||||
left, else return 0.
|
||||
"""
|
||||
self.RemoveEmptySections()
|
||||
if self.sections():
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
def RemoveOption(self,section,option):
|
||||
"""
|
||||
If section/option exists, remove it.
|
||||
Returns 1 if option was removed, 0 otherwise.
|
||||
"""
|
||||
if self.has_section(section):
|
||||
return self.remove_option(section,option)
|
||||
|
||||
def SetOption(self,section,option,value):
|
||||
"""
|
||||
Sets option to value, adding section if required.
|
||||
Returns 1 if option was added or changed, otherwise 0.
|
||||
"""
|
||||
if self.has_option(section,option):
|
||||
if self.get(section,option)==value:
|
||||
return 0
|
||||
else:
|
||||
self.set(section,option,value)
|
||||
return 1
|
||||
else:
|
||||
if not self.has_section(section):
|
||||
self.add_section(section)
|
||||
self.set(section,option,value)
|
||||
return 1
|
||||
|
||||
def RemoveFile(self):
|
||||
"""
|
||||
Removes the user config file from disk if it exists.
|
||||
"""
|
||||
if os.path.exists(self.file):
|
||||
os.remove(self.file)
|
||||
|
||||
def Save(self):
|
||||
"""Update user configuration file.
|
||||
|
||||
Remove empty sections. If resulting config isn't empty, write the file
|
||||
to disk. If config is empty, remove the file from disk if it exists.
|
||||
|
||||
"""
|
||||
if not self.IsEmpty():
|
||||
fname = self.file
|
||||
try:
|
||||
cfgFile = open(fname, 'w')
|
||||
except IOError:
|
||||
os.unlink(fname)
|
||||
cfgFile = open(fname, 'w')
|
||||
self.write(cfgFile)
|
||||
else:
|
||||
self.RemoveFile()
|
||||
|
||||
class IdleConf:
|
||||
"""
|
||||
holds config parsers for all idle config files:
|
||||
default config files
|
||||
(idle install dir)/config-main.def
|
||||
(idle install dir)/config-extensions.def
|
||||
(idle install dir)/config-highlight.def
|
||||
(idle install dir)/config-keys.def
|
||||
user config files
|
||||
(user home dir)/.idlerc/config-main.cfg
|
||||
(user home dir)/.idlerc/config-extensions.cfg
|
||||
(user home dir)/.idlerc/config-highlight.cfg
|
||||
(user home dir)/.idlerc/config-keys.cfg
|
||||
"""
|
||||
def __init__(self):
|
||||
self.defaultCfg={}
|
||||
self.userCfg={}
|
||||
self.cfg={}
|
||||
self.CreateConfigHandlers()
|
||||
self.LoadCfgFiles()
|
||||
#self.LoadCfg()
|
||||
|
||||
def CreateConfigHandlers(self):
|
||||
"""
|
||||
set up a dictionary of config parsers for default and user
|
||||
configurations respectively
|
||||
"""
|
||||
#build idle install path
|
||||
if __name__ != '__main__': # we were imported
|
||||
idleDir=os.path.dirname(__file__)
|
||||
else: # we were exec'ed (for testing only)
|
||||
idleDir=os.path.abspath(sys.path[0])
|
||||
userDir=self.GetUserCfgDir()
|
||||
configTypes=('main','extensions','highlight','keys')
|
||||
defCfgFiles={}
|
||||
usrCfgFiles={}
|
||||
for cfgType in configTypes: #build config file names
|
||||
defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
|
||||
usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
|
||||
for cfgType in configTypes: #create config parsers
|
||||
self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
|
||||
self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
|
||||
|
||||
def GetUserCfgDir(self):
|
||||
"""
|
||||
Creates (if required) and returns a filesystem directory for storing
|
||||
user config files.
|
||||
|
||||
"""
|
||||
cfgDir = '.idlerc'
|
||||
userDir = os.path.expanduser('~')
|
||||
if userDir != '~': # expanduser() found user home dir
|
||||
if not os.path.exists(userDir):
|
||||
warn = ('\n Warning: os.path.expanduser("~") points to\n '+
|
||||
userDir+',\n but the path does not exist.\n')
|
||||
try:
|
||||
sys.stderr.write(warn)
|
||||
except IOError:
|
||||
pass
|
||||
userDir = '~'
|
||||
if userDir == "~": # still no path to home!
|
||||
# traditionally IDLE has defaulted to os.getcwd(), is this adequate?
|
||||
userDir = os.getcwd()
|
||||
userDir = os.path.join(userDir, cfgDir)
|
||||
if not os.path.exists(userDir):
|
||||
try:
|
||||
os.mkdir(userDir)
|
||||
except (OSError, IOError):
|
||||
warn = ('\n Warning: unable to create user config directory\n'+
|
||||
userDir+'\n Check path and permissions.\n Exiting!\n\n')
|
||||
sys.stderr.write(warn)
|
||||
raise SystemExit
|
||||
return userDir
|
||||
|
||||
def GetOption(self, configType, section, option, default=None, type=None,
|
||||
warn_on_default=True, raw=False):
|
||||
"""
|
||||
Get an option value for given config type and given general
|
||||
configuration section/option or return a default. If type is specified,
|
||||
return as type. Firstly the user configuration is checked, with a
|
||||
fallback to the default configuration, and a final 'catch all'
|
||||
fallback to a useable passed-in default if the option isn't present in
|
||||
either the user or the default configuration.
|
||||
configType must be one of ('main','extensions','highlight','keys')
|
||||
If a default is returned, and warn_on_default is True, a warning is
|
||||
printed to stderr.
|
||||
|
||||
"""
|
||||
try:
|
||||
if self.userCfg[configType].has_option(section,option):
|
||||
return self.userCfg[configType].Get(section, option,
|
||||
type=type, raw=raw)
|
||||
except ValueError:
|
||||
warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
|
||||
' invalid %r value for configuration option %r\n'
|
||||
' from section %r: %r\n' %
|
||||
(type, option, section,
|
||||
self.userCfg[configType].Get(section, option,
|
||||
raw=raw)))
|
||||
try:
|
||||
sys.stderr.write(warning)
|
||||
except IOError:
|
||||
pass
|
||||
try:
|
||||
if self.defaultCfg[configType].has_option(section,option):
|
||||
return self.defaultCfg[configType].Get(section, option,
|
||||
type=type, raw=raw)
|
||||
except ValueError:
|
||||
pass
|
||||
#returning default, print warning
|
||||
if warn_on_default:
|
||||
warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
|
||||
' problem retrieving configuration option %r\n'
|
||||
' from section %r.\n'
|
||||
' returning default value: %r\n' %
|
||||
(option, section, default))
|
||||
try:
|
||||
sys.stderr.write(warning)
|
||||
except IOError:
|
||||
pass
|
||||
return default
|
||||
|
||||
def SetOption(self, configType, section, option, value):
|
||||
"""In user's config file, set section's option to value.
|
||||
|
||||
"""
|
||||
self.userCfg[configType].SetOption(section, option, value)
|
||||
|
||||
def GetSectionList(self, configSet, configType):
|
||||
"""
|
||||
Get a list of sections from either the user or default config for
|
||||
the given config type.
|
||||
configSet must be either 'user' or 'default'
|
||||
configType must be one of ('main','extensions','highlight','keys')
|
||||
"""
|
||||
if not (configType in ('main','extensions','highlight','keys')):
|
||||
raise InvalidConfigType, 'Invalid configType specified'
|
||||
if configSet == 'user':
|
||||
cfgParser=self.userCfg[configType]
|
||||
elif configSet == 'default':
|
||||
cfgParser=self.defaultCfg[configType]
|
||||
else:
|
||||
raise InvalidConfigSet, 'Invalid configSet specified'
|
||||
return cfgParser.sections()
|
||||
|
||||
def GetHighlight(self, theme, element, fgBg=None):
|
||||
"""
|
||||
return individual highlighting theme elements.
|
||||
fgBg - string ('fg'or'bg') or None, if None return a dictionary
|
||||
containing fg and bg colours (appropriate for passing to Tkinter in,
|
||||
e.g., a tag_config call), otherwise fg or bg colour only as specified.
|
||||
"""
|
||||
if self.defaultCfg['highlight'].has_section(theme):
|
||||
themeDict=self.GetThemeDict('default',theme)
|
||||
else:
|
||||
themeDict=self.GetThemeDict('user',theme)
|
||||
fore=themeDict[element+'-foreground']
|
||||
if element=='cursor': #there is no config value for cursor bg
|
||||
back=themeDict['normal-background']
|
||||
else:
|
||||
back=themeDict[element+'-background']
|
||||
highlight={"foreground": fore,"background": back}
|
||||
if not fgBg: #return dict of both colours
|
||||
return highlight
|
||||
else: #return specified colour only
|
||||
if fgBg == 'fg':
|
||||
return highlight["foreground"]
|
||||
if fgBg == 'bg':
|
||||
return highlight["background"]
|
||||
else:
|
||||
raise InvalidFgBg, 'Invalid fgBg specified'
|
||||
|
||||
def GetThemeDict(self,type,themeName):
|
||||
"""
|
||||
type - string, 'default' or 'user' theme type
|
||||
themeName - string, theme name
|
||||
Returns a dictionary which holds {option:value} for each element
|
||||
in the specified theme. Values are loaded over a set of ultimate last
|
||||
fallback defaults to guarantee that all theme elements are present in
|
||||
a newly created theme.
|
||||
"""
|
||||
if type == 'user':
|
||||
cfgParser=self.userCfg['highlight']
|
||||
elif type == 'default':
|
||||
cfgParser=self.defaultCfg['highlight']
|
||||
else:
|
||||
raise InvalidTheme, 'Invalid theme type specified'
|
||||
#foreground and background values are provded for each theme element
|
||||
#(apart from cursor) even though all these values are not yet used
|
||||
#by idle, to allow for their use in the future. Default values are
|
||||
#generally black and white.
|
||||
theme={ 'normal-foreground':'#000000',
|
||||
'normal-background':'#ffffff',
|
||||
'keyword-foreground':'#000000',
|
||||
'keyword-background':'#ffffff',
|
||||
'builtin-foreground':'#000000',
|
||||
'builtin-background':'#ffffff',
|
||||
'comment-foreground':'#000000',
|
||||
'comment-background':'#ffffff',
|
||||
'string-foreground':'#000000',
|
||||
'string-background':'#ffffff',
|
||||
'definition-foreground':'#000000',
|
||||
'definition-background':'#ffffff',
|
||||
'hilite-foreground':'#000000',
|
||||
'hilite-background':'gray',
|
||||
'break-foreground':'#ffffff',
|
||||
'break-background':'#000000',
|
||||
'hit-foreground':'#ffffff',
|
||||
'hit-background':'#000000',
|
||||
'error-foreground':'#ffffff',
|
||||
'error-background':'#000000',
|
||||
#cursor (only foreground can be set)
|
||||
'cursor-foreground':'#000000',
|
||||
#shell window
|
||||
'stdout-foreground':'#000000',
|
||||
'stdout-background':'#ffffff',
|
||||
'stderr-foreground':'#000000',
|
||||
'stderr-background':'#ffffff',
|
||||
'console-foreground':'#000000',
|
||||
'console-background':'#ffffff' }
|
||||
for element in theme.keys():
|
||||
if not cfgParser.has_option(themeName,element):
|
||||
#we are going to return a default, print warning
|
||||
warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'
|
||||
' -\n problem retrieving theme element %r'
|
||||
'\n from theme %r.\n'
|
||||
' returning default value: %r\n' %
|
||||
(element, themeName, theme[element]))
|
||||
try:
|
||||
sys.stderr.write(warning)
|
||||
except IOError:
|
||||
pass
|
||||
colour=cfgParser.Get(themeName,element,default=theme[element])
|
||||
theme[element]=colour
|
||||
return theme
|
||||
|
||||
def CurrentTheme(self):
|
||||
"""
|
||||
Returns the name of the currently active theme
|
||||
"""
|
||||
return self.GetOption('main','Theme','name',default='')
|
||||
|
||||
def CurrentKeys(self):
|
||||
"""
|
||||
Returns the name of the currently active key set
|
||||
"""
|
||||
return self.GetOption('main','Keys','name',default='')
|
||||
|
||||
def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
|
||||
"""
|
||||
Gets a list of all idle extensions declared in the config files.
|
||||
active_only - boolean, if true only return active (enabled) extensions
|
||||
"""
|
||||
extns=self.RemoveKeyBindNames(
|
||||
self.GetSectionList('default','extensions'))
|
||||
userExtns=self.RemoveKeyBindNames(
|
||||
self.GetSectionList('user','extensions'))
|
||||
for extn in userExtns:
|
||||
if extn not in extns: #user has added own extension
|
||||
extns.append(extn)
|
||||
if active_only:
|
||||
activeExtns=[]
|
||||
for extn in extns:
|
||||
if self.GetOption('extensions', extn, 'enable', default=True,
|
||||
type='bool'):
|
||||
#the extension is enabled
|
||||
if editor_only or shell_only:
|
||||
if editor_only:
|
||||
option = "enable_editor"
|
||||
else:
|
||||
option = "enable_shell"
|
||||
if self.GetOption('extensions', extn,option,
|
||||
default=True, type='bool',
|
||||
warn_on_default=False):
|
||||
activeExtns.append(extn)
|
||||
else:
|
||||
activeExtns.append(extn)
|
||||
return activeExtns
|
||||
else:
|
||||
return extns
|
||||
|
||||
def RemoveKeyBindNames(self,extnNameList):
|
||||
#get rid of keybinding section names
|
||||
names=extnNameList
|
||||
kbNameIndicies=[]
|
||||
for name in names:
|
||||
if name.endswith(('_bindings', '_cfgBindings')):
|
||||
kbNameIndicies.append(names.index(name))
|
||||
kbNameIndicies.sort()
|
||||
kbNameIndicies.reverse()
|
||||
for index in kbNameIndicies: #delete each keybinding section name
|
||||
del(names[index])
|
||||
return names
|
||||
|
||||
def GetExtnNameForEvent(self,virtualEvent):
|
||||
"""
|
||||
Returns the name of the extension that virtualEvent is bound in, or
|
||||
None if not bound in any extension.
|
||||
virtualEvent - string, name of the virtual event to test for, without
|
||||
the enclosing '<< >>'
|
||||
"""
|
||||
extName=None
|
||||
vEvent='<<'+virtualEvent+'>>'
|
||||
for extn in self.GetExtensions(active_only=0):
|
||||
for event in self.GetExtensionKeys(extn).keys():
|
||||
if event == vEvent:
|
||||
extName=extn
|
||||
return extName
|
||||
|
||||
def GetExtensionKeys(self,extensionName):
|
||||
"""
|
||||
returns a dictionary of the configurable keybindings for a particular
|
||||
extension,as they exist in the dictionary returned by GetCurrentKeySet;
|
||||
that is, where previously used bindings are disabled.
|
||||
"""
|
||||
keysName=extensionName+'_cfgBindings'
|
||||
activeKeys=self.GetCurrentKeySet()
|
||||
extKeys={}
|
||||
if self.defaultCfg['extensions'].has_section(keysName):
|
||||
eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
|
||||
for eventName in eventNames:
|
||||
event='<<'+eventName+'>>'
|
||||
binding=activeKeys[event]
|
||||
extKeys[event]=binding
|
||||
return extKeys
|
||||
|
||||
def __GetRawExtensionKeys(self,extensionName):
|
||||
"""
|
||||
returns a dictionary of the configurable keybindings for a particular
|
||||
extension, as defined in the configuration files, or an empty dictionary
|
||||
if no bindings are found
|
||||
"""
|
||||
keysName=extensionName+'_cfgBindings'
|
||||
extKeys={}
|
||||
if self.defaultCfg['extensions'].has_section(keysName):
|
||||
eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
|
||||
for eventName in eventNames:
|
||||
binding=self.GetOption('extensions',keysName,
|
||||
eventName,default='').split()
|
||||
event='<<'+eventName+'>>'
|
||||
extKeys[event]=binding
|
||||
return extKeys
|
||||
|
||||
def GetExtensionBindings(self,extensionName):
|
||||
"""
|
||||
Returns a dictionary of all the event bindings for a particular
|
||||
extension. The configurable keybindings are returned as they exist in
|
||||
the dictionary returned by GetCurrentKeySet; that is, where re-used
|
||||
keybindings are disabled.
|
||||
"""
|
||||
bindsName=extensionName+'_bindings'
|
||||
extBinds=self.GetExtensionKeys(extensionName)
|
||||
#add the non-configurable bindings
|
||||
if self.defaultCfg['extensions'].has_section(bindsName):
|
||||
eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
|
||||
for eventName in eventNames:
|
||||
binding=self.GetOption('extensions',bindsName,
|
||||
eventName,default='').split()
|
||||
event='<<'+eventName+'>>'
|
||||
extBinds[event]=binding
|
||||
|
||||
return extBinds
|
||||
|
||||
def GetKeyBinding(self, keySetName, eventStr):
|
||||
"""
|
||||
returns the keybinding for a specific event.
|
||||
keySetName - string, name of key binding set
|
||||
eventStr - string, the virtual event we want the binding for,
|
||||
represented as a string, eg. '<<event>>'
|
||||
"""
|
||||
eventName=eventStr[2:-2] #trim off the angle brackets
|
||||
binding=self.GetOption('keys',keySetName,eventName,default='').split()
|
||||
return binding
|
||||
|
||||
def GetCurrentKeySet(self):
|
||||
result = self.GetKeySet(self.CurrentKeys())
|
||||
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
# We're using AquaTk, replace all keybingings that use the
|
||||
# Alt key by ones that use the Option key because the former
|
||||
# don't work reliably.
|
||||
for k, v in result.items():
|
||||
v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
|
||||
if v != v2:
|
||||
result[k] = v2
|
||||
|
||||
return result
|
||||
|
||||
def GetKeySet(self,keySetName):
|
||||
"""
|
||||
Returns a dictionary of: all requested core keybindings, plus the
|
||||
keybindings for all currently active extensions. If a binding defined
|
||||
in an extension is already in use, that binding is disabled.
|
||||
"""
|
||||
keySet=self.GetCoreKeys(keySetName)
|
||||
activeExtns=self.GetExtensions(active_only=1)
|
||||
for extn in activeExtns:
|
||||
extKeys=self.__GetRawExtensionKeys(extn)
|
||||
if extKeys: #the extension defines keybindings
|
||||
for event in extKeys.keys():
|
||||
if extKeys[event] in keySet.values():
|
||||
#the binding is already in use
|
||||
extKeys[event]='' #disable this binding
|
||||
keySet[event]=extKeys[event] #add binding
|
||||
return keySet
|
||||
|
||||
def IsCoreBinding(self,virtualEvent):
|
||||
"""
|
||||
returns true if the virtual event is bound in the core idle keybindings.
|
||||
virtualEvent - string, name of the virtual event to test for, without
|
||||
the enclosing '<< >>'
|
||||
"""
|
||||
return ('<<'+virtualEvent+'>>') in self.GetCoreKeys().keys()
|
||||
|
||||
def GetCoreKeys(self, keySetName=None):
|
||||
"""
|
||||
returns the requested set of core keybindings, with fallbacks if
|
||||
required.
|
||||
Keybindings loaded from the config file(s) are loaded _over_ these
|
||||
defaults, so if there is a problem getting any core binding there will
|
||||
be an 'ultimate last resort fallback' to the CUA-ish bindings
|
||||
defined here.
|
||||
"""
|
||||
keyBindings={
|
||||
'<<copy>>': ['<Control-c>', '<Control-C>'],
|
||||
'<<cut>>': ['<Control-x>', '<Control-X>'],
|
||||
'<<paste>>': ['<Control-v>', '<Control-V>'],
|
||||
'<<beginning-of-line>>': ['<Control-a>', '<Home>'],
|
||||
'<<center-insert>>': ['<Control-l>'],
|
||||
'<<close-all-windows>>': ['<Control-q>'],
|
||||
'<<close-window>>': ['<Alt-F4>'],
|
||||
'<<do-nothing>>': ['<Control-x>'],
|
||||
'<<end-of-file>>': ['<Control-d>'],
|
||||
'<<python-docs>>': ['<F1>'],
|
||||
'<<python-context-help>>': ['<Shift-F1>'],
|
||||
'<<history-next>>': ['<Alt-n>'],
|
||||
'<<history-previous>>': ['<Alt-p>'],
|
||||
'<<interrupt-execution>>': ['<Control-c>'],
|
||||
'<<view-restart>>': ['<F6>'],
|
||||
'<<restart-shell>>': ['<Control-F6>'],
|
||||
'<<open-class-browser>>': ['<Alt-c>'],
|
||||
'<<open-module>>': ['<Alt-m>'],
|
||||
'<<open-new-window>>': ['<Control-n>'],
|
||||
'<<open-window-from-file>>': ['<Control-o>'],
|
||||
'<<plain-newline-and-indent>>': ['<Control-j>'],
|
||||
'<<print-window>>': ['<Control-p>'],
|
||||
'<<redo>>': ['<Control-y>'],
|
||||
'<<remove-selection>>': ['<Escape>'],
|
||||
'<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
|
||||
'<<save-window-as-file>>': ['<Alt-s>'],
|
||||
'<<save-window>>': ['<Control-s>'],
|
||||
'<<select-all>>': ['<Alt-a>'],
|
||||
'<<toggle-auto-coloring>>': ['<Control-slash>'],
|
||||
'<<undo>>': ['<Control-z>'],
|
||||
'<<find-again>>': ['<Control-g>', '<F3>'],
|
||||
'<<find-in-files>>': ['<Alt-F3>'],
|
||||
'<<find-selection>>': ['<Control-F3>'],
|
||||
'<<find>>': ['<Control-f>'],
|
||||
'<<replace>>': ['<Control-h>'],
|
||||
'<<goto-line>>': ['<Alt-g>'],
|
||||
'<<smart-backspace>>': ['<Key-BackSpace>'],
|
||||
'<<newline-and-indent>>': ['<Key-Return>', '<Key-KP_Enter>'],
|
||||
'<<smart-indent>>': ['<Key-Tab>'],
|
||||
'<<indent-region>>': ['<Control-Key-bracketright>'],
|
||||
'<<dedent-region>>': ['<Control-Key-bracketleft>'],
|
||||
'<<comment-region>>': ['<Alt-Key-3>'],
|
||||
'<<uncomment-region>>': ['<Alt-Key-4>'],
|
||||
'<<tabify-region>>': ['<Alt-Key-5>'],
|
||||
'<<untabify-region>>': ['<Alt-Key-6>'],
|
||||
'<<toggle-tabs>>': ['<Alt-Key-t>'],
|
||||
'<<change-indentwidth>>': ['<Alt-Key-u>'],
|
||||
'<<del-word-left>>': ['<Control-Key-BackSpace>'],
|
||||
'<<del-word-right>>': ['<Control-Key-Delete>']
|
||||
}
|
||||
if keySetName:
|
||||
for event in keyBindings.keys():
|
||||
binding=self.GetKeyBinding(keySetName,event)
|
||||
if binding:
|
||||
keyBindings[event]=binding
|
||||
else: #we are going to return a default, print warning
|
||||
warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
|
||||
' -\n problem retrieving key binding for event %r'
|
||||
'\n from key set %r.\n'
|
||||
' returning default value: %r\n' %
|
||||
(event, keySetName, keyBindings[event]))
|
||||
try:
|
||||
sys.stderr.write(warning)
|
||||
except IOError:
|
||||
pass
|
||||
return keyBindings
|
||||
|
||||
def GetExtraHelpSourceList(self,configSet):
|
||||
"""Fetch list of extra help sources from a given configSet.
|
||||
|
||||
Valid configSets are 'user' or 'default'. Return a list of tuples of
|
||||
the form (menu_item , path_to_help_file , option), or return the empty
|
||||
list. 'option' is the sequence number of the help resource. 'option'
|
||||
values determine the position of the menu items on the Help menu,
|
||||
therefore the returned list must be sorted by 'option'.
|
||||
|
||||
"""
|
||||
helpSources=[]
|
||||
if configSet=='user':
|
||||
cfgParser=self.userCfg['main']
|
||||
elif configSet=='default':
|
||||
cfgParser=self.defaultCfg['main']
|
||||
else:
|
||||
raise InvalidConfigSet, 'Invalid configSet specified'
|
||||
options=cfgParser.GetOptionList('HelpFiles')
|
||||
for option in options:
|
||||
value=cfgParser.Get('HelpFiles',option,default=';')
|
||||
if value.find(';')==-1: #malformed config entry with no ';'
|
||||
menuItem='' #make these empty
|
||||
helpPath='' #so value won't be added to list
|
||||
else: #config entry contains ';' as expected
|
||||
value=string.split(value,';')
|
||||
menuItem=value[0].strip()
|
||||
helpPath=value[1].strip()
|
||||
if menuItem and helpPath: #neither are empty strings
|
||||
helpSources.append( (menuItem,helpPath,option) )
|
||||
helpSources.sort(key=lambda x: int(x[2]))
|
||||
return helpSources
|
||||
|
||||
def GetAllExtraHelpSourcesList(self):
|
||||
"""
|
||||
Returns a list of tuples containing the details of all additional help
|
||||
sources configured, or an empty list if there are none. Tuples are of
|
||||
the format returned by GetExtraHelpSourceList.
|
||||
"""
|
||||
allHelpSources=( self.GetExtraHelpSourceList('default')+
|
||||
self.GetExtraHelpSourceList('user') )
|
||||
return allHelpSources
|
||||
|
||||
def LoadCfgFiles(self):
|
||||
"""
|
||||
load all configuration files.
|
||||
"""
|
||||
for key in self.defaultCfg.keys():
|
||||
self.defaultCfg[key].Load()
|
||||
self.userCfg[key].Load() #same keys
|
||||
|
||||
def SaveUserCfgFiles(self):
|
||||
"""
|
||||
write all loaded user configuration files back to disk
|
||||
"""
|
||||
for key in self.userCfg.keys():
|
||||
self.userCfg[key].Save()
|
||||
|
||||
idleConf=IdleConf()
|
||||
|
||||
### module test
|
||||
if __name__ == '__main__':
|
||||
def dumpCfg(cfg):
|
||||
print '\n',cfg,'\n'
|
||||
for key in cfg.keys():
|
||||
sections=cfg[key].sections()
|
||||
print key
|
||||
print sections
|
||||
for section in sections:
|
||||
options=cfg[key].options(section)
|
||||
print section
|
||||
print options
|
||||
for option in options:
|
||||
print option, '=', cfg[key].Get(section,option)
|
||||
dumpCfg(idleConf.defaultCfg)
|
||||
dumpCfg(idleConf.userCfg)
|
||||
print idleConf.userCfg['main'].Get('Theme','name')
|
||||
#print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')
|
||||
169
Darwin/lib/python2.7/idlelib/configHelpSourceEdit.py
Normal file
169
Darwin/lib/python2.7/idlelib/configHelpSourceEdit.py
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
"Dialog to specify or edit the parameters for a user configured help source."
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from Tkinter import *
|
||||
import tkMessageBox
|
||||
import tkFileDialog
|
||||
|
||||
class GetHelpSourceDialog(Toplevel):
|
||||
def __init__(self, parent, title, menuItem='', filePath=''):
|
||||
"""Get menu entry and url/ local file location for Additional Help
|
||||
|
||||
User selects a name for the Help resource and provides a web url
|
||||
or a local file as its source. The user can enter a url or browse
|
||||
for the file.
|
||||
|
||||
"""
|
||||
Toplevel.__init__(self, parent)
|
||||
self.configure(borderwidth=5)
|
||||
self.resizable(height=FALSE, width=FALSE)
|
||||
self.title(title)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.protocol("WM_DELETE_WINDOW", self.Cancel)
|
||||
self.parent = parent
|
||||
self.result = None
|
||||
self.CreateWidgets()
|
||||
self.menu.set(menuItem)
|
||||
self.path.set(filePath)
|
||||
self.withdraw() #hide while setting geometry
|
||||
#needs to be done here so that the winfo_reqwidth is valid
|
||||
self.update_idletasks()
|
||||
#centre dialog over parent:
|
||||
self.geometry("+%d+%d" %
|
||||
((parent.winfo_rootx() + ((parent.winfo_width()/2)
|
||||
-(self.winfo_reqwidth()/2)),
|
||||
parent.winfo_rooty() + ((parent.winfo_height()/2)
|
||||
-(self.winfo_reqheight()/2)))))
|
||||
self.deiconify() #geometry set, unhide
|
||||
self.bind('<Return>', self.Ok)
|
||||
self.wait_window()
|
||||
|
||||
def CreateWidgets(self):
|
||||
self.menu = StringVar(self)
|
||||
self.path = StringVar(self)
|
||||
self.fontSize = StringVar(self)
|
||||
self.frameMain = Frame(self, borderwidth=2, relief=GROOVE)
|
||||
self.frameMain.pack(side=TOP, expand=TRUE, fill=BOTH)
|
||||
labelMenu = Label(self.frameMain, anchor=W, justify=LEFT,
|
||||
text='Menu Item:')
|
||||
self.entryMenu = Entry(self.frameMain, textvariable=self.menu,
|
||||
width=30)
|
||||
self.entryMenu.focus_set()
|
||||
labelPath = Label(self.frameMain, anchor=W, justify=LEFT,
|
||||
text='Help File Path: Enter URL or browse for file')
|
||||
self.entryPath = Entry(self.frameMain, textvariable=self.path,
|
||||
width=40)
|
||||
self.entryMenu.focus_set()
|
||||
labelMenu.pack(anchor=W, padx=5, pady=3)
|
||||
self.entryMenu.pack(anchor=W, padx=5, pady=3)
|
||||
labelPath.pack(anchor=W, padx=5, pady=3)
|
||||
self.entryPath.pack(anchor=W, padx=5, pady=3)
|
||||
browseButton = Button(self.frameMain, text='Browse', width=8,
|
||||
command=self.browseFile)
|
||||
browseButton.pack(pady=3)
|
||||
frameButtons = Frame(self)
|
||||
frameButtons.pack(side=BOTTOM, fill=X)
|
||||
self.buttonOk = Button(frameButtons, text='OK',
|
||||
width=8, default=ACTIVE, command=self.Ok)
|
||||
self.buttonOk.grid(row=0, column=0, padx=5,pady=5)
|
||||
self.buttonCancel = Button(frameButtons, text='Cancel',
|
||||
width=8, command=self.Cancel)
|
||||
self.buttonCancel.grid(row=0, column=1, padx=5, pady=5)
|
||||
|
||||
def browseFile(self):
|
||||
filetypes = [
|
||||
("HTML Files", "*.htm *.html", "TEXT"),
|
||||
("PDF Files", "*.pdf", "TEXT"),
|
||||
("Windows Help Files", "*.chm"),
|
||||
("Text Files", "*.txt", "TEXT"),
|
||||
("All Files", "*")]
|
||||
path = self.path.get()
|
||||
if path:
|
||||
dir, base = os.path.split(path)
|
||||
else:
|
||||
base = None
|
||||
if sys.platform[:3] == 'win':
|
||||
dir = os.path.join(os.path.dirname(sys.executable), 'Doc')
|
||||
if not os.path.isdir(dir):
|
||||
dir = os.getcwd()
|
||||
else:
|
||||
dir = os.getcwd()
|
||||
opendialog = tkFileDialog.Open(parent=self, filetypes=filetypes)
|
||||
file = opendialog.show(initialdir=dir, initialfile=base)
|
||||
if file:
|
||||
self.path.set(file)
|
||||
|
||||
def MenuOk(self):
|
||||
"Simple validity check for a sensible menu item name"
|
||||
menuOk = True
|
||||
menu = self.menu.get()
|
||||
menu.strip()
|
||||
if not menu:
|
||||
tkMessageBox.showerror(title='Menu Item Error',
|
||||
message='No menu item specified',
|
||||
parent=self)
|
||||
self.entryMenu.focus_set()
|
||||
menuOk = False
|
||||
elif len(menu) > 30:
|
||||
tkMessageBox.showerror(title='Menu Item Error',
|
||||
message='Menu item too long:'
|
||||
'\nLimit 30 characters.',
|
||||
parent=self)
|
||||
self.entryMenu.focus_set()
|
||||
menuOk = False
|
||||
return menuOk
|
||||
|
||||
def PathOk(self):
|
||||
"Simple validity check for menu file path"
|
||||
pathOk = True
|
||||
path = self.path.get()
|
||||
path.strip()
|
||||
if not path: #no path specified
|
||||
tkMessageBox.showerror(title='File Path Error',
|
||||
message='No help file path specified.',
|
||||
parent=self)
|
||||
self.entryPath.focus_set()
|
||||
pathOk = False
|
||||
elif path.startswith(('www.', 'http')):
|
||||
pass
|
||||
else:
|
||||
if path[:5] == 'file:':
|
||||
path = path[5:]
|
||||
if not os.path.exists(path):
|
||||
tkMessageBox.showerror(title='File Path Error',
|
||||
message='Help file path does not exist.',
|
||||
parent=self)
|
||||
self.entryPath.focus_set()
|
||||
pathOk = False
|
||||
return pathOk
|
||||
|
||||
def Ok(self, event=None):
|
||||
if self.MenuOk() and self.PathOk():
|
||||
self.result = (self.menu.get().strip(),
|
||||
self.path.get().strip())
|
||||
if sys.platform == 'darwin':
|
||||
path = self.result[1]
|
||||
if path.startswith(('www', 'file:', 'http:')):
|
||||
pass
|
||||
else:
|
||||
# Mac Safari insists on using the URI form for local files
|
||||
self.result = list(self.result)
|
||||
self.result[1] = "file://" + path
|
||||
self.destroy()
|
||||
|
||||
def Cancel(self, event=None):
|
||||
self.result = None
|
||||
self.destroy()
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test the dialog
|
||||
root = Tk()
|
||||
def run():
|
||||
keySeq = ''
|
||||
dlg = GetHelpSourceDialog(root, 'Get Help Source')
|
||||
print dlg.result
|
||||
Button(root,text='Dialog', command=run).pack()
|
||||
root.mainloop()
|
||||
100
Darwin/lib/python2.7/idlelib/configSectionNameDialog.py
Normal file
100
Darwin/lib/python2.7/idlelib/configSectionNameDialog.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
"""
|
||||
Dialog that allows user to specify a new config file section name.
|
||||
Used to get new highlight theme and keybinding set names.
|
||||
The 'return value' for the dialog, used two placed in configDialog.py,
|
||||
is the .result attribute set in the Ok and Cancel methods.
|
||||
"""
|
||||
from Tkinter import *
|
||||
import tkMessageBox
|
||||
class GetCfgSectionNameDialog(Toplevel):
|
||||
def __init__(self, parent, title, message, used_names):
|
||||
"""
|
||||
message - string, informational message to display
|
||||
used_names - string collection, names already in use for validity check
|
||||
"""
|
||||
Toplevel.__init__(self, parent)
|
||||
self.configure(borderwidth=5)
|
||||
self.resizable(height=FALSE, width=FALSE)
|
||||
self.title(title)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.protocol("WM_DELETE_WINDOW", self.Cancel)
|
||||
self.parent = parent
|
||||
self.message = message
|
||||
self.used_names = used_names
|
||||
self.create_widgets()
|
||||
self.withdraw() #hide while setting geometry
|
||||
self.update_idletasks()
|
||||
#needs to be done here so that the winfo_reqwidth is valid
|
||||
self.messageInfo.config(width=self.frameMain.winfo_reqwidth())
|
||||
self.geometry(
|
||||
"+%d+%d" % (
|
||||
parent.winfo_rootx() +
|
||||
(parent.winfo_width()/2 - self.winfo_reqwidth()/2),
|
||||
parent.winfo_rooty() +
|
||||
(parent.winfo_height()/2 - self.winfo_reqheight()/2)
|
||||
) ) #centre dialog over parent
|
||||
self.deiconify() #geometry set, unhide
|
||||
self.wait_window()
|
||||
def create_widgets(self):
|
||||
self.name = StringVar(self.parent)
|
||||
self.fontSize = StringVar(self.parent)
|
||||
self.frameMain = Frame(self, borderwidth=2, relief=SUNKEN)
|
||||
self.frameMain.pack(side=TOP, expand=TRUE, fill=BOTH)
|
||||
self.messageInfo = Message(self.frameMain, anchor=W, justify=LEFT,
|
||||
padx=5, pady=5, text=self.message) #,aspect=200)
|
||||
entryName = Entry(self.frameMain, textvariable=self.name, width=30)
|
||||
entryName.focus_set()
|
||||
self.messageInfo.pack(padx=5, pady=5) #, expand=TRUE, fill=BOTH)
|
||||
entryName.pack(padx=5, pady=5)
|
||||
frameButtons = Frame(self, pady=2)
|
||||
frameButtons.pack(side=BOTTOM)
|
||||
self.buttonOk = Button(frameButtons, text='Ok',
|
||||
width=8, command=self.Ok)
|
||||
self.buttonOk.pack(side=LEFT, padx=5)
|
||||
self.buttonCancel = Button(frameButtons, text='Cancel',
|
||||
width=8, command=self.Cancel)
|
||||
self.buttonCancel.pack(side=RIGHT, padx=5)
|
||||
|
||||
def name_ok(self):
|
||||
''' After stripping entered name, check that it is a sensible
|
||||
ConfigParser file section name. Return it if it is, '' if not.
|
||||
'''
|
||||
name = self.name.get().strip()
|
||||
if not name: #no name specified
|
||||
tkMessageBox.showerror(title='Name Error',
|
||||
message='No name specified.', parent=self)
|
||||
elif len(name)>30: #name too long
|
||||
tkMessageBox.showerror(title='Name Error',
|
||||
message='Name too long. It should be no more than '+
|
||||
'30 characters.', parent=self)
|
||||
name = ''
|
||||
elif name in self.used_names:
|
||||
tkMessageBox.showerror(title='Name Error',
|
||||
message='This name is already in use.', parent=self)
|
||||
name = ''
|
||||
return name
|
||||
def Ok(self, event=None):
|
||||
name = self.name_ok()
|
||||
if name:
|
||||
self.result = name
|
||||
self.destroy()
|
||||
def Cancel(self, event=None):
|
||||
self.result = ''
|
||||
self.destroy()
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
unittest.main('idlelib.idle_test.test_config_name', verbosity=2, exit=False)
|
||||
|
||||
# also human test the dialog
|
||||
root = Tk()
|
||||
def run():
|
||||
dlg=GetCfgSectionNameDialog(root,'Get Name',
|
||||
"After the text entered with [Ok] is stripped, <nothing>, "
|
||||
"'abc', or more that 30 chars are errors. "
|
||||
"Close with a valid entry (printed), [Cancel], or [X]",
|
||||
{'abc'})
|
||||
print dlg.result
|
||||
Message(root, text='').pack() # will be needed for oher dialog tests
|
||||
Button(root, text='Click to begin dialog test', command=run).pack()
|
||||
root.mainloop()
|
||||
35
Darwin/lib/python2.7/idlelib/dynOptionMenuWidget.py
Normal file
35
Darwin/lib/python2.7/idlelib/dynOptionMenuWidget.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""
|
||||
OptionMenu widget modified to allow dynamic menu reconfiguration
|
||||
and setting of highlightthickness
|
||||
"""
|
||||
from Tkinter import OptionMenu
|
||||
from Tkinter import _setit
|
||||
import copy
|
||||
|
||||
class DynOptionMenu(OptionMenu):
|
||||
"""
|
||||
unlike OptionMenu, our kwargs can include highlightthickness
|
||||
"""
|
||||
def __init__(self, master, variable, value, *values, **kwargs):
|
||||
#get a copy of kwargs before OptionMenu.__init__ munges them
|
||||
kwargsCopy=copy.copy(kwargs)
|
||||
if 'highlightthickness' in kwargs.keys():
|
||||
del(kwargs['highlightthickness'])
|
||||
OptionMenu.__init__(self, master, variable, value, *values, **kwargs)
|
||||
self.config(highlightthickness=kwargsCopy.get('highlightthickness'))
|
||||
#self.menu=self['menu']
|
||||
self.variable=variable
|
||||
self.command=kwargs.get('command')
|
||||
|
||||
def SetMenu(self,valueList,value=None):
|
||||
"""
|
||||
clear and reload the menu with a new set of options.
|
||||
valueList - list of new options
|
||||
value - initial value to set the optionmenu's menubutton to
|
||||
"""
|
||||
self['menu'].delete(0,'end')
|
||||
for item in valueList:
|
||||
self['menu'].add_command(label=item,
|
||||
command=_setit(self.variable,item,self.command))
|
||||
if value:
|
||||
self.variable.set(value)
|
||||
83
Darwin/lib/python2.7/idlelib/extend.txt
Normal file
83
Darwin/lib/python2.7/idlelib/extend.txt
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
Writing an IDLE extension
|
||||
=========================
|
||||
|
||||
An IDLE extension can define new key bindings and menu entries for IDLE
|
||||
edit windows. There is a simple mechanism to load extensions when IDLE
|
||||
starts up and to attach them to each edit window. (It is also possible
|
||||
to make other changes to IDLE, but this must be done by editing the IDLE
|
||||
source code.)
|
||||
|
||||
The list of extensions loaded at startup time is configured by editing
|
||||
the file config-extensions.def. See below for details.
|
||||
|
||||
An IDLE extension is defined by a class. Methods of the class define
|
||||
actions that are invoked by event bindings or menu entries. Class (or
|
||||
instance) variables define the bindings and menu additions; these are
|
||||
automatically applied by IDLE when the extension is linked to an edit
|
||||
window.
|
||||
|
||||
An IDLE extension class is instantiated with a single argument,
|
||||
`editwin', an EditorWindow instance. The extension cannot assume much
|
||||
about this argument, but it is guaranteed to have the following instance
|
||||
variables:
|
||||
|
||||
text a Text instance (a widget)
|
||||
io an IOBinding instance (more about this later)
|
||||
flist the FileList instance (shared by all edit windows)
|
||||
|
||||
(There are a few more, but they are rarely useful.)
|
||||
|
||||
The extension class must not directly bind Window Manager (e.g. X) events.
|
||||
Rather, it must define one or more virtual events, e.g. <<zoom-height>>, and
|
||||
corresponding methods, e.g. zoom_height_event(). The virtual events will be
|
||||
bound to the corresponding methods, and Window Manager events can then be bound
|
||||
to the virtual events. (This indirection is done so that the key bindings can
|
||||
easily be changed, and so that other sources of virtual events can exist, such
|
||||
as menu entries.)
|
||||
|
||||
An extension can define menu entries. This is done with a class or instance
|
||||
variable named menudefs; it should be a list of pairs, where each pair is a
|
||||
menu name (lowercase) and a list of menu entries. Each menu entry is either
|
||||
None (to insert a separator entry) or a pair of strings (menu_label,
|
||||
virtual_event). Here, menu_label is the label of the menu entry, and
|
||||
virtual_event is the virtual event to be generated when the entry is selected.
|
||||
An underscore in the menu label is removed; the character following the
|
||||
underscore is displayed underlined, to indicate the shortcut character (for
|
||||
Windows).
|
||||
|
||||
At the moment, extensions cannot define whole new menus; they must define
|
||||
entries in existing menus. Some menus are not present on some windows; such
|
||||
entry definitions are then ignored, but key bindings are still applied. (This
|
||||
should probably be refined in the future.)
|
||||
|
||||
Extensions are not required to define menu entries for all the events they
|
||||
implement. (They are also not required to create keybindings, but in that
|
||||
case there must be empty bindings in cofig-extensions.def)
|
||||
|
||||
Here is a complete example:
|
||||
|
||||
class ZoomHeight:
|
||||
|
||||
menudefs = [
|
||||
('edit', [
|
||||
None, # Separator
|
||||
('_Zoom Height', '<<zoom-height>>'),
|
||||
])
|
||||
]
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
|
||||
def zoom_height_event(self, event):
|
||||
"...Do what you want here..."
|
||||
|
||||
The final piece of the puzzle is the file "config-extensions.def", which is
|
||||
used to configure the loading of extensions and to establish key (or, more
|
||||
generally, event) bindings to the virtual events defined in the extensions.
|
||||
|
||||
See the comments at the top of config-extensions.def for information. It's
|
||||
currently necessary to manually modify that file to change IDLE's extension
|
||||
loading or extension key bindings.
|
||||
|
||||
For further information on binding refer to the Tkinter Resources web page at
|
||||
python.org and to the Tk Command "bind" man page.
|
||||
302
Darwin/lib/python2.7/idlelib/help.txt
Normal file
302
Darwin/lib/python2.7/idlelib/help.txt
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
[See the end of this file for ** TIPS ** on using IDLE !!]
|
||||
|
||||
Click on the dotted line at the top of a menu to "tear it off": a
|
||||
separate window containing the menu is created.
|
||||
|
||||
File Menu:
|
||||
|
||||
New File -- Create a new editing window
|
||||
Open... -- Open an existing file
|
||||
Recent Files... -- Open a list of recent files
|
||||
Open Module... -- Open an existing module (searches sys.path)
|
||||
Class Browser -- Show classes and methods in current file
|
||||
Path Browser -- Show sys.path directories, modules, classes
|
||||
and methods
|
||||
---
|
||||
Save -- Save current window to the associated file (unsaved
|
||||
windows have a * before and after the window title)
|
||||
|
||||
Save As... -- Save current window to new file, which becomes
|
||||
the associated file
|
||||
Save Copy As... -- Save current window to different file
|
||||
without changing the associated file
|
||||
---
|
||||
Print Window -- Print the current window
|
||||
---
|
||||
Close -- Close current window (asks to save if unsaved)
|
||||
Exit -- Close all windows, quit (asks to save if unsaved)
|
||||
|
||||
Edit Menu:
|
||||
|
||||
Undo -- Undo last change to current window
|
||||
(A maximum of 1000 changes may be undone)
|
||||
Redo -- Redo last undone change to current window
|
||||
---
|
||||
Cut -- Copy a selection into system-wide clipboard,
|
||||
then delete the selection
|
||||
Copy -- Copy selection into system-wide clipboard
|
||||
Paste -- Insert system-wide clipboard into window
|
||||
Select All -- Select the entire contents of the edit buffer
|
||||
---
|
||||
Find... -- Open a search dialog box with many options
|
||||
Find Again -- Repeat last search
|
||||
Find Selection -- Search for the string in the selection
|
||||
Find in Files... -- Open a search dialog box for searching files
|
||||
Replace... -- Open a search-and-replace dialog box
|
||||
Go to Line -- Ask for a line number and show that line
|
||||
Show Calltip -- Open a small window with function param hints
|
||||
Show Completions -- Open a scroll window allowing selection keywords
|
||||
and attributes. (see '*TIPS*', below)
|
||||
Show Parens -- Highlight the surrounding parenthesis
|
||||
Expand Word -- Expand the word you have typed to match another
|
||||
word in the same buffer; repeat to get a
|
||||
different expansion
|
||||
|
||||
Format Menu (only in Edit window):
|
||||
|
||||
Indent Region -- Shift selected lines right 4 spaces
|
||||
Dedent Region -- Shift selected lines left 4 spaces
|
||||
Comment Out Region -- Insert ## in front of selected lines
|
||||
Uncomment Region -- Remove leading # or ## from selected lines
|
||||
Tabify Region -- Turns *leading* stretches of spaces into tabs
|
||||
(Note: We recommend using 4 space blocks to indent Python code.)
|
||||
Untabify Region -- Turn *all* tabs into the right number of spaces
|
||||
New Indent Width... -- Open dialog to change indent width
|
||||
Format Paragraph -- Reformat the current blank-line-separated
|
||||
paragraph
|
||||
|
||||
Run Menu (only in Edit window):
|
||||
|
||||
Python Shell -- Open or wake up the Python shell window
|
||||
---
|
||||
Check Module -- Run a syntax check on the module
|
||||
Run Module -- Execute the current file in the __main__ namespace
|
||||
|
||||
Shell Menu (only in Shell window):
|
||||
|
||||
View Last Restart -- Scroll the shell window to the last restart
|
||||
Restart Shell -- Restart the interpreter with a fresh environment
|
||||
|
||||
Debug Menu (only in Shell window):
|
||||
|
||||
Go to File/Line -- look around the insert point for a filename
|
||||
and line number, open the file, and show the line
|
||||
Debugger (toggle) -- Run commands in the shell under the debugger
|
||||
Stack Viewer -- Show the stack traceback of the last exception
|
||||
Auto-open Stack Viewer (toggle) -- Open stack viewer on traceback
|
||||
|
||||
Options Menu:
|
||||
|
||||
Configure IDLE -- Open a configuration dialog. Fonts, indentation,
|
||||
keybindings, and color themes may be altered.
|
||||
Startup Preferences may be set, and Additional Help
|
||||
Sources can be specified.
|
||||
|
||||
On OS X this menu is not present, use
|
||||
menu 'IDLE -> Preferences...' instead.
|
||||
---
|
||||
Code Context -- Open a pane at the top of the edit window which
|
||||
shows the block context of the section of code
|
||||
which is scrolling off the top or the window.
|
||||
(Not present in Shell window.)
|
||||
|
||||
Windows Menu:
|
||||
|
||||
Zoom Height -- toggles the window between configured size
|
||||
and maximum height.
|
||||
---
|
||||
The rest of this menu lists the names of all open windows;
|
||||
select one to bring it to the foreground (deiconifying it if
|
||||
necessary).
|
||||
|
||||
Help Menu:
|
||||
|
||||
About IDLE -- Version, copyright, license, credits
|
||||
IDLE Readme -- Background discussion and change details
|
||||
---
|
||||
IDLE Help -- Display this file
|
||||
Python Docs -- Access local Python documentation, if
|
||||
installed. Otherwise, access www.python.org.
|
||||
---
|
||||
(Additional Help Sources may be added here)
|
||||
|
||||
Edit context menu (Right-click / Control-click on OS X in Edit window):
|
||||
|
||||
Cut -- Copy a selection into system-wide clipboard,
|
||||
then delete the selection
|
||||
Copy -- Copy selection into system-wide clipboard
|
||||
Paste -- Insert system-wide clipboard into window
|
||||
Set Breakpoint -- Sets a breakpoint (when debugger open)
|
||||
Clear Breakpoint -- Clears the breakpoint on that line
|
||||
|
||||
Shell context menu (Right-click / Control-click on OS X in Shell window):
|
||||
|
||||
Cut -- Copy a selection into system-wide clipboard,
|
||||
then delete the selection
|
||||
Copy -- Copy selection into system-wide clipboard
|
||||
Paste -- Insert system-wide clipboard into window
|
||||
---
|
||||
Go to file/line -- Same as in Debug menu
|
||||
|
||||
|
||||
** TIPS **
|
||||
==========
|
||||
|
||||
Additional Help Sources:
|
||||
|
||||
Windows users can Google on zopeshelf.chm to access Zope help files in
|
||||
the Windows help format. The Additional Help Sources feature of the
|
||||
configuration GUI supports .chm, along with any other filetypes
|
||||
supported by your browser. Supply a Menu Item title, and enter the
|
||||
location in the Help File Path slot of the New Help Source dialog. Use
|
||||
http:// and/or www. to identify external URLs, or download the file and
|
||||
browse for its path on your machine using the Browse button.
|
||||
|
||||
All users can access the extensive sources of help, including
|
||||
tutorials, available at www.python.org/doc. Selected URLs can be added
|
||||
or removed from the Help menu at any time using Configure IDLE.
|
||||
|
||||
Basic editing and navigation:
|
||||
|
||||
Backspace deletes char to the left; DEL deletes char to the right.
|
||||
Control-backspace deletes word left, Control-DEL deletes word right.
|
||||
Arrow keys and Page Up/Down move around.
|
||||
Control-left/right Arrow moves by words in a strange but useful way.
|
||||
Home/End go to begin/end of line.
|
||||
Control-Home/End go to begin/end of file.
|
||||
Some useful Emacs bindings are inherited from Tcl/Tk:
|
||||
Control-a beginning of line
|
||||
Control-e end of line
|
||||
Control-k kill line (but doesn't put it in clipboard)
|
||||
Control-l center window around the insertion point
|
||||
Standard Windows bindings may work on that platform.
|
||||
Keybindings are selected in the Settings Dialog, look there.
|
||||
|
||||
Automatic indentation:
|
||||
|
||||
After a block-opening statement, the next line is indented by 4 spaces
|
||||
(in the Python Shell window by one tab). After certain keywords
|
||||
(break, return etc.) the next line is dedented. In leading
|
||||
indentation, Backspace deletes up to 4 spaces if they are there. Tab
|
||||
inserts spaces (in the Python Shell window one tab), number depends on
|
||||
Indent Width. (N.B. Currently tabs are restricted to four spaces due
|
||||
to Tcl/Tk issues.)
|
||||
|
||||
See also the indent/dedent region commands in the edit menu.
|
||||
|
||||
Completions:
|
||||
|
||||
Completions are supplied for functions, classes, and attributes of
|
||||
classes, both built-in and user-defined. Completions are also provided
|
||||
for filenames.
|
||||
|
||||
The AutoCompleteWindow (ACW) will open after a predefined delay
|
||||
(default is two seconds) after a '.' or (in a string) an os.sep is
|
||||
typed. If after one of those characters (plus zero or more other
|
||||
characters) you type a Tab the ACW will open immediately if a possible
|
||||
continuation is found.
|
||||
|
||||
If there is only one possible completion for the characters entered, a
|
||||
Tab will supply that completion without opening the ACW.
|
||||
|
||||
'Show Completions' will force open a completions window. In an empty
|
||||
string, this will contain the files in the current directory. On a
|
||||
blank line, it will contain the built-in and user-defined functions and
|
||||
classes in the current name spaces, plus any modules imported. If some
|
||||
characters have been entered, the ACW will attempt to be more specific.
|
||||
|
||||
If string of characters is typed, the ACW selection will jump to the
|
||||
entry most closely matching those characters. Entering a Tab will cause
|
||||
the longest non-ambiguous match to be entered in the Edit window or
|
||||
Shell. Two Tabs in a row will supply the current ACW selection, as
|
||||
will Return or a double click. Cursor keys, Page Up/Down, mouse
|
||||
selection, and the scrollwheel all operate on the ACW.
|
||||
|
||||
'Hidden' attributes can be accessed by typing the beginning of hidden
|
||||
name after a '.'. e.g. '_'. This allows access to modules with
|
||||
'__all__' set, or to class-private attributes.
|
||||
|
||||
Completions and the 'Expand Word' facility can save a lot of typing!
|
||||
|
||||
Completions are currently limited to those in the namespaces. Names in
|
||||
an Edit window which are not via __main__ or sys.modules will not be
|
||||
found. Run the module once with your imports to correct this
|
||||
situation. Note that IDLE itself places quite a few modules in
|
||||
sys.modules, so much can be found by default, e.g. the re module.
|
||||
|
||||
If you don't like the ACW popping up unbidden, simply make the delay
|
||||
longer or disable the extension. OTOH, you could make the delay zero.
|
||||
|
||||
You could also switch off the CallTips extension. (We will be adding
|
||||
a delay to the call tip window.)
|
||||
|
||||
Python Shell window:
|
||||
|
||||
Control-c interrupts executing command.
|
||||
Control-d sends end-of-file; closes window if typed at >>> prompt.
|
||||
|
||||
Command history:
|
||||
|
||||
Alt-p retrieves previous command matching what you have typed.
|
||||
Alt-n retrieves next.
|
||||
(These are Control-p, Control-n on OS X)
|
||||
Return while cursor is on a previous command retrieves that command.
|
||||
Expand word is also useful to reduce typing.
|
||||
|
||||
Syntax colors:
|
||||
|
||||
The coloring is applied in a background "thread", so you may
|
||||
occasionally see uncolorized text. To change the color
|
||||
scheme, use the Configure IDLE / Highlighting dialog.
|
||||
|
||||
Python default syntax colors:
|
||||
|
||||
Keywords orange
|
||||
Builtins royal purple
|
||||
Strings green
|
||||
Comments red
|
||||
Definitions blue
|
||||
|
||||
Shell default colors:
|
||||
|
||||
Console output brown
|
||||
stdout blue
|
||||
stderr red
|
||||
stdin black
|
||||
|
||||
Other preferences:
|
||||
|
||||
The font preferences, keybinding, and startup preferences can
|
||||
be changed using the Settings dialog.
|
||||
|
||||
Command line usage:
|
||||
|
||||
Enter idle -h at the command prompt to get a usage message.
|
||||
|
||||
Running without a subprocess:
|
||||
|
||||
If IDLE is started with the -n command line switch it will run in a
|
||||
single process and will not create the subprocess which runs the RPC
|
||||
Python execution server. This can be useful if Python cannot create
|
||||
the subprocess or the RPC socket interface on your platform. However,
|
||||
in this mode user code is not isolated from IDLE itself. Also, the
|
||||
environment is not restarted when Run/Run Module (F5) is selected. If
|
||||
your code has been modified, you must reload() the affected modules and
|
||||
re-import any specific items (e.g. from foo import baz) if the changes
|
||||
are to take effect. For these reasons, it is preferable to run IDLE
|
||||
with the default subprocess if at all possible.
|
||||
|
||||
Extensions:
|
||||
|
||||
IDLE contains an extension facility. See the beginning of
|
||||
config-extensions.def in the idlelib directory for further information.
|
||||
The default extensions are currently:
|
||||
|
||||
FormatParagraph
|
||||
AutoExpand
|
||||
ZoomHeight
|
||||
ScriptBinding
|
||||
CallTips
|
||||
ParenMatch
|
||||
AutoComplete
|
||||
CodeContext
|
||||
4
Darwin/lib/python2.7/idlelib/idle.bat
Executable file
4
Darwin/lib/python2.7/idlelib/idle.bat
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
@echo off
|
||||
rem Start IDLE using the appropriate Python interpreter
|
||||
set CURRDIR=%~dp0
|
||||
start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
11
Darwin/lib/python2.7/idlelib/idle.py
Normal file
11
Darwin/lib/python2.7/idlelib/idle.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import os.path
|
||||
import sys
|
||||
|
||||
# If we are working on a development version of IDLE, we need to prepend the
|
||||
# parent of this idlelib dir to sys.path. Otherwise, importing idlelib gets
|
||||
# the version installed with the Python used to call this module:
|
||||
idlelib_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, idlelib_dir)
|
||||
|
||||
import idlelib.PyShell
|
||||
idlelib.PyShell.main()
|
||||
21
Darwin/lib/python2.7/idlelib/idle.pyw
Normal file
21
Darwin/lib/python2.7/idlelib/idle.pyw
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
try:
|
||||
import idlelib.PyShell
|
||||
except ImportError:
|
||||
# IDLE is not installed, but maybe PyShell is on sys.path:
|
||||
try:
|
||||
import PyShell
|
||||
except ImportError:
|
||||
raise
|
||||
else:
|
||||
import os
|
||||
idledir = os.path.dirname(os.path.abspath(PyShell.__file__))
|
||||
if idledir != os.getcwd():
|
||||
# We're not in the IDLE directory, help the subprocess find run.py
|
||||
pypath = os.environ.get('PYTHONPATH', '')
|
||||
if pypath:
|
||||
os.environ['PYTHONPATH'] = pypath + ':' + idledir
|
||||
else:
|
||||
os.environ['PYTHONPATH'] = idledir
|
||||
PyShell.main()
|
||||
else:
|
||||
idlelib.PyShell.main()
|
||||
1
Darwin/lib/python2.7/idlelib/idlever.py
Normal file
1
Darwin/lib/python2.7/idlelib/idlever.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
IDLE_VERSION = "2.7.6"
|
||||
268
Darwin/lib/python2.7/idlelib/keybindingDialog.py
Normal file
268
Darwin/lib/python2.7/idlelib/keybindingDialog.py
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
"""
|
||||
Dialog for building Tkinter accelerator key bindings
|
||||
"""
|
||||
from Tkinter import *
|
||||
import tkMessageBox
|
||||
import string
|
||||
|
||||
class GetKeysDialog(Toplevel):
|
||||
def __init__(self,parent,title,action,currentKeySequences):
|
||||
"""
|
||||
action - string, the name of the virtual event these keys will be
|
||||
mapped to
|
||||
currentKeys - list, a list of all key sequence lists currently mapped
|
||||
to virtual events, for overlap checking
|
||||
"""
|
||||
Toplevel.__init__(self, parent)
|
||||
self.configure(borderwidth=5)
|
||||
self.resizable(height=FALSE,width=FALSE)
|
||||
self.title(title)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.protocol("WM_DELETE_WINDOW", self.Cancel)
|
||||
self.parent = parent
|
||||
self.action=action
|
||||
self.currentKeySequences=currentKeySequences
|
||||
self.result=''
|
||||
self.keyString=StringVar(self)
|
||||
self.keyString.set('')
|
||||
self.SetModifiersForPlatform() # set self.modifiers, self.modifier_label
|
||||
self.modifier_vars = []
|
||||
for modifier in self.modifiers:
|
||||
variable = StringVar(self)
|
||||
variable.set('')
|
||||
self.modifier_vars.append(variable)
|
||||
self.advanced = False
|
||||
self.CreateWidgets()
|
||||
self.LoadFinalKeyList()
|
||||
self.withdraw() #hide while setting geometry
|
||||
self.update_idletasks()
|
||||
self.geometry("+%d+%d" %
|
||||
((parent.winfo_rootx()+((parent.winfo_width()/2)
|
||||
-(self.winfo_reqwidth()/2)),
|
||||
parent.winfo_rooty()+((parent.winfo_height()/2)
|
||||
-(self.winfo_reqheight()/2)) )) ) #centre dialog over parent
|
||||
self.deiconify() #geometry set, unhide
|
||||
self.wait_window()
|
||||
|
||||
def CreateWidgets(self):
|
||||
frameMain = Frame(self,borderwidth=2,relief=SUNKEN)
|
||||
frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
|
||||
frameButtons=Frame(self)
|
||||
frameButtons.pack(side=BOTTOM,fill=X)
|
||||
self.buttonOK = Button(frameButtons,text='OK',
|
||||
width=8,command=self.OK)
|
||||
self.buttonOK.grid(row=0,column=0,padx=5,pady=5)
|
||||
self.buttonCancel = Button(frameButtons,text='Cancel',
|
||||
width=8,command=self.Cancel)
|
||||
self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
|
||||
self.frameKeySeqBasic = Frame(frameMain)
|
||||
self.frameKeySeqAdvanced = Frame(frameMain)
|
||||
self.frameControlsBasic = Frame(frameMain)
|
||||
self.frameHelpAdvanced = Frame(frameMain)
|
||||
self.frameKeySeqAdvanced.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
|
||||
self.frameKeySeqBasic.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
|
||||
self.frameKeySeqBasic.lift()
|
||||
self.frameHelpAdvanced.grid(row=1,column=0,sticky=NSEW,padx=5)
|
||||
self.frameControlsBasic.grid(row=1,column=0,sticky=NSEW,padx=5)
|
||||
self.frameControlsBasic.lift()
|
||||
self.buttonLevel = Button(frameMain,command=self.ToggleLevel,
|
||||
text='Advanced Key Binding Entry >>')
|
||||
self.buttonLevel.grid(row=2,column=0,stick=EW,padx=5,pady=5)
|
||||
labelTitleBasic = Label(self.frameKeySeqBasic,
|
||||
text="New keys for '"+self.action+"' :")
|
||||
labelTitleBasic.pack(anchor=W)
|
||||
labelKeysBasic = Label(self.frameKeySeqBasic,justify=LEFT,
|
||||
textvariable=self.keyString,relief=GROOVE,borderwidth=2)
|
||||
labelKeysBasic.pack(ipadx=5,ipady=5,fill=X)
|
||||
self.modifier_checkbuttons = {}
|
||||
column = 0
|
||||
for modifier, variable in zip(self.modifiers, self.modifier_vars):
|
||||
label = self.modifier_label.get(modifier, modifier)
|
||||
check=Checkbutton(self.frameControlsBasic,
|
||||
command=self.BuildKeyString,
|
||||
text=label,variable=variable,onvalue=modifier,offvalue='')
|
||||
check.grid(row=0,column=column,padx=2,sticky=W)
|
||||
self.modifier_checkbuttons[modifier] = check
|
||||
column += 1
|
||||
labelFnAdvice=Label(self.frameControlsBasic,justify=LEFT,
|
||||
text=\
|
||||
"Select the desired modifier keys\n"+
|
||||
"above, and the final key from the\n"+
|
||||
"list on the right.\n\n" +
|
||||
"Use upper case Symbols when using\n" +
|
||||
"the Shift modifier. (Letters will be\n" +
|
||||
"converted automatically.)")
|
||||
labelFnAdvice.grid(row=1,column=0,columnspan=4,padx=2,sticky=W)
|
||||
self.listKeysFinal=Listbox(self.frameControlsBasic,width=15,height=10,
|
||||
selectmode=SINGLE)
|
||||
self.listKeysFinal.bind('<ButtonRelease-1>',self.FinalKeySelected)
|
||||
self.listKeysFinal.grid(row=0,column=4,rowspan=4,sticky=NS)
|
||||
scrollKeysFinal=Scrollbar(self.frameControlsBasic,orient=VERTICAL,
|
||||
command=self.listKeysFinal.yview)
|
||||
self.listKeysFinal.config(yscrollcommand=scrollKeysFinal.set)
|
||||
scrollKeysFinal.grid(row=0,column=5,rowspan=4,sticky=NS)
|
||||
self.buttonClear=Button(self.frameControlsBasic,
|
||||
text='Clear Keys',command=self.ClearKeySeq)
|
||||
self.buttonClear.grid(row=2,column=0,columnspan=4)
|
||||
labelTitleAdvanced = Label(self.frameKeySeqAdvanced,justify=LEFT,
|
||||
text="Enter new binding(s) for '"+self.action+"' :\n"+
|
||||
"(These bindings will not be checked for validity!)")
|
||||
labelTitleAdvanced.pack(anchor=W)
|
||||
self.entryKeysAdvanced=Entry(self.frameKeySeqAdvanced,
|
||||
textvariable=self.keyString)
|
||||
self.entryKeysAdvanced.pack(fill=X)
|
||||
labelHelpAdvanced=Label(self.frameHelpAdvanced,justify=LEFT,
|
||||
text="Key bindings are specified using Tkinter keysyms as\n"+
|
||||
"in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
|
||||
"<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
|
||||
"Upper case is used when the Shift modifier is present!\n\n" +
|
||||
"'Emacs style' multi-keystroke bindings are specified as\n" +
|
||||
"follows: <Control-x><Control-y>, where the first key\n" +
|
||||
"is the 'do-nothing' keybinding.\n\n" +
|
||||
"Multiple separate bindings for one action should be\n"+
|
||||
"separated by a space, eg., <Alt-v> <Meta-v>." )
|
||||
labelHelpAdvanced.grid(row=0,column=0,sticky=NSEW)
|
||||
|
||||
def SetModifiersForPlatform(self):
|
||||
"""Determine list of names of key modifiers for this platform.
|
||||
|
||||
The names are used to build Tk bindings -- it doesn't matter if the
|
||||
keyboard has these keys, it matters if Tk understands them. The
|
||||
order is also important: key binding equality depends on it, so
|
||||
config-keys.def must use the same ordering.
|
||||
"""
|
||||
from idlelib import macosxSupport
|
||||
if macosxSupport.runningAsOSXApp():
|
||||
self.modifiers = ['Shift', 'Control', 'Option', 'Command']
|
||||
else:
|
||||
self.modifiers = ['Control', 'Alt', 'Shift']
|
||||
self.modifier_label = {'Control': 'Ctrl'} # short name
|
||||
|
||||
def ToggleLevel(self):
|
||||
if self.buttonLevel.cget('text')[:8]=='Advanced':
|
||||
self.ClearKeySeq()
|
||||
self.buttonLevel.config(text='<< Basic Key Binding Entry')
|
||||
self.frameKeySeqAdvanced.lift()
|
||||
self.frameHelpAdvanced.lift()
|
||||
self.entryKeysAdvanced.focus_set()
|
||||
self.advanced = True
|
||||
else:
|
||||
self.ClearKeySeq()
|
||||
self.buttonLevel.config(text='Advanced Key Binding Entry >>')
|
||||
self.frameKeySeqBasic.lift()
|
||||
self.frameControlsBasic.lift()
|
||||
self.advanced = False
|
||||
|
||||
def FinalKeySelected(self,event):
|
||||
self.BuildKeyString()
|
||||
|
||||
def BuildKeyString(self):
|
||||
keyList = modifiers = self.GetModifiers()
|
||||
finalKey = self.listKeysFinal.get(ANCHOR)
|
||||
if finalKey:
|
||||
finalKey = self.TranslateKey(finalKey, modifiers)
|
||||
keyList.append(finalKey)
|
||||
self.keyString.set('<' + string.join(keyList,'-') + '>')
|
||||
|
||||
def GetModifiers(self):
|
||||
modList = [variable.get() for variable in self.modifier_vars]
|
||||
return [mod for mod in modList if mod]
|
||||
|
||||
def ClearKeySeq(self):
|
||||
self.listKeysFinal.select_clear(0,END)
|
||||
self.listKeysFinal.yview(MOVETO, '0.0')
|
||||
for variable in self.modifier_vars:
|
||||
variable.set('')
|
||||
self.keyString.set('')
|
||||
|
||||
def LoadFinalKeyList(self):
|
||||
#these tuples are also available for use in validity checks
|
||||
self.functionKeys=('F1','F2','F2','F4','F5','F6','F7','F8','F9',
|
||||
'F10','F11','F12')
|
||||
self.alphanumKeys=tuple(string.ascii_lowercase+string.digits)
|
||||
self.punctuationKeys=tuple('~!@#%^&*()_-+={}[]|;:,.<>/?')
|
||||
self.whitespaceKeys=('Tab','Space','Return')
|
||||
self.editKeys=('BackSpace','Delete','Insert')
|
||||
self.moveKeys=('Home','End','Page Up','Page Down','Left Arrow',
|
||||
'Right Arrow','Up Arrow','Down Arrow')
|
||||
#make a tuple of most of the useful common 'final' keys
|
||||
keys=(self.alphanumKeys+self.punctuationKeys+self.functionKeys+
|
||||
self.whitespaceKeys+self.editKeys+self.moveKeys)
|
||||
self.listKeysFinal.insert(END, *keys)
|
||||
|
||||
def TranslateKey(self, key, modifiers):
|
||||
"Translate from keycap symbol to the Tkinter keysym"
|
||||
translateDict = {'Space':'space',
|
||||
'~':'asciitilde','!':'exclam','@':'at','#':'numbersign',
|
||||
'%':'percent','^':'asciicircum','&':'ampersand','*':'asterisk',
|
||||
'(':'parenleft',')':'parenright','_':'underscore','-':'minus',
|
||||
'+':'plus','=':'equal','{':'braceleft','}':'braceright',
|
||||
'[':'bracketleft',']':'bracketright','|':'bar',';':'semicolon',
|
||||
':':'colon',',':'comma','.':'period','<':'less','>':'greater',
|
||||
'/':'slash','?':'question','Page Up':'Prior','Page Down':'Next',
|
||||
'Left Arrow':'Left','Right Arrow':'Right','Up Arrow':'Up',
|
||||
'Down Arrow': 'Down', 'Tab':'Tab'}
|
||||
if key in translateDict.keys():
|
||||
key = translateDict[key]
|
||||
if 'Shift' in modifiers and key in string.ascii_lowercase:
|
||||
key = key.upper()
|
||||
key = 'Key-' + key
|
||||
return key
|
||||
|
||||
def OK(self, event=None):
|
||||
if self.advanced or self.KeysOK(): # doesn't check advanced string yet
|
||||
self.result=self.keyString.get()
|
||||
self.destroy()
|
||||
|
||||
def Cancel(self, event=None):
|
||||
self.result=''
|
||||
self.destroy()
|
||||
|
||||
def KeysOK(self):
|
||||
'''Validity check on user's 'basic' keybinding selection.
|
||||
|
||||
Doesn't check the string produced by the advanced dialog because
|
||||
'modifiers' isn't set.
|
||||
|
||||
'''
|
||||
keys = self.keyString.get()
|
||||
keys.strip()
|
||||
finalKey = self.listKeysFinal.get(ANCHOR)
|
||||
modifiers = self.GetModifiers()
|
||||
# create a key sequence list for overlap check:
|
||||
keySequence = keys.split()
|
||||
keysOK = False
|
||||
title = 'Key Sequence Error'
|
||||
if not keys:
|
||||
tkMessageBox.showerror(title=title, parent=self,
|
||||
message='No keys specified.')
|
||||
elif not keys.endswith('>'):
|
||||
tkMessageBox.showerror(title=title, parent=self,
|
||||
message='Missing the final Key')
|
||||
elif (not modifiers
|
||||
and finalKey not in self.functionKeys + self.moveKeys):
|
||||
tkMessageBox.showerror(title=title, parent=self,
|
||||
message='No modifier key(s) specified.')
|
||||
elif (modifiers == ['Shift']) \
|
||||
and (finalKey not in
|
||||
self.functionKeys + self.moveKeys + ('Tab', 'Space')):
|
||||
msg = 'The shift modifier by itself may not be used with'\
|
||||
' this key symbol.'
|
||||
tkMessageBox.showerror(title=title, parent=self, message=msg)
|
||||
elif keySequence in self.currentKeySequences:
|
||||
msg = 'This key combination is already in use.'
|
||||
tkMessageBox.showerror(title=title, parent=self, message=msg)
|
||||
else:
|
||||
keysOK = True
|
||||
return keysOK
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test the dialog
|
||||
root=Tk()
|
||||
def run():
|
||||
keySeq=''
|
||||
dlg=GetKeysDialog(root,'Get Keys','find-again',[])
|
||||
print dlg.result
|
||||
Button(root,text='Dialog',command=run).pack()
|
||||
root.mainloop()
|
||||
175
Darwin/lib/python2.7/idlelib/macosxSupport.py
Normal file
175
Darwin/lib/python2.7/idlelib/macosxSupport.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
"""
|
||||
A number of function that enhance IDLE on MacOSX when it used as a normal
|
||||
GUI application (as opposed to an X11 application).
|
||||
"""
|
||||
import sys
|
||||
import Tkinter
|
||||
from os import path
|
||||
|
||||
|
||||
_appbundle = None
|
||||
|
||||
def runningAsOSXApp():
|
||||
"""
|
||||
Returns True if Python is running from within an app on OSX.
|
||||
If so, assume that Python was built with Aqua Tcl/Tk rather than
|
||||
X11 Tcl/Tk.
|
||||
"""
|
||||
global _appbundle
|
||||
if _appbundle is None:
|
||||
_appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
|
||||
return _appbundle
|
||||
|
||||
_carbonaquatk = None
|
||||
|
||||
def isCarbonAquaTk(root):
|
||||
"""
|
||||
Returns True if IDLE is using a Carbon Aqua Tk (instead of the
|
||||
newer Cocoa Aqua Tk).
|
||||
"""
|
||||
global _carbonaquatk
|
||||
if _carbonaquatk is None:
|
||||
_carbonaquatk = (runningAsOSXApp() and
|
||||
'aqua' in root.tk.call('tk', 'windowingsystem') and
|
||||
'AppKit' not in root.tk.call('winfo', 'server', '.'))
|
||||
return _carbonaquatk
|
||||
|
||||
def tkVersionWarning(root):
|
||||
"""
|
||||
Returns a string warning message if the Tk version in use appears to
|
||||
be one known to cause problems with IDLE.
|
||||
1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable.
|
||||
2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but
|
||||
can still crash unexpectedly.
|
||||
"""
|
||||
|
||||
if (runningAsOSXApp() and
|
||||
('AppKit' in root.tk.call('winfo', 'server', '.')) ):
|
||||
patchlevel = root.tk.call('info', 'patchlevel')
|
||||
if patchlevel not in ('8.5.7', '8.5.9'):
|
||||
return False
|
||||
return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
|
||||
r" be unstable.\n"
|
||||
r"Visit http://www.python.org/download/mac/tcltk/"
|
||||
r" for current information.".format(patchlevel))
|
||||
else:
|
||||
return False
|
||||
|
||||
def addOpenEventSupport(root, flist):
|
||||
"""
|
||||
This ensures that the application will respond to open AppleEvents, which
|
||||
makes is feasible to use IDLE as the default application for python files.
|
||||
"""
|
||||
def doOpenFile(*args):
|
||||
for fn in args:
|
||||
flist.open(fn)
|
||||
|
||||
# The command below is a hook in aquatk that is called whenever the app
|
||||
# receives a file open event. The callback can have multiple arguments,
|
||||
# one for every file that should be opened.
|
||||
root.createcommand("::tk::mac::OpenDocument", doOpenFile)
|
||||
|
||||
def hideTkConsole(root):
|
||||
try:
|
||||
root.tk.call('console', 'hide')
|
||||
except Tkinter.TclError:
|
||||
# Some versions of the Tk framework don't have a console object
|
||||
pass
|
||||
|
||||
def overrideRootMenu(root, flist):
|
||||
"""
|
||||
Replace the Tk root menu by something that's more appropriate for
|
||||
IDLE.
|
||||
"""
|
||||
# The menu that is attached to the Tk root (".") is also used by AquaTk for
|
||||
# all windows that don't specify a menu of their own. The default menubar
|
||||
# contains a number of menus, none of which are appropriate for IDLE. The
|
||||
# Most annoying of those is an 'About Tck/Tk...' menu in the application
|
||||
# menu.
|
||||
#
|
||||
# This function replaces the default menubar by a mostly empty one, it
|
||||
# should only contain the correct application menu and the window menu.
|
||||
#
|
||||
# Due to a (mis-)feature of TkAqua the user will also see an empty Help
|
||||
# menu.
|
||||
from Tkinter import Menu, Text, Text
|
||||
from idlelib.EditorWindow import prepstr, get_accelerator
|
||||
from idlelib import Bindings
|
||||
from idlelib import WindowList
|
||||
from idlelib.MultiCall import MultiCallCreator
|
||||
|
||||
menubar = Menu(root)
|
||||
root.configure(menu=menubar)
|
||||
menudict = {}
|
||||
|
||||
menudict['windows'] = menu = Menu(menubar, name='windows')
|
||||
menubar.add_cascade(label='Window', menu=menu, underline=0)
|
||||
|
||||
def postwindowsmenu(menu=menu):
|
||||
end = menu.index('end')
|
||||
if end is None:
|
||||
end = -1
|
||||
|
||||
if end > 0:
|
||||
menu.delete(0, end)
|
||||
WindowList.add_windows_to_menu(menu)
|
||||
WindowList.register_callback(postwindowsmenu)
|
||||
|
||||
def about_dialog(event=None):
|
||||
from idlelib import aboutDialog
|
||||
aboutDialog.AboutDialog(root, 'About IDLE')
|
||||
|
||||
def config_dialog(event=None):
|
||||
from idlelib import configDialog
|
||||
root.instance_dict = flist.inversedict
|
||||
configDialog.ConfigDialog(root, 'Settings')
|
||||
|
||||
def help_dialog(event=None):
|
||||
from idlelib import textView
|
||||
fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
|
||||
textView.view_file(root, 'Help', fn)
|
||||
|
||||
root.bind('<<about-idle>>', about_dialog)
|
||||
root.bind('<<open-config-dialog>>', config_dialog)
|
||||
root.createcommand('::tk::mac::ShowPreferences', config_dialog)
|
||||
if flist:
|
||||
root.bind('<<close-all-windows>>', flist.close_all_callback)
|
||||
|
||||
# The binding above doesn't reliably work on all versions of Tk
|
||||
# on MacOSX. Adding command definition below does seem to do the
|
||||
# right thing for now.
|
||||
root.createcommand('exit', flist.close_all_callback)
|
||||
|
||||
if isCarbonAquaTk(root):
|
||||
# for Carbon AquaTk, replace the default Tk apple menu
|
||||
menudict['application'] = menu = Menu(menubar, name='apple')
|
||||
menubar.add_cascade(label='IDLE', menu=menu)
|
||||
Bindings.menudefs.insert(0,
|
||||
('application', [
|
||||
('About IDLE', '<<about-idle>>'),
|
||||
None,
|
||||
]))
|
||||
tkversion = root.tk.eval('info patchlevel')
|
||||
if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
|
||||
# for earlier AquaTk versions, supply a Preferences menu item
|
||||
Bindings.menudefs[0][1].append(
|
||||
('_Preferences....', '<<open-config-dialog>>'),
|
||||
)
|
||||
else:
|
||||
# assume Cocoa AquaTk
|
||||
# replace default About dialog with About IDLE one
|
||||
root.createcommand('tkAboutDialog', about_dialog)
|
||||
# replace default "Help" item in Help menu
|
||||
root.createcommand('::tk::mac::ShowHelp', help_dialog)
|
||||
# remove redundant "IDLE Help" from menu
|
||||
del Bindings.menudefs[-1][1][0]
|
||||
|
||||
def setupApp(root, flist):
|
||||
"""
|
||||
Perform setup for the OSX application bundle.
|
||||
"""
|
||||
if not runningAsOSXApp(): return
|
||||
|
||||
hideTkConsole(root)
|
||||
overrideRootMenu(root, flist)
|
||||
addOpenEventSupport(root, flist)
|
||||
600
Darwin/lib/python2.7/idlelib/rpc.py
Normal file
600
Darwin/lib/python2.7/idlelib/rpc.py
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
"""RPC Implemention, originally written for the Python Idle IDE
|
||||
|
||||
For security reasons, GvR requested that Idle's Python execution server process
|
||||
connect to the Idle process, which listens for the connection. Since Idle has
|
||||
only one client per server, this was not a limitation.
|
||||
|
||||
+---------------------------------+ +-------------+
|
||||
| SocketServer.BaseRequestHandler | | SocketIO |
|
||||
+---------------------------------+ +-------------+
|
||||
^ | register() |
|
||||
| | unregister()|
|
||||
| +-------------+
|
||||
| ^ ^
|
||||
| | |
|
||||
| + -------------------+ |
|
||||
| | |
|
||||
+-------------------------+ +-----------------+
|
||||
| RPCHandler | | RPCClient |
|
||||
| [attribute of RPCServer]| | |
|
||||
+-------------------------+ +-----------------+
|
||||
|
||||
The RPCServer handler class is expected to provide register/unregister methods.
|
||||
RPCHandler inherits the mix-in class SocketIO, which provides these methods.
|
||||
|
||||
See the Idle run.main() docstring for further information on how this was
|
||||
accomplished in Idle.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import socket
|
||||
import select
|
||||
import SocketServer
|
||||
import struct
|
||||
import cPickle as pickle
|
||||
import threading
|
||||
import Queue
|
||||
import traceback
|
||||
import copy_reg
|
||||
import types
|
||||
import marshal
|
||||
|
||||
|
||||
def unpickle_code(ms):
|
||||
co = marshal.loads(ms)
|
||||
assert isinstance(co, types.CodeType)
|
||||
return co
|
||||
|
||||
def pickle_code(co):
|
||||
assert isinstance(co, types.CodeType)
|
||||
ms = marshal.dumps(co)
|
||||
return unpickle_code, (ms,)
|
||||
|
||||
# XXX KBK 24Aug02 function pickling capability not used in Idle
|
||||
# def unpickle_function(ms):
|
||||
# return ms
|
||||
|
||||
# def pickle_function(fn):
|
||||
# assert isinstance(fn, type.FunctionType)
|
||||
# return repr(fn)
|
||||
|
||||
copy_reg.pickle(types.CodeType, pickle_code, unpickle_code)
|
||||
# copy_reg.pickle(types.FunctionType, pickle_function, unpickle_function)
|
||||
|
||||
BUFSIZE = 8*1024
|
||||
LOCALHOST = '127.0.0.1'
|
||||
|
||||
class RPCServer(SocketServer.TCPServer):
|
||||
|
||||
def __init__(self, addr, handlerclass=None):
|
||||
if handlerclass is None:
|
||||
handlerclass = RPCHandler
|
||||
SocketServer.TCPServer.__init__(self, addr, handlerclass)
|
||||
|
||||
def server_bind(self):
|
||||
"Override TCPServer method, no bind() phase for connecting entity"
|
||||
pass
|
||||
|
||||
def server_activate(self):
|
||||
"""Override TCPServer method, connect() instead of listen()
|
||||
|
||||
Due to the reversed connection, self.server_address is actually the
|
||||
address of the Idle Client to which we are connecting.
|
||||
|
||||
"""
|
||||
self.socket.connect(self.server_address)
|
||||
|
||||
def get_request(self):
|
||||
"Override TCPServer method, return already connected socket"
|
||||
return self.socket, self.server_address
|
||||
|
||||
def handle_error(self, request, client_address):
|
||||
"""Override TCPServer method
|
||||
|
||||
Error message goes to __stderr__. No error message if exiting
|
||||
normally or socket raised EOF. Other exceptions not handled in
|
||||
server code will cause os._exit.
|
||||
|
||||
"""
|
||||
try:
|
||||
raise
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
erf = sys.__stderr__
|
||||
print>>erf, '\n' + '-'*40
|
||||
print>>erf, 'Unhandled server exception!'
|
||||
print>>erf, 'Thread: %s' % threading.currentThread().getName()
|
||||
print>>erf, 'Client Address: ', client_address
|
||||
print>>erf, 'Request: ', repr(request)
|
||||
traceback.print_exc(file=erf)
|
||||
print>>erf, '\n*** Unrecoverable, server exiting!'
|
||||
print>>erf, '-'*40
|
||||
os._exit(0)
|
||||
|
||||
#----------------- end class RPCServer --------------------
|
||||
|
||||
objecttable = {}
|
||||
request_queue = Queue.Queue(0)
|
||||
response_queue = Queue.Queue(0)
|
||||
|
||||
|
||||
class SocketIO(object):
|
||||
|
||||
nextseq = 0
|
||||
|
||||
def __init__(self, sock, objtable=None, debugging=None):
|
||||
self.sockthread = threading.currentThread()
|
||||
if debugging is not None:
|
||||
self.debugging = debugging
|
||||
self.sock = sock
|
||||
if objtable is None:
|
||||
objtable = objecttable
|
||||
self.objtable = objtable
|
||||
self.responses = {}
|
||||
self.cvars = {}
|
||||
|
||||
def close(self):
|
||||
sock = self.sock
|
||||
self.sock = None
|
||||
if sock is not None:
|
||||
sock.close()
|
||||
|
||||
def exithook(self):
|
||||
"override for specific exit action"
|
||||
os._exit(0)
|
||||
|
||||
def debug(self, *args):
|
||||
if not self.debugging:
|
||||
return
|
||||
s = self.location + " " + str(threading.currentThread().getName())
|
||||
for a in args:
|
||||
s = s + " " + str(a)
|
||||
print>>sys.__stderr__, s
|
||||
|
||||
def register(self, oid, object):
|
||||
self.objtable[oid] = object
|
||||
|
||||
def unregister(self, oid):
|
||||
try:
|
||||
del self.objtable[oid]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def localcall(self, seq, request):
|
||||
self.debug("localcall:", request)
|
||||
try:
|
||||
how, (oid, methodname, args, kwargs) = request
|
||||
except TypeError:
|
||||
return ("ERROR", "Bad request format")
|
||||
if oid not in self.objtable:
|
||||
return ("ERROR", "Unknown object id: %r" % (oid,))
|
||||
obj = self.objtable[oid]
|
||||
if methodname == "__methods__":
|
||||
methods = {}
|
||||
_getmethods(obj, methods)
|
||||
return ("OK", methods)
|
||||
if methodname == "__attributes__":
|
||||
attributes = {}
|
||||
_getattributes(obj, attributes)
|
||||
return ("OK", attributes)
|
||||
if not hasattr(obj, methodname):
|
||||
return ("ERROR", "Unsupported method name: %r" % (methodname,))
|
||||
method = getattr(obj, methodname)
|
||||
try:
|
||||
if how == 'CALL':
|
||||
ret = method(*args, **kwargs)
|
||||
if isinstance(ret, RemoteObject):
|
||||
ret = remoteref(ret)
|
||||
return ("OK", ret)
|
||||
elif how == 'QUEUE':
|
||||
request_queue.put((seq, (method, args, kwargs)))
|
||||
return("QUEUED", None)
|
||||
else:
|
||||
return ("ERROR", "Unsupported message type: %s" % how)
|
||||
except SystemExit:
|
||||
raise
|
||||
except socket.error:
|
||||
raise
|
||||
except:
|
||||
msg = "*** Internal Error: rpc.py:SocketIO.localcall()\n\n"\
|
||||
" Object: %s \n Method: %s \n Args: %s\n"
|
||||
print>>sys.__stderr__, msg % (oid, method, args)
|
||||
traceback.print_exc(file=sys.__stderr__)
|
||||
return ("EXCEPTION", None)
|
||||
|
||||
def remotecall(self, oid, methodname, args, kwargs):
|
||||
self.debug("remotecall:asynccall: ", oid, methodname)
|
||||
seq = self.asynccall(oid, methodname, args, kwargs)
|
||||
return self.asyncreturn(seq)
|
||||
|
||||
def remotequeue(self, oid, methodname, args, kwargs):
|
||||
self.debug("remotequeue:asyncqueue: ", oid, methodname)
|
||||
seq = self.asyncqueue(oid, methodname, args, kwargs)
|
||||
return self.asyncreturn(seq)
|
||||
|
||||
def asynccall(self, oid, methodname, args, kwargs):
|
||||
request = ("CALL", (oid, methodname, args, kwargs))
|
||||
seq = self.newseq()
|
||||
if threading.currentThread() != self.sockthread:
|
||||
cvar = threading.Condition()
|
||||
self.cvars[seq] = cvar
|
||||
self.debug(("asynccall:%d:" % seq), oid, methodname, args, kwargs)
|
||||
self.putmessage((seq, request))
|
||||
return seq
|
||||
|
||||
def asyncqueue(self, oid, methodname, args, kwargs):
|
||||
request = ("QUEUE", (oid, methodname, args, kwargs))
|
||||
seq = self.newseq()
|
||||
if threading.currentThread() != self.sockthread:
|
||||
cvar = threading.Condition()
|
||||
self.cvars[seq] = cvar
|
||||
self.debug(("asyncqueue:%d:" % seq), oid, methodname, args, kwargs)
|
||||
self.putmessage((seq, request))
|
||||
return seq
|
||||
|
||||
def asyncreturn(self, seq):
|
||||
self.debug("asyncreturn:%d:call getresponse(): " % seq)
|
||||
response = self.getresponse(seq, wait=0.05)
|
||||
self.debug(("asyncreturn:%d:response: " % seq), response)
|
||||
return self.decoderesponse(response)
|
||||
|
||||
def decoderesponse(self, response):
|
||||
how, what = response
|
||||
if how == "OK":
|
||||
return what
|
||||
if how == "QUEUED":
|
||||
return None
|
||||
if how == "EXCEPTION":
|
||||
self.debug("decoderesponse: EXCEPTION")
|
||||
return None
|
||||
if how == "EOF":
|
||||
self.debug("decoderesponse: EOF")
|
||||
self.decode_interrupthook()
|
||||
return None
|
||||
if how == "ERROR":
|
||||
self.debug("decoderesponse: Internal ERROR:", what)
|
||||
raise RuntimeError, what
|
||||
raise SystemError, (how, what)
|
||||
|
||||
def decode_interrupthook(self):
|
||||
""
|
||||
raise EOFError
|
||||
|
||||
def mainloop(self):
|
||||
"""Listen on socket until I/O not ready or EOF
|
||||
|
||||
pollresponse() will loop looking for seq number None, which
|
||||
never comes, and exit on EOFError.
|
||||
|
||||
"""
|
||||
try:
|
||||
self.getresponse(myseq=None, wait=0.05)
|
||||
except EOFError:
|
||||
self.debug("mainloop:return")
|
||||
return
|
||||
|
||||
def getresponse(self, myseq, wait):
|
||||
response = self._getresponse(myseq, wait)
|
||||
if response is not None:
|
||||
how, what = response
|
||||
if how == "OK":
|
||||
response = how, self._proxify(what)
|
||||
return response
|
||||
|
||||
def _proxify(self, obj):
|
||||
if isinstance(obj, RemoteProxy):
|
||||
return RPCProxy(self, obj.oid)
|
||||
if isinstance(obj, types.ListType):
|
||||
return map(self._proxify, obj)
|
||||
# XXX Check for other types -- not currently needed
|
||||
return obj
|
||||
|
||||
def _getresponse(self, myseq, wait):
|
||||
self.debug("_getresponse:myseq:", myseq)
|
||||
if threading.currentThread() is self.sockthread:
|
||||
# this thread does all reading of requests or responses
|
||||
while 1:
|
||||
response = self.pollresponse(myseq, wait)
|
||||
if response is not None:
|
||||
return response
|
||||
else:
|
||||
# wait for notification from socket handling thread
|
||||
cvar = self.cvars[myseq]
|
||||
cvar.acquire()
|
||||
while myseq not in self.responses:
|
||||
cvar.wait()
|
||||
response = self.responses[myseq]
|
||||
self.debug("_getresponse:%s: thread woke up: response: %s" %
|
||||
(myseq, response))
|
||||
del self.responses[myseq]
|
||||
del self.cvars[myseq]
|
||||
cvar.release()
|
||||
return response
|
||||
|
||||
def newseq(self):
|
||||
self.nextseq = seq = self.nextseq + 2
|
||||
return seq
|
||||
|
||||
def putmessage(self, message):
|
||||
self.debug("putmessage:%d:" % message[0])
|
||||
try:
|
||||
s = pickle.dumps(message)
|
||||
except pickle.PicklingError:
|
||||
print >>sys.__stderr__, "Cannot pickle:", repr(message)
|
||||
raise
|
||||
s = struct.pack("<i", len(s)) + s
|
||||
while len(s) > 0:
|
||||
try:
|
||||
r, w, x = select.select([], [self.sock], [])
|
||||
n = self.sock.send(s[:BUFSIZE])
|
||||
except (AttributeError, TypeError):
|
||||
raise IOError, "socket no longer exists"
|
||||
except socket.error:
|
||||
raise
|
||||
else:
|
||||
s = s[n:]
|
||||
|
||||
buffer = ""
|
||||
bufneed = 4
|
||||
bufstate = 0 # meaning: 0 => reading count; 1 => reading data
|
||||
|
||||
def pollpacket(self, wait):
|
||||
self._stage0()
|
||||
if len(self.buffer) < self.bufneed:
|
||||
r, w, x = select.select([self.sock.fileno()], [], [], wait)
|
||||
if len(r) == 0:
|
||||
return None
|
||||
try:
|
||||
s = self.sock.recv(BUFSIZE)
|
||||
except socket.error:
|
||||
raise EOFError
|
||||
if len(s) == 0:
|
||||
raise EOFError
|
||||
self.buffer += s
|
||||
self._stage0()
|
||||
return self._stage1()
|
||||
|
||||
def _stage0(self):
|
||||
if self.bufstate == 0 and len(self.buffer) >= 4:
|
||||
s = self.buffer[:4]
|
||||
self.buffer = self.buffer[4:]
|
||||
self.bufneed = struct.unpack("<i", s)[0]
|
||||
self.bufstate = 1
|
||||
|
||||
def _stage1(self):
|
||||
if self.bufstate == 1 and len(self.buffer) >= self.bufneed:
|
||||
packet = self.buffer[:self.bufneed]
|
||||
self.buffer = self.buffer[self.bufneed:]
|
||||
self.bufneed = 4
|
||||
self.bufstate = 0
|
||||
return packet
|
||||
|
||||
def pollmessage(self, wait):
|
||||
packet = self.pollpacket(wait)
|
||||
if packet is None:
|
||||
return None
|
||||
try:
|
||||
message = pickle.loads(packet)
|
||||
except pickle.UnpicklingError:
|
||||
print >>sys.__stderr__, "-----------------------"
|
||||
print >>sys.__stderr__, "cannot unpickle packet:", repr(packet)
|
||||
traceback.print_stack(file=sys.__stderr__)
|
||||
print >>sys.__stderr__, "-----------------------"
|
||||
raise
|
||||
return message
|
||||
|
||||
def pollresponse(self, myseq, wait):
|
||||
"""Handle messages received on the socket.
|
||||
|
||||
Some messages received may be asynchronous 'call' or 'queue' requests,
|
||||
and some may be responses for other threads.
|
||||
|
||||
'call' requests are passed to self.localcall() with the expectation of
|
||||
immediate execution, during which time the socket is not serviced.
|
||||
|
||||
'queue' requests are used for tasks (which may block or hang) to be
|
||||
processed in a different thread. These requests are fed into
|
||||
request_queue by self.localcall(). Responses to queued requests are
|
||||
taken from response_queue and sent across the link with the associated
|
||||
sequence numbers. Messages in the queues are (sequence_number,
|
||||
request/response) tuples and code using this module removing messages
|
||||
from the request_queue is responsible for returning the correct
|
||||
sequence number in the response_queue.
|
||||
|
||||
pollresponse() will loop until a response message with the myseq
|
||||
sequence number is received, and will save other responses in
|
||||
self.responses and notify the owning thread.
|
||||
|
||||
"""
|
||||
while 1:
|
||||
# send queued response if there is one available
|
||||
try:
|
||||
qmsg = response_queue.get(0)
|
||||
except Queue.Empty:
|
||||
pass
|
||||
else:
|
||||
seq, response = qmsg
|
||||
message = (seq, ('OK', response))
|
||||
self.putmessage(message)
|
||||
# poll for message on link
|
||||
try:
|
||||
message = self.pollmessage(wait)
|
||||
if message is None: # socket not ready
|
||||
return None
|
||||
except EOFError:
|
||||
self.handle_EOF()
|
||||
return None
|
||||
except AttributeError:
|
||||
return None
|
||||
seq, resq = message
|
||||
how = resq[0]
|
||||
self.debug("pollresponse:%d:myseq:%s" % (seq, myseq))
|
||||
# process or queue a request
|
||||
if how in ("CALL", "QUEUE"):
|
||||
self.debug("pollresponse:%d:localcall:call:" % seq)
|
||||
response = self.localcall(seq, resq)
|
||||
self.debug("pollresponse:%d:localcall:response:%s"
|
||||
% (seq, response))
|
||||
if how == "CALL":
|
||||
self.putmessage((seq, response))
|
||||
elif how == "QUEUE":
|
||||
# don't acknowledge the 'queue' request!
|
||||
pass
|
||||
continue
|
||||
# return if completed message transaction
|
||||
elif seq == myseq:
|
||||
return resq
|
||||
# must be a response for a different thread:
|
||||
else:
|
||||
cv = self.cvars.get(seq, None)
|
||||
# response involving unknown sequence number is discarded,
|
||||
# probably intended for prior incarnation of server
|
||||
if cv is not None:
|
||||
cv.acquire()
|
||||
self.responses[seq] = resq
|
||||
cv.notify()
|
||||
cv.release()
|
||||
continue
|
||||
|
||||
def handle_EOF(self):
|
||||
"action taken upon link being closed by peer"
|
||||
self.EOFhook()
|
||||
self.debug("handle_EOF")
|
||||
for key in self.cvars:
|
||||
cv = self.cvars[key]
|
||||
cv.acquire()
|
||||
self.responses[key] = ('EOF', None)
|
||||
cv.notify()
|
||||
cv.release()
|
||||
# call our (possibly overridden) exit function
|
||||
self.exithook()
|
||||
|
||||
def EOFhook(self):
|
||||
"Classes using rpc client/server can override to augment EOF action"
|
||||
pass
|
||||
|
||||
#----------------- end class SocketIO --------------------
|
||||
|
||||
class RemoteObject(object):
|
||||
# Token mix-in class
|
||||
pass
|
||||
|
||||
def remoteref(obj):
|
||||
oid = id(obj)
|
||||
objecttable[oid] = obj
|
||||
return RemoteProxy(oid)
|
||||
|
||||
class RemoteProxy(object):
|
||||
|
||||
def __init__(self, oid):
|
||||
self.oid = oid
|
||||
|
||||
class RPCHandler(SocketServer.BaseRequestHandler, SocketIO):
|
||||
|
||||
debugging = False
|
||||
location = "#S" # Server
|
||||
|
||||
def __init__(self, sock, addr, svr):
|
||||
svr.current_handler = self ## cgt xxx
|
||||
SocketIO.__init__(self, sock)
|
||||
SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr)
|
||||
|
||||
def handle(self):
|
||||
"handle() method required by SocketServer"
|
||||
self.mainloop()
|
||||
|
||||
def get_remote_proxy(self, oid):
|
||||
return RPCProxy(self, oid)
|
||||
|
||||
class RPCClient(SocketIO):
|
||||
|
||||
debugging = False
|
||||
location = "#C" # Client
|
||||
|
||||
nextseq = 1 # Requests coming from the client are odd numbered
|
||||
|
||||
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
|
||||
self.listening_sock = socket.socket(family, type)
|
||||
self.listening_sock.bind(address)
|
||||
self.listening_sock.listen(1)
|
||||
|
||||
def accept(self):
|
||||
working_sock, address = self.listening_sock.accept()
|
||||
if self.debugging:
|
||||
print>>sys.__stderr__, "****** Connection request from ", address
|
||||
if address[0] == LOCALHOST:
|
||||
SocketIO.__init__(self, working_sock)
|
||||
else:
|
||||
print>>sys.__stderr__, "** Invalid host: ", address
|
||||
raise socket.error
|
||||
|
||||
def get_remote_proxy(self, oid):
|
||||
return RPCProxy(self, oid)
|
||||
|
||||
class RPCProxy(object):
|
||||
|
||||
__methods = None
|
||||
__attributes = None
|
||||
|
||||
def __init__(self, sockio, oid):
|
||||
self.sockio = sockio
|
||||
self.oid = oid
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.__methods is None:
|
||||
self.__getmethods()
|
||||
if self.__methods.get(name):
|
||||
return MethodProxy(self.sockio, self.oid, name)
|
||||
if self.__attributes is None:
|
||||
self.__getattributes()
|
||||
if name in self.__attributes:
|
||||
value = self.sockio.remotecall(self.oid, '__getattribute__',
|
||||
(name,), {})
|
||||
return value
|
||||
else:
|
||||
raise AttributeError, name
|
||||
|
||||
def __getattributes(self):
|
||||
self.__attributes = self.sockio.remotecall(self.oid,
|
||||
"__attributes__", (), {})
|
||||
|
||||
def __getmethods(self):
|
||||
self.__methods = self.sockio.remotecall(self.oid,
|
||||
"__methods__", (), {})
|
||||
|
||||
def _getmethods(obj, methods):
|
||||
# Helper to get a list of methods from an object
|
||||
# Adds names to dictionary argument 'methods'
|
||||
for name in dir(obj):
|
||||
attr = getattr(obj, name)
|
||||
if hasattr(attr, '__call__'):
|
||||
methods[name] = 1
|
||||
if type(obj) == types.InstanceType:
|
||||
_getmethods(obj.__class__, methods)
|
||||
if type(obj) == types.ClassType:
|
||||
for super in obj.__bases__:
|
||||
_getmethods(super, methods)
|
||||
|
||||
def _getattributes(obj, attributes):
|
||||
for name in dir(obj):
|
||||
attr = getattr(obj, name)
|
||||
if not hasattr(attr, '__call__'):
|
||||
attributes[name] = 1
|
||||
|
||||
class MethodProxy(object):
|
||||
|
||||
def __init__(self, sockio, oid, name):
|
||||
self.sockio = sockio
|
||||
self.oid = oid
|
||||
self.name = name
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
|
||||
return value
|
||||
|
||||
|
||||
# XXX KBK 09Sep03 We need a proper unit test for this module. Previously
|
||||
# existing test code was removed at Rev 1.27 (r34098).
|
||||
374
Darwin/lib/python2.7/idlelib/run.py
Normal file
374
Darwin/lib/python2.7/idlelib/run.py
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
import sys
|
||||
import io
|
||||
import linecache
|
||||
import time
|
||||
import socket
|
||||
import traceback
|
||||
import thread
|
||||
import threading
|
||||
import Queue
|
||||
|
||||
from idlelib import CallTips
|
||||
from idlelib import AutoComplete
|
||||
|
||||
from idlelib import RemoteDebugger
|
||||
from idlelib import RemoteObjectBrowser
|
||||
from idlelib import StackViewer
|
||||
from idlelib import rpc
|
||||
from idlelib import PyShell
|
||||
from idlelib import IOBinding
|
||||
|
||||
import __main__
|
||||
|
||||
LOCALHOST = '127.0.0.1'
|
||||
|
||||
import warnings
|
||||
|
||||
def idle_showwarning_subproc(
|
||||
message, category, filename, lineno, file=None, line=None):
|
||||
"""Show Idle-format warning after replacing warnings.showwarning.
|
||||
|
||||
The only difference is the formatter called.
|
||||
"""
|
||||
if file is None:
|
||||
file = sys.stderr
|
||||
try:
|
||||
file.write(PyShell.idle_formatwarning(
|
||||
message, category, filename, lineno, line))
|
||||
except IOError:
|
||||
pass # the file (probably stderr) is invalid - this warning gets lost.
|
||||
|
||||
_warnings_showwarning = None
|
||||
|
||||
def capture_warnings(capture):
|
||||
"Replace warning.showwarning with idle_showwarning_subproc, or reverse."
|
||||
|
||||
global _warnings_showwarning
|
||||
if capture:
|
||||
if _warnings_showwarning is None:
|
||||
_warnings_showwarning = warnings.showwarning
|
||||
warnings.showwarning = idle_showwarning_subproc
|
||||
else:
|
||||
if _warnings_showwarning is not None:
|
||||
warnings.showwarning = _warnings_showwarning
|
||||
_warnings_showwarning = None
|
||||
|
||||
capture_warnings(True)
|
||||
|
||||
# Thread shared globals: Establish a queue between a subthread (which handles
|
||||
# the socket) and the main thread (which runs user code), plus global
|
||||
# completion, exit and interruptable (the main thread) flags:
|
||||
|
||||
exit_now = False
|
||||
quitting = False
|
||||
interruptable = False
|
||||
|
||||
def main(del_exitfunc=False):
|
||||
"""Start the Python execution server in a subprocess
|
||||
|
||||
In the Python subprocess, RPCServer is instantiated with handlerclass
|
||||
MyHandler, which inherits register/unregister methods from RPCHandler via
|
||||
the mix-in class SocketIO.
|
||||
|
||||
When the RPCServer 'server' is instantiated, the TCPServer initialization
|
||||
creates an instance of run.MyHandler and calls its handle() method.
|
||||
handle() instantiates a run.Executive object, passing it a reference to the
|
||||
MyHandler object. That reference is saved as attribute rpchandler of the
|
||||
Executive instance. The Executive methods have access to the reference and
|
||||
can pass it on to entities that they command
|
||||
(e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
|
||||
call MyHandler(SocketIO) register/unregister methods via the reference to
|
||||
register and unregister themselves.
|
||||
|
||||
"""
|
||||
global exit_now
|
||||
global quitting
|
||||
global no_exitfunc
|
||||
no_exitfunc = del_exitfunc
|
||||
#time.sleep(15) # test subprocess not responding
|
||||
try:
|
||||
assert(len(sys.argv) > 1)
|
||||
port = int(sys.argv[-1])
|
||||
except:
|
||||
print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
|
||||
return
|
||||
|
||||
capture_warnings(True)
|
||||
sys.argv[:] = [""]
|
||||
sockthread = threading.Thread(target=manage_socket,
|
||||
name='SockThread',
|
||||
args=((LOCALHOST, port),))
|
||||
sockthread.setDaemon(True)
|
||||
sockthread.start()
|
||||
while 1:
|
||||
try:
|
||||
if exit_now:
|
||||
try:
|
||||
exit()
|
||||
except KeyboardInterrupt:
|
||||
# exiting but got an extra KBI? Try again!
|
||||
continue
|
||||
try:
|
||||
seq, request = rpc.request_queue.get(block=True, timeout=0.05)
|
||||
except Queue.Empty:
|
||||
continue
|
||||
method, args, kwargs = request
|
||||
ret = method(*args, **kwargs)
|
||||
rpc.response_queue.put((seq, ret))
|
||||
except KeyboardInterrupt:
|
||||
if quitting:
|
||||
exit_now = True
|
||||
continue
|
||||
except SystemExit:
|
||||
capture_warnings(False)
|
||||
raise
|
||||
except:
|
||||
type, value, tb = sys.exc_info()
|
||||
try:
|
||||
print_exception()
|
||||
rpc.response_queue.put((seq, None))
|
||||
except:
|
||||
# Link didn't work, print same exception to __stderr__
|
||||
traceback.print_exception(type, value, tb, file=sys.__stderr__)
|
||||
exit()
|
||||
else:
|
||||
continue
|
||||
|
||||
def manage_socket(address):
|
||||
for i in range(3):
|
||||
time.sleep(i)
|
||||
try:
|
||||
server = MyRPCServer(address, MyHandler)
|
||||
break
|
||||
except socket.error as err:
|
||||
print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
|
||||
+ err.args[1] + ", retrying...."
|
||||
else:
|
||||
print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
|
||||
"IDLE GUI failed, exiting."
|
||||
show_socket_error(err, address)
|
||||
global exit_now
|
||||
exit_now = True
|
||||
return
|
||||
server.handle_request() # A single request only
|
||||
|
||||
def show_socket_error(err, address):
|
||||
import Tkinter
|
||||
import tkMessageBox
|
||||
root = Tkinter.Tk()
|
||||
root.withdraw()
|
||||
if err.args[0] == 61: # connection refused
|
||||
msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
|
||||
"to your personal firewall configuration. It is safe to "\
|
||||
"allow this internal connection because no data is visible on "\
|
||||
"external ports." % address
|
||||
tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
|
||||
else:
|
||||
tkMessageBox.showerror("IDLE Subprocess Error",
|
||||
"Socket Error: %s" % err.args[1])
|
||||
root.destroy()
|
||||
|
||||
def print_exception():
|
||||
import linecache
|
||||
linecache.checkcache()
|
||||
flush_stdout()
|
||||
efile = sys.stderr
|
||||
typ, val, tb = excinfo = sys.exc_info()
|
||||
sys.last_type, sys.last_value, sys.last_traceback = excinfo
|
||||
tbe = traceback.extract_tb(tb)
|
||||
print>>efile, '\nTraceback (most recent call last):'
|
||||
exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
|
||||
"RemoteDebugger.py", "bdb.py")
|
||||
cleanup_traceback(tbe, exclude)
|
||||
traceback.print_list(tbe, file=efile)
|
||||
lines = traceback.format_exception_only(typ, val)
|
||||
for line in lines:
|
||||
print>>efile, line,
|
||||
|
||||
def cleanup_traceback(tb, exclude):
|
||||
"Remove excluded traces from beginning/end of tb; get cached lines"
|
||||
orig_tb = tb[:]
|
||||
while tb:
|
||||
for rpcfile in exclude:
|
||||
if tb[0][0].count(rpcfile):
|
||||
break # found an exclude, break for: and delete tb[0]
|
||||
else:
|
||||
break # no excludes, have left RPC code, break while:
|
||||
del tb[0]
|
||||
while tb:
|
||||
for rpcfile in exclude:
|
||||
if tb[-1][0].count(rpcfile):
|
||||
break
|
||||
else:
|
||||
break
|
||||
del tb[-1]
|
||||
if len(tb) == 0:
|
||||
# exception was in IDLE internals, don't prune!
|
||||
tb[:] = orig_tb[:]
|
||||
print>>sys.stderr, "** IDLE Internal Exception: "
|
||||
rpchandler = rpc.objecttable['exec'].rpchandler
|
||||
for i in range(len(tb)):
|
||||
fn, ln, nm, line = tb[i]
|
||||
if nm == '?':
|
||||
nm = "-toplevel-"
|
||||
if not line and fn.startswith("<pyshell#"):
|
||||
line = rpchandler.remotecall('linecache', 'getline',
|
||||
(fn, ln), {})
|
||||
tb[i] = fn, ln, nm, line
|
||||
|
||||
def flush_stdout():
|
||||
try:
|
||||
if sys.stdout.softspace:
|
||||
sys.stdout.softspace = 0
|
||||
sys.stdout.write("\n")
|
||||
except (AttributeError, EOFError):
|
||||
pass
|
||||
|
||||
def exit():
|
||||
"""Exit subprocess, possibly after first deleting sys.exitfunc
|
||||
|
||||
If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
|
||||
sys.exitfunc will be removed before exiting. (VPython support)
|
||||
|
||||
"""
|
||||
if no_exitfunc:
|
||||
try:
|
||||
del sys.exitfunc
|
||||
except AttributeError:
|
||||
pass
|
||||
capture_warnings(False)
|
||||
sys.exit(0)
|
||||
|
||||
class MyRPCServer(rpc.RPCServer):
|
||||
|
||||
def handle_error(self, request, client_address):
|
||||
"""Override RPCServer method for IDLE
|
||||
|
||||
Interrupt the MainThread and exit server if link is dropped.
|
||||
|
||||
"""
|
||||
global quitting
|
||||
try:
|
||||
raise
|
||||
except SystemExit:
|
||||
raise
|
||||
except EOFError:
|
||||
global exit_now
|
||||
exit_now = True
|
||||
thread.interrupt_main()
|
||||
except:
|
||||
erf = sys.__stderr__
|
||||
print>>erf, '\n' + '-'*40
|
||||
print>>erf, 'Unhandled server exception!'
|
||||
print>>erf, 'Thread: %s' % threading.currentThread().getName()
|
||||
print>>erf, 'Client Address: ', client_address
|
||||
print>>erf, 'Request: ', repr(request)
|
||||
traceback.print_exc(file=erf)
|
||||
print>>erf, '\n*** Unrecoverable, server exiting!'
|
||||
print>>erf, '-'*40
|
||||
quitting = True
|
||||
thread.interrupt_main()
|
||||
|
||||
class MyHandler(rpc.RPCHandler):
|
||||
|
||||
def handle(self):
|
||||
"""Override base method"""
|
||||
executive = Executive(self)
|
||||
self.register("exec", executive)
|
||||
self.console = self.get_remote_proxy("console")
|
||||
sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
|
||||
IOBinding.encoding)
|
||||
sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
|
||||
IOBinding.encoding)
|
||||
sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
|
||||
IOBinding.encoding)
|
||||
|
||||
# Keep a reference to stdin so that it won't try to exit IDLE if
|
||||
# sys.stdin gets changed from within IDLE's shell. See issue17838.
|
||||
self._keep_stdin = sys.stdin
|
||||
|
||||
self.interp = self.get_remote_proxy("interp")
|
||||
rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
|
||||
|
||||
def exithook(self):
|
||||
"override SocketIO method - wait for MainThread to shut us down"
|
||||
time.sleep(10)
|
||||
|
||||
def EOFhook(self):
|
||||
"Override SocketIO method - terminate wait on callback and exit thread"
|
||||
global quitting
|
||||
quitting = True
|
||||
thread.interrupt_main()
|
||||
|
||||
def decode_interrupthook(self):
|
||||
"interrupt awakened thread"
|
||||
global quitting
|
||||
quitting = True
|
||||
thread.interrupt_main()
|
||||
|
||||
|
||||
class Executive(object):
|
||||
|
||||
def __init__(self, rpchandler):
|
||||
self.rpchandler = rpchandler
|
||||
self.locals = __main__.__dict__
|
||||
self.calltip = CallTips.CallTips()
|
||||
self.autocomplete = AutoComplete.AutoComplete()
|
||||
|
||||
def runcode(self, code):
|
||||
global interruptable
|
||||
try:
|
||||
self.usr_exc_info = None
|
||||
interruptable = True
|
||||
try:
|
||||
exec code in self.locals
|
||||
finally:
|
||||
interruptable = False
|
||||
except SystemExit:
|
||||
# Scripts that raise SystemExit should just
|
||||
# return to the interactive prompt
|
||||
pass
|
||||
except:
|
||||
self.usr_exc_info = sys.exc_info()
|
||||
if quitting:
|
||||
exit()
|
||||
print_exception()
|
||||
jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
|
||||
if jit:
|
||||
self.rpchandler.interp.open_remote_stack_viewer()
|
||||
else:
|
||||
flush_stdout()
|
||||
|
||||
def interrupt_the_server(self):
|
||||
if interruptable:
|
||||
thread.interrupt_main()
|
||||
|
||||
def start_the_debugger(self, gui_adap_oid):
|
||||
return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
|
||||
|
||||
def stop_the_debugger(self, idb_adap_oid):
|
||||
"Unregister the Idb Adapter. Link objects and Idb then subject to GC"
|
||||
self.rpchandler.unregister(idb_adap_oid)
|
||||
|
||||
def get_the_calltip(self, name):
|
||||
return self.calltip.fetch_tip(name)
|
||||
|
||||
def get_the_completion_list(self, what, mode):
|
||||
return self.autocomplete.fetch_completions(what, mode)
|
||||
|
||||
def stackviewer(self, flist_oid=None):
|
||||
if self.usr_exc_info:
|
||||
typ, val, tb = self.usr_exc_info
|
||||
else:
|
||||
return None
|
||||
flist = None
|
||||
if flist_oid is not None:
|
||||
flist = self.rpchandler.get_remote_proxy(flist_oid)
|
||||
while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
|
||||
tb = tb.tb_next
|
||||
sys.last_type = typ
|
||||
sys.last_value = val
|
||||
item = StackViewer.StackTreeItem(flist, tb)
|
||||
return RemoteObjectBrowser.remote_object_tree_item(item)
|
||||
|
||||
capture_warnings(False) # Make sure turned off; see issue 18081
|
||||
490
Darwin/lib/python2.7/idlelib/tabbedpages.py
Normal file
490
Darwin/lib/python2.7/idlelib/tabbedpages.py
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
"""An implementation of tabbed pages using only standard Tkinter.
|
||||
|
||||
Originally developed for use in IDLE. Based on tabpage.py.
|
||||
|
||||
Classes exported:
|
||||
TabbedPageSet -- A Tkinter implementation of a tabbed-page widget.
|
||||
TabSet -- A widget containing tabs (buttons) in one or more rows.
|
||||
|
||||
"""
|
||||
from Tkinter import *
|
||||
|
||||
class InvalidNameError(Exception): pass
|
||||
class AlreadyExistsError(Exception): pass
|
||||
|
||||
|
||||
class TabSet(Frame):
|
||||
"""A widget containing tabs (buttons) in one or more rows.
|
||||
|
||||
Only one tab may be selected at a time.
|
||||
|
||||
"""
|
||||
def __init__(self, page_set, select_command,
|
||||
tabs=None, n_rows=1, max_tabs_per_row=5,
|
||||
expand_tabs=False, **kw):
|
||||
"""Constructor arguments:
|
||||
|
||||
select_command -- A callable which will be called when a tab is
|
||||
selected. It is called with the name of the selected tab as an
|
||||
argument.
|
||||
|
||||
tabs -- A list of strings, the names of the tabs. Should be specified in
|
||||
the desired tab order. The first tab will be the default and first
|
||||
active tab. If tabs is None or empty, the TabSet will be initialized
|
||||
empty.
|
||||
|
||||
n_rows -- Number of rows of tabs to be shown. If n_rows <= 0 or is
|
||||
None, then the number of rows will be decided by TabSet. See
|
||||
_arrange_tabs() for details.
|
||||
|
||||
max_tabs_per_row -- Used for deciding how many rows of tabs are needed,
|
||||
when the number of rows is not constant. See _arrange_tabs() for
|
||||
details.
|
||||
|
||||
"""
|
||||
Frame.__init__(self, page_set, **kw)
|
||||
self.select_command = select_command
|
||||
self.n_rows = n_rows
|
||||
self.max_tabs_per_row = max_tabs_per_row
|
||||
self.expand_tabs = expand_tabs
|
||||
self.page_set = page_set
|
||||
|
||||
self._tabs = {}
|
||||
self._tab2row = {}
|
||||
if tabs:
|
||||
self._tab_names = list(tabs)
|
||||
else:
|
||||
self._tab_names = []
|
||||
self._selected_tab = None
|
||||
self._tab_rows = []
|
||||
|
||||
self.padding_frame = Frame(self, height=2,
|
||||
borderwidth=0, relief=FLAT,
|
||||
background=self.cget('background'))
|
||||
self.padding_frame.pack(side=TOP, fill=X, expand=False)
|
||||
|
||||
self._arrange_tabs()
|
||||
|
||||
def add_tab(self, tab_name):
|
||||
"""Add a new tab with the name given in tab_name."""
|
||||
if not tab_name:
|
||||
raise InvalidNameError("Invalid Tab name: '%s'" % tab_name)
|
||||
if tab_name in self._tab_names:
|
||||
raise AlreadyExistsError("Tab named '%s' already exists" %tab_name)
|
||||
|
||||
self._tab_names.append(tab_name)
|
||||
self._arrange_tabs()
|
||||
|
||||
def remove_tab(self, tab_name):
|
||||
"""Remove the tab named <tab_name>"""
|
||||
if not tab_name in self._tab_names:
|
||||
raise KeyError("No such Tab: '%s" % page_name)
|
||||
|
||||
self._tab_names.remove(tab_name)
|
||||
self._arrange_tabs()
|
||||
|
||||
def set_selected_tab(self, tab_name):
|
||||
"""Show the tab named <tab_name> as the selected one"""
|
||||
if tab_name == self._selected_tab:
|
||||
return
|
||||
if tab_name is not None and tab_name not in self._tabs:
|
||||
raise KeyError("No such Tab: '%s" % page_name)
|
||||
|
||||
# deselect the current selected tab
|
||||
if self._selected_tab is not None:
|
||||
self._tabs[self._selected_tab].set_normal()
|
||||
self._selected_tab = None
|
||||
|
||||
if tab_name is not None:
|
||||
# activate the tab named tab_name
|
||||
self._selected_tab = tab_name
|
||||
tab = self._tabs[tab_name]
|
||||
tab.set_selected()
|
||||
# move the tab row with the selected tab to the bottom
|
||||
tab_row = self._tab2row[tab]
|
||||
tab_row.pack_forget()
|
||||
tab_row.pack(side=TOP, fill=X, expand=0)
|
||||
|
||||
def _add_tab_row(self, tab_names, expand_tabs):
|
||||
if not tab_names:
|
||||
return
|
||||
|
||||
tab_row = Frame(self)
|
||||
tab_row.pack(side=TOP, fill=X, expand=0)
|
||||
self._tab_rows.append(tab_row)
|
||||
|
||||
for tab_name in tab_names:
|
||||
tab = TabSet.TabButton(tab_name, self.select_command,
|
||||
tab_row, self)
|
||||
if expand_tabs:
|
||||
tab.pack(side=LEFT, fill=X, expand=True)
|
||||
else:
|
||||
tab.pack(side=LEFT)
|
||||
self._tabs[tab_name] = tab
|
||||
self._tab2row[tab] = tab_row
|
||||
|
||||
# tab is the last one created in the above loop
|
||||
tab.is_last_in_row = True
|
||||
|
||||
def _reset_tab_rows(self):
|
||||
while self._tab_rows:
|
||||
tab_row = self._tab_rows.pop()
|
||||
tab_row.destroy()
|
||||
self._tab2row = {}
|
||||
|
||||
def _arrange_tabs(self):
|
||||
"""
|
||||
Arrange the tabs in rows, in the order in which they were added.
|
||||
|
||||
If n_rows >= 1, this will be the number of rows used. Otherwise the
|
||||
number of rows will be calculated according to the number of tabs and
|
||||
max_tabs_per_row. In this case, the number of rows may change when
|
||||
adding/removing tabs.
|
||||
|
||||
"""
|
||||
# remove all tabs and rows
|
||||
for tab_name in self._tabs.keys():
|
||||
self._tabs.pop(tab_name).destroy()
|
||||
self._reset_tab_rows()
|
||||
|
||||
if not self._tab_names:
|
||||
return
|
||||
|
||||
if self.n_rows is not None and self.n_rows > 0:
|
||||
n_rows = self.n_rows
|
||||
else:
|
||||
# calculate the required number of rows
|
||||
n_rows = (len(self._tab_names) - 1) // self.max_tabs_per_row + 1
|
||||
|
||||
# not expanding the tabs with more than one row is very ugly
|
||||
expand_tabs = self.expand_tabs or n_rows > 1
|
||||
i = 0 # index in self._tab_names
|
||||
for row_index in xrange(n_rows):
|
||||
# calculate required number of tabs in this row
|
||||
n_tabs = (len(self._tab_names) - i - 1) // (n_rows - row_index) + 1
|
||||
tab_names = self._tab_names[i:i + n_tabs]
|
||||
i += n_tabs
|
||||
self._add_tab_row(tab_names, expand_tabs)
|
||||
|
||||
# re-select selected tab so it is properly displayed
|
||||
selected = self._selected_tab
|
||||
self.set_selected_tab(None)
|
||||
if selected in self._tab_names:
|
||||
self.set_selected_tab(selected)
|
||||
|
||||
class TabButton(Frame):
|
||||
"""A simple tab-like widget."""
|
||||
|
||||
bw = 2 # borderwidth
|
||||
|
||||
def __init__(self, name, select_command, tab_row, tab_set):
|
||||
"""Constructor arguments:
|
||||
|
||||
name -- The tab's name, which will appear in its button.
|
||||
|
||||
select_command -- The command to be called upon selection of the
|
||||
tab. It is called with the tab's name as an argument.
|
||||
|
||||
"""
|
||||
Frame.__init__(self, tab_row, borderwidth=self.bw, relief=RAISED)
|
||||
|
||||
self.name = name
|
||||
self.select_command = select_command
|
||||
self.tab_set = tab_set
|
||||
self.is_last_in_row = False
|
||||
|
||||
self.button = Radiobutton(
|
||||
self, text=name, command=self._select_event,
|
||||
padx=5, pady=1, takefocus=FALSE, indicatoron=FALSE,
|
||||
highlightthickness=0, selectcolor='', borderwidth=0)
|
||||
self.button.pack(side=LEFT, fill=X, expand=True)
|
||||
|
||||
self._init_masks()
|
||||
self.set_normal()
|
||||
|
||||
def _select_event(self, *args):
|
||||
"""Event handler for tab selection.
|
||||
|
||||
With TabbedPageSet, this calls TabbedPageSet.change_page, so that
|
||||
selecting a tab changes the page.
|
||||
|
||||
Note that this does -not- call set_selected -- it will be called by
|
||||
TabSet.set_selected_tab, which should be called when whatever the
|
||||
tabs are related to changes.
|
||||
|
||||
"""
|
||||
self.select_command(self.name)
|
||||
return
|
||||
|
||||
def set_selected(self):
|
||||
"""Assume selected look"""
|
||||
self._place_masks(selected=True)
|
||||
|
||||
def set_normal(self):
|
||||
"""Assume normal look"""
|
||||
self._place_masks(selected=False)
|
||||
|
||||
def _init_masks(self):
|
||||
page_set = self.tab_set.page_set
|
||||
background = page_set.pages_frame.cget('background')
|
||||
# mask replaces the middle of the border with the background color
|
||||
self.mask = Frame(page_set, borderwidth=0, relief=FLAT,
|
||||
background=background)
|
||||
# mskl replaces the bottom-left corner of the border with a normal
|
||||
# left border
|
||||
self.mskl = Frame(page_set, borderwidth=0, relief=FLAT,
|
||||
background=background)
|
||||
self.mskl.ml = Frame(self.mskl, borderwidth=self.bw,
|
||||
relief=RAISED)
|
||||
self.mskl.ml.place(x=0, y=-self.bw,
|
||||
width=2*self.bw, height=self.bw*4)
|
||||
# mskr replaces the bottom-right corner of the border with a normal
|
||||
# right border
|
||||
self.mskr = Frame(page_set, borderwidth=0, relief=FLAT,
|
||||
background=background)
|
||||
self.mskr.mr = Frame(self.mskr, borderwidth=self.bw,
|
||||
relief=RAISED)
|
||||
|
||||
def _place_masks(self, selected=False):
|
||||
height = self.bw
|
||||
if selected:
|
||||
height += self.bw
|
||||
|
||||
self.mask.place(in_=self,
|
||||
relx=0.0, x=0,
|
||||
rely=1.0, y=0,
|
||||
relwidth=1.0, width=0,
|
||||
relheight=0.0, height=height)
|
||||
|
||||
self.mskl.place(in_=self,
|
||||
relx=0.0, x=-self.bw,
|
||||
rely=1.0, y=0,
|
||||
relwidth=0.0, width=self.bw,
|
||||
relheight=0.0, height=height)
|
||||
|
||||
page_set = self.tab_set.page_set
|
||||
if selected and ((not self.is_last_in_row) or
|
||||
(self.winfo_rootx() + self.winfo_width() <
|
||||
page_set.winfo_rootx() + page_set.winfo_width())
|
||||
):
|
||||
# for a selected tab, if its rightmost edge isn't on the
|
||||
# rightmost edge of the page set, the right mask should be one
|
||||
# borderwidth shorter (vertically)
|
||||
height -= self.bw
|
||||
|
||||
self.mskr.place(in_=self,
|
||||
relx=1.0, x=0,
|
||||
rely=1.0, y=0,
|
||||
relwidth=0.0, width=self.bw,
|
||||
relheight=0.0, height=height)
|
||||
|
||||
self.mskr.mr.place(x=-self.bw, y=-self.bw,
|
||||
width=2*self.bw, height=height + self.bw*2)
|
||||
|
||||
# finally, lower the tab set so that all of the frames we just
|
||||
# placed hide it
|
||||
self.tab_set.lower()
|
||||
|
||||
class TabbedPageSet(Frame):
|
||||
"""A Tkinter tabbed-pane widget.
|
||||
|
||||
Constains set of 'pages' (or 'panes') with tabs above for selecting which
|
||||
page is displayed. Only one page will be displayed at a time.
|
||||
|
||||
Pages may be accessed through the 'pages' attribute, which is a dictionary
|
||||
of pages, using the name given as the key. A page is an instance of a
|
||||
subclass of Tk's Frame widget.
|
||||
|
||||
The page widgets will be created (and destroyed when required) by the
|
||||
TabbedPageSet. Do not call the page's pack/place/grid/destroy methods.
|
||||
|
||||
Pages may be added or removed at any time using the add_page() and
|
||||
remove_page() methods.
|
||||
|
||||
"""
|
||||
class Page(object):
|
||||
"""Abstract base class for TabbedPageSet's pages.
|
||||
|
||||
Subclasses must override the _show() and _hide() methods.
|
||||
|
||||
"""
|
||||
uses_grid = False
|
||||
|
||||
def __init__(self, page_set):
|
||||
self.frame = Frame(page_set, borderwidth=2, relief=RAISED)
|
||||
|
||||
def _show(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def _hide(self):
|
||||
raise NotImplementedError
|
||||
|
||||
class PageRemove(Page):
|
||||
"""Page class using the grid placement manager's "remove" mechanism."""
|
||||
uses_grid = True
|
||||
|
||||
def _show(self):
|
||||
self.frame.grid(row=0, column=0, sticky=NSEW)
|
||||
|
||||
def _hide(self):
|
||||
self.frame.grid_remove()
|
||||
|
||||
class PageLift(Page):
|
||||
"""Page class using the grid placement manager's "lift" mechanism."""
|
||||
uses_grid = True
|
||||
|
||||
def __init__(self, page_set):
|
||||
super(TabbedPageSet.PageLift, self).__init__(page_set)
|
||||
self.frame.grid(row=0, column=0, sticky=NSEW)
|
||||
self.frame.lower()
|
||||
|
||||
def _show(self):
|
||||
self.frame.lift()
|
||||
|
||||
def _hide(self):
|
||||
self.frame.lower()
|
||||
|
||||
class PagePackForget(Page):
|
||||
"""Page class using the pack placement manager's "forget" mechanism."""
|
||||
def _show(self):
|
||||
self.frame.pack(fill=BOTH, expand=True)
|
||||
|
||||
def _hide(self):
|
||||
self.frame.pack_forget()
|
||||
|
||||
def __init__(self, parent, page_names=None, page_class=PageLift,
|
||||
n_rows=1, max_tabs_per_row=5, expand_tabs=False,
|
||||
**kw):
|
||||
"""Constructor arguments:
|
||||
|
||||
page_names -- A list of strings, each will be the dictionary key to a
|
||||
page's widget, and the name displayed on the page's tab. Should be
|
||||
specified in the desired page order. The first page will be the default
|
||||
and first active page. If page_names is None or empty, the
|
||||
TabbedPageSet will be initialized empty.
|
||||
|
||||
n_rows, max_tabs_per_row -- Parameters for the TabSet which will
|
||||
manage the tabs. See TabSet's docs for details.
|
||||
|
||||
page_class -- Pages can be shown/hidden using three mechanisms:
|
||||
|
||||
* PageLift - All pages will be rendered one on top of the other. When
|
||||
a page is selected, it will be brought to the top, thus hiding all
|
||||
other pages. Using this method, the TabbedPageSet will not be resized
|
||||
when pages are switched. (It may still be resized when pages are
|
||||
added/removed.)
|
||||
|
||||
* PageRemove - When a page is selected, the currently showing page is
|
||||
hidden, and the new page shown in its place. Using this method, the
|
||||
TabbedPageSet may resize when pages are changed.
|
||||
|
||||
* PagePackForget - This mechanism uses the pack placement manager.
|
||||
When a page is shown it is packed, and when it is hidden it is
|
||||
unpacked (i.e. pack_forget). This mechanism may also cause the
|
||||
TabbedPageSet to resize when the page is changed.
|
||||
|
||||
"""
|
||||
Frame.__init__(self, parent, **kw)
|
||||
|
||||
self.page_class = page_class
|
||||
self.pages = {}
|
||||
self._pages_order = []
|
||||
self._current_page = None
|
||||
self._default_page = None
|
||||
|
||||
self.columnconfigure(0, weight=1)
|
||||
self.rowconfigure(1, weight=1)
|
||||
|
||||
self.pages_frame = Frame(self)
|
||||
self.pages_frame.grid(row=1, column=0, sticky=NSEW)
|
||||
if self.page_class.uses_grid:
|
||||
self.pages_frame.columnconfigure(0, weight=1)
|
||||
self.pages_frame.rowconfigure(0, weight=1)
|
||||
|
||||
# the order of the following commands is important
|
||||
self._tab_set = TabSet(self, self.change_page, n_rows=n_rows,
|
||||
max_tabs_per_row=max_tabs_per_row,
|
||||
expand_tabs=expand_tabs)
|
||||
if page_names:
|
||||
for name in page_names:
|
||||
self.add_page(name)
|
||||
self._tab_set.grid(row=0, column=0, sticky=NSEW)
|
||||
|
||||
self.change_page(self._default_page)
|
||||
|
||||
def add_page(self, page_name):
|
||||
"""Add a new page with the name given in page_name."""
|
||||
if not page_name:
|
||||
raise InvalidNameError("Invalid TabPage name: '%s'" % page_name)
|
||||
if page_name in self.pages:
|
||||
raise AlreadyExistsError(
|
||||
"TabPage named '%s' already exists" % page_name)
|
||||
|
||||
self.pages[page_name] = self.page_class(self.pages_frame)
|
||||
self._pages_order.append(page_name)
|
||||
self._tab_set.add_tab(page_name)
|
||||
|
||||
if len(self.pages) == 1: # adding first page
|
||||
self._default_page = page_name
|
||||
self.change_page(page_name)
|
||||
|
||||
def remove_page(self, page_name):
|
||||
"""Destroy the page whose name is given in page_name."""
|
||||
if not page_name in self.pages:
|
||||
raise KeyError("No such TabPage: '%s" % page_name)
|
||||
|
||||
self._pages_order.remove(page_name)
|
||||
|
||||
# handle removing last remaining, default, or currently shown page
|
||||
if len(self._pages_order) > 0:
|
||||
if page_name == self._default_page:
|
||||
# set a new default page
|
||||
self._default_page = self._pages_order[0]
|
||||
else:
|
||||
self._default_page = None
|
||||
|
||||
if page_name == self._current_page:
|
||||
self.change_page(self._default_page)
|
||||
|
||||
self._tab_set.remove_tab(page_name)
|
||||
page = self.pages.pop(page_name)
|
||||
page.frame.destroy()
|
||||
|
||||
def change_page(self, page_name):
|
||||
"""Show the page whose name is given in page_name."""
|
||||
if self._current_page == page_name:
|
||||
return
|
||||
if page_name is not None and page_name not in self.pages:
|
||||
raise KeyError("No such TabPage: '%s'" % page_name)
|
||||
|
||||
if self._current_page is not None:
|
||||
self.pages[self._current_page]._hide()
|
||||
self._current_page = None
|
||||
|
||||
if page_name is not None:
|
||||
self._current_page = page_name
|
||||
self.pages[page_name]._show()
|
||||
|
||||
self._tab_set.set_selected_tab(page_name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test dialog
|
||||
root=Tk()
|
||||
tabPage=TabbedPageSet(root, page_names=['Foobar','Baz'], n_rows=0,
|
||||
expand_tabs=False,
|
||||
)
|
||||
tabPage.pack(side=TOP, expand=TRUE, fill=BOTH)
|
||||
Label(tabPage.pages['Foobar'].frame, text='Foo', pady=20).pack()
|
||||
Label(tabPage.pages['Foobar'].frame, text='Bar', pady=20).pack()
|
||||
Label(tabPage.pages['Baz'].frame, text='Baz').pack()
|
||||
entryPgName=Entry(root)
|
||||
buttonAdd=Button(root, text='Add Page',
|
||||
command=lambda:tabPage.add_page(entryPgName.get()))
|
||||
buttonRemove=Button(root, text='Remove Page',
|
||||
command=lambda:tabPage.remove_page(entryPgName.get()))
|
||||
labelPgName=Label(root, text='name of page to add/remove:')
|
||||
buttonAdd.pack(padx=5, pady=5)
|
||||
buttonRemove.pack(padx=5, pady=5)
|
||||
labelPgName.pack(padx=5)
|
||||
entryPgName.pack(padx=5)
|
||||
root.mainloop()
|
||||
31
Darwin/lib/python2.7/idlelib/testcode.py
Normal file
31
Darwin/lib/python2.7/idlelib/testcode.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import string
|
||||
|
||||
def f():
|
||||
a = 0
|
||||
b = 1
|
||||
c = 2
|
||||
d = 3
|
||||
e = 4
|
||||
g()
|
||||
|
||||
def g():
|
||||
h()
|
||||
|
||||
def h():
|
||||
i()
|
||||
|
||||
def i():
|
||||
j()
|
||||
|
||||
def j():
|
||||
k()
|
||||
|
||||
def k():
|
||||
l()
|
||||
|
||||
l = lambda: test()
|
||||
|
||||
def test():
|
||||
string.capwords(1)
|
||||
|
||||
f()
|
||||
99
Darwin/lib/python2.7/idlelib/textView.py
Normal file
99
Darwin/lib/python2.7/idlelib/textView.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
"""Simple text browser for IDLE
|
||||
|
||||
"""
|
||||
|
||||
from Tkinter import *
|
||||
import tkMessageBox
|
||||
|
||||
class TextViewer(Toplevel):
|
||||
"""A simple text viewer dialog for IDLE
|
||||
|
||||
"""
|
||||
def __init__(self, parent, title, text, modal=True):
|
||||
"""Show the given text in a scrollable window with a 'close' button
|
||||
|
||||
"""
|
||||
Toplevel.__init__(self, parent)
|
||||
self.configure(borderwidth=5)
|
||||
self.geometry("=%dx%d+%d+%d" % (625, 500,
|
||||
parent.winfo_rootx() + 10,
|
||||
parent.winfo_rooty() + 10))
|
||||
#elguavas - config placeholders til config stuff completed
|
||||
self.bg = '#ffffff'
|
||||
self.fg = '#000000'
|
||||
|
||||
self.CreateWidgets()
|
||||
self.title(title)
|
||||
self.protocol("WM_DELETE_WINDOW", self.Ok)
|
||||
self.parent = parent
|
||||
self.textView.focus_set()
|
||||
#key bindings for this dialog
|
||||
self.bind('<Return>',self.Ok) #dismiss dialog
|
||||
self.bind('<Escape>',self.Ok) #dismiss dialog
|
||||
self.textView.insert(0.0, text)
|
||||
self.textView.config(state=DISABLED)
|
||||
|
||||
if modal:
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.wait_window()
|
||||
|
||||
def CreateWidgets(self):
|
||||
frameText = Frame(self, relief=SUNKEN, height=700)
|
||||
frameButtons = Frame(self)
|
||||
self.buttonOk = Button(frameButtons, text='Close',
|
||||
command=self.Ok, takefocus=FALSE)
|
||||
self.scrollbarView = Scrollbar(frameText, orient=VERTICAL,
|
||||
takefocus=FALSE, highlightthickness=0)
|
||||
self.textView = Text(frameText, wrap=WORD, highlightthickness=0,
|
||||
fg=self.fg, bg=self.bg)
|
||||
self.scrollbarView.config(command=self.textView.yview)
|
||||
self.textView.config(yscrollcommand=self.scrollbarView.set)
|
||||
self.buttonOk.pack()
|
||||
self.scrollbarView.pack(side=RIGHT,fill=Y)
|
||||
self.textView.pack(side=LEFT,expand=TRUE,fill=BOTH)
|
||||
frameButtons.pack(side=BOTTOM,fill=X)
|
||||
frameText.pack(side=TOP,expand=TRUE,fill=BOTH)
|
||||
|
||||
def Ok(self, event=None):
|
||||
self.destroy()
|
||||
|
||||
|
||||
def view_text(parent, title, text, modal=True):
|
||||
return TextViewer(parent, title, text, modal)
|
||||
|
||||
def view_file(parent, title, filename, encoding=None, modal=True):
|
||||
try:
|
||||
if encoding:
|
||||
import codecs
|
||||
textFile = codecs.open(filename, 'r')
|
||||
else:
|
||||
textFile = open(filename, 'r')
|
||||
except IOError:
|
||||
import tkMessageBox
|
||||
tkMessageBox.showerror(title='File Load Error',
|
||||
message='Unable to load file %r .' % filename,
|
||||
parent=parent)
|
||||
else:
|
||||
return view_text(parent, title, textFile.read(), modal)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test the dialog
|
||||
root=Tk()
|
||||
root.title('textView test')
|
||||
filename = './textView.py'
|
||||
text = file(filename, 'r').read()
|
||||
btn1 = Button(root, text='view_text',
|
||||
command=lambda:view_text(root, 'view_text', text))
|
||||
btn1.pack(side=LEFT)
|
||||
btn2 = Button(root, text='view_file',
|
||||
command=lambda:view_file(root, 'view_file', filename))
|
||||
btn2.pack(side=LEFT)
|
||||
btn3 = Button(root, text='nonmodal view_text',
|
||||
command=lambda:view_text(root, 'nonmodal view_text', text,
|
||||
modal=False))
|
||||
btn3.pack(side=LEFT)
|
||||
close = Button(root, text='Close', command=root.destroy)
|
||||
close.pack(side=RIGHT)
|
||||
root.mainloop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue