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