blob: 2bad07df1b344471c9ea2e33749e149978c0565b [file] [log] [blame]
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001import W
2import Wkeys
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00003from Carbon import Fm
Just van Rossum40f9b7b1999-01-30 22:39:17 +00004import WASTEconst
5from types import *
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00006from Carbon import Events
Just van Rossum40f9b7b1999-01-30 22:39:17 +00007import string
8import sys
9import traceback
10import MacOS
11import MacPrefs
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000012from Carbon import Qd
Jack Jansenfd0b00e2003-01-26 22:15:48 +000013import EasyDialogs
Just van Rossum40f9b7b1999-01-30 22:39:17 +000014import PyInteractive
15
16if not hasattr(sys, 'ps1'):
17 sys.ps1 = '>>> '
18if not hasattr(sys, 'ps2'):
19 sys.ps2 = '... '
20
21def 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)
25
26class ConsoleTextWidget(W.EditText):
27
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()
33
34 import __main__
35 self._namespace = __main__.__dict__
36 self._namespace['inspect'] = inspect # JJS 1/25/99
37
38 def insert(self, text):
39 self.checkselection()
40 self.ted.WEInsert(text, None, None)
41 self.changed = 1
42 self.selchanged = 1
43
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
49
50 def open(self):
Just van Rossume6e745f2001-08-06 11:12:18 +000051 import __main__
Just van Rossum40f9b7b1999-01-30 22:39:17 +000052 W.EditText.open(self)
Just van Rossume6e745f2001-08-06 11:12:18 +000053 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__)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000056 self.write(sys.ps1)
57 self.flush()
58
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")
Jack Jansen815d2bf2002-01-21 23:00:52 +000079 if hasattr(MacOS, 'EnableAppswitch'):
80 saveyield = MacOS.EnableAppswitch(0)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000081 self.pyinteractive.executeline(text, self, self._namespace)
Jack Jansen815d2bf2002-01-21 23:00:52 +000082 if hasattr(MacOS, 'EnableAppswitch'):
83 MacOS.EnableAppswitch(saveyield)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000084 selstart, selend = self.getselection()
85 self._inputstart = selstart
86
87 def domenu_save_as(self, *args):
Jack Jansenfd0b00e2003-01-26 22:15:48 +000088 filename = EasyDialogs.AskFileForSave(message='Save console text as:',
89 savedFileName='console.txt')
90 if not filename:
Just van Rossum40f9b7b1999-01-30 22:39:17 +000091 return
Jack Jansenfd0b00e2003-01-26 22:15:48 +000092 f = open(filename, 'wb')
Just van Rossum40f9b7b1999-01-30 22:39:17 +000093 f.write(self.get())
94 f.close()
Jack Jansene7ee17c2003-02-06 22:32:35 +000095 MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
Just van Rossum40f9b7b1999-01-30 22:39:17 +000096
97 def write(self, text):
98 self._buf = self._buf + text
99 if '\n' in self._buf:
100 self.flush()
101
102 def flush(self):
103 stuff = string.split(self._buf, '\n')
104 stuff = string.join(stuff, '\r')
105 self.setselection_at_end()
106 self.ted.WEInsert(stuff, None, None)
107 selstart, selend = self.getselection()
108 self._inputstart = selstart
109 self._buf = ""
110 self.ted.WEClearUndo()
111 self.updatescrollbars()
Jack Jansen362c7cd2002-11-30 00:01:29 +0000112 if self._parentwindow.wid.GetWindowPort().QDIsPortBuffered():
113 self._parentwindow.wid.GetWindowPort().QDFlushPortBuffer(None)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000114
115 def selection_ok(self):
116 selstart, selend = self.getselection()
117 return not (selstart < self._inputstart or selend < self._inputstart)
118
119 def checkselection(self):
120 if not self.selection_ok():
121 self.setselection_at_end()
122
123 def setselection_at_end(self):
124 end = self.ted.WEGetTextLength()
125 self.setselection(end, end)
126 self.updatescrollbars()
127
128 def domenu_cut(self, *args):
129 if not self.selection_ok():
130 return
131 W.EditText.domenu_cut(self)
132
133 def domenu_paste(self, *args):
134 if not self.selection_ok():
135 self.setselection_at_end()
136 W.EditText.domenu_paste(self)
137
138 def domenu_clear(self, *args):
139 if not self.selection_ok():
140 return
141 W.EditText.domenu_clear(self)
142
143
144class PyConsole(W.Window):
145
146 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
147 tabsettings = (32, 0), unclosable = 0):
148 W.Window.__init__(self,
149 bounds,
150 "Python Interactive",
151 minsize = (200, 100),
152 tabbable = 0,
153 show = show)
154
155 self._unclosable = unclosable
156 consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
157 fontsettings = fontsettings, tabsettings = tabsettings)
158 self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
159 self.consoletext = consoletext
160 self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
161 self.namespacemenu.bind('<click>', self.makenamespacemenu)
162 self.open()
163
164 def makenamespacemenu(self, *args):
165 W.SetCursor('watch')
166 namespacelist = self.getnamespacelist()
Just van Rossumdc3c6172001-06-19 21:37:33 +0000167 self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
168 ["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000169 currentname = self.consoletext._namespace["__name__"]
170 for i in range(len(namespacelist)):
171 if namespacelist[i][0] == currentname:
172 break
173 else:
174 return
175 # XXX this functionality should be generally available in Wmenus
176 submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
177 menu = self.namespacemenu.menu.bar.menus[submenuid]
Jack Jansenafd0aa62001-01-29 13:29:47 +0000178 menu.menu.CheckMenuItem(i + 1, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000179
180 def browsenamespace(self):
181 import PyBrowser, W
182 W.SetCursor('watch')
183 PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
184
185 def clearbuffer(self):
Jack Jansen5a6fdcd2001-08-25 12:15:04 +0000186 from Carbon import Res
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000187 self.consoletext.ted.WEUseText(Res.Resource(''))
188 self.consoletext.write(sys.ps1)
189 self.consoletext.flush()
190
191 def getnamespacelist(self):
192 import os
193 import __main__
194 editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
195
196 namespaces = [ ("__main__",__main__.__dict__) ]
197 for ed in editors:
198 modname = os.path.splitext(ed.title)[0]
199 if sys.modules.has_key(modname):
200 module = sys.modules[modname]
201 namespaces.append((modname, module.__dict__))
202 else:
203 if ed.title[-3:] == '.py':
204 modname = ed.title[:-3]
205 else:
206 modname = ed.title
207 ed.globals["__name__"] = modname
208 namespaces.append((modname, ed.globals))
209 return namespaces
210
211 def dofontsettings(self):
212 import FontSettings
213 settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
214 self.consoletext.gettabsettings())
215 if settings:
216 fontsettings, tabsettings = settings
217 self.consoletext.setfontsettings(fontsettings)
218 self.consoletext.settabsettings(tabsettings)
219
220 def show(self, onoff = 1):
221 W.Window.show(self, onoff)
222 if onoff:
223 self.select()
224
225 def close(self):
226 if self._unclosable:
227 self.show(0)
228 return -1
229 W.Window.close(self)
230
231 def writeprefs(self):
232 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
233 prefs.console.show = self.isvisible()
234 prefs.console.windowbounds = self.getbounds()
235 prefs.console.fontsettings = self.consoletext.getfontsettings()
236 prefs.console.tabsettings = self.consoletext.gettabsettings()
237 prefs.save()
238
239
240class OutputTextWidget(W.EditText):
241
242 def domenu_save_as(self, *args):
243 title = self._parentwindow.gettitle()
Jack Jansenfd0b00e2003-01-26 22:15:48 +0000244 filename = EasyDialogs.AskFileForSave(message='Save %s text as:' % title,
245 savedFileName=title + '.txt')
246 if not filename:
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000247 return
Jack Jansenfd0b00e2003-01-26 22:15:48 +0000248 f = open(filename, 'wb')
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000249 f.write(self.get())
250 f.close()
Jack Jansene7ee17c2003-02-06 22:32:35 +0000251 MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000252
Just van Rossum7a503a42003-01-20 09:02:23 +0000253 def domenu_cut(self, *args):
254 self.domenu_copy(*args)
255
256 def domenu_clear(self, *args):
257 self.set('')
258
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000259
260class PyOutput:
261
262 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
263 self.bounds = bounds
264 self.fontsettings = fontsettings
265 self.tabsettings = tabsettings
266 self.w = None
267 self.closed = 1
268 self._buf = ''
269 # should be able to set this
270 self.savestdout, self.savestderr = sys.stdout, sys.stderr
271 sys.stderr = sys.stdout = self
272 if show:
273 self.show()
274
275 def setupwidgets(self):
276 self.w = W.Window(self.bounds, "Output",
277 minsize = (200, 100),
278 tabbable = 0)
279 self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
280 fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
Just van Rossumdc3c6172001-06-19 21:37:33 +0000281 menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000282 self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
283
284 self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
285 self.w.bind("<close>", self.close)
286 self.w.bind("<activate>", self.activate)
287
288 def write(self, text):
Jack Jansen815d2bf2002-01-21 23:00:52 +0000289 if hasattr(MacOS, 'EnableAppswitch'):
290 oldyield = MacOS.EnableAppswitch(-1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000291 try:
292 self._buf = self._buf + text
293 if '\n' in self._buf:
294 self.flush()
295 finally:
Jack Jansen815d2bf2002-01-21 23:00:52 +0000296 if hasattr(MacOS, 'EnableAppswitch'):
297 MacOS.EnableAppswitch(oldyield)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000298
299 def flush(self):
300 self.show()
301 stuff = string.split(self._buf, '\n')
302 stuff = string.join(stuff, '\r')
303 end = self.w.outputtext.ted.WEGetTextLength()
304 self.w.outputtext.setselection(end, end)
305 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
306 self.w.outputtext.ted.WEInsert(stuff, None, None)
307 self._buf = ""
308 self.w.outputtext.updatescrollbars()
309 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
Jack Jansen362c7cd2002-11-30 00:01:29 +0000310 if self.w.wid.GetWindowPort().QDIsPortBuffered():
311 self.w.wid.GetWindowPort().QDFlushPortBuffer(None)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000312
313 def show(self):
314 if self.closed:
315 if not self.w:
316 self.setupwidgets()
317 self.w.open()
318 self.w.outputtext.updatescrollbars()
319 self.closed = 0
320 else:
321 self.w.show(1)
322 self.closed = 0
323 self.w.select()
324
325 def writeprefs(self):
326 if self.w is not None:
327 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
328 prefs.output.show = self.w.isvisible()
329 prefs.output.windowbounds = self.w.getbounds()
330 prefs.output.fontsettings = self.w.outputtext.getfontsettings()
331 prefs.output.tabsettings = self.w.outputtext.gettabsettings()
332 prefs.save()
333
334 def dofontsettings(self):
335 import FontSettings
336 settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
337 self.w.outputtext.gettabsettings())
338 if settings:
339 fontsettings, tabsettings = settings
340 self.w.outputtext.setfontsettings(fontsettings)
341 self.w.outputtext.settabsettings(tabsettings)
342
343 def clearbuffer(self):
Jack Jansen5a6fdcd2001-08-25 12:15:04 +0000344 from Carbon import Res
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000345 self.w.outputtext.set('')
346
347 def activate(self, onoff):
348 if onoff:
349 self.closed = 0
350
351 def close(self):
352 self.w.show(0)
353 self.closed = 1
354 return -1
355
356
357class SimpleStdin:
358
359 def readline(self):
360 import EasyDialogs
Jack Jansendac238b2001-05-26 20:01:41 +0000361 # A trick to make the input dialog box a bit more palatable
362 if hasattr(sys.stdout, '_buf'):
363 prompt = sys.stdout._buf
364 else:
365 prompt = ""
366 if not prompt:
367 prompt = "Stdin input:"
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000368 sys.stdout.flush()
Jack Jansendac238b2001-05-26 20:01:41 +0000369 rv = EasyDialogs.AskString(prompt)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000370 if rv is None:
371 return ""
Just van Rossum226275f2001-12-27 10:29:07 +0000372 rv = rv + "\n" # readline should include line terminator
373 sys.stdout.write(rv) # echo user's reply
374 return rv
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000375
376
377def installconsole(defaultshow = 1):
378 global console
379 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
380 if not prefs.console or not hasattr(prefs.console, 'show'):
381 prefs.console.show = defaultshow
382 if not hasattr(prefs.console, "windowbounds"):
383 prefs.console.windowbounds = (450, 250)
384 if not hasattr(prefs.console, "fontsettings"):
385 prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
386 if not hasattr(prefs.console, "tabsettings"):
387 prefs.console.tabsettings = (32, 0)
388 console = PyConsole(prefs.console.windowbounds, prefs.console.show,
389 prefs.console.fontsettings, prefs.console.tabsettings, 1)
390
391def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
392 global output
393
394 # quick 'n' dirty std in emulation
395 sys.stdin = SimpleStdin()
396
397 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
398 if not prefs.output or not hasattr(prefs.output, 'show'):
399 prefs.output.show = defaultshow
400 if not hasattr(prefs.output, "windowbounds"):
401 prefs.output.windowbounds = (450, 250)
402 if not hasattr(prefs.output, "fontsettings"):
403 prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
404 if not hasattr(prefs.output, "tabsettings"):
405 prefs.output.tabsettings = (32, 0)
406 output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
407 prefs.output.fontsettings, prefs.output.tabsettings)