mirror of
https://github.com/python/cpython.git
synced 2024-11-27 11:55:13 +08:00
438 lines
13 KiB
Python
438 lines
13 KiB
Python
import W
|
|
import Wkeys
|
|
from Carbon import Fm
|
|
import WASTEconst
|
|
from types import *
|
|
from Carbon import Events
|
|
import string
|
|
import sys
|
|
import traceback
|
|
import MacOS
|
|
import MacPrefs
|
|
from Carbon import Qd
|
|
import EasyDialogs
|
|
import PyInteractive
|
|
|
|
if not hasattr(sys, 'ps1'):
|
|
sys.ps1 = '>>> '
|
|
if not hasattr(sys, 'ps2'):
|
|
sys.ps2 = '... '
|
|
|
|
def inspect(foo): # JJS 1/25/99
|
|
"Launch the browser on the given object. This is a general built-in function."
|
|
import PyBrowser
|
|
PyBrowser.Browser(foo)
|
|
|
|
class ConsoleTextWidget(W.EditText):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
apply(W.EditText.__init__, (self,) + args, kwargs)
|
|
self._inputstart = 0
|
|
self._buf = ''
|
|
self.pyinteractive = PyInteractive.PyInteractive()
|
|
|
|
import __main__
|
|
self._namespace = __main__.__dict__
|
|
self._namespace['inspect'] = inspect # JJS 1/25/99
|
|
|
|
def insert(self, text):
|
|
self.checkselection()
|
|
self.ted.WEInsert(text, None, None)
|
|
self.changed = 1
|
|
self.selchanged = 1
|
|
|
|
def set_namespace(self, dict):
|
|
if type(dict) <> DictionaryType:
|
|
raise TypeError, "The namespace needs to be a dictionary"
|
|
if 'inspect' not in dict.keys(): dict['inspect'] = inspect # JJS 1/25/99
|
|
self._namespace = dict
|
|
|
|
def open(self):
|
|
import __main__
|
|
W.EditText.open(self)
|
|
self.write('Python %s\n' % sys.version)
|
|
self.write('Type "copyright", "credits" or "license" for more information.\n')
|
|
self.write('MacPython IDE %s\n' % __main__.__version__)
|
|
self.write(sys.ps1)
|
|
self.flush()
|
|
|
|
def key(self, char, event):
|
|
(what, message, when, where, modifiers) = event
|
|
if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
|
|
if char not in Wkeys.navigationkeys:
|
|
self.checkselection()
|
|
if char == Wkeys.enterkey:
|
|
char = Wkeys.returnkey
|
|
selstart, selend = self.getselection()
|
|
if char == Wkeys.backspacekey:
|
|
if selstart <= (self._inputstart - (selstart <> selend)):
|
|
return
|
|
self.ted.WEKey(ord(char), modifiers)
|
|
if char not in Wkeys.navigationkeys:
|
|
self.changed = 1
|
|
if char not in Wkeys.scrollkeys:
|
|
self.selchanged = 1
|
|
self.updatescrollbars()
|
|
if char == Wkeys.returnkey:
|
|
text = self.get()[self._inputstart:selstart]
|
|
text = string.join(string.split(text, "\r"), "\n")
|
|
if hasattr(MacOS, 'EnableAppswitch'):
|
|
saveyield = MacOS.EnableAppswitch(0)
|
|
self._scriptDone = False
|
|
if sys.platform == "darwin":
|
|
# see identical construct in PyEdit.py
|
|
from threading import Thread
|
|
t = Thread(target=self._userCancelledMonitor,
|
|
name="UserCancelledMonitor")
|
|
t.start()
|
|
try:
|
|
self.pyinteractive.executeline(text, self, self._namespace)
|
|
finally:
|
|
self._scriptDone = True
|
|
if hasattr(MacOS, 'EnableAppswitch'):
|
|
MacOS.EnableAppswitch(saveyield)
|
|
selstart, selend = self.getselection()
|
|
self._inputstart = selstart
|
|
|
|
def _userCancelledMonitor(self):
|
|
# XXX duplicate code from PyEdit.py
|
|
import time, os
|
|
from signal import SIGINT
|
|
from Carbon import Evt
|
|
while not self._scriptDone:
|
|
if Evt.CheckEventQueueForUserCancel():
|
|
# Send a SIGINT signal to ourselves.
|
|
# This gets delivered to the main thread,
|
|
# cancelling the running script.
|
|
os.kill(os.getpid(), SIGINT)
|
|
break
|
|
time.sleep(0.25)
|
|
|
|
def domenu_save_as(self, *args):
|
|
filename = EasyDialogs.AskFileForSave(message='Save console text as:',
|
|
savedFileName='console.txt')
|
|
if not filename:
|
|
return
|
|
f = open(filename, 'wb')
|
|
f.write(self.get())
|
|
f.close()
|
|
MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
|
|
|
|
def write(self, text):
|
|
self._buf = self._buf + text
|
|
if '\n' in self._buf:
|
|
self.flush()
|
|
|
|
def flush(self):
|
|
stuff = string.split(self._buf, '\n')
|
|
stuff = string.join(stuff, '\r')
|
|
self.setselection_at_end()
|
|
try:
|
|
self.ted.WEInsert(stuff, None, None)
|
|
finally:
|
|
self._buf = ""
|
|
selstart, selend = self.getselection()
|
|
self._inputstart = selstart
|
|
self.ted.WEClearUndo()
|
|
self.updatescrollbars()
|
|
if self._parentwindow.wid.GetWindowPort().QDIsPortBuffered():
|
|
self._parentwindow.wid.GetWindowPort().QDFlushPortBuffer(None)
|
|
|
|
def selection_ok(self):
|
|
selstart, selend = self.getselection()
|
|
return not (selstart < self._inputstart or selend < self._inputstart)
|
|
|
|
def checkselection(self):
|
|
if not self.selection_ok():
|
|
self.setselection_at_end()
|
|
|
|
def setselection_at_end(self):
|
|
end = self.ted.WEGetTextLength()
|
|
self.setselection(end, end)
|
|
self.updatescrollbars()
|
|
|
|
def domenu_cut(self, *args):
|
|
if not self.selection_ok():
|
|
return
|
|
W.EditText.domenu_cut(self)
|
|
|
|
def domenu_paste(self, *args):
|
|
if not self.selection_ok():
|
|
self.setselection_at_end()
|
|
W.EditText.domenu_paste(self)
|
|
|
|
def domenu_clear(self, *args):
|
|
if not self.selection_ok():
|
|
return
|
|
W.EditText.domenu_clear(self)
|
|
|
|
|
|
class PyConsole(W.Window):
|
|
|
|
def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
|
|
tabsettings = (32, 0), unclosable = 0):
|
|
W.Window.__init__(self,
|
|
bounds,
|
|
"Python Interactive",
|
|
minsize = (200, 100),
|
|
tabbable = 0,
|
|
show = show)
|
|
|
|
self._unclosable = unclosable
|
|
consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
|
|
fontsettings = fontsettings, tabsettings = tabsettings)
|
|
self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
|
|
self.consoletext = consoletext
|
|
self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
|
|
self.namespacemenu.bind('<click>', self.makenamespacemenu)
|
|
self.open()
|
|
|
|
def makenamespacemenu(self, *args):
|
|
W.SetCursor('watch')
|
|
namespacelist = self.getnamespacelist()
|
|
self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
|
|
["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
|
|
currentname = self.consoletext._namespace["__name__"]
|
|
for i in range(len(namespacelist)):
|
|
if namespacelist[i][0] == currentname:
|
|
break
|
|
else:
|
|
return
|
|
# XXX this functionality should be generally available in Wmenus
|
|
submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
|
|
menu = self.namespacemenu.menu.bar.menus[submenuid]
|
|
menu.menu.CheckMenuItem(i + 1, 1)
|
|
|
|
def browsenamespace(self):
|
|
import PyBrowser, W
|
|
W.SetCursor('watch')
|
|
PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
|
|
|
|
def clearbuffer(self):
|
|
from Carbon import Res
|
|
self.consoletext.ted.WEUseText(Res.Resource(''))
|
|
self.consoletext.write(sys.ps1)
|
|
self.consoletext.flush()
|
|
|
|
def getnamespacelist(self):
|
|
import os
|
|
import __main__
|
|
editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
|
|
|
|
namespaces = [ ("__main__",__main__.__dict__) ]
|
|
for ed in editors:
|
|
modname = os.path.splitext(ed.title)[0]
|
|
if sys.modules.has_key(modname):
|
|
module = sys.modules[modname]
|
|
namespaces.append((modname, module.__dict__))
|
|
else:
|
|
if ed.title[-3:] == '.py':
|
|
modname = ed.title[:-3]
|
|
else:
|
|
modname = ed.title
|
|
ed.globals["__name__"] = modname
|
|
namespaces.append((modname, ed.globals))
|
|
return namespaces
|
|
|
|
def dofontsettings(self):
|
|
import FontSettings
|
|
settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
|
|
self.consoletext.gettabsettings())
|
|
if settings:
|
|
fontsettings, tabsettings = settings
|
|
self.consoletext.setfontsettings(fontsettings)
|
|
self.consoletext.settabsettings(tabsettings)
|
|
|
|
def show(self, onoff = 1):
|
|
W.Window.show(self, onoff)
|
|
if onoff:
|
|
self.select()
|
|
|
|
def close(self):
|
|
if self._unclosable:
|
|
self.show(0)
|
|
return -1
|
|
W.Window.close(self)
|
|
|
|
def writeprefs(self):
|
|
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
|
|
prefs.console.show = self.isvisible()
|
|
prefs.console.windowbounds = self.getbounds()
|
|
prefs.console.fontsettings = self.consoletext.getfontsettings()
|
|
prefs.console.tabsettings = self.consoletext.gettabsettings()
|
|
prefs.save()
|
|
|
|
def getselectedtext(self):
|
|
return self.consoletext.getselectedtext()
|
|
|
|
class OutputTextWidget(W.EditText):
|
|
|
|
def domenu_save_as(self, *args):
|
|
title = self._parentwindow.gettitle()
|
|
filename = EasyDialogs.AskFileForSave(message='Save %s text as:' % title,
|
|
savedFileName=title + '.txt')
|
|
if not filename:
|
|
return
|
|
f = open(filename, 'wb')
|
|
f.write(self.get())
|
|
f.close()
|
|
MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
|
|
|
|
def domenu_cut(self, *args):
|
|
self.domenu_copy(*args)
|
|
|
|
def domenu_clear(self, *args):
|
|
self.set('')
|
|
|
|
|
|
class PyOutput:
|
|
|
|
def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
|
|
self.bounds = bounds
|
|
self.fontsettings = fontsettings
|
|
self.tabsettings = tabsettings
|
|
self.w = None
|
|
self.closed = 1
|
|
self._buf = ''
|
|
# should be able to set this
|
|
self.savestdout, self.savestderr = sys.stdout, sys.stderr
|
|
sys.stderr = sys.stdout = self
|
|
if show:
|
|
self.show()
|
|
|
|
def setupwidgets(self):
|
|
self.w = W.Window(self.bounds, "Output",
|
|
minsize = (200, 100),
|
|
tabbable = 0)
|
|
self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
|
|
fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
|
|
menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
|
|
self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
|
|
|
|
self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
|
|
self.w.bind("<close>", self.close)
|
|
self.w.bind("<activate>", self.activate)
|
|
|
|
def write(self, text):
|
|
if hasattr(MacOS, 'EnableAppswitch'):
|
|
oldyield = MacOS.EnableAppswitch(-1)
|
|
try:
|
|
self._buf = self._buf + text
|
|
if '\n' in self._buf:
|
|
self.flush()
|
|
finally:
|
|
if hasattr(MacOS, 'EnableAppswitch'):
|
|
MacOS.EnableAppswitch(oldyield)
|
|
|
|
def flush(self):
|
|
self.show()
|
|
stuff = string.split(self._buf, '\n')
|
|
stuff = string.join(stuff, '\r')
|
|
end = self.w.outputtext.ted.WEGetTextLength()
|
|
self.w.outputtext.setselection(end, end)
|
|
self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
|
|
try:
|
|
self.w.outputtext.ted.WEInsert(stuff, None, None)
|
|
finally:
|
|
self._buf = ""
|
|
self.w.outputtext.updatescrollbars()
|
|
self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
|
|
if self.w.wid.GetWindowPort().QDIsPortBuffered():
|
|
self.w.wid.GetWindowPort().QDFlushPortBuffer(None)
|
|
|
|
def show(self):
|
|
if self.closed:
|
|
if not self.w:
|
|
self.setupwidgets()
|
|
self.w.open()
|
|
self.w.outputtext.updatescrollbars()
|
|
self.closed = 0
|
|
else:
|
|
self.w.show(1)
|
|
self.closed = 0
|
|
self.w.select()
|
|
|
|
def writeprefs(self):
|
|
if self.w is not None:
|
|
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
|
|
prefs.output.show = self.w.isvisible()
|
|
prefs.output.windowbounds = self.w.getbounds()
|
|
prefs.output.fontsettings = self.w.outputtext.getfontsettings()
|
|
prefs.output.tabsettings = self.w.outputtext.gettabsettings()
|
|
prefs.save()
|
|
|
|
def dofontsettings(self):
|
|
import FontSettings
|
|
settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
|
|
self.w.outputtext.gettabsettings())
|
|
if settings:
|
|
fontsettings, tabsettings = settings
|
|
self.w.outputtext.setfontsettings(fontsettings)
|
|
self.w.outputtext.settabsettings(tabsettings)
|
|
|
|
def clearbuffer(self):
|
|
from Carbon import Res
|
|
self.w.outputtext.set('')
|
|
|
|
def activate(self, onoff):
|
|
if onoff:
|
|
self.closed = 0
|
|
|
|
def close(self):
|
|
self.w.show(0)
|
|
self.closed = 1
|
|
return -1
|
|
|
|
|
|
class SimpleStdin:
|
|
|
|
def readline(self):
|
|
import EasyDialogs
|
|
# A trick to make the input dialog box a bit more palatable
|
|
if hasattr(sys.stdout, '_buf'):
|
|
prompt = sys.stdout._buf
|
|
else:
|
|
prompt = ""
|
|
if not prompt:
|
|
prompt = "Stdin input:"
|
|
sys.stdout.flush()
|
|
rv = EasyDialogs.AskString(prompt)
|
|
if rv is None:
|
|
return ""
|
|
rv = rv + "\n" # readline should include line terminator
|
|
sys.stdout.write(rv) # echo user's reply
|
|
return rv
|
|
|
|
|
|
def installconsole(defaultshow = 1):
|
|
global console
|
|
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
|
|
if not prefs.console or not hasattr(prefs.console, 'show'):
|
|
prefs.console.show = defaultshow
|
|
if not hasattr(prefs.console, "windowbounds"):
|
|
prefs.console.windowbounds = (450, 250)
|
|
if not hasattr(prefs.console, "fontsettings"):
|
|
prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
|
|
if not hasattr(prefs.console, "tabsettings"):
|
|
prefs.console.tabsettings = (32, 0)
|
|
console = PyConsole(prefs.console.windowbounds, prefs.console.show,
|
|
prefs.console.fontsettings, prefs.console.tabsettings, 1)
|
|
|
|
def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
|
|
global output
|
|
|
|
# quick 'n' dirty std in emulation
|
|
sys.stdin = SimpleStdin()
|
|
|
|
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
|
|
if not prefs.output or not hasattr(prefs.output, 'show'):
|
|
prefs.output.show = defaultshow
|
|
if not hasattr(prefs.output, "windowbounds"):
|
|
prefs.output.windowbounds = (450, 250)
|
|
if not hasattr(prefs.output, "fontsettings"):
|
|
prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
|
|
if not hasattr(prefs.output, "tabsettings"):
|
|
prefs.output.tabsettings = (32, 0)
|
|
output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
|
|
prefs.output.fontsettings, prefs.output.tabsettings)
|