blob: b8d6489487fa78af00661790c3706494b040b31e [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'):
Tim Peters182b5ac2004-07-18 06:16:08 +000017 sys.ps1 = '>>> '
Just van Rossum40f9b7b1999-01-30 22:39:17 +000018if not hasattr(sys, 'ps2'):
Tim Peters182b5ac2004-07-18 06:16:08 +000019 sys.ps2 = '... '
Just van Rossum40f9b7b1999-01-30 22:39:17 +000020
Tim Peters182b5ac2004-07-18 06:16:08 +000021def 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)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000025
26class ConsoleTextWidget(W.EditText):
Tim Peters182b5ac2004-07-18 06:16:08 +000027
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):
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()
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")
79 if hasattr(MacOS, 'EnableAppswitch'):
80 saveyield = MacOS.EnableAppswitch(0)
81 self._scriptDone = False
82 if sys.platform == "darwin":
83 # see identical construct in PyEdit.py
84 from threading import Thread
85 t = Thread(target=self._userCancelledMonitor,
86 name="UserCancelledMonitor")
87 t.start()
88 try:
89 self.pyinteractive.executeline(text, self, self._namespace)
90 finally:
91 self._scriptDone = True
92 if hasattr(MacOS, 'EnableAppswitch'):
93 MacOS.EnableAppswitch(saveyield)
94 selstart, selend = self.getselection()
95 self._inputstart = selstart
96
97 def _userCancelledMonitor(self):
98 # XXX duplicate code from PyEdit.py
99 import time, os
100 from signal import SIGINT
101 from Carbon import Evt
102 while not self._scriptDone:
103 if Evt.CheckEventQueueForUserCancel():
104 # Send a SIGINT signal to ourselves.
105 # This gets delivered to the main thread,
106 # cancelling the running script.
107 os.kill(os.getpid(), SIGINT)
108 break
109 time.sleep(0.25)
110
111 def domenu_save_as(self, *args):
112 filename = EasyDialogs.AskFileForSave(message='Save console text as:',
113 savedFileName='console.txt')
114 if not filename:
115 return
116 f = open(filename, 'wb')
117 f.write(self.get())
118 f.close()
119 MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
120
121 def write(self, text):
122 self._buf = self._buf + text
123 if '\n' in self._buf:
124 self.flush()
125
126 def flush(self):
127 stuff = string.split(self._buf, '\n')
128 stuff = string.join(stuff, '\r')
129 self.setselection_at_end()
130 try:
131 self.ted.WEInsert(stuff, None, None)
132 finally:
133 self._buf = ""
134 selstart, selend = self.getselection()
135 self._inputstart = selstart
136 self.ted.WEClearUndo()
137 self.updatescrollbars()
138 if self._parentwindow.wid.GetWindowPort().QDIsPortBuffered():
139 self._parentwindow.wid.GetWindowPort().QDFlushPortBuffer(None)
140
141 def selection_ok(self):
142 selstart, selend = self.getselection()
143 return not (selstart < self._inputstart or selend < self._inputstart)
144
145 def checkselection(self):
146 if not self.selection_ok():
147 self.setselection_at_end()
148
149 def setselection_at_end(self):
150 end = self.ted.WEGetTextLength()
151 self.setselection(end, end)
152 self.updatescrollbars()
153
154 def domenu_cut(self, *args):
155 if not self.selection_ok():
156 return
157 W.EditText.domenu_cut(self)
158
159 def domenu_paste(self, *args):
160 if not self.selection_ok():
161 self.setselection_at_end()
162 W.EditText.domenu_paste(self)
163
164 def domenu_clear(self, *args):
165 if not self.selection_ok():
166 return
167 W.EditText.domenu_clear(self)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000168
169
170class PyConsole(W.Window):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000171
Tim Peters182b5ac2004-07-18 06:16:08 +0000172 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
173 tabsettings = (32, 0), unclosable = 0):
174 W.Window.__init__(self,
175 bounds,
176 "Python Interactive",
177 minsize = (200, 100),
178 tabbable = 0,
179 show = show)
180
181 self._unclosable = unclosable
182 consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
183 fontsettings = fontsettings, tabsettings = tabsettings)
184 self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
185 self.consoletext = consoletext
186 self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
187 self.namespacemenu.bind('<click>', self.makenamespacemenu)
188 self.open()
189
190 def makenamespacemenu(self, *args):
191 W.SetCursor('watch')
192 namespacelist = self.getnamespacelist()
193 self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
194 ["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
195 currentname = self.consoletext._namespace["__name__"]
196 for i in range(len(namespacelist)):
197 if namespacelist[i][0] == currentname:
198 break
199 else:
200 return
201 # XXX this functionality should be generally available in Wmenus
202 submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
203 menu = self.namespacemenu.menu.bar.menus[submenuid]
204 menu.menu.CheckMenuItem(i + 1, 1)
205
206 def browsenamespace(self):
207 import PyBrowser, W
208 W.SetCursor('watch')
209 PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
210
211 def clearbuffer(self):
212 from Carbon import Res
213 self.consoletext.ted.WEUseText(Res.Resource(''))
214 self.consoletext.write(sys.ps1)
215 self.consoletext.flush()
216
217 def getnamespacelist(self):
218 import os
219 import __main__
220 editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
221
222 namespaces = [ ("__main__",__main__.__dict__) ]
223 for ed in editors:
224 modname = os.path.splitext(ed.title)[0]
225 if sys.modules.has_key(modname):
226 module = sys.modules[modname]
227 namespaces.append((modname, module.__dict__))
228 else:
229 if ed.title[-3:] == '.py':
230 modname = ed.title[:-3]
231 else:
232 modname = ed.title
233 ed.globals["__name__"] = modname
234 namespaces.append((modname, ed.globals))
235 return namespaces
236
237 def dofontsettings(self):
238 import FontSettings
239 settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
240 self.consoletext.gettabsettings())
241 if settings:
242 fontsettings, tabsettings = settings
243 self.consoletext.setfontsettings(fontsettings)
244 self.consoletext.settabsettings(tabsettings)
245
246 def show(self, onoff = 1):
247 W.Window.show(self, onoff)
248 if onoff:
249 self.select()
250
251 def close(self):
252 if self._unclosable:
253 self.show(0)
254 return -1
255 W.Window.close(self)
256
257 def writeprefs(self):
258 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
259 prefs.console.show = self.isvisible()
260 prefs.console.windowbounds = self.getbounds()
261 prefs.console.fontsettings = self.consoletext.getfontsettings()
262 prefs.console.tabsettings = self.consoletext.gettabsettings()
263 prefs.save()
264
265 def getselectedtext(self):
266 return self.consoletext.getselectedtext()
267
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000268class OutputTextWidget(W.EditText):
Tim Peters182b5ac2004-07-18 06:16:08 +0000269
270 def domenu_save_as(self, *args):
271 title = self._parentwindow.gettitle()
272 filename = EasyDialogs.AskFileForSave(message='Save %s text as:' % title,
273 savedFileName=title + '.txt')
274 if not filename:
275 return
276 f = open(filename, 'wb')
277 f.write(self.get())
278 f.close()
279 MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
280
281 def domenu_cut(self, *args):
282 self.domenu_copy(*args)
283
284 def domenu_clear(self, *args):
285 self.set('')
Just van Rossum7a503a42003-01-20 09:02:23 +0000286
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000287
288class PyOutput:
Tim Peters182b5ac2004-07-18 06:16:08 +0000289
290 def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
291 self.bounds = bounds
292 self.fontsettings = fontsettings
293 self.tabsettings = tabsettings
294 self.w = None
295 self.closed = 1
296 self._buf = ''
297 # should be able to set this
298 self.savestdout, self.savestderr = sys.stdout, sys.stderr
299 sys.stderr = sys.stdout = self
300 if show:
301 self.show()
302
303 def setupwidgets(self):
304 self.w = W.Window(self.bounds, "Output",
305 minsize = (200, 100),
306 tabbable = 0)
307 self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
308 fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
309 menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
310 self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
311
312 self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
313 self.w.bind("<close>", self.close)
314 self.w.bind("<activate>", self.activate)
315
316 def write(self, text):
317 if hasattr(MacOS, 'EnableAppswitch'):
318 oldyield = MacOS.EnableAppswitch(-1)
319 try:
320 self._buf = self._buf + text
321 if '\n' in self._buf:
322 self.flush()
323 finally:
324 if hasattr(MacOS, 'EnableAppswitch'):
325 MacOS.EnableAppswitch(oldyield)
326
327 def flush(self):
328 self.show()
329 stuff = string.split(self._buf, '\n')
330 stuff = string.join(stuff, '\r')
331 end = self.w.outputtext.ted.WEGetTextLength()
332 self.w.outputtext.setselection(end, end)
333 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
334 try:
335 self.w.outputtext.ted.WEInsert(stuff, None, None)
336 finally:
337 self._buf = ""
338 self.w.outputtext.updatescrollbars()
339 self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
340 if self.w.wid.GetWindowPort().QDIsPortBuffered():
341 self.w.wid.GetWindowPort().QDFlushPortBuffer(None)
342
343 def show(self):
344 if self.closed:
345 if not self.w:
346 self.setupwidgets()
347 self.w.open()
348 self.w.outputtext.updatescrollbars()
349 self.closed = 0
350 else:
351 self.w.show(1)
352 self.closed = 0
353 self.w.select()
354
355 def writeprefs(self):
356 if self.w is not None:
357 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
358 prefs.output.show = self.w.isvisible()
359 prefs.output.windowbounds = self.w.getbounds()
360 prefs.output.fontsettings = self.w.outputtext.getfontsettings()
361 prefs.output.tabsettings = self.w.outputtext.gettabsettings()
362 prefs.save()
363
364 def dofontsettings(self):
365 import FontSettings
366 settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
367 self.w.outputtext.gettabsettings())
368 if settings:
369 fontsettings, tabsettings = settings
370 self.w.outputtext.setfontsettings(fontsettings)
371 self.w.outputtext.settabsettings(tabsettings)
372
373 def clearbuffer(self):
374 from Carbon import Res
375 self.w.outputtext.set('')
376
377 def activate(self, onoff):
378 if onoff:
379 self.closed = 0
380
381 def close(self):
382 self.w.show(0)
383 self.closed = 1
384 return -1
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000385
386
387class SimpleStdin:
Tim Peters182b5ac2004-07-18 06:16:08 +0000388
389 def readline(self):
390 import EasyDialogs
391 # A trick to make the input dialog box a bit more palatable
392 if hasattr(sys.stdout, '_buf'):
393 prompt = sys.stdout._buf
394 else:
395 prompt = ""
396 if not prompt:
397 prompt = "Stdin input:"
398 sys.stdout.flush()
399 rv = EasyDialogs.AskString(prompt)
400 if rv is None:
401 return ""
402 rv = rv + "\n" # readline should include line terminator
403 sys.stdout.write(rv) # echo user's reply
404 return rv
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000405
406
407def installconsole(defaultshow = 1):
Tim Peters182b5ac2004-07-18 06:16:08 +0000408 global console
409 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
410 if not prefs.console or not hasattr(prefs.console, 'show'):
411 prefs.console.show = defaultshow
412 if not hasattr(prefs.console, "windowbounds"):
413 prefs.console.windowbounds = (450, 250)
414 if not hasattr(prefs.console, "fontsettings"):
415 prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
416 if not hasattr(prefs.console, "tabsettings"):
417 prefs.console.tabsettings = (32, 0)
418 console = PyConsole(prefs.console.windowbounds, prefs.console.show,
419 prefs.console.fontsettings, prefs.console.tabsettings, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000420
421def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
Tim Peters182b5ac2004-07-18 06:16:08 +0000422 global output
423
424 # quick 'n' dirty std in emulation
425 sys.stdin = SimpleStdin()
426
427 prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
428 if not prefs.output or not hasattr(prefs.output, 'show'):
429 prefs.output.show = defaultshow
430 if not hasattr(prefs.output, "windowbounds"):
431 prefs.output.windowbounds = (450, 250)
432 if not hasattr(prefs.output, "fontsettings"):
433 prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
434 if not hasattr(prefs.output, "tabsettings"):
435 prefs.output.tabsettings = (32, 0)
436 output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
437 prefs.output.fontsettings, prefs.output.tabsettings)