py-cvs-rel2_1 (Rev 1.2) merge
[python/dscho.git] / Mac / Tools / IDE / PyConsole.py
blob4c3278544e0379257f0be096d609062f93652006
1 import W
2 import Wkeys
3 import Fm
4 import WASTEconst
5 from types import *
6 import Events
7 import string
8 import sys
9 import traceback
10 import MacOS
11 import MacPrefs
12 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 W.EditText.open(self)
51 self.write('Python ' + sys.version + '\nType "copyright", "credits" or "license" for more information.\n')
52 self.write(sys.ps1)
53 self.flush()
55 def key(self, char, event):
56 (what, message, when, where, modifiers) = event
57 if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
58 if char not in Wkeys.navigationkeys:
59 self.checkselection()
60 if char == Wkeys.enterkey:
61 char = Wkeys.returnkey
62 selstart, selend = self.getselection()
63 if char == Wkeys.backspacekey:
64 if selstart <= (self._inputstart - (selstart <> selend)):
65 return
66 self.ted.WEKey(ord(char), modifiers)
67 if char not in Wkeys.navigationkeys:
68 self.changed = 1
69 if char not in Wkeys.scrollkeys:
70 self.selchanged = 1
71 self.updatescrollbars()
72 if char == Wkeys.returnkey:
73 text = self.get()[self._inputstart:selstart]
74 text = string.join(string.split(text, "\r"), "\n")
75 saveyield = MacOS.EnableAppswitch(0)
76 self.pyinteractive.executeline(text, self, self._namespace)
77 MacOS.EnableAppswitch(saveyield)
78 selstart, selend = self.getselection()
79 self._inputstart = selstart
81 def domenu_save_as(self, *args):
82 import macfs
83 fss, ok = macfs.StandardPutFile('Save console text as:', 'console.txt')
84 if not ok:
85 return
86 f = open(fss.as_pathname(), 'wb')
87 f.write(self.get())
88 f.close()
89 fss.SetCreatorType(W._signature, 'TEXT')
91 def write(self, text):
92 self._buf = self._buf + text
93 if '\n' in self._buf:
94 self.flush()
96 def flush(self):
97 stuff = string.split(self._buf, '\n')
98 stuff = string.join(stuff, '\r')
99 self.setselection_at_end()
100 self.ted.WEInsert(stuff, None, None)
101 selstart, selend = self.getselection()
102 self._inputstart = selstart
103 self._buf = ""
104 self.ted.WEClearUndo()
105 self.updatescrollbars()
107 def selection_ok(self):
108 selstart, selend = self.getselection()
109 return not (selstart < self._inputstart or selend < self._inputstart)
111 def checkselection(self):
112 if not self.selection_ok():
113 self.setselection_at_end()
115 def setselection_at_end(self):
116 end = self.ted.WEGetTextLength()
117 self.setselection(end, end)
118 self.updatescrollbars()
120 def domenu_cut(self, *args):
121 if not self.selection_ok():
122 return
123 W.EditText.domenu_cut(self)
125 def domenu_paste(self, *args):
126 if not self.selection_ok():
127 self.setselection_at_end()
128 W.EditText.domenu_paste(self)
130 def domenu_clear(self, *args):
131 if not self.selection_ok():
132 return
133 W.EditText.domenu_clear(self)
136 class PyConsole(W.Window):
138 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
139 tabsettings = (32, 0), unclosable = 0):
140 W.Window.__init__(self,
141 bounds,
142 "Python Interactive",
143 minsize = (200, 100),
144 tabbable = 0,
145 show = show)
147 self._unclosable = unclosable
148 consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
149 fontsettings = fontsettings, tabsettings = tabsettings)
150 self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
151 self.consoletext = consoletext
152 self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
153 self.namespacemenu.bind('<click>', self.makenamespacemenu)
154 self.open()
156 def makenamespacemenu(self, *args):
157 W.SetCursor('watch')
158 namespacelist = self.getnamespacelist()
159 self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
160 ["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
161 currentname = self.consoletext._namespace["__name__"]
162 for i in range(len(namespacelist)):
163 if namespacelist[i][0] == currentname:
164 break
165 else:
166 return
167 # XXX this functionality should be generally available in Wmenus
168 submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
169 menu = self.namespacemenu.menu.bar.menus[submenuid]
170 menu.menu.CheckMenuItem(i + 1, 1)
172 def browsenamespace(self):
173 import PyBrowser, W
174 W.SetCursor('watch')
175 PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
177 def clearbuffer(self):
178 import Res
179 self.consoletext.ted.WEUseText(Res.Resource(''))
180 self.consoletext.write(sys.ps1)
181 self.consoletext.flush()
183 def getnamespacelist(self):
184 import os
185 import __main__
186 editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
188 namespaces = [ ("__main__",__main__.__dict__) ]
189 for ed in editors:
190 modname = os.path.splitext(ed.title)[0]
191 if sys.modules.has_key(modname):
192 module = sys.modules[modname]
193 namespaces.append((modname, module.__dict__))
194 else:
195 if ed.title[-3:] == '.py':
196 modname = ed.title[:-3]
197 else:
198 modname = ed.title
199 ed.globals["__name__"] = modname
200 namespaces.append((modname, ed.globals))
201 return namespaces
203 def dofontsettings(self):
204 import FontSettings
205 settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
206 self.consoletext.gettabsettings())
207 if settings:
208 fontsettings, tabsettings = settings
209 self.consoletext.setfontsettings(fontsettings)
210 self.consoletext.settabsettings(tabsettings)
212 def show(self, onoff = 1):
213 W.Window.show(self, onoff)
214 if onoff:
215 self.select()
217 def close(self):
218 if self._unclosable:
219 self.show(0)
220 return -1
221 W.Window.close(self)
223 def writeprefs(self):
224 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
225 prefs.console.show = self.isvisible()
226 prefs.console.windowbounds = self.getbounds()
227 prefs.console.fontsettings = self.consoletext.getfontsettings()
228 prefs.console.tabsettings = self.consoletext.gettabsettings()
229 prefs.save()
232 class OutputTextWidget(W.EditText):
234 def domenu_save_as(self, *args):
235 title = self._parentwindow.gettitle()
236 import macfs
237 fss, ok = macfs.StandardPutFile('Save %s text as:' % title, title + '.txt')
238 if not ok:
239 return
240 f = open(fss.as_pathname(), 'wb')
241 f.write(self.get())
242 f.close()
243 fss.SetCreatorType(W._signature, 'TEXT')
246 class PyOutput:
248 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
249 self.bounds = bounds
250 self.fontsettings = fontsettings
251 self.tabsettings = tabsettings
252 self.w = None
253 self.closed = 1
254 self._buf = ''
255 # should be able to set this
256 self.savestdout, self.savestderr = sys.stdout, sys.stderr
257 sys.stderr = sys.stdout = self
258 if show:
259 self.show()
261 def setupwidgets(self):
262 self.w = W.Window(self.bounds, "Output",
263 minsize = (200, 100),
264 tabbable = 0)
265 self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
266 fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
267 menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
268 self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
270 self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
271 self.w.bind("<close>", self.close)
272 self.w.bind("<activate>", self.activate)
274 def write(self, text):
275 oldyield = MacOS.EnableAppswitch(-1)
276 try:
277 self._buf = self._buf + text
278 if '\n' in self._buf:
279 self.flush()
280 finally:
281 MacOS.EnableAppswitch(oldyield)
283 def flush(self):
284 self.show()
285 stuff = string.split(self._buf, '\n')
286 stuff = string.join(stuff, '\r')
287 end = self.w.outputtext.ted.WEGetTextLength()
288 self.w.outputtext.setselection(end, end)
289 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
290 self.w.outputtext.ted.WEInsert(stuff, None, None)
291 self._buf = ""
292 self.w.outputtext.updatescrollbars()
293 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
295 def show(self):
296 if self.closed:
297 if not self.w:
298 self.setupwidgets()
299 self.w.open()
300 self.w.outputtext.updatescrollbars()
301 self.closed = 0
302 else:
303 self.w.show(1)
304 self.closed = 0
305 self.w.select()
307 def writeprefs(self):
308 if self.w is not None:
309 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
310 prefs.output.show = self.w.isvisible()
311 prefs.output.windowbounds = self.w.getbounds()
312 prefs.output.fontsettings = self.w.outputtext.getfontsettings()
313 prefs.output.tabsettings = self.w.outputtext.gettabsettings()
314 prefs.save()
316 def dofontsettings(self):
317 import FontSettings
318 settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
319 self.w.outputtext.gettabsettings())
320 if settings:
321 fontsettings, tabsettings = settings
322 self.w.outputtext.setfontsettings(fontsettings)
323 self.w.outputtext.settabsettings(tabsettings)
325 def clearbuffer(self):
326 import Res
327 self.w.outputtext.set('')
329 def activate(self, onoff):
330 if onoff:
331 self.closed = 0
333 def close(self):
334 self.w.show(0)
335 self.closed = 1
336 return -1
339 class SimpleStdin:
341 def readline(self):
342 import EasyDialogs
343 # A trick to make the input dialog box a bit more palatable
344 if hasattr(sys.stdout, '_buf'):
345 prompt = sys.stdout._buf
346 else:
347 prompt = ""
348 if not prompt:
349 prompt = "Stdin input:"
350 sys.stdout.flush()
351 rv = EasyDialogs.AskString(prompt)
352 if rv is None:
353 return ""
354 return rv + '\n'
357 def installconsole(defaultshow = 1):
358 global console
359 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
360 if not prefs.console or not hasattr(prefs.console, 'show'):
361 prefs.console.show = defaultshow
362 if not hasattr(prefs.console, "windowbounds"):
363 prefs.console.windowbounds = (450, 250)
364 if not hasattr(prefs.console, "fontsettings"):
365 prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
366 if not hasattr(prefs.console, "tabsettings"):
367 prefs.console.tabsettings = (32, 0)
368 console = PyConsole(prefs.console.windowbounds, prefs.console.show,
369 prefs.console.fontsettings, prefs.console.tabsettings, 1)
371 def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
372 global output
374 # quick 'n' dirty std in emulation
375 sys.stdin = SimpleStdin()
377 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
378 if not prefs.output or not hasattr(prefs.output, 'show'):
379 prefs.output.show = defaultshow
380 if not hasattr(prefs.output, "windowbounds"):
381 prefs.output.windowbounds = (450, 250)
382 if not hasattr(prefs.output, "fontsettings"):
383 prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
384 if not hasattr(prefs.output, "tabsettings"):
385 prefs.output.tabsettings = (32, 0)
386 output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
387 prefs.output.fontsettings, prefs.output.tabsettings)