Update for release.
[python/dscho.git] / Mac / Tools / IDE / PyConsole.py
blob27fc0cdf9dea132baea3d9472e29055df7656aa0
1 import W
2 import Wkeys
3 from Carbon import Fm
4 import WASTEconst
5 from types import *
6 from Carbon import Events
7 import string
8 import sys
9 import traceback
10 import MacOS
11 import MacPrefs
12 from Carbon import Qd
13 import EasyDialogs
14 import PyInteractive
16 if not hasattr(sys, 'ps1'):
17 sys.ps1 = '>>> '
18 if not hasattr(sys, 'ps2'):
19 sys.ps2 = '... '
21 def inspect(foo): # JJS 1/25/99
22 "Launch the browser on the given object. This is a general built-in function."
23 import PyBrowser
24 PyBrowser.Browser(foo)
26 class ConsoleTextWidget(W.EditText):
28 def __init__(self, *args, **kwargs):
29 apply(W.EditText.__init__, (self,) + args, kwargs)
30 self._inputstart = 0
31 self._buf = ''
32 self.pyinteractive = PyInteractive.PyInteractive()
34 import __main__
35 self._namespace = __main__.__dict__
36 self._namespace['inspect'] = inspect # JJS 1/25/99
38 def insert(self, text):
39 self.checkselection()
40 self.ted.WEInsert(text, None, None)
41 self.changed = 1
42 self.selchanged = 1
44 def set_namespace(self, dict):
45 if type(dict) <> DictionaryType:
46 raise TypeError, "The namespace needs to be a dictionary"
47 if 'inspect' not in dict.keys(): dict['inspect'] = inspect # JJS 1/25/99
48 self._namespace = dict
50 def open(self):
51 import __main__
52 W.EditText.open(self)
53 self.write('Python %s\n' % sys.version)
54 self.write('Type "copyright", "credits" or "license" for more information.\n')
55 self.write('MacPython IDE %s\n' % __main__.__version__)
56 self.write(sys.ps1)
57 self.flush()
59 def key(self, char, event):
60 (what, message, when, where, modifiers) = event
61 if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
62 if char not in Wkeys.navigationkeys:
63 self.checkselection()
64 if char == Wkeys.enterkey:
65 char = Wkeys.returnkey
66 selstart, selend = self.getselection()
67 if char == Wkeys.backspacekey:
68 if selstart <= (self._inputstart - (selstart <> selend)):
69 return
70 self.ted.WEKey(ord(char), modifiers)
71 if char not in Wkeys.navigationkeys:
72 self.changed = 1
73 if char not in Wkeys.scrollkeys:
74 self.selchanged = 1
75 self.updatescrollbars()
76 if char == Wkeys.returnkey:
77 text = self.get()[self._inputstart:selstart]
78 text = string.join(string.split(text, "\r"), "\n")
79 if hasattr(MacOS, 'EnableAppswitch'):
80 saveyield = MacOS.EnableAppswitch(0)
81 self.pyinteractive.executeline(text, self, self._namespace)
82 if hasattr(MacOS, 'EnableAppswitch'):
83 MacOS.EnableAppswitch(saveyield)
84 selstart, selend = self.getselection()
85 self._inputstart = selstart
87 def domenu_save_as(self, *args):
88 import macfs
89 filename = EasyDialogs.AskFileForSave(message='Save console text as:',
90 savedFileName='console.txt')
91 if not filename:
92 return
93 f = open(filename, 'wb')
94 f.write(self.get())
95 f.close()
96 fss.SetCreatorType(W._signature, 'TEXT')
98 def write(self, text):
99 self._buf = self._buf + text
100 if '\n' in self._buf:
101 self.flush()
103 def flush(self):
104 stuff = string.split(self._buf, '\n')
105 stuff = string.join(stuff, '\r')
106 self.setselection_at_end()
107 self.ted.WEInsert(stuff, None, None)
108 selstart, selend = self.getselection()
109 self._inputstart = selstart
110 self._buf = ""
111 self.ted.WEClearUndo()
112 self.updatescrollbars()
113 if self._parentwindow.wid.GetWindowPort().QDIsPortBuffered():
114 self._parentwindow.wid.GetWindowPort().QDFlushPortBuffer(None)
116 def selection_ok(self):
117 selstart, selend = self.getselection()
118 return not (selstart < self._inputstart or selend < self._inputstart)
120 def checkselection(self):
121 if not self.selection_ok():
122 self.setselection_at_end()
124 def setselection_at_end(self):
125 end = self.ted.WEGetTextLength()
126 self.setselection(end, end)
127 self.updatescrollbars()
129 def domenu_cut(self, *args):
130 if not self.selection_ok():
131 return
132 W.EditText.domenu_cut(self)
134 def domenu_paste(self, *args):
135 if not self.selection_ok():
136 self.setselection_at_end()
137 W.EditText.domenu_paste(self)
139 def domenu_clear(self, *args):
140 if not self.selection_ok():
141 return
142 W.EditText.domenu_clear(self)
145 class PyConsole(W.Window):
147 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
148 tabsettings = (32, 0), unclosable = 0):
149 W.Window.__init__(self,
150 bounds,
151 "Python Interactive",
152 minsize = (200, 100),
153 tabbable = 0,
154 show = show)
156 self._unclosable = unclosable
157 consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
158 fontsettings = fontsettings, tabsettings = tabsettings)
159 self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
160 self.consoletext = consoletext
161 self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
162 self.namespacemenu.bind('<click>', self.makenamespacemenu)
163 self.open()
165 def makenamespacemenu(self, *args):
166 W.SetCursor('watch')
167 namespacelist = self.getnamespacelist()
168 self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
169 ["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
170 currentname = self.consoletext._namespace["__name__"]
171 for i in range(len(namespacelist)):
172 if namespacelist[i][0] == currentname:
173 break
174 else:
175 return
176 # XXX this functionality should be generally available in Wmenus
177 submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
178 menu = self.namespacemenu.menu.bar.menus[submenuid]
179 menu.menu.CheckMenuItem(i + 1, 1)
181 def browsenamespace(self):
182 import PyBrowser, W
183 W.SetCursor('watch')
184 PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
186 def clearbuffer(self):
187 from Carbon import Res
188 self.consoletext.ted.WEUseText(Res.Resource(''))
189 self.consoletext.write(sys.ps1)
190 self.consoletext.flush()
192 def getnamespacelist(self):
193 import os
194 import __main__
195 editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
197 namespaces = [ ("__main__",__main__.__dict__) ]
198 for ed in editors:
199 modname = os.path.splitext(ed.title)[0]
200 if sys.modules.has_key(modname):
201 module = sys.modules[modname]
202 namespaces.append((modname, module.__dict__))
203 else:
204 if ed.title[-3:] == '.py':
205 modname = ed.title[:-3]
206 else:
207 modname = ed.title
208 ed.globals["__name__"] = modname
209 namespaces.append((modname, ed.globals))
210 return namespaces
212 def dofontsettings(self):
213 import FontSettings
214 settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
215 self.consoletext.gettabsettings())
216 if settings:
217 fontsettings, tabsettings = settings
218 self.consoletext.setfontsettings(fontsettings)
219 self.consoletext.settabsettings(tabsettings)
221 def show(self, onoff = 1):
222 W.Window.show(self, onoff)
223 if onoff:
224 self.select()
226 def close(self):
227 if self._unclosable:
228 self.show(0)
229 return -1
230 W.Window.close(self)
232 def writeprefs(self):
233 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
234 prefs.console.show = self.isvisible()
235 prefs.console.windowbounds = self.getbounds()
236 prefs.console.fontsettings = self.consoletext.getfontsettings()
237 prefs.console.tabsettings = self.consoletext.gettabsettings()
238 prefs.save()
241 class OutputTextWidget(W.EditText):
243 def domenu_save_as(self, *args):
244 title = self._parentwindow.gettitle()
245 import macfs
246 filename = EasyDialogs.AskFileForSave(message='Save %s text as:' % title,
247 savedFileName=title + '.txt')
248 if not filename:
249 return
250 f = open(filename, 'wb')
251 f.write(self.get())
252 f.close()
253 fss.SetCreatorType(W._signature, 'TEXT')
255 def domenu_cut(self, *args):
256 self.domenu_copy(*args)
258 def domenu_clear(self, *args):
259 self.set('')
262 class PyOutput:
264 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
265 self.bounds = bounds
266 self.fontsettings = fontsettings
267 self.tabsettings = tabsettings
268 self.w = None
269 self.closed = 1
270 self._buf = ''
271 # should be able to set this
272 self.savestdout, self.savestderr = sys.stdout, sys.stderr
273 sys.stderr = sys.stdout = self
274 if show:
275 self.show()
277 def setupwidgets(self):
278 self.w = W.Window(self.bounds, "Output",
279 minsize = (200, 100),
280 tabbable = 0)
281 self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
282 fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
283 menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
284 self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
286 self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
287 self.w.bind("<close>", self.close)
288 self.w.bind("<activate>", self.activate)
290 def write(self, text):
291 if hasattr(MacOS, 'EnableAppswitch'):
292 oldyield = MacOS.EnableAppswitch(-1)
293 try:
294 self._buf = self._buf + text
295 if '\n' in self._buf:
296 self.flush()
297 finally:
298 if hasattr(MacOS, 'EnableAppswitch'):
299 MacOS.EnableAppswitch(oldyield)
301 def flush(self):
302 self.show()
303 stuff = string.split(self._buf, '\n')
304 stuff = string.join(stuff, '\r')
305 end = self.w.outputtext.ted.WEGetTextLength()
306 self.w.outputtext.setselection(end, end)
307 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
308 self.w.outputtext.ted.WEInsert(stuff, None, None)
309 self._buf = ""
310 self.w.outputtext.updatescrollbars()
311 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
312 if self.w.wid.GetWindowPort().QDIsPortBuffered():
313 self.w.wid.GetWindowPort().QDFlushPortBuffer(None)
315 def show(self):
316 if self.closed:
317 if not self.w:
318 self.setupwidgets()
319 self.w.open()
320 self.w.outputtext.updatescrollbars()
321 self.closed = 0
322 else:
323 self.w.show(1)
324 self.closed = 0
325 self.w.select()
327 def writeprefs(self):
328 if self.w is not None:
329 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
330 prefs.output.show = self.w.isvisible()
331 prefs.output.windowbounds = self.w.getbounds()
332 prefs.output.fontsettings = self.w.outputtext.getfontsettings()
333 prefs.output.tabsettings = self.w.outputtext.gettabsettings()
334 prefs.save()
336 def dofontsettings(self):
337 import FontSettings
338 settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
339 self.w.outputtext.gettabsettings())
340 if settings:
341 fontsettings, tabsettings = settings
342 self.w.outputtext.setfontsettings(fontsettings)
343 self.w.outputtext.settabsettings(tabsettings)
345 def clearbuffer(self):
346 from Carbon import Res
347 self.w.outputtext.set('')
349 def activate(self, onoff):
350 if onoff:
351 self.closed = 0
353 def close(self):
354 self.w.show(0)
355 self.closed = 1
356 return -1
359 class SimpleStdin:
361 def readline(self):
362 import EasyDialogs
363 # A trick to make the input dialog box a bit more palatable
364 if hasattr(sys.stdout, '_buf'):
365 prompt = sys.stdout._buf
366 else:
367 prompt = ""
368 if not prompt:
369 prompt = "Stdin input:"
370 sys.stdout.flush()
371 rv = EasyDialogs.AskString(prompt)
372 if rv is None:
373 return ""
374 rv = rv + "\n" # readline should include line terminator
375 sys.stdout.write(rv) # echo user's reply
376 return rv
379 def installconsole(defaultshow = 1):
380 global console
381 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
382 if not prefs.console or not hasattr(prefs.console, 'show'):
383 prefs.console.show = defaultshow
384 if not hasattr(prefs.console, "windowbounds"):
385 prefs.console.windowbounds = (450, 250)
386 if not hasattr(prefs.console, "fontsettings"):
387 prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
388 if not hasattr(prefs.console, "tabsettings"):
389 prefs.console.tabsettings = (32, 0)
390 console = PyConsole(prefs.console.windowbounds, prefs.console.show,
391 prefs.console.fontsettings, prefs.console.tabsettings, 1)
393 def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
394 global output
396 # quick 'n' dirty std in emulation
397 sys.stdin = SimpleStdin()
399 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
400 if not prefs.output or not hasattr(prefs.output, 'show'):
401 prefs.output.show = defaultshow
402 if not hasattr(prefs.output, "windowbounds"):
403 prefs.output.windowbounds = (450, 250)
404 if not hasattr(prefs.output, "fontsettings"):
405 prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
406 if not hasattr(prefs.output, "tabsettings"):
407 prefs.output.tabsettings = (32, 0)
408 output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
409 prefs.output.fontsettings, prefs.output.tabsettings)