blob: cb38411a3b3611c1bc044200870a0a8c16592553 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
2
David Scherer7aced172000-08-15 01:13:23 +00003import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00004import os.path
David Scherer7aced172000-08-15 01:13:23 +00005import sys
6import string
7import getopt
8import re
Chui Tey5d2af632002-05-26 13:36:41 +00009import socket
10import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000011import threading
Chui Tey5d2af632002-05-26 13:36:41 +000012import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000013import types
Kurt B. Kaiser0930c432002-12-06 21:45:24 +000014import exceptions
David Scherer7aced172000-08-15 01:13:23 +000015
16import linecache
17from code import InteractiveInterpreter
18
19from Tkinter import *
20import tkMessageBox
21
Tony Lowndsb693f8e2002-12-24 17:21:43 +000022# Preserve 2.2 compatibility for Mac OS X:
23import boolcheck
24
David Scherer7aced172000-08-15 01:13:23 +000025from EditorWindow import EditorWindow, fixwordbreaks
26from FileList import FileList
27from ColorDelegator import ColorDelegator
28from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000029from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000030from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000031import idlever
32
Chui Tey5d2af632002-05-26 13:36:41 +000033import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000034import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000035import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000036
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000037IDENTCHARS = string.ascii_letters + string.digits + "_"
38
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000039try:
40 from signal import SIGTERM
41except ImportError:
42 SIGTERM = 15
43
Chui Tey5d2af632002-05-26 13:36:41 +000044# Change warnings module to write to sys.__stderr__
45try:
46 import warnings
47except ImportError:
48 pass
49else:
50 def idle_showwarning(message, category, filename, lineno):
51 file = sys.__stderr__
52 file.write(warnings.formatwarning(message, category, filename, lineno))
53 warnings.showwarning = idle_showwarning
54
Kurt B. Kaiser81885592002-11-29 22:10:53 +000055def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000056 """Extend linecache.checkcache to preserve the <pyshell#...> entries
57
Kurt B. Kaiser81885592002-11-29 22:10:53 +000058 Rather than repeating the linecache code, patch it to save the pyshell#
59 entries, call the original linecache.checkcache(), and then restore the
60 saved entries. Assigning the orig_checkcache keyword arg freezes its value
61 at definition time to the (original) method linecache.checkcache(), i.e.
62 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000063
64 """
David Scherer7aced172000-08-15 01:13:23 +000065 cache = linecache.cache
66 save = {}
67 for filename in cache.keys():
68 if filename[:1] + filename[-1:] == '<>':
69 save[filename] = cache[filename]
70 orig_checkcache()
71 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000072
Kurt B. Kaiser81885592002-11-29 22:10:53 +000073# Patch linecache.checkcache():
74linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000075
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000076
David Scherer7aced172000-08-15 01:13:23 +000077class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000078 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000079
David Scherer7aced172000-08-15 01:13:23 +000080 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000081 self.breakpoints = []
David Scherer7aced172000-08-15 01:13:23 +000082 apply(EditorWindow.__init__, (self,) + args)
83 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000084 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +000085 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
86
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000087 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
88 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +000089 # whenever a file is changed, restore breakpoints
90 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000091 def filename_changed_hook(old_hook=self.io.filename_change_hook,
92 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +000093 self.restore_file_breaks()
94 old_hook()
95 self.io.set_filename_change_hook(filename_changed_hook)
96
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000097 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
98 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +000099
Chui Teya2adb0f2002-11-04 22:14:54 +0000100 def set_breakpoint(self, lineno):
101 text = self.text
102 filename = self.io.filename
103 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
104 try:
105 i = self.breakpoints.index(lineno)
106 except ValueError: # only add if missing, i.e. do once
107 self.breakpoints.append(lineno)
108 try: # update the subprocess debugger
109 debug = self.flist.pyshell.interp.debugger
110 debug.set_breakpoint_here(filename, lineno)
111 except: # but debugger may not be active right now....
112 pass
113
David Scherer7aced172000-08-15 01:13:23 +0000114 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000115 text = self.text
116 filename = self.io.filename
117 if not filename:
118 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000119 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000120 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000121 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000122
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000123 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000124 text = self.text
125 filename = self.io.filename
126 if not filename:
127 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000128 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000129 lineno = int(float(text.index("insert")))
130 try:
131 self.breakpoints.remove(lineno)
132 except:
133 pass
134 text.tag_remove("BREAK", "insert linestart",\
135 "insert lineend +1char")
136 try:
137 debug = self.flist.pyshell.interp.debugger
138 debug.clear_breakpoint_here(filename, lineno)
139 except:
140 pass
141
142 def clear_file_breaks(self):
143 if self.breakpoints:
144 text = self.text
145 filename = self.io.filename
146 if not filename:
147 text.bell()
148 return
149 self.breakpoints = []
150 text.tag_remove("BREAK", "1.0", END)
151 try:
152 debug = self.flist.pyshell.interp.debugger
153 debug.clear_file_breaks(filename)
154 except:
155 pass
156
Chui Teya2adb0f2002-11-04 22:14:54 +0000157 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000158 "Save breakpoints when file is saved"
159 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
160 # be run. The breaks are saved at that time. If we introduce
161 # a temporary file save feature the save breaks functionality
162 # needs to be re-verified, since the breaks at the time the
163 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000164 # permanent save of the file. Currently, a break introduced
165 # after a save will be effective, but not persistent.
166 # This is necessary to keep the saved breaks synched with the
167 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000168 #
169 # Breakpoints are set as tagged ranges in the text. Certain
170 # kinds of edits cause these ranges to be deleted: Inserting
171 # or deleting a line just before a breakpoint, and certain
172 # deletions prior to a breakpoint. These issues need to be
173 # investigated and understood. It's not clear if they are
174 # Tk issues or IDLE issues, or whether they can actually
175 # be fixed. Since a modified file has to be saved before it is
176 # run, and since self.breakpoints (from which the subprocess
177 # debugger is loaded) is updated during the save, the visible
178 # breaks stay synched with the subprocess even if one of these
179 # unexpected breakpoint deletions occurs.
180 breaks = self.breakpoints
181 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000182 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000183 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000184 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000185 lines = []
186 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000187 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000188 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000189 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000190 self.update_breakpoints()
191 breaks = self.breakpoints
192 if breaks:
193 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000194 new_file.close()
195
196 def restore_file_breaks(self):
197 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000198 filename = self.io.filename
199 if filename is None:
200 return
Chui Tey69371d62002-11-04 23:39:45 +0000201 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000202 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000203 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000204 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000205 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000206 for breakpoint_linenumber in breakpoint_linenumbers:
207 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000208
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 def update_breakpoints(self):
210 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000211 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000212 ranges = text.tag_ranges("BREAK")
213 linenumber_list = self.ranges_to_linenumbers(ranges)
214 self.breakpoints = linenumber_list
215
216 def ranges_to_linenumbers(self, ranges):
217 lines = []
218 for index in range(0, len(ranges), 2):
219 lineno = int(float(ranges[index]))
220 end = int(float(ranges[index+1]))
221 while lineno < end:
222 lines.append(lineno)
223 lineno += 1
224 return lines
225
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000226# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000227# def saved_change_hook(self):
228# "Extend base method - clear breaks if module is modified"
229# if not self.get_saved():
230# self.clear_file_breaks()
231# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000232
233 def _close(self):
234 "Extend base method - clear breaks when module is closed"
235 self.clear_file_breaks()
236 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000237
David Scherer7aced172000-08-15 01:13:23 +0000238
239class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000240 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000241
242 EditorWindow = PyShellEditorWindow
243
244 pyshell = None
245
246 def open_shell(self, event=None):
247 if self.pyshell:
248 self.pyshell.wakeup()
249 else:
250 self.pyshell = PyShell(self)
251 self.pyshell.begin()
252 return self.pyshell
253
254
255class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000256 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000257
Steven M. Gavab77d3432002-03-02 07:16:21 +0000258 def __init__(self):
259 ColorDelegator.__init__(self)
260 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000261
262 def recolorize_main(self):
263 self.tag_remove("TODO", "1.0", "iomark")
264 self.tag_add("SYNC", "1.0", "iomark")
265 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000266
Steven M. Gavab77d3432002-03-02 07:16:21 +0000267 def LoadTagDefs(self):
268 ColorDelegator.LoadTagDefs(self)
269 theme = idleConf.GetOption('main','Theme','name')
270 self.tagdefs.update({
271 "stdin": {'background':None,'foreground':None},
272 "stdout": idleConf.GetHighlight(theme, "stdout"),
273 "stderr": idleConf.GetHighlight(theme, "stderr"),
274 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000275 None: idleConf.GetHighlight(theme, "normal"),
276 })
David Scherer7aced172000-08-15 01:13:23 +0000277
David Scherer7aced172000-08-15 01:13:23 +0000278class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000279 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000280
281 def insert(self, index, chars, tags=None):
282 try:
283 if self.delegate.compare(index, "<", "iomark"):
284 self.delegate.bell()
285 return
286 except TclError:
287 pass
288 UndoDelegator.insert(self, index, chars, tags)
289
290 def delete(self, index1, index2=None):
291 try:
292 if self.delegate.compare(index1, "<", "iomark"):
293 self.delegate.bell()
294 return
295 except TclError:
296 pass
297 UndoDelegator.delete(self, index1, index2)
298
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000299
300class MyRPCClient(rpc.RPCClient):
301
302 def handle_EOF(self):
303 "Override the base class - just re-raise EOFError"
304 raise EOFError
305
306
David Scherer7aced172000-08-15 01:13:23 +0000307class ModifiedInterpreter(InteractiveInterpreter):
308
309 def __init__(self, tkconsole):
310 self.tkconsole = tkconsole
311 locals = sys.modules['__main__'].__dict__
312 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000313 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000314
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000315 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000316 rpcclt = None
317 rpcpid = None
318
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000319 def spawn_subprocess(self):
Tony Lowndsf53dec22002-12-20 04:24:43 +0000320 args = self.build_subprocess_arglist()
Chui Tey5d2af632002-05-26 13:36:41 +0000321 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000322
Tony Lowndsf53dec22002-12-20 04:24:43 +0000323 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000324 w = ['-W' + s for s in sys.warnoptions]
325 # Maybe IDLE is installed and is being accessed via sys.path,
326 # or maybe it's not installed and the idle.py script is being
327 # run from the IDLE source directory.
328 if __name__ == 'idlelib.PyShell':
329 command = "__import__('idlelib.run').run.main()"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000330 else:
Tony Lownds2398d572003-05-13 15:28:21 +0000331 command = "__import__('run').main()"
332 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000333
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000334 def start_subprocess(self):
335 addr = ("localhost", self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000336 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000337 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000338 time.sleep(i)
339 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000340 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000341 break
342 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000343 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000344 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000345 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000346 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000347 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000348 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000349 # Accept the connection from the Python execution server
350 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000351 self.rpcclt.register("stdin", self.tkconsole)
352 self.rpcclt.register("stdout", self.tkconsole.stdout)
353 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000354 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000355 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000356 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000357 self.poll_subprocess()
358
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000359 def restart_subprocess(self):
360 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000361 debug = self.getdebugger()
362 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000363 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000364 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000365 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
366 except:
367 pass
368 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000369 self.rpcclt.close()
370 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000371 console = self.tkconsole
372 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000373 self.spawn_subprocess()
374 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000375 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000376 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000377 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000378 halfbar = ((int(console.width) - 16) // 2) * '='
379 console.write(halfbar + ' RESTART ' + halfbar)
380 console.text.mark_set("restart", "end-1c")
381 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000382 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000383 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000384 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000385 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000386 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000387 # reload remote debugger breakpoints for all PyShellEditWindows
388 debug.load_breakpoints()
389
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000390 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000391 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000392
393 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000394 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000395
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000396 def kill_subprocess(self):
397 self.rpcclt.close()
398 self.unix_terminate()
399 self.tkconsole.executing = False
400 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000401
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000402 def unix_terminate(self):
403 "UNIX: make sure subprocess is terminated and collect status"
404 if hasattr(os, 'kill'):
405 try:
406 os.kill(self.rpcpid, SIGTERM)
407 except OSError:
408 # process already terminated:
409 return
410 else:
411 try:
412 os.waitpid(self.rpcpid, 0)
413 except OSError:
414 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000415
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000416 def transfer_path(self):
417 self.runcommand("""if 1:
418 import sys as _sys
419 _sys.path = %s
420 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000421 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
422 __builtins__.quit = __builtins__.exit = _msg
423 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000424 \n""" % `sys.path`)
425
Chui Tey5d2af632002-05-26 13:36:41 +0000426 active_seq = None
427
428 def poll_subprocess(self):
429 clt = self.rpcclt
430 if clt is None:
431 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000432 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000433 response = clt.pollresponse(self.active_seq, wait=0.05)
434 except (EOFError, IOError, KeyboardInterrupt):
435 # lost connection or subprocess terminated itself, restart
436 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000437 if self.tkconsole.closing:
438 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000439 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000440 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000441 if response:
442 self.tkconsole.resetoutput()
443 self.active_seq = None
444 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000445 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000446 if how == "OK":
447 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000448 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000449 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000450 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
451 self.remote_stack_viewer()
452 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000453 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
454 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000455 print >>console, errmsg, what
456 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000457 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000458 # Reschedule myself
459 if not self.tkconsole.closing:
460 self.tkconsole.text.after(self.tkconsole.pollinterval,
461 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000462
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000463 debugger = None
464
465 def setdebugger(self, debugger):
466 self.debugger = debugger
467
468 def getdebugger(self):
469 return self.debugger
470
Chui Tey5d2af632002-05-26 13:36:41 +0000471 def remote_stack_viewer(self):
472 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000473 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000474 if oid is None:
475 self.tkconsole.root.bell()
476 return
477 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
478 from TreeWidget import ScrolledCanvas, TreeNode
479 top = Toplevel(self.tkconsole.root)
480 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
481 sc.frame.pack(expand=1, fill="both")
482 node = TreeNode(sc.canvas, None, item)
483 node.expand()
484 # XXX Should GC the remote tree when closing the window
485
David Scherer7aced172000-08-15 01:13:23 +0000486 gid = 0
487
488 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000489 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000490 filename = self.stuffsource(source)
491 self.execfile(filename, source)
492
493 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000494 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000495 if source is None:
496 source = open(filename, "r").read()
497 try:
498 code = compile(source, filename, "exec")
499 except (OverflowError, SyntaxError):
500 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000501 tkerr = self.tkconsole.stderr
502 print>>tkerr, '*** Error in script or command!\n'
503 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000504 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000505 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000506 else:
507 self.runcode(code)
508
509 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000510 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000511 filename = self.stuffsource(source)
512 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000513 self.save_warnings_filters = warnings.filters[:]
514 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000515 if isinstance(source, types.UnicodeType):
516 import IOBinding
517 try:
518 source = source.encode(IOBinding.encoding)
519 except UnicodeError:
520 self.tkconsole.resetoutput()
521 self.write("Unsupported characters in input")
522 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000523 try:
524 return InteractiveInterpreter.runsource(self, source, filename)
525 finally:
526 if self.save_warnings_filters is not None:
527 warnings.filters[:] = self.save_warnings_filters
528 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000529
530 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000531 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000532 filename = "<pyshell#%d>" % self.gid
533 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000534 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000535 linecache.cache[filename] = len(source)+1, 0, lines, filename
536 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000537
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000538 def prepend_syspath(self, filename):
539 "Prepend sys.path with file's directory if not already included"
540 self.runcommand("""if 1:
541 _filename = %s
542 import sys as _sys
543 from os.path import dirname as _dirname
544 _dir = _dirname(_filename)
545 if not _dir in _sys.path:
546 _sys.path.insert(0, _dir)
547 del _filename, _sys, _dirname, _dir
548 \n""" % `filename`)
549
David Scherer7aced172000-08-15 01:13:23 +0000550 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000551 """Extend base class method: Add Colorizing
552
553 Color the offending position instead of printing it and pointing at it
554 with a caret.
555
556 """
David Scherer7aced172000-08-15 01:13:23 +0000557 text = self.tkconsole.text
558 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000559 if stuff:
560 msg, lineno, offset, line = stuff
561 if lineno == 1:
562 pos = "iomark + %d chars" % (offset-1)
563 else:
564 pos = "iomark linestart + %d lines + %d chars" % \
565 (lineno-1, offset-1)
566 text.tag_add("ERROR", pos)
567 text.see(pos)
568 char = text.get(pos)
569 if char and char in IDENTCHARS:
570 text.tag_add("ERROR", pos + " wordstart", pos)
571 self.tkconsole.resetoutput()
572 self.write("SyntaxError: %s\n" % str(msg))
573 else:
David Scherer7aced172000-08-15 01:13:23 +0000574 self.tkconsole.resetoutput()
575 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000576 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000577
578 def unpackerror(self):
579 type, value, tb = sys.exc_info()
580 ok = type is SyntaxError
581 if ok:
582 try:
583 msg, (dummy_filename, lineno, offset, line) = value
584 except:
585 ok = 0
586 if ok:
587 return msg, lineno, offset, line
588 else:
589 return None
590
591 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000592 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000593 self.tkconsole.resetoutput()
594 self.checklinecache()
595 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000596 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
597 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000598
599 def checklinecache(self):
600 c = linecache.cache
601 for key in c.keys():
602 if key[:1] + key[-1:] != "<>":
603 del c[key]
604
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000605 def display_executing_dialog(self):
606 tkMessageBox.showerror(
607 "Already executing",
608 "The Python Shell window is already executing a command; "
609 "please wait until it is finished.",
610 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000611
Chui Tey5d2af632002-05-26 13:36:41 +0000612 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000613 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000614 # The code better not raise an exception!
615 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000616 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000617 return 0
618 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000619 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000620 else:
621 exec code in self.locals
622 return 1
623
David Scherer7aced172000-08-15 01:13:23 +0000624 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000625 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000626 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000627 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000628 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000629 if self.save_warnings_filters is not None:
630 warnings.filters[:] = self.save_warnings_filters
631 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000632 debugger = self.debugger
633 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000634 self.tkconsole.beginexecuting()
635 try:
636 if not debugger and self.rpcclt is not None:
637 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
638 (code,), {})
639 elif debugger:
640 debugger.run(code, self.locals)
641 else:
642 exec code in self.locals
643 except SystemExit:
644 if tkMessageBox.askyesno(
645 "Exit?",
646 "Do you want to exit altogether?",
647 default="yes",
648 master=self.tkconsole.text):
649 raise
650 else:
651 self.showtraceback()
652 except:
David Scherer7aced172000-08-15 01:13:23 +0000653 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000654 finally:
655 if not use_subprocess:
656 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000657
658 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000659 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000660 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000661
David Scherer7aced172000-08-15 01:13:23 +0000662class PyShell(OutputWindow):
663
664 shell_title = "Python Shell"
665
666 # Override classes
667 ColorDelegator = ModifiedColorDelegator
668 UndoDelegator = ModifiedUndoDelegator
669
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000670 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000671 menu_specs = [
672 ("file", "_File"),
673 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000674 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000675 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000676 ("windows", "_Windows"),
677 ("help", "_Help"),
678 ]
David Scherer7aced172000-08-15 01:13:23 +0000679
680 # New classes
681 from IdleHistory import History
682
683 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000684 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000685 ms = self.menu_specs
686 if ms[2][0] != "shell":
687 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000688 self.interp = ModifiedInterpreter(self)
689 if flist is None:
690 root = Tk()
691 fixwordbreaks(root)
692 root.withdraw()
693 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000694 #
David Scherer7aced172000-08-15 01:13:23 +0000695 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000696 #
David Scherer7aced172000-08-15 01:13:23 +0000697 import __builtin__
698 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000699 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000700 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000701 #
David Scherer7aced172000-08-15 01:13:23 +0000702 text = self.text
703 text.configure(wrap="char")
704 text.bind("<<newline-and-indent>>", self.enter_callback)
705 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
706 text.bind("<<interrupt-execution>>", self.cancel_callback)
707 text.bind("<<beginning-of-line>>", self.home_callback)
708 text.bind("<<end-of-file>>", self.eof_callback)
709 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000710 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000711 text.bind("<<open-python-shell>>", self.flist.open_shell)
712 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000713 if use_subprocess:
714 text.bind("<<view-restart>>", self.view_restart_mark)
715 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000716 #
David Scherer7aced172000-08-15 01:13:23 +0000717 self.save_stdout = sys.stdout
718 self.save_stderr = sys.stderr
719 self.save_stdin = sys.stdin
Chui Tey5d2af632002-05-26 13:36:41 +0000720 self.stdout = PseudoFile(self, "stdout")
721 self.stderr = PseudoFile(self, "stderr")
David Scherer7aced172000-08-15 01:13:23 +0000722 self.console = PseudoFile(self, "console")
Chui Tey5d2af632002-05-26 13:36:41 +0000723 if not use_subprocess:
724 sys.stdout = self.stdout
725 sys.stderr = self.stderr
726 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000727 #
David Scherer7aced172000-08-15 01:13:23 +0000728 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000729 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000730 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000731 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000732 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000733
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000734 reading = False
735 executing = False
736 canceled = False
737 endoffile = False
738 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000739
740 def toggle_debugger(self, event=None):
741 if self.executing:
742 tkMessageBox.showerror("Don't debug now",
743 "You can only toggle the debugger when idle",
744 master=self.text)
745 self.set_debugger_indicator()
746 return "break"
747 else:
748 db = self.interp.getdebugger()
749 if db:
750 self.close_debugger()
751 else:
752 self.open_debugger()
753
754 def set_debugger_indicator(self):
755 db = self.interp.getdebugger()
756 self.setvar("<<toggle-debugger>>", not not db)
757
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000758 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000759 pass # All we need is the variable
760
761 def close_debugger(self):
762 db = self.interp.getdebugger()
763 if db:
764 self.interp.setdebugger(None)
765 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000766 if self.interp.rpcclt:
767 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000768 self.resetoutput()
769 self.console.write("[DEBUG OFF]\n")
770 sys.ps1 = ">>> "
771 self.showprompt()
772 self.set_debugger_indicator()
773
774 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000775 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000776 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
777 self)
778 else:
779 dbg_gui = Debugger.Debugger(self)
780 self.interp.setdebugger(dbg_gui)
781 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000782 sys.ps1 = "[DEBUG ON]\n>>> "
783 self.showprompt()
784 self.set_debugger_indicator()
785
David Scherer7aced172000-08-15 01:13:23 +0000786 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000787 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000788 self.resetoutput()
789 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000790
791 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000792 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000793 self.executing = 0
794 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000795 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000796
797 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000798 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000799 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000800 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000801 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000802 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000803 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000804 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000805 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000806 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000807 self.closing = True
808 # Wait for poll_subprocess() rescheduling to stop
809 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000810
811 def close2(self):
812 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000813
814 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000815 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000816 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000817 if use_subprocess:
818 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000819 # Restore std streams
820 sys.stdout = self.save_stdout
821 sys.stderr = self.save_stderr
822 sys.stdin = self.save_stdin
823 # Break cycles
824 self.interp = None
825 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000826 self.flist.pyshell = None
827 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000828 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000829
830 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000831 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000832 return True
David Scherer7aced172000-08-15 01:13:23 +0000833
834 def short_title(self):
835 return self.shell_title
836
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000837 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000838 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000839
David Scherer7aced172000-08-15 01:13:23 +0000840 def begin(self):
841 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000842 if use_subprocess:
843 nosub = ''
844 else:
845 nosub = "==== No Subprocess ===="
846 self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000847 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000848 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000849 self.showprompt()
850 import Tkinter
851 Tkinter._default_root = None
852
853 def interact(self):
854 self.begin()
855 self.top.mainloop()
856
857 def readline(self):
858 save = self.reading
859 try:
860 self.reading = 1
861 self.top.mainloop()
862 finally:
863 self.reading = save
864 line = self.text.get("iomark", "end-1c")
865 self.resetoutput()
866 if self.canceled:
867 self.canceled = 0
868 raise KeyboardInterrupt
869 if self.endoffile:
870 self.endoffile = 0
871 return ""
872 return line
873
874 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000875 return True
David Scherer7aced172000-08-15 01:13:23 +0000876
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000877 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000878 try:
879 if self.text.compare("sel.first", "!=", "sel.last"):
880 return # Active selection -- always use default binding
881 except:
882 pass
883 if not (self.executing or self.reading):
884 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000885 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000886 self.showprompt()
887 return "break"
888 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000889 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000890 if self.reading:
891 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000892 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000893 if self.interp.getdebugger():
894 self.interp.restart_subprocess()
895 else:
896 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000897 return "break"
898
899 def eof_callback(self, event):
900 if self.executing and not self.reading:
901 return # Let the default binding (delete next char) take over
902 if not (self.text.compare("iomark", "==", "insert") and
903 self.text.compare("insert", "==", "end-1c")):
904 return # Let the default binding (delete next char) take over
905 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000906 self.resetoutput()
907 self.close()
908 else:
909 self.canceled = 0
910 self.endoffile = 1
911 self.top.quit()
912 return "break"
913
914 def home_callback(self, event):
915 if event.state != 0 and event.keysym == "Home":
916 return # <Modifier-Home>; fall back to class binding
917 if self.text.compare("iomark", "<=", "insert") and \
918 self.text.compare("insert linestart", "<=", "iomark"):
919 self.text.mark_set("insert", "iomark")
920 self.text.tag_remove("sel", "1.0", "end")
921 self.text.see("insert")
922 return "break"
923
924 def linefeed_callback(self, event):
925 # Insert a linefeed without entering anything (still autoindented)
926 if self.reading:
927 self.text.insert("insert", "\n")
928 self.text.see("insert")
929 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000930 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000931 return "break"
932
933 def enter_callback(self, event):
934 if self.executing and not self.reading:
935 return # Let the default binding (insert '\n') take over
936 # If some text is selected, recall the selection
937 # (but only if this before the I/O mark)
938 try:
939 sel = self.text.get("sel.first", "sel.last")
940 if sel:
941 if self.text.compare("sel.last", "<=", "iomark"):
942 self.recall(sel)
943 return "break"
944 except:
945 pass
946 # If we're strictly before the line containing iomark, recall
947 # the current line, less a leading prompt, less leading or
948 # trailing whitespace
949 if self.text.compare("insert", "<", "iomark linestart"):
950 # Check if there's a relevant stdin range -- if so, use it
951 prev = self.text.tag_prevrange("stdin", "insert")
952 if prev and self.text.compare("insert", "<", prev[1]):
953 self.recall(self.text.get(prev[0], prev[1]))
954 return "break"
955 next = self.text.tag_nextrange("stdin", "insert")
956 if next and self.text.compare("insert lineend", ">=", next[0]):
957 self.recall(self.text.get(next[0], next[1]))
958 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000959 # No stdin mark -- just get the current line, less any prompt
960 line = self.text.get("insert linestart", "insert lineend")
961 last_line_of_prompt = sys.ps1.split('\n')[-1]
962 if line.startswith(last_line_of_prompt):
963 line = line[len(last_line_of_prompt):]
964 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000965 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000966 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000967 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000968 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000969 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +0000970 # If we're in the current input and there's only whitespace
971 # beyond the cursor, erase that whitespace first
972 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000973 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +0000974 self.text.delete("insert", "end-1c")
975 # If we're in the current input before its last line,
976 # insert a newline right at the insert point
977 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000978 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000979 return "break"
980 # We're in the last line; append a newline and submit it
981 self.text.mark_set("insert", "end-1c")
982 if self.reading:
983 self.text.insert("insert", "\n")
984 self.text.see("insert")
985 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000986 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000987 self.text.tag_add("stdin", "iomark", "end-1c")
988 self.text.update_idletasks()
989 if self.reading:
990 self.top.quit() # Break out of recursive mainloop() in raw_input()
991 else:
992 self.runit()
993 return "break"
994
995 def recall(self, s):
996 if self.history:
997 self.history.recall(s)
998
999 def runit(self):
1000 line = self.text.get("iomark", "end-1c")
1001 # Strip off last newline and surrounding whitespace.
1002 # (To allow you to hit return twice to end a statement.)
1003 i = len(line)
1004 while i > 0 and line[i-1] in " \t":
1005 i = i-1
1006 if i > 0 and line[i-1] == "\n":
1007 i = i-1
1008 while i > 0 and line[i-1] in " \t":
1009 i = i-1
1010 line = line[:i]
1011 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001012
David Scherer7aced172000-08-15 01:13:23 +00001013 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001014 if self.interp.rpcclt:
1015 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001016 try:
1017 sys.last_traceback
1018 except:
1019 tkMessageBox.showerror("No stack trace",
1020 "There is no stack trace yet.\n"
1021 "(sys.last_traceback is not defined)",
1022 master=self.text)
1023 return
1024 from StackViewer import StackBrowser
1025 sv = StackBrowser(self.root, self.flist)
1026
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001027 def view_restart_mark(self, event=None):
1028 self.text.see("iomark")
1029 self.text.see("restart")
1030
1031 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001032 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001033
David Scherer7aced172000-08-15 01:13:23 +00001034 def showprompt(self):
1035 self.resetoutput()
1036 try:
1037 s = str(sys.ps1)
1038 except:
1039 s = ""
1040 self.console.write(s)
1041 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001042 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001043 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001044
1045 def resetoutput(self):
1046 source = self.text.get("iomark", "end-1c")
1047 if self.history:
1048 self.history.history_store(source)
1049 if self.text.get("end-2c") != "\n":
1050 self.text.insert("end-1c", "\n")
1051 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001052 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001053 sys.stdout.softspace = 0
1054
1055 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001056 try:
1057 self.text.mark_gravity("iomark", "right")
1058 OutputWindow.write(self, s, tags, "iomark")
1059 self.text.mark_gravity("iomark", "left")
1060 except:
1061 pass
David Scherer7aced172000-08-15 01:13:23 +00001062 if self.canceled:
1063 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001064 if not use_subprocess:
1065 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001066
1067class PseudoFile:
1068
1069 def __init__(self, shell, tags):
1070 self.shell = shell
1071 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001072 self.softspace = 0
David Scherer7aced172000-08-15 01:13:23 +00001073
1074 def write(self, s):
1075 self.shell.write(s, self.tags)
1076
1077 def writelines(self, l):
1078 map(self.write, l)
1079
1080 def flush(self):
1081 pass
1082
1083 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001084 return True
David Scherer7aced172000-08-15 01:13:23 +00001085
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001086
David Scherer7aced172000-08-15 01:13:23 +00001087usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001088
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001089USAGE: idle [-deins] [-t title] [file]*
1090 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1091 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001092
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001093 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001094 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001095
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001096The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001097
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001098 -e open an edit window
1099 -i open a shell window
1100
1101The following options imply -i and will open a shell:
1102
1103 -c cmd run the command in a shell, or
1104 -r file run script from file
1105
1106 -d enable the debugger
1107 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1108 -t title set title of shell window
1109
1110A default edit window will be bypassed when -c, -r, or - are used.
1111
1112[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1113
1114Examples:
1115
1116idle
1117 Open an edit window or shell depending on IDLE's configuration.
1118
1119idle foo.py foobar.py
1120 Edit the files, also open a shell if configured to start with shell.
1121
1122idle -est "Baz" foo.py
1123 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1124 window with the title "Baz".
1125
1126idle -c "import sys; print sys.argv" "foo"
1127 Open a shell window and run the command, passing "-c" in sys.argv[0]
1128 and "foo" in sys.argv[1].
1129
1130idle -d -s -r foo.py "Hello World"
1131 Open a shell window, run a startup script, enable the debugger, and
1132 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1133 sys.argv[1].
1134
1135echo "import sys; print sys.argv" | idle - "foobar"
1136 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1137 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001138"""
1139
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001140def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001141 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001142
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001143 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001144 enable_shell = False
1145 enable_edit = False
1146 debug = False
1147 cmd = None
1148 script = None
1149 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001150 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001151 sys.ps1
1152 except AttributeError:
1153 sys.ps1 = '>>> '
1154 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001155 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001156 except getopt.error, msg:
1157 sys.stderr.write("Error: %s\n" % str(msg))
1158 sys.stderr.write(usage_msg)
1159 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001160 for o, a in opts:
1161 if o == '-c':
1162 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001163 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001164 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001165 debug = True
1166 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001167 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001168 enable_edit = True
1169 if o == '-h':
1170 sys.stdout.write(usage_msg)
1171 sys.exit()
1172 if o == '-i':
1173 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001174 if o == '-n':
1175 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001176 if o == '-r':
1177 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001178 if os.path.isfile(script):
1179 pass
1180 else:
1181 print "No script file: ", script
1182 sys.exit()
1183 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001184 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001185 startup = True
1186 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001187 if o == '-t':
1188 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001189 enable_shell = True
1190 if args and args[0] == '-':
1191 cmd = sys.stdin.read()
1192 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001193 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001194 for i in range(len(sys.path)):
1195 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001196 if args and args[0] == '-':
1197 sys.argv = [''] + args[1:]
1198 elif cmd:
1199 sys.argv = ['-c'] + args
1200 elif script:
1201 sys.argv = [script] + args
1202 elif args:
1203 enable_edit = True
1204 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001205 for filename in args:
1206 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001207 for dir in pathx:
1208 dir = os.path.abspath(dir)
1209 if not dir in sys.path:
1210 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001211 else:
1212 dir = os.getcwd()
1213 if not dir in sys.path:
1214 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001215 # check the IDLE settings configuration (but command line overrides)
1216 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001217 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001218 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001219 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001220 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001221 root = Tk(className="Idle")
1222 fixwordbreaks(root)
1223 root.withdraw()
1224 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001225 if enable_edit:
1226 if not (cmd or script):
1227 for filename in args:
1228 flist.open(filename)
1229 if not args:
1230 flist.new()
1231 if enable_shell:
1232 flist.open_shell()
1233 elif enable_shell:
1234 flist.pyshell = PyShell(flist)
1235 flist.pyshell.begin()
1236 shell = flist.pyshell
1237 # handle remaining options:
1238 if debug:
1239 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001240 if startup:
1241 filename = os.environ.get("IDLESTARTUP") or \
1242 os.environ.get("PYTHONSTARTUP")
1243 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001244 shell.interp.execfile(filename)
1245 if cmd or script:
1246 shell.interp.runcommand("""if 1:
1247 import sys as _sys
1248 _sys.argv = %s
1249 del _sys
1250 \n""" % `sys.argv`)
1251 if cmd:
1252 shell.interp.execsource(cmd)
1253 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001254 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001255 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001256 root.mainloop()
1257 root.destroy()
1258
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001259
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001260def display_port_binding_error():
1261 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001262\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001263
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001264IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1265its Python execution server. IDLE is unable to bind to this port, and so
1266cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001267
1268 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001269 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001270 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001271
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001272Run IDLE with the -n command line switch to start without a subprocess
1273and refer to Help/IDLE Help "Running without a subprocess" for further
1274details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001275"""
David Scherer7aced172000-08-15 01:13:23 +00001276
1277if __name__ == "__main__":
1278 main()